about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/io/buffer.nim93
-rw-r--r--src/io/cell.nim81
-rw-r--r--src/layout/box.nim4
-rw-r--r--src/layout/engine.nim9
4 files changed, 112 insertions, 75 deletions
diff --git a/src/io/buffer.nim b/src/io/buffer.nim
index 9196504b..da33ae34 100644
--- a/src/io/buffer.nim
+++ b/src/io/buffer.nim
@@ -200,6 +200,7 @@ proc clearDisplay*(buffer: Buffer) =
   buffer.display = newFixedGrid(buffer.width, buffer.height)
 
 proc refreshDisplay*(buffer: Buffer) =
+  var r: Rune
   var y = 0
   buffer.clearDisplay()
 
@@ -207,21 +208,31 @@ proc refreshDisplay*(buffer: Buffer) =
                            buffer.lastVisibleLine - 1]:
     var w = 0
     var i = 0
+    var j = 0
     while w < buffer.fromx and i < line.len:
-      w += line[i].rune.width()
-      inc i
+      fastRuneAt(line.str, i, r)
+      w += r.width()
+      inc j
 
     let dls = y * buffer.width
-    var j = 0
+    var k = 0
     var n = 0
-    while w < buffer.fromx + buffer.width and i < line.len:
-      w += line[i].rune.width()
-      if line[i].rune.width() == 0 and j != 0:
+    var cf = line.findFormat(j)
+    var nf = line.findNextFormat(j)
+    while w < buffer.fromx + buffer.width and i < line.str.len:
+      fastRuneAt(line.str, i, r)
+      w += r.width()
+      if nf.pos != -1 and nf.pos <= j:
+        cf = nf
+        nf = line.findNextFormat(j)
+      if r.width() == 0 and k != 0:
         inc n
-      buffer.display[dls + j - n].runes.add(line[i].rune)
-      buffer.display[dls + j - n].formatting = line[i].formatting
-      j += line[i].rune.width()
-      inc i
+      buffer.display[dls + k - n].runes.add(r)
+      if cf.pos != -1:
+        buffer.display[dls + k - n].formatting = cf.formatting
+        buffer.display[dls + k - n].nodes = cf.nodes
+      k += r.width()
+      inc j
 
     inc y
 
@@ -528,7 +539,7 @@ proc refreshTermAttrs*(buffer: Buffer): bool =
   if newAttrs != buffer.attrs:
     buffer.attrs = newAttrs
     buffer.width = newAttrs.width
-    buffer.height = newAttrs.height
+    buffer.height = newAttrs.height - 1
     return true
   return false
 
@@ -546,46 +557,47 @@ func formatFromLine(line: CSSRowBox): Formatting =
     result.strike = true
 
 proc setRowBox(buffer: Buffer, line: CSSRowBox) =
-  if line.runes.len == 0:
-    return
+  var r: Rune
 
   let x = line.x
   let y = line.y
 
-  let format = line.formatFromLine()
   while buffer.lines.len <= y:
     buffer.addLine()
 
   var i = 0
+  var j = 0
   var cx = 0
-  while cx < x and i < buffer.lines[y].len:
-    cx += buffer.lines[y][i].rune.width()
-    inc i
+  while cx < x and i < buffer.lines[y].str.len:
+    fastRuneAt(buffer.lines[y].str, i, r)
+    cx += r.width()
+    inc j
 
-  var oline = buffer.lines[y].subline(i)
-  buffer.lines[y].setLen(i)
-  var j = 0
-  var nx = cx
+  let ostr = buffer.lines[y].str.substr(i)
+  let oformats = buffer.lines[y].formats.subformats(j)
+  buffer.lines[y].str.setLen(i)
+  buffer.lines[y].setLen(j)
 
-  #TODO not sure
-  while nx < x:
-    buffer.lines.addCell(y, Rune(' '))
-    inc nx
+  buffer.lines.addFormat(y, j, line.formatFromLine(), line.nodes)
 
-  buffer.lines.addFormat(y, format)
-  while j < line.runes.len:
-    buffer.lines.addCell(y, line.runes[j])
-    nx += line.runes[j].width()
-    inc j
+  var nx = cx
+  if nx < x:
+    buffer.lines[y].str &= ' '.repeat(x - nx)
+    nx = x
+
+  buffer.lines[y].str &= line.str
+  nx += line.str.width()
 
   i = 0
-  while cx < nx and i < oline.len:
-    cx += oline[i].rune.width()
-    inc i
+  j = 0
+  while cx < nx and i < ostr.len:
+    fastRuneAt(ostr, i, r)
+    cx += r.width()
+    inc j
 
-  if i < oline.len:
-    let nol = oline.subLine(i)
-    buffer.lines[y].add(nol)
+  if i < ostr.len:
+    let oline = FlexibleLine(str: ostr.substr(i), formats: oformats.subformats(j))
+    buffer.lines[y].add(oline)
 
 proc updateCursor(buffer: Buffer) =
   if buffer.fromy > buffer.lastVisibleLine - 1:
@@ -633,6 +645,7 @@ proc renderPlainText*(buffer: Buffer, text: string) =
   while i < text.len:
     if text[i] == '\n':
       buffer.addLine()
+      buffer.lines.addFormat(buffer.lines.len - 1, format)
       inc y
       x = 0
       inc i
@@ -640,17 +653,17 @@ proc renderPlainText*(buffer: Buffer, text: string) =
       inc i
     elif text[i] == '\t':
       for i in 0..8:
-        buffer.lines.addCell(Rune(' '), format)
+        buffer.lines[^1].str &= ' '
       inc i
     elif text[i] == '\e':
       i = format.parseAnsiCode(text, i)
     elif text[i].isControlChar():
-      buffer.lines.addCell(Rune('^'), format)
-      buffer.lines.addCell(Rune(text[i].getControlLetter()), format)
+      buffer.lines.addCell(Rune('^'))
+      buffer.lines.addCell(Rune(text[i].getControlLetter()))
       inc i
     else:
       fastRuneAt(text, i, r)
-      buffer.lines.addCell(r, format)
+      buffer.lines.addCell(r)
   buffer.updateCursor()
 
 proc renderDocument*(buffer: Buffer) =
diff --git a/src/io/cell.nim b/src/io/cell.nim
index 40ce2c57..74b07353 100644
--- a/src/io/cell.nim
+++ b/src/io/cell.nim
@@ -21,15 +21,12 @@ type
     formatting*: Formatting
     nodes*: seq[Node]
 
-  FlexibleCell* = object of Cell
-    rune*: Rune
-
-  FormattingCell = object of Cell
-    pos: int
+  FormattingCell* = object of Cell
+    pos*: int
 
   FlexibleLine* = object
     str*: string
-    formats: seq[FormattingCell]
+    formats*: seq[FormattingCell]
 
   FlexibleGrid* = seq[FlexibleLine]
 
@@ -38,6 +35,12 @@ type
 
   FixedGrid* = seq[FixedCell]
 
+#TODO ?????
+func `==`*(a: FixedCell, b: FixedCell): bool =
+  return a.formatting == b.formatting and
+    a.runes == b.runes and
+    a.nodes == b.nodes
+
 func newFixedGrid*(w: int, h: int = 1): FixedGrid =
   return newSeq[FixedCell](w * h)
 
@@ -53,8 +56,7 @@ func len*(line: FlexibleLine): int =
 func newFormatting*(): Formatting =
   return Formatting(fgcolor: defaultColor, bgcolor: defaultColor)
 
-func `[]`*(line: FlexibleLine, pos: int): FlexibleCell =
-  result.rune = line.str.runeAtPos(pos)
+func findFormat*(line: FlexibleLine, pos: int): FormattingCell =
   var i = 0
   while i < line.formats.len:
     if line.formats[i].pos > pos:
@@ -62,26 +64,49 @@ func `[]`*(line: FlexibleLine, pos: int): FlexibleCell =
     inc i 
   dec i
   if i != -1:
-    result.formatting = line.formats[i].formatting
+    result = line.formats[i]
   else:
-    result.formatting = newFormatting()
+    result.pos = -1
 
-func subLine*(line: FlexibleLine, i: int): FlexibleLine =
-  for f in line.formats:
-    if f.pos >= i:
-      result.formats.add(f)
-  result.str = line.str.runeSubstr(i)
+func findNextFormat*(line: FlexibleLine, pos: int): FormattingCell =
+  var i = 0
+  while i < line.formats.len:
+    if line.formats[i].pos > pos:
+      break
+    inc i 
+  if i < line.formats.len:
+    result = line.formats[i]
+  else:
+    result.pos = -1
 
-proc setLen*(line: var FlexibleLine, i: int) =
-  var nf = newSeq[FormattingCell]()
-  for f in line.formats:
-    if f.pos < i:
-      nf.add(f)
-  line.str = line.str.runeSubstr(0, i)
+func subformats*(formats: seq[FormattingCell], pos: int): seq[FormattingCell] =
+  var i = 0
+  while i < formats.len:
+    if formats[i].pos >= pos:
+      if result.len == 0 and i > 0:
+        var f = formats[i - 1]
+        f.pos = 0
+        result.add(f)
+      var f = formats[i]
+      f.pos -= pos
+      result.add(f)
+    inc i
+
+  if result.len == 0 and i > 0:
+    var f = formats[i - 1]
+    f.pos = 0
+    result.add(f)
+
+proc setLen*(line: var FlexibleLine, len: int) =
+  for i in 0 ..< line.formats.len:
+    if line.formats[i].pos >= len:
+      line.formats.setLen(i)
+      break
+  #line.formats = line.formats.filter((x) => x.pos < len)
 
 proc add*(a: var FlexibleLine, b: FlexibleLine) =
   let l = a.len
-  a.formats.add(b.formats.map((x) => FormattingCell(formatting: x.formatting, pos: l + x.pos)))
+  a.formats.add(b.formats.map((x) => FormattingCell(formatting: x.formatting, nodes: x.nodes, pos: l + x.pos)))
   a.str &= b.str
 
 proc addLine*(grid: var FlexibleGrid) =
@@ -90,16 +115,14 @@ proc addLine*(grid: var FlexibleGrid) =
 proc addFormat*(grid: var FlexibleGrid, y: int, format: Formatting) =
   grid[y].formats.add(FormattingCell(formatting: format, pos: grid[y].len))
 
-proc addCell*(grid: var FlexibleGrid, y: int, r: Rune) =
-  grid[y].str &= $r
+proc addFormat*(grid: var FlexibleGrid, y: int, pos: int, format: Formatting, nodes: seq[Node]) =
+  grid[y].formats.add(FormattingCell(formatting: format, nodes: nodes, pos: pos))
 
-proc addCell*(grid: var FlexibleGrid, y: int, r: Rune, format: Formatting) =
-  if grid[y].formats.len == 0 or grid[y].formats[^1].formatting != format:
-    grid[y].formats.add(FormattingCell(formatting: format, pos: grid[y].len))
+proc addCell*(grid: var FlexibleGrid, y: int, r: Rune) =
   grid[y].str &= $r
 
-proc addCell*(grid: var FlexibleGrid, r: Rune, format: Formatting) =
-  grid.addCell(grid.len - 1, r, format)
+proc addCell*(grid: var FlexibleGrid, r: Rune) =
+  grid.addCell(grid.len - 1, r)
 
 template inc_check(i: int) =
   inc i
diff --git a/src/layout/box.nim b/src/layout/box.nim
index bee93363..07bc5f5b 100644
--- a/src/layout/box.nim
+++ b/src/layout/box.nim
@@ -1,5 +1,3 @@
-import unicode
-
 import types/enums
 import css/style
 import html/dom
@@ -50,7 +48,7 @@ type
     fontstyle*: CSSFontStyle
     fontweight*: int
     textdecoration*: CSSTextDecoration
-    runes*: seq[Rune]
+    str*: string
     nodes*: seq[Node]
 
   CSSInlineBox* = ref CSSInlineBoxObj
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index 506770b9..71dab4c2 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -84,8 +84,10 @@ proc processInlineBox(parent: CSSBox, str: string): CSSBox =
   rowbox.setup(ibox.cssvalues, ibox.bcontext.nodes)
   var r: Rune
   while i < str.len:
+    var rw = 0
     case str[i]
     of ' ', '\n', '\t':
+      rw = 1
       inc i
       let wsr = ibox.cssvalues[PROPERTY_WHITESPACE].whitespace
       if ibox.context.whitespace:
@@ -113,12 +115,13 @@ proc processInlineBox(parent: CSSBox, str: string): CSSBox =
     else:
       ibox.context.whitespace = false
       fastRuneAt(str, i, r)
+      rw = r.width()
       if rowbox.width + r.width() > ibox.width:
         inlineWrap(ibox, rowi, fromx, rowbox)
 
-    rowbox.width += r.width()
-    rowbox.runes.add(r)
-  if rowbox.runes.len > 0:
+    rowbox.width += rw
+    rowbox.str &= $r
+  if rowbox.str.len > 0:
     ibox.content.add(rowbox)
     ibox.context.fromx = fromx + rowbox.width
     ibox.context.conty = true