diff options
author | bptato <nincsnevem662@gmail.com> | 2022-08-02 21:36:57 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2022-08-02 22:14:14 +0200 |
commit | 7de898bd05fd54f216009ebc3775a007fd92c417 (patch) | |
tree | 8ea375792a27977a79b5932bf6bc786b19b3ec5f | |
parent | 8f7eb1f7d0ec0cac610c5dcc73188fdbe1577def (diff) | |
download | chawan-7de898bd05fd54f216009ebc3775a007fd92c417.tar.gz |
Fix renderdocument setText etc.
-rw-r--r-- | src/io/buffer.nim | 7 | ||||
-rw-r--r-- | src/io/cell.nim | 47 | ||||
-rw-r--r-- | src/render/renderdocument.nim | 198 | ||||
-rw-r--r-- | src/types/color.nim | 6 |
4 files changed, 138 insertions, 120 deletions
diff --git a/src/io/buffer.nim b/src/io/buffer.nim index 4f434e5d..15853da7 100644 --- a/src/io/buffer.nim +++ b/src/io/buffer.nim @@ -1215,15 +1215,14 @@ proc drawBuffer*(buffer: Buffer) = var format = newFormat() for line in buffer.lines: if line.formats.len == 0: - print(line.str & "\r\n") + print(line.str & "\n") else: var x = 0 var i = 0 for f in line.formats: var outstr = "" - #TODO TODO TODO renderhtml has broken format outputting #assert f.pos < line.str.width(), "fpos " & $f.pos & "\nstr" & line.str & "\n" - while x < f.pos and i < line.str.len: #TODO x < f.pos should be enough + while x < f.pos: var r: Rune fastRuneAt(line.str, i, r) outstr &= r @@ -1232,7 +1231,7 @@ proc drawBuffer*(buffer: Buffer) = print(format.processFormat(f.format)) print(line.str.substr(i)) print(format.processFormat(newFormat())) - print("\r\n") + print("\n") proc refreshBuffer*(buffer: Buffer, peek = false) = buffer.title = buffer.getTitle() diff --git a/src/io/cell.nim b/src/io/cell.nim index d8f3d23b..2faced78 100644 --- a/src/io/cell.nim +++ b/src/io/cell.nim @@ -28,6 +28,8 @@ type format*: Format node*: StyledNode + # A FormatCell *starts* a new terminal formatting context. + # If no FormatCell exists before a given cell, the default formatting is used. FormatCell* = object of Cell pos*: int computed*: ComputedFormat @@ -71,7 +73,6 @@ template `strike=`*(f: var Format, b: bool) = flag_template f, b, FLAG_STRIKE template `overline=`*(f: var Format, b: bool) = flag_template f, b, FLAG_OVERLINE template `blink=`*(f: var Format, b: bool) = flag_template f, b, FLAG_BLINK -#TODO ????? func `==`*(a: FixedCell, b: FixedCell): bool = return a.format == b.format and a.runes == b.runes and @@ -89,6 +90,7 @@ func width*(cell: FixedCell): int = func newFormat*(): Format = return Format(fgcolor: defaultColor, bgcolor: defaultColor) +# Get the first format cell after pos, if any. func findFormatN*(line: FlexibleLine, pos: int): int = var i = 0 while i < line.formats.len: @@ -111,46 +113,21 @@ func findNextFormat*(line: FlexibleLine, pos: int): FormatCell = else: result.pos = -1 -func subformats*(formats: seq[FormatCell], pos: int): seq[FormatCell] = - 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.str.setLen(len) - #line.formats = line.formats.filter((x) => x.pos < len) - -proc add*(a: var FlexibleLine, b: FlexibleLine) = - let l = a.str.len - a.formats.add(b.formats.map((x) => FormatCell(format: x.format, node: x.node, pos: l + x.pos))) - a.str &= b.str - proc addLine*(grid: var FlexibleGrid) = grid.add(FlexibleLine()) +proc insertFormat*(line: var FlexibleLine, pos, i: int, format: Format, computed: ComputedFormat = nil) = + if computed == nil: + line.formats.insert(FormatCell(format: format, pos: pos), i) + else: + line.formats.insert(FormatCell(format: format, computed: computed, node: computed.node, pos: pos), i) + proc addFormat*(line: var FlexibleLine, pos: int, format: Format) = - line.formats.add(FormatCell(format: format, pos: line.str.len)) + line.formats.add(FormatCell(format: format, 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 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: diff --git a/src/render/renderdocument.nim b/src/render/renderdocument.nim index 54628946..484f8fb5 100644 --- a/src/render/renderdocument.nim +++ b/src/render/renderdocument.nim @@ -30,97 +30,128 @@ func formatFromWord(computed: ComputedFormat): Format = result.blink = true else: discard -proc setFormats(line: var FlexibleLine, ox, newwidth, oldwidth: int, - newformat: Format, oformats: seq[FormatCell], computed: ComputedFormat = nil) {.inline.} = - let obg = newformat.bgcolor - var newformat = newformat - for format in oformats: - #assert format.pos < ox + oldwidth #TODO TODO TODO - if format.format.bgcolor != newformat.bgcolor: - newformat.bgcolor = format.format.bgcolor - - if format.pos < ox: - line.addFormat(ox, newformat, computed) - else: - line.addFormat(format.pos, newformat, computed) - - if ox + oldwidth < ox + newwidth: - newformat.bgcolor = obg - - #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: - line.addFormat(ox + oldwidth, newformat, computed) - -proc setText(lines: var FlexibleGrid, linestr: string, format: ComputedFormat, x, y: int) {.inline.} = - var r: Rune - var x = x - var y = y +proc setText(lines: var FlexibleGrid, linestr: string, cformat: ComputedFormat, x, y: int) {.inline.} = var i = 0 - + var r: Rune + # make sure we have line y while lines.len <= y: lines.addLine() - var cx = 0 + var cx = 0 # first x of new string (before padding) while cx < x and i < lines[y].str.len: fastRuneAt(lines[y].str, i, r) cx += r.width() let ostr = lines[y].str.substr(i) - let oformats = lines[y].formats.subformats(i) - lines[y].setLen(i) - - var nx = cx - let oldstrwidth = ostr.width() - if nx < x: - let spacelength = x - nx - var spaceformat = newFormat() - let str = ' '.repeat(spacelength) - lines[y].setFormats(nx, spacelength, oldstrwidth, spaceformat, oformats) - - lines[y].str &= str - i += spacelength - nx = x - - var wordformat = format.formatFromWord() - let newstrwidth = linestr.width() - lines[y].setFormats(nx, newstrwidth, oldstrwidth, wordformat, oformats, format) - nx += newstrwidth + lines[y].str.setLen(i) + var linestrwidth = 0 + let padwidth = x - cx + if padwidth > 0: + lines[y].str &= ' '.repeat(padwidth) + linestrwidth += padwidth lines[y].str &= linestr + linestrwidth += linestr.width() i = 0 - while cx < nx and i < ostr.len: + var nx = x # last x of new string + while nx < x + linestrwidth and i < ostr.len: fastRuneAt(ostr, i, r) - cx += r.width() + nx += r.width() if i < ostr.len: - let oline = FlexibleLine(str: ostr.substr(i), formats: oformats.subformats(i)) - lines[y].add(oline) + lines[y].str &= ostr.substr(i) + + # Skip unchanged formats before the new string + var fi = lines[y].findFormatN(cx) - 1 + + if padwidth > 0: + # Replace formats for padding + var padformat = newFormat() + if fi == -1: + # No formats + inc fi # insert after first format (meaning fi = 0) + lines[y].insertFormat(cx, fi, padformat) + else: + # First format's pos may be == cx here. + if lines[y].formats[fi].pos == cx: + padformat.bgcolor = lines[y].formats[fi].format.bgcolor + lines[y].formats.delete(fi) + lines[y].insertFormat(cx, fi, padformat) + else: + # First format < cx => split it up + assert lines[y].formats[fi].pos < cx + padformat.bgcolor = lines[y].formats[fi].format.bgcolor + inc fi # insert after first format + lines[y].insertFormat(cx, fi, padformat) + inc fi # skip last format + while fi < lines[y].formats.len and lines[y].formats[fi].pos < x: + # Other formats must be > cx => replace them + padformat.bgcolor = lines[y].formats[fi].format.bgcolor + let px = lines[y].formats[fi].pos + lines[y].formats.delete(fi) + lines[y].insertFormat(px, fi, padformat) + inc fi + dec fi # go back to previous format, so that pos <= x + assert lines[y].formats[fi].pos <= x + + # Now for the text's formats: + var format = cformat.formatFromWord() + if fi == -1: + # No formats => just insert a new format at 0 + inc fi + lines[y].insertFormat(x, fi, format, cformat) + else: + # First format's pos may be == x here. + if lines[y].formats[fi].pos == x: + # Replace. + format.bgcolor = lines[y].formats[fi].format.bgcolor + lines[y].formats.delete(fi) + lines[y].insertFormat(x, fi, format, cformat) + else: + # First format's pos < x => split it up. + assert lines[y].formats[fi].pos < x + format.bgcolor = lines[y].formats[fi].format.bgcolor + inc fi # insert after first format + lines[y].insertFormat(x, fi, format, cformat) + inc fi # skip last format + + while fi < lines[y].formats.len and lines[y].formats[fi].pos < nx: + # Other formats must be > x => replace them + format.bgcolor = lines[y].formats[fi].format.bgcolor + let px = lines[y].formats[fi].pos + lines[y].formats.delete(fi) + lines[y].insertFormat(px, fi, format, cformat) + inc fi + + dec fi # go back to previous format, so that pos <= nx + assert lines[y].formats[fi].pos <= nx + # That's it! proc setRowWord(lines: var FlexibleGrid, word: InlineWord, x, y: int, term: TermAttributes) = var r: Rune - var y = (y + word.offset.y) div term.ppl - if y < 0: y = 0 + var y = (y + word.offset.y) div term.ppl # y cell + if y < 0: return # y is outside the canvas, no need to draw - var x = (x + word.offset.x) div term.ppc + var x = (x + word.offset.x) div term.ppc # x cell var i = 0 while x < 0 and i < word.str.len: fastRuneAt(word.str, i, r) x += r.width() + if x < 0: return # highest x is outside the canvas, no need to draw let linestr = word.str.substr(i) lines.setText(linestr, word.format, x, y) proc setSpacing(lines: var FlexibleGrid, spacing: InlineSpacing, x, y: int, term: TermAttributes) = - var y = (y + spacing.offset.y) div term.ppl - if y < 0: y = 0 + var y = (y + spacing.offset.y) div term.ppl # y cell + if y < 0: return # y is outside the canvas, no need to draw - var x = (x + spacing.offset.x) div term.ppc - let width = spacing.width div term.ppc + var x = (x + spacing.offset.x) div term.ppc # x cell + let width = spacing.width div term.ppc # cell width + if x + width < 0: return # highest x is outside the canvas, no need to draw var i = 0 if x < 0: i -= x @@ -133,32 +164,32 @@ proc paintBackground(lines: var FlexibleGrid, color: CSSColor, startx, starty, e let color = color.cellColor() var starty = starty div term.ppl - if starty < 0: starty = 0 - var endy = endy div term.ppl - if endy < 0: endy = 0 if starty > endy: - let swap = endy - endy = starty - starty = swap + swap(starty, endy) - var startx = startx div term.ppc + if endy <= 0: return # highest y is outside canvas, no need to paint if starty < 0: starty = 0 + if starty == endy: return # height is 0, no need to paint + + var startx = startx div term.ppc var endx = endx div term.ppc if endy < 0: endy = 0 if startx > endx: - let swap = endx - endx = startx - startx = swap + swap(startx, endx) + if endx <= 0: return # highest x is outside the canvas, no need to paint + if startx < 0: startx = 0 + if startx == endx: return # width is 0, no need to paint + + # make sure we have line y while lines.len <= endy: lines.addLine() - var y = starty - while y < endy: + for y in starty..<endy: # Make sure line.width() >= endx let linewidth = lines[y].width() if linewidth < endx: @@ -171,7 +202,10 @@ proc paintBackground(lines: var FlexibleGrid, color: CSSColor, startx, starty, e lines[y].addFormat(startx, newFormat()) else: let fi = lines[y].findFormatN(startx) - 1 - if lines[y].formats[fi].pos == startx: + if fi == -1: + # No format <= startx + lines[y].insertFormat(startx, 0, newFormat()) + elif lines[y].formats[fi].pos == startx: # Last format equals startx => next comes after, nothing to be done discard else: @@ -183,24 +217,26 @@ proc paintBackground(lines: var FlexibleGrid, color: CSSColor, startx, starty, e # Process formatting around endx 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 + if fi == -1: + # Last format > endx -> 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) + if lines[y].formats[fi].pos != endx: + let copy = lines[y].formats[fi] + if linewidth != endx: + lines[y].formats[fi].pos = endx + lines[y].formats.insert(copy, fi) + else: + lines[y].formats.delete(fi) + lines[y].formats.insert(copy, fi) # Paint format backgrounds between startx and endx for fi in 0..lines[y].formats.high: - if lines[y].formats[fi].pos > endx: + if lines[y].formats[fi].pos >= endx: break if lines[y].formats[fi].pos >= startx: lines[y].formats[fi].format.bgcolor = color - inc y - proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockBox, x, y: int, term: TermAttributes) proc renderInlineContext(grid: var FlexibleGrid, ctx: InlineContext, x, y: int, term: TermAttributes) = diff --git a/src/types/color.nim b/src/types/color.nim index e5f72158..d0e13544 100644 --- a/src/types/color.nim +++ b/src/types/color.nim @@ -211,3 +211,9 @@ converter toRGBColor*(i: RGBAColor): RGBColor = converter toRGBAColor*(i: RGBColor): RGBAColor = return RGBAColor(uint32(i) or 0xFF000000u32) + +func `$`*(color: CellColor): string = + if color.rgb: + "r" & $color.rgbcolor.r & "g" & $color.rgbcolor.g & "b" & $color.rgbcolor.b + else: + "tcolor" & $color.color |