about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/io/buffer.nim91
-rw-r--r--src/io/cell.nim162
-rw-r--r--src/render/renderdocument.nim10
3 files changed, 98 insertions, 165 deletions
diff --git a/src/io/buffer.nim b/src/io/buffer.nim
index 82b5b46e..56de9938 100644
--- a/src/io/buffer.nim
+++ b/src/io/buffer.nim
@@ -191,15 +191,10 @@ func cellOrigin(buffer: Buffer, x, y: int): int =
 func currentCellOrigin(buffer: Buffer): int =
   return buffer.cellOrigin(buffer.acursorx, buffer.acursory)
 
-#TODO counter-intuitive naming?
 func currentDisplayCell(buffer: Buffer): FixedCell =
   let row = (buffer.cursory - buffer.fromy) * buffer.width
   return buffer.display[row + buffer.currentCellOrigin()]
 
-func cell(buffer: Buffer): FixedCell =
-  let row = (buffer.cursory - buffer.fromy) * buffer.width
-  return buffer.display[row + buffer.acursorx]
-
 func getLink(nodes: seq[Node]): Element =
   for node in nodes:
     if node.nodeType == ELEMENT_NODE:
@@ -240,23 +235,20 @@ func currentWidth(buffer: Buffer): int =
 
 func prevWidth(buffer: Buffer): int =
   let line = buffer.currentLine
+  if line.len == 0: return 0
   var w = 0
   var i = 0
   let cc = buffer.fromx + buffer.cursorx
-  if i >= line.len:
-    assert i == 0
-    return 0
-  var r: Rune
   var pr: Rune
+  var r: Rune
+  fastRuneAt(line, i, r)
   while i < line.len and w < cc:
     pr = r
     fastRuneAt(line, i, r)
     w += r.width()
-  if pr == Rune(0):
-    return 0
   return pr.width()
 
-func maxScreenWidth*(buffer: Buffer): int =
+func maxScreenWidth(buffer: Buffer): int =
   for line in buffer.lines[buffer.fromy..buffer.lastVisibleLine - 1]:
     result = max(line.width(), result)
 
@@ -267,9 +259,6 @@ func atPercentOf(buffer: Buffer): int =
 func hasAnchor*(buffer: Buffer, anchor: string): bool =
   return buffer.document.getElementById(anchor) != nil
 
-proc addLine(buffer: Buffer) =
-  buffer.lines.addLine()
-
 proc clearDisplay(buffer: Buffer) =
   buffer.prevdisplay = buffer.display
   buffer.display = newFixedGrid(buffer.width, buffer.height)
@@ -294,7 +283,6 @@ proc refreshDisplay(buffer: Buffer) =
     if w > buffer.fromx:
       while k < w - buffer.fromx:
         buffer.display[dls + k].runes.add(Rune(' '))
-        buffer.display[dls + k].ow = r.width()
         inc k
 
     while i < line.str.len:
@@ -302,7 +290,6 @@ proc refreshDisplay(buffer: Buffer) =
       fastRuneAt(line.str, i, r)
       w += r.width()
       if w > buffer.fromx + buffer.width:
-        buffer.display[dls + k].ow += r.width()
         break
       if nf.pos != -1 and nf.pos <= j:
         cf = nf
@@ -313,19 +300,12 @@ proc refreshDisplay(buffer: Buffer) =
         buffer.display[dls + k].nodes = cf.nodes
       let tk = k + r.width()
       while k < tk and k < buffer.width - 1:
-        buffer.display[dls + k].ow += r.width()
         inc k
 
     inc y
 
-proc restoreCursorX(buffer: Buffer) =
-  buffer.cursorx = max(min(buffer.currentLineWidth() - 1, buffer.xend), 0)
-
 proc setCursorXB(buffer: Buffer, byte: int) =
   var b = buffer.currentCursorBytes()
-  if byte == b:
-    return
-
   var w = buffer.fromx + buffer.cursorx
   if b < byte:
     while b < byte:
@@ -350,31 +330,25 @@ proc setCursorXB(buffer: Buffer, byte: int) =
     buffer.redraw = true
   buffer.xend = buffer.cursorx
 
-proc setCursorX(buffer: Buffer, x: int) =
-  if buffer.cursorx == x:
-    return
-  var b = buffer.currentCursorBytes()
-  var w = buffer.fromx + buffer.cursorx
-  while b < buffer.currentLine.len and w < x:
-    var r: Rune
-    fastRuneAt(buffer.currentLine, b, r)
-    w += r.width()
-
-  while b > 0 and w > x:
-    let (r, o) = lastRune(buffer.currentLine, b - 1)
-    w -= r.width()
-    b -= o
-
-  if x - buffer.fromx >= 0 and x - buffer.width < buffer.fromx:
+proc setCursorX(buffer: Buffer, x: int, refresh = true, save = true) =
+  if (not refresh) or (buffer.fromx <= x and x < buffer.fromx + buffer.width):
     buffer.cursorx = x
   else:
-    if x > buffer.cursorx:
+    if refresh and buffer.fromx > buffer.cursorx:
+      buffer.fromx = max(buffer.currentLineWidth() - 1, 0)
+      buffer.cursorx = buffer.fromx
+    elif x > buffer.cursorx:
       buffer.fromx = max(x - buffer.width + 1, 0)
+      buffer.cursorx = x
     elif x < buffer.cursorx:
-      buffer.fromx = min(x, buffer.maxfromx)
-    buffer.cursorx = x
+      buffer.fromx = x
+      buffer.cursorx = x
     buffer.redraw = true
-  buffer.xend = buffer.cursorx
+  if save:
+    buffer.xend = buffer.cursorx
+
+proc restoreCursorX(buffer: Buffer) =
+  buffer.setCursorX(max(min(buffer.currentLineWidth() - 1, buffer.xend), 0), false, false)
 
 proc setCursorY(buffer: Buffer, y: int) =
   if buffer.cursory == y:
@@ -416,9 +390,7 @@ proc cursorRight*(buffer: Buffer) =
     buffer.setCursorX(buffer.cursorx + cellwidth)
 
 proc cursorLeft*(buffer: Buffer) =
-  let cellwidth = buffer.currentWidth()
-  if buffer.cursorx >= cellwidth:
-    buffer.setCursorX(buffer.cursorx - cellwidth)
+  buffer.setCursorX(max(buffer.cursorx - buffer.prevWidth(), 0))
 
 proc cursorLineBegin*(buffer: Buffer) =
   buffer.setCursorX(0)
@@ -568,16 +540,13 @@ proc cursorBottom*(buffer: Buffer) =
   buffer.setCursorY(min(buffer.fromy + buffer.height - 1, buffer.numLines - 1))
 
 proc cursorLeftEdge*(buffer: Buffer) =
-  buffer.cursorx = buffer.fromx
-  buffer.xend = buffer.cursorx
+  buffer.setCursorX(buffer.fromx)
 
 proc cursorVertMiddle*(buffer: Buffer) =
-  buffer.cursorx = min(buffer.fromx + (buffer.width - 2) div 2, buffer.currentLineWidth)
-  buffer.xend = buffer.cursorx
+  buffer.setCursorX(min(buffer.fromx + (buffer.width - 2) div 2, buffer.currentLineWidth))
 
 proc cursorRightEdge*(buffer: Buffer) =
-  buffer.cursorx = min(buffer.fromx + buffer.width - 1, buffer.currentLineWidth)
-  buffer.xend = buffer.cursorx
+  buffer.setCursorX(min(buffer.fromx + buffer.width - 1, buffer.currentLineWidth))
 
 proc centerLine*(buffer: Buffer) =
   let ny = max(min(buffer.cursory - buffer.height div 2, buffer.numLines - buffer.height), 0)
@@ -652,15 +621,13 @@ proc scrollUp*(buffer: Buffer) =
 proc scrollRight*(buffer: Buffer) =
   if buffer.fromx + buffer.width < buffer.maxScreenWidth():
     inc buffer.fromx
-    if buffer.fromx >= buffer.cursorx:
-      buffer.cursorRight()
     buffer.redraw = true
 
 proc scrollLeft*(buffer: Buffer) =
   if buffer.fromx > 0:
     dec buffer.fromx
-    if buffer.fromx + buffer.height <= buffer.cursorx:
-      buffer.cursorLeft()
+    if buffer.cursorx < buffer.fromx:
+      buffer.setCursorX(max(buffer.currentLineWidth() - 1, 0))
     buffer.redraw = true
 
 proc gotoAnchor*(buffer: Buffer) =
@@ -698,10 +665,6 @@ proc updateCursor(buffer: Buffer) =
     buffer.fromy = 0
     buffer.cursory = buffer.lastVisibleLine - 1
 
-  if buffer.cursorx >= buffer.currentLineWidth() - 1:
-    buffer.cursorx = max(buffer.currentLineWidth() - 1, 0)
-    buffer.fromx = max(buffer.cursorx - buffer.width + 1, 0)
-
   if buffer.lines.len == 0:
     buffer.cursory = 0
 
@@ -762,8 +725,8 @@ proc render*(buffer: Buffer) =
   buffer.updateCursor()
 
 proc cursorBufferPos(buffer: Buffer) =
-  let x = max(buffer.cursorx - buffer.fromx, 0)
-  let y = buffer.cursory - buffer.fromy
+  let x = buffer.acursorx
+  let y = buffer.acursory
   print(HVP(y + 1, x + 1))
 
 proc clearStatusMessage(buffer: Buffer) =
@@ -787,7 +750,7 @@ proc statusMsgForBuffer(buffer: Buffer) =
   if buffer.hovertext.len > 0:
     msg &= " " & buffer.hovertext
   var formatting: Formatting
-  formatting.reverse_on
+  formatting.reverse = true
   buffer.writeStatusMessage(msg, formatting)
 
 proc setStatusMessage*(buffer: Buffer, str: string) =
diff --git a/src/io/cell.nim b/src/io/cell.nim
index a4f56d61..f477bafd 100644
--- a/src/io/cell.nim
+++ b/src/io/cell.nim
@@ -9,12 +9,12 @@ import html/dom
 
 type
   FormatFlags* = enum
-    FLAG_ITALIC
     FLAG_BOLD
+    FLAG_ITALIC
     FLAG_UNDERLINE
+    FLAG_REVERSE
     FLAG_STRIKE
     FLAG_OVERLINE
-    FLAG_REVERSE
 
   Formatting* = object
     fgcolor*: CellColor
@@ -36,34 +36,35 @@ type
 
   FixedCell* = object of Cell
     runes*: seq[Rune]
-    ow*: int
 
   FixedGrid* = seq[FixedCell]
 
-func italic(formatting: Formatting): bool = FLAG_ITALIC in formatting.flags
+const FormatCodes: array[FormatFlags, tuple[s: int, e: int]] = [
+  FLAG_BOLD: (1, 22),
+  FLAG_ITALIC: (3, 23),
+  FLAG_UNDERLINE: (4, 24),
+  FLAG_REVERSE: (7, 27),
+  FLAG_STRIKE: (9, 29),
+  FLAG_OVERLINE: (53, 55),
+]
+
 func bold(formatting: Formatting): bool = FLAG_BOLD in formatting.flags
+func italic(formatting: Formatting): bool = FLAG_ITALIC in formatting.flags
 func underline(formatting: Formatting): bool = FLAG_UNDERLINE in formatting.flags
 func reverse(formatting: Formatting): bool = FLAG_REVERSE in formatting.flags
 func strike(formatting: Formatting): bool = FLAG_STRIKE in formatting.flags
 func overline(formatting: Formatting): bool = FLAG_OVERLINE in formatting.flags
 
-proc italic_on*(formatting: var Formatting) = formatting.flags.incl(FLAG_ITALIC)
-proc italic_off*(formatting: var Formatting) = formatting.flags.excl(FLAG_ITALIC)
-
-proc bold_on*(formatting: var Formatting) = formatting.flags.incl(FLAG_BOLD)
-proc bold_off*(formatting: var Formatting) = formatting.flags.excl(FLAG_BOLD)
-
-proc underline_on*(formatting: var Formatting) = formatting.flags.incl(FLAG_UNDERLINE)
-proc underline_off*(formatting: var Formatting) = formatting.flags.excl(FLAG_UNDERLINE)
+template flag_template(formatting: Formatting, val: bool, flag: FormatFlags) =
+  if val: formatting.flags.incl(flag)
+  else: formatting.flags.excl(flag)
 
-proc reverse_on*(formatting: var Formatting) = formatting.flags.incl(FLAG_REVERSE)
-proc reverse_off*(formatting: var Formatting) = formatting.flags.excl(FLAG_REVERSE)
-
-proc strike_on*(formatting: var Formatting) = formatting.flags.incl(FLAG_STRIKE)
-proc strike_off*(formatting: var Formatting) = formatting.flags.excl(FLAG_STRIKE)
-
-proc overline_on*(formatting: var Formatting) = formatting.flags.incl(FLAG_OVERLINE)
-proc overline_off*(formatting: var Formatting) = formatting.flags.excl(FLAG_OVERLINE)
+template `italic=`*(f: var Formatting, b: bool) = flag_template f, b, FLAG_ITALIC
+template `bold=`*(f: var Formatting, b: bool) = flag_template f, b, FLAG_BOLD
+template `underline=`*(f: var Formatting, b: bool) = flag_template f, b, FLAG_UNDERLINE
+template `reverse=`*(f: var Formatting, b: bool) = flag_template f, b, FLAG_REVERSE
+template `strike=`*(f: var Formatting, b: bool) = flag_template f, b, FLAG_STRIKE
+template `overline=`*(f: var Formatting, b: bool) = flag_template f, b, FLAG_OVERLINE
 
 #TODO ?????
 func `==`*(a: FixedCell, b: FixedCell): bool =
@@ -178,7 +179,7 @@ proc parseAnsiCode*(formatting: var Formatting, buf: string, fi: int): int =
   #intermediate bytes
   while 0x20 <= int(buf[i]) and int(buf[i]) <= 0x2F:
     inc_check i
-  let interm = buf.substr(si, i)
+  #let interm = buf.substr(si, i)
 
   let final = buf[i]
   #final byte
@@ -198,26 +199,16 @@ proc parseAnsiCode*(formatting: var Formatting, buf: string, fi: int): int =
           case ip[pi]
           of 0:
             formatting = newFormatting()
-          of 1:
-            formatting.bold_on
-          of 3:
-            formatting.italic_on
-          of 4:
-            formatting.underline_on
-          of 7:
-            formatting.reverse_on
-          of 9:
-            formatting.strike_on
-          of 22:
-            formatting.bold_off
-          of 23:
-            formatting.italic_off
-          of 27:
-            formatting.reverse_off
-          of 29:
-            formatting.strike_off
-          of 30..37:
-            formatting.fgcolor = CellColor(rgb: false, color: uint8(ip[pi]))
+          of 1: formatting.bold = true
+          of 3: formatting.italic = true
+          of 4: formatting.underline = true
+          of 7: formatting.reverse = true
+          of 9: formatting.strike = true
+          of 22: formatting.bold = false
+          of 23: formatting.italic = false
+          of 27: formatting.reverse = false
+          of 29: formatting.strike = false
+          of 30..37: formatting.fgcolor = CellColor(rgb: false, color: uint8(ip[pi]))
           of 38:
             inc pi
             if pi < ip.len:
@@ -258,12 +249,9 @@ proc parseAnsiCode*(formatting: var Formatting, buf: string, fi: int): int =
                 continue
             else:
               break
-          of 49:
-            formatting.bgcolor = defaultColor
-          of 53:
-            formatting.overline_on
-          of 55:
-            formatting.overline_off
+          of 49: formatting.bgcolor = defaultColor
+          of 53: formatting.overline = true
+          of 55: formatting.overline = false
           else: discard
           inc pi
       except ValueError: discard
@@ -272,52 +260,34 @@ proc parseAnsiCode*(formatting: var Formatting, buf: string, fi: int): int =
   return i
 
 proc processFormatting*(formatting: var Formatting, cellf: Formatting): string =
-    if formatting.bold and not cellf.bold:
-      result &= SGR(22)
-    if formatting.italic and not cellf.italic:
-      result &= SGR(23)
-    if formatting.underline and not cellf.underline:
-      result &= SGR(24)
-    if formatting.reverse and not cellf.reverse:
-      result &= SGR(27)
-    if formatting.strike and not cellf.strike:
-      result &= SGR(29)
-    if formatting.overline and not cellf.overline:
-      result &= SGR(55)
-
-    if cellf.fgcolor != formatting.fgcolor:
-      var color = cellf.fgcolor
-      if color.rgb:
-        let rgb = color.rgbcolor
-        result &= SGR(38, 2, rgb.r, rgb.g, rgb.b)
-      elif color == defaultColor:
-        result &= SGR()
-        formatting = newFormatting()
-      else:
-        result &= SGR(color.color)
-
-    if cellf.bgcolor != formatting.bgcolor:
-      var color = cellf.bgcolor
-      if color.rgb:
-        let rgb = color.rgbcolor
-        result &= SGR(48, 2, rgb.r, rgb.g, rgb.b)
-      elif color == defaultColor:
-        result &= SGR()
-        formatting = newFormatting()
-      else:
-        result &= SGR(color.color)
-
-    if not formatting.bold and cellf.bold:
-      result &= SGR(1)
-    if not formatting.italic and cellf.italic:
-      result &= SGR(3)
-    if not formatting.underline and cellf.underline:
-      result &= SGR(4)
-    if not formatting.reverse and cellf.reverse:
-      result &= SGR(7)
-    if not formatting.strike and cellf.strike:
-      result &= SGR(9)
-    if not formatting.overline and cellf.overline:
-      result &= SGR(53)
-
-    formatting = cellf
+  for flag in FormatFlags:
+    if flag in formatting.flags and flag notin cellf.flags:
+      result &= SGR(FormatCodes[flag].e)
+
+  if cellf.fgcolor != formatting.fgcolor:
+    var color = cellf.fgcolor
+    if color.rgb:
+      let rgb = color.rgbcolor
+      result &= SGR(38, 2, rgb.r, rgb.g, rgb.b)
+    elif color == defaultColor:
+      result &= SGR()
+      formatting = newFormatting()
+    else:
+      result &= SGR(color.color)
+
+  if cellf.bgcolor != formatting.bgcolor:
+    var color = cellf.bgcolor
+    if color.rgb:
+      let rgb = color.rgbcolor
+      result &= SGR(48, 2, rgb.r, rgb.g, rgb.b)
+    elif color == defaultColor:
+      result &= SGR()
+      formatting = newFormatting()
+    else:
+      result &= SGR(color.color)
+
+  for flag in FormatFlags:
+    if flag notin formatting.flags and flag in cellf.flags:
+      result &= SGR(FormatCodes[flag].s)
+
+  formatting = cellf
diff --git a/src/render/renderdocument.nim b/src/render/renderdocument.nim
index c3ad6cfe..21ae0945 100644
--- a/src/render/renderdocument.nim
+++ b/src/render/renderdocument.nim
@@ -14,15 +14,15 @@ import utils/twtstr
 func formatFromLine(line: CSSRowBox): Formatting =
   result.fgcolor = line.color.cellColor()
   if line.fontstyle in { FONT_STYLE_ITALIC, FONT_STYLE_OBLIQUE }:
-    result.italic_on
+    result.italic = true
   if line.fontweight > 500:
-    result.bold_on
+    result.bold = true
   if line.textdecoration == TEXT_DECORATION_UNDERLINE:
-    result.underline_on
+    result.underline = true
   if line.textdecoration == TEXT_DECORATION_OVERLINE:
-    result.overline_on
+    result.overline = true
   if line.textdecoration == TEXT_DECORATION_LINE_THROUGH:
-    result.strike_on
+    result.strike = true
 
 proc setRowBox(lines: var FlexibleGrid, line: CSSRowBox) =
   var r: Rune