about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-02-19 12:38:15 +0100
committerbptato <nincsnevem662@gmail.com>2022-02-19 12:44:01 +0100
commit7d80da8a8e40c591d0dbceb4d0c79ca6dab16917 (patch)
tree03999396581ac4b0a2d23882b9241448fb92ce2d
parent1aec6113a6dbae0878f849675ec9d1417cb6a787 (diff)
downloadchawan-7d80da8a8e40c591d0dbceb4d0c79ca6dab16917.tar.gz
Reduce formatting complexity
Formatting based on cells instead of bytes. No clue why I'd ever thought
the latter would be a good idea.
This fixes background colors too. I think.
-rw-r--r--src/io/buffer.nim37
-rw-r--r--src/io/cell.nim10
-rw-r--r--src/render/renderdocument.nim155
-rw-r--r--src/render/rendertext.nim4
4 files changed, 79 insertions, 127 deletions
diff --git a/src/io/buffer.nim b/src/io/buffer.nim
index 85b59620..c309682e 100644
--- a/src/io/buffer.nim
+++ b/src/io/buffer.nim
@@ -308,22 +308,22 @@ proc refreshDisplay(buffer: Buffer) =
 
     let dls = y * buffer.width
     var k = 0
-    var cf = line.findFormat(i)
-    var nf = line.findNextFormat(i)
+    var cf = line.findFormat(w)
+    var nf = line.findNextFormat(w)
     if w > buffer.fromx:
       while k < w - buffer.fromx:
         buffer.display[dls + k].runes.add(Rune(' '))
         inc k
 
     while i < line.str.len:
-      let j = i
+      let pw = w
       fastRuneAt(line.str, i, r)
       w += r.width()
       if w > buffer.fromx + buffer.width:
         break
-      if nf.pos != -1 and nf.pos <= j:
+      if nf.pos != -1 and nf.pos <= pw:
         cf = nf
-        nf = line.findNextFormat(j)
+        nf = line.findNextFormat(pw)
       buffer.display[dls + k].runes.add(r)
       if cf.pos != -1:
         buffer.display[dls + k].format = cf.format
@@ -483,7 +483,7 @@ proc cursorPrevWord*(buffer: Buffer) =
 
 proc cursorNextLink*(buffer: Buffer) =
   let line = buffer.lines[buffer.cursory]
-  var i = line.findFormatN(buffer.currentCursorBytes()) - 1
+  var i = line.findFormatN(buffer.cursorx) - 1
   var link: Element = nil
   if i >= 0:
     link = line.formats[i].node.getClickable()
@@ -493,7 +493,7 @@ proc cursorNextLink*(buffer: Buffer) =
     let format = line.formats[i]
     let fl = format.node.getClickable()
     if fl != nil and fl != link:
-      buffer.setCursorXB(format.pos)
+      buffer.setCursorX(format.pos)
       return
     inc i
 
@@ -504,13 +504,13 @@ proc cursorNextLink*(buffer: Buffer) =
       let format = line.formats[i]
       let fl = format.node.getClickable()
       if fl != nil and fl != link:
-        buffer.setCursorXBY(format.pos, y)
+        buffer.setCursorXY(format.pos, y)
         return
       inc i
 
 proc cursorPrevLink*(buffer: Buffer) =
   let line = buffer.lines[buffer.cursory]
-  var i = line.findFormatN(buffer.currentCursorBytes()) - 1
+  var i = line.findFormatN(buffer.cursorx) - 1
   var link: Element = nil
   if i >= 0:
     link = line.formats[i].node.getClickable()
@@ -520,7 +520,7 @@ proc cursorPrevLink*(buffer: Buffer) =
     let format = line.formats[i]
     let fl = format.node.getClickable()
     if fl != nil and fl != link:
-      buffer.setCursorXB(format.pos)
+      buffer.setCursorX(format.pos)
       return
     dec i
 
@@ -544,7 +544,7 @@ proc cursorPrevLink*(buffer: Buffer) =
               ly = iy
               lx = format.pos
             dec i
-        buffer.setCursorXBY(lx, ly)
+        buffer.setCursorXY(lx, ly)
         return
       dec i
 
@@ -665,7 +665,7 @@ proc gotoAnchor*(buffer: Buffer) =
       if anchor in format.node:
         buffer.setCursorY(y)
         buffer.centerLine()
-        buffer.setCursorXB(format.pos)
+        buffer.setCursorX(format.pos)
         return
       inc i
 
@@ -1051,11 +1051,18 @@ proc drawBuffer*(buffer: Buffer) =
       print(line.str & '\n')
     else:
       var x = 0
+      var i = 0
       for f in line.formats:
-        print(line.str.substr(x, f.pos - 1))
+        var outstr = ""
+        assert f.pos < line.str.width(), "fpos " & $f.pos & "\nstr" & line.str & "\n"
+        while x < f.pos:
+          var r: Rune
+          fastRuneAt(line.str, i, r)
+          outstr &= r
+          x += r.width()
+        print(outstr)
         print(format.processFormat(f.format))
-        x = f.pos
-      print(line.str.substr(x, line.str.len))
+      print(line.str.substr(i))
       print(format.processFormat(newFormat()))
       print('\n')
 
diff --git a/src/io/cell.nim b/src/io/cell.nim
index af142967..abcb8f92 100644
--- a/src/io/cell.nim
+++ b/src/io/cell.nim
@@ -142,9 +142,13 @@ proc addLine*(grid: var FlexibleGrid) =
 proc addFormat*(line: var FlexibleLine, pos: int, format: Format) =
   line.formats.add(FormatCell(format: format, pos: line.str.len))
 
-proc addFormat*(grid: var FlexibleGrid, y, pos: int, format: Format, computed: ComputedFormat = nil, node: Node = nil) =
-  if computed == nil or grid[y].formats.len == 0 or grid[y].formats[^1].computed != computed:
-    grid[y].formats.add(FormatCell(format: format, node: node, computed: computed, pos: pos))
+proc addFormat*(line: var FlexibleLine, pos: int, format: Format, computed: ComputedFormat) =
+  if computed != nil and line.formats.len > 0 and line.formats[^1].computed == computed and line.formats[^1].format.bgcolor != format.bgcolor:
+    return
+  if computed == nil:
+    line.formats.add(FormatCell(format: format, pos: pos))
+  else:
+    line.formats.add(FormatCell(format: format, computed: computed, node: computed.node, pos: pos))
 
 template inc_check(i: int) =
   inc i
diff --git a/src/render/renderdocument.nim b/src/render/renderdocument.nim
index 983999a9..ab7c906e 100644
--- a/src/render/renderdocument.nim
+++ b/src/render/renderdocument.nim
@@ -18,81 +18,39 @@ func formatFromWord(computed: ComputedFormat): Format =
     result.italic = true
   if computed.fontweight > 500:
     result.bold = true
-  if computed.textdecoration == TEXT_DECORATION_UNDERLINE:
+  case computed.textdecoration
+  of TEXT_DECORATION_UNDERLINE:
     result.underline = true
-  if computed.textdecoration == TEXT_DECORATION_OVERLINE:
+  of TEXT_DECORATION_OVERLINE:
     result.overline = true
-  if computed.textdecoration == TEXT_DECORATION_LINE_THROUGH:
+  of TEXT_DECORATION_LINE_THROUGH:
     result.strike = true
-  if computed.textdecoration == TEXT_DECORATION_BLINK:
+  of TEXT_DECORATION_BLINK:
     result.blink = true
+  else: discard
 
-#TODO format.pos signifying byte instead of actual position was a huge
-# mistake...
-proc setFormats(lines: var FlexibleGrid, y, ox, i: int, nx, cx: var int,
-                newformat: Format, oformats: seq[FormatCell],
-                str, ostr: string, computed: ComputedFormat = nil) {.inline.} =
+proc setFormats(line: var FlexibleLine, ox, newwidth, oldwidth: int,
+                newformat: Format, oformats: seq[FormatCell], computed: ComputedFormat = nil) {.inline.} =
   let obg = newformat.bgcolor
-  let newstrwidth = str.width()
   var newformat = newformat
-  var osi = 0
-  var nsi = 0
   for format in oformats:
-    assert i + ostr.len > format.pos
-    # move cx to format.pos
-    while i + osi < format.pos:
-      var r: Rune
-      fastRuneAt(ostr, osi, r)
-      cx += r.width()
-
-    if cx > newstrwidth + ox:
-      # last oformat starts after newformat ends
-      nx = ox + newstrwidth
-      eprint "ret"
-      return
-
-    if osi >= ostr.len:
-      # I don't even know anymore
-      break
-
-    # move nx to cx
-    while nsi < str.len and nx < cx:
-      var r: Rune
-      fastRuneAt(str, nsi, r)
-      nx += r.width()
-
+    assert format.pos < ox + oldwidth
     if format.format.bgcolor != newformat.bgcolor:
       newformat.bgcolor = format.format.bgcolor
-      eprint "odd", i + nsi, newformat.bgcolor, ox, nx
-      if computed == nil:
-        lines.addFormat(y, i + nsi, newformat)
-      else:
-        # have to pass nil to force new format... TODO?
-        lines.addFormat(y, i + nsi, newformat, nil, computed.node)
 
-  eprint "end", ostr, "->", str, obg, nsi
-  # last oformat starts before newformat ends
-
-  # move cx to last old char
-  while osi < ostr.len:
-    var r: Rune
-    fastRuneAt(ostr, osi, r)
-    cx += r.width()
-
-  # move nx to cx
-  while nsi < str.len and nx < cx:
-    var r: Rune
-    fastRuneAt(str, nsi, r)
-    nx += r.width()
+      if format.pos < ox:
+        line.addFormat(ox, newformat, computed)
+      else:
+        line.addFormat(format.pos, newformat, computed)
 
-  if nsi < str.len:
+  if ox + oldwidth < ox + newwidth:
     newformat.bgcolor = obg
-    eprint "add", str, ":", i + nsi
-    if computed == nil:
-      lines.addFormat(y, i + nsi, newformat)
+
+    #TODO this is probably a workaround for a bug...
+    if line.formats.len > 0 and line.formats[^1].pos == ox + oldwidth:
+      line.formats[^1].format.bgcolor = obg
     else:
-      lines.addFormat(y, i + nsi, newformat, computed, computed.node)
-    nx = ox + newstrwidth
+      line.addFormat(ox + oldwidth, newformat, computed)
 
 proc setText(lines: var FlexibleGrid, linestr: string, format: ComputedFormat, x, y: int) {.inline.} =
   var r: Rune
@@ -113,24 +71,25 @@ proc setText(lines: var FlexibleGrid, linestr: string, format: ComputedFormat, x
   lines[y].setLen(i)
 
   var nx = cx
-  let ox = cx
+  let oldstrwidth = ostr.width()
   if nx < x:
     let spacelength = x - nx
     var spaceformat = newFormat()
     let str = ' '.repeat(spacelength)
-    lines.setFormats(y, ox, i, nx, cx, spaceformat, oformats, str, ostr)
+    lines[y].setFormats(nx, spacelength, oldstrwidth, spaceformat, oformats)
 
     lines[y].str &= str
     i += spacelength
-    assert nx == x
+    nx = x
 
   var wordformat = format.formatFromWord()
-  lines.setFormats(y, x, i, nx, cx, wordformat, oformats, linestr, ostr, format)
+  let newstrwidth = linestr.width()
+  lines[y].setFormats(nx, newstrwidth, oldstrwidth, wordformat, oformats, format)
+  nx += newstrwidth
 
   lines[y].str &= linestr
 
   i = 0
-  cx = ox
   while cx < nx and i < ostr.len:
     fastRuneAt(ostr, i, r)
     cx += r.width()
@@ -204,60 +163,42 @@ proc paintBackground(lines: var FlexibleGrid, color: CSSColor, startx, starty, e
     # Make sure line.width() >= endx
     let linewidth = lines[y].width()
     if linewidth < endx:
-      lines.addFormat(y, lines[y].str.len, newFormat())
+      lines[y].addFormat(linewidth, newFormat())
       lines[y].str &= ' '.repeat(endx - linewidth)
 
-    # Find byte (i) of startx
-    var i = 0
-    var x = 0
-    while x < startx:
-      var r: Rune
-      fastRuneAt(lines[y].str, i, r)
-      x += r.width()
-
     # Process formatting around startx
     if lines[y].formats.len == 0:
       # No formats
-      lines.addFormat(y, startx, newFormat())
+      lines[y].addFormat(startx, newFormat())
     else:
-      let fi = lines[y].findFormatN(i) - 1
-      if lines[y].formats[fi].pos == i:
-        # Previous format equals i => next comes after, nothing to be done
+      let fi = lines[y].findFormatN(startx) - 1
+      if lines[y].formats[fi].pos == startx:
+        # Last format equals startx => next comes after, nothing to be done
         discard
       else:
-        # Previous format lower than i => separate format from startx
+        # Last format lower than startx => separate format from startx
         let copy = lines[y].formats[fi]
-        lines[y].formats[fi].pos = i
+        lines[y].formats[fi].pos = startx
         lines[y].formats.insert(copy, fi)
 
-    # Find byte (ei) of endx
-    var ei = i
-    while x < endx:
-      var r: Rune
-      fastRuneAt(lines[y].str, ei, r)
-      x += r.width()
-
     # Process formatting around endx
-    block:
-      assert lines[y].formats.len > 0
-      let fi = lines[y].findFormatN(ei) - 1
-      if fi == lines[y].formats.len - 1:
-        # Last format => nothing to be done
-        discard
-      else:
-        # Format ends before endx => separate format from endx
-        let copy = lines[y].formats[fi]
-        lines[y].formats[fi].pos = ei
-        lines[y].formats.insert(copy, fi + 1)
-
-    # Paint format backgrounds between startx (byte i) and endx (byte ei)
-    var fi = 0
-    while fi < lines[y].formats.len:
-      if lines[y].formats[fi].pos > ei:
+    assert lines[y].formats.len > 0
+    let fi = lines[y].findFormatN(endx) - 1
+    if fi == lines[y].formats.len - 1:
+      # Last format => nothing to be done
+      discard
+    else:
+      # Format ends before endx => separate format from endx
+      let copy = lines[y].formats[fi]
+      lines[y].formats[fi].pos = endx
+      lines[y].formats.insert(copy, fi + 1)
+
+    # Paint format backgrounds between startx and endx
+    for fi in 0..lines[y].formats.high:
+      if lines[y].formats[fi].pos > endx:
         break
-      if lines[y].formats[fi].pos >= i:
+      if lines[y].formats[fi].pos >= startx:
         lines[y].formats[fi].format.bgcolor = color
-      inc fi
 
     inc y
 
@@ -294,7 +235,7 @@ proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockContext, x, y: int, te
     x += ctx.relx
     y += ctx.rely
 
-    if ctx.specified{"background-color"}.rgba.a != 0: #TODO color mixing
+    if ctx.specified{"background-color"}.rgba.a != 0: #TODO color blending
       grid.paintBackground(ctx.specified{"background-color"}, x, y, x + ctx.width, y + ctx.height, term)
 
     if ctx.inline != nil:
diff --git a/src/render/rendertext.nim b/src/render/rendertext.nim
index 15a58c4c..b893d781 100644
--- a/src/render/rendertext.nim
+++ b/src/render/rendertext.nim
@@ -8,7 +8,7 @@ proc renderPlainText*(text: string): FlexibleGrid =
   template add_format() =
     if af:
       af = false
-      result.addFormat(result.high, result[^1].str.len, format)
+      result[result.high].addFormat(result[^1].str.len, format)
 
   result.addLine()
   var i = 0
@@ -42,7 +42,7 @@ proc renderStream*(stream: Stream): FlexibleGrid =
   template add_format() =
     if af:
       af = false
-      result.addFormat(result.high, result[^1].str.len, format)
+      result[result.high].addFormat(result[^1].str.len, format)
 
   result.addLine()
   var af = false