diff options
author | bptato <nincsnevem662@gmail.com> | 2022-11-19 17:30:53 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2022-11-19 17:30:53 +0100 |
commit | 986522a915233dc068e00b47ca8b16e42cb50c7f (patch) | |
tree | 2c3d76a1a3f9829a6057d0c070f9d87ef1e0b1ce /src | |
parent | d4e20ebe854083110a2ed732276848dc0dbd9eb3 (diff) | |
download | chawan-986522a915233dc068e00b47ca8b16e42cb50c7f.tar.gz |
Re-implement highlighting
Diffstat (limited to 'src')
-rw-r--r-- | src/buffer/buffer.nim | 4 | ||||
-rw-r--r-- | src/buffer/container.nim | 54 | ||||
-rw-r--r-- | src/config/config.nim | 24 | ||||
-rw-r--r-- | src/display/client.nim | 3 | ||||
-rw-r--r-- | src/display/pager.nim | 27 |
5 files changed, 82 insertions, 30 deletions
diff --git a/src/buffer/buffer.nim b/src/buffer/buffer.nim index 6c2654dd..40527d94 100644 --- a/src/buffer/buffer.nim +++ b/src/buffer/buffer.nim @@ -770,7 +770,7 @@ proc runBuffer(buffer: Buffer, istream, ostream: Stream) = istream.sread(wrap) let match = buffer.findPrevMatch(regex, cx, cy, wrap) if match.success: - buffer.writeCommand(JUMP, match.x, match.y) + buffer.writeCommand(JUMP, match.x, match.y, match.x + match.str.width() - 1) of FIND_NEXT_MATCH: var cx, cy: int var regex: Regex @@ -781,7 +781,7 @@ proc runBuffer(buffer: Buffer, istream, ostream: Stream) = istream.sread(wrap) let match = buffer.findNextMatch(regex, cx, cy, wrap) if match.success: - buffer.writeCommand(JUMP, match.x, match.y) + buffer.writeCommand(JUMP, match.x, match.y, match.x + match.str.width() - 1) of READ_SUCCESS: var s: string istream.sread(s) diff --git a/src/buffer/container.nim b/src/buffer/container.nim index beb5fedc..4232ae09 100644 --- a/src/buffer/container.nim +++ b/src/buffer/container.nim @@ -40,6 +40,12 @@ type request*: Request else: discard + Highlight* = ref object + x*, y*: int + endy*, endx*: int + rect*: bool + clear*: bool + Container* = ref object attrs*: TermAttributes width*: int @@ -51,6 +57,7 @@ type children*: seq[Container] pos: CursorPosition bpos: seq[CursorPosition] + highlights: seq[Highlight] parent*: Container sourcepair*: Container istream*: Stream @@ -66,6 +73,7 @@ type redirect*: Option[URL] ispipe: bool jump: bool + hlon*: bool pipeto: Container tty: FileHandle @@ -94,6 +102,7 @@ proc newBuffer*(config: Config, source: BufferSource, tty: FileHandle, ispipe = raise newException(Defect, "Failed to open input handle") if not open(writef, pipefd_out[1], fmWrite): raise newException(Defect, "Failed to open output handle") + discard c_setvbuf(writef, nil, IONBF, 0) let istream = newFileStream(readf) let ostream = newFileStream(writef) launchBuffer(config, source, attrs, istream, ostream) @@ -226,6 +235,37 @@ func lineWindow(container: Container): Slice[int] = y = container.numLines return max(x, 0) .. min(y, container.numLines - 1) +func contains*(hl: Highlight, x, y: int): bool = + if hl.rect: + let rx = hl.x .. hl.endx + let ry = hl.y .. hl.endy + return x in rx and y in ry + else: + return (y > hl.y or y == hl.y and x >= hl.x) and + (y < hl.endy or y == hl.endy and x <= hl.endx) + +func contains*(hl: Highlight, y: int): bool = + return y in hl.y .. hl.endy + +func colorArea*(hl: Highlight, y: int, limitx: Slice[int]): Slice[int] = + if hl.rect: + if y in hl.y .. hl.endy: + return max(hl.x, limitx.a) .. min(hl.endx, limitx.b) + else: + if y in hl.y + 1 .. hl.endy - 1: + return limitx + if y == hl.y and y == hl.endy: + return max(hl.x, limitx.a) .. min(hl.endx, limitx.b) + if y == hl.y: + return max(hl.x, limitx.a) .. limitx.b + if y == hl.endy: + return limitx.a .. min(hl.endx, limitx.b) + +func findHighlights*(container: Container, y: int): seq[Highlight] = + for hl in container.highlights: + if y in hl: + result.add(hl) + macro writeCommand(container: Container, cmd: BufferCommand, args: varargs[typed]) = result = newStmtList() result.add(quote do: `container`.ostream.swrite(`cmd`)) @@ -560,6 +600,11 @@ proc windowChange*(container: Container, attrs: TermAttributes) = container.height = attrs.height - 1 container.writeCommand(WINDOW_CHANGE, attrs) +proc clearSearchHighlights*(container: Container) = + for i in countdown(container.highlights.high, 0): + if container.highlights[i].clear: + container.highlights.del(i) + proc handleEvent*(container: Container): ContainerEvent = var cmd: ContainerCommand container.istream.sread(cmd) @@ -610,10 +655,15 @@ proc handleEvent*(container: Container): ContainerEvent = container.istream.sread(pwd) return ContainerEvent(t: READ_LINE, prompt: prompt, value: str, password: pwd) of JUMP: - var x, y: int + var x, y, ex: int container.istream.sread(x) container.istream.sread(y) - if container.jump and x >= 0 and y >= 0: + container.istream.sread(ex) + if container.jump: + if container.hlon: + let hl = Highlight(x: x, y: y, endx: ex, endy: y, clear: true) + container.highlights.add(hl) + container.hlon = false container.setCursorXY(x, y) container.jump = false return ContainerEvent(t: UPDATE) diff --git a/src/config/config.nim b/src/config/config.nim index a3b121ba..9db896e5 100644 --- a/src/config/config.nim +++ b/src/config/config.nim @@ -15,7 +15,7 @@ type stylesheet*: string startup*: string ambiguous_double*: bool - markcolor*: CellColor + hlcolor*: CellColor func getRealKey(key: string): string = var realk: string @@ -115,17 +115,17 @@ proc parseConfig(config: Config, dir: string, t: TomlValue) = config.stylesheet &= css["inline"].s if "display" in t: let display = t["display"] - if "mark-color" in display: - case display["mark-color"].s - of "black": config.markcolor = CellColor(rgb: false, color: 40u8) - of "red": config.markcolor = CellColor(rgb: false, color: 41u8) - of "green": config.markcolor = CellColor(rgb: false, color: 42u8) - of "yellow": config.markcolor = CellColor(rgb: false, color: 43u8) - of "blue": config.markcolor = CellColor(rgb: false, color: 44u8) - of "magenta": config.markcolor = CellColor(rgb: false, color: 45u8) - of "cyan": config.markcolor = CellColor(rgb: false, color: 46u8) - of "white": config.markcolor = CellColor(rgb: false, color: 47u8) - of "terminal": config.markcolor = CellColor(rgb: false, color: 0) + if "highlight-color" in display: + case display["highlight-color"].s + of "black": config.hlcolor = CellColor(rgb: false, color: 40u8) + of "red": config.hlcolor = CellColor(rgb: false, color: 41u8) + of "green": config.hlcolor = CellColor(rgb: false, color: 42u8) + of "yellow": config.hlcolor = CellColor(rgb: false, color: 43u8) + of "blue": config.hlcolor = CellColor(rgb: false, color: 44u8) + of "magenta": config.hlcolor = CellColor(rgb: false, color: 45u8) + of "cyan": config.hlcolor = CellColor(rgb: false, color: 46u8) + of "white": config.hlcolor = CellColor(rgb: false, color: 47u8) + of "terminal": config.hlcolor = CellColor(rgb: false, color: 0) proc parseConfig(config: Config, dir: string, stream: Stream) = config.parseConfig(dir, parseToml(stream)) diff --git a/src/display/client.nim b/src/display/client.nim index 2f4771f8..a45e64e3 100644 --- a/src/display/client.nim +++ b/src/display/client.nim @@ -172,9 +172,10 @@ proc input(client: Client) = client.feedNext = true elif not client.feedNext: client.evalJSFree(action, "<command>") - client.pager.updateReadLine() if client.pager.lineedit.isNone: client.line = nil + if not client.feedNext: + client.pager.updateReadLine() else: let action = getNormalAction(client.config, client.s) client.evalJSFree(action, "<command>") diff --git a/src/display/pager.nim b/src/display/pager.nim index 1b98b0e2..e34d94eb 100644 --- a/src/display/pager.nim +++ b/src/display/pager.nim @@ -153,6 +153,8 @@ proc refreshDisplay*(pager: Pager, container = pager.container) = var r: Rune var by = 0 pager.clearDisplay() + var hlformat = newFormat() + hlformat.bgcolor = pager.config.hlcolor for line in container.ilines(container.fromy ..< min(container.fromy + pager.bheight, container.numLines)): var w = 0 # width of the row so far var i = 0 # byte in line.str @@ -187,19 +189,13 @@ proc refreshDisplay*(pager: Pager, container = pager.container) = let tk = k + r.width() while k < tk and k < pager.bwidth - 1: inc k - # Then, for each cell that has a mark, override its formatting with that - # specified by the mark. - #TODO honestly this was always broken anyways. not sure about how to re-implement it - #var l = 0 - #while l < pager.marks.len and buffer.marks[l].y < by: - # inc l # linear search to find the first applicable mark - #let aw = buffer.width - (startw - buffer.fromx) # actual width - #while l < buffer.marks.len and buffer.marks[l].y == by: - # let mark = buffer.marks[l] - # inc l - # if mark.x >= startw + aw or mark.x + mark.width < startw: continue - # for i in max(mark.x, startw)..<min(mark.x + mark.width, startw + aw): - # buffer.display[dls + i - startw].format = mark.format + # Finally, override cell formatting for highlighted cells. + let hls = container.findHighlights(by) + let aw = container.width - (startw - container.fromx) # actual width + for hl in hls: + let area = hl.colorArea(by, startw .. startw + aw) + for i in area: + pager.display[dls + i - startw].format = hlformat inc by func generateStatusMessage*(pager: Pager): string = @@ -474,15 +470,18 @@ proc updateReadLineISearch(pager: Pager, linemode: LineMode) = of CANCEL: pager.iregex = none(Regex) pager.container.popCursorPos() + pager.container.clearSearchHighlights() of EDIT: let x = $lineedit.news if x != "": pager.iregex = compileSearchRegex(x) + pager.container.clearSearchHighlights() pager.container.popCursorPos() if pager.iregex.isSome: if linemode == ISEARCH_F: pager.container.cursorNextMatch(pager.iregex.get, true) else: pager.container.cursorPrevMatch(pager.iregex.get, true) + pager.container.hlon = true pager.container.pushCursorPos() pager.displayPage() pager.statusMode() @@ -491,6 +490,8 @@ proc updateReadLineISearch(pager: Pager, linemode: LineMode) = if pager.iregex.isSome: pager.regex = pager.iregex pager.reverseSearch = linemode == ISEARCH_B + pager.container.clearSearchHighlights() + pager.redraw() proc updateReadLine*(pager: Pager) = let lineedit = pager.lineedit.get |