diff options
author | bptato <nincsnevem662@gmail.com> | 2021-08-06 17:15:17 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2021-08-06 17:15:17 +0200 |
commit | 6d50a0f7d1af3da77fcea7290ac02a43e8f454e4 (patch) | |
tree | d5f61a0c533d535908e4b224774dcc9378b05bf4 | |
parent | b94597a68eb8572cf8f521ee9c39cc7d9d310827 (diff) | |
download | chawan-6d50a0f7d1af3da77fcea7290ac02a43e8f454e4.tar.gz |
Config refactoring, width aware cursor movement
-rw-r--r-- | src/config.nim | 65 | ||||
-rw-r--r-- | src/io/buffer.nim | 67 | ||||
-rw-r--r-- | src/io/display.nim | 2 | ||||
-rw-r--r-- | src/io/twtio.nim | 18 | ||||
-rw-r--r-- | src/main.nim | 4 |
5 files changed, 87 insertions, 69 deletions
diff --git a/src/config.nim b/src/config.nim index 41d4a6d4..4713db07 100644 --- a/src/config.nim +++ b/src/config.nim @@ -1,4 +1,5 @@ import tables +import os import strutils import utils/twtstr @@ -33,11 +34,18 @@ type ACTION_LINED_COMPOSE_TOGGLE, ACTION_LINED_ESC ActionMap = Table[string, TwtAction] - ComposeMap = RadixNode[string] + StaticConfig = object + nmap: ActionMap + lemap: ActionMap + cmap: Table[string, string] -var normalActionRemap*: ActionMap -var linedActionRemap*: ActionMap -var composeRemap*: ComposeMap + Config = object + nmap*: ActionMap + lemap*: ActionMap + cmap*: RadixNode[string] + +func getConfig(s: StaticConfig): Config = + return Config(nmap: s.nmap, lemap: s.lemap, cmap: s.cmap.toRadixTree()) func getRealKey(key: string): string = var realk: string @@ -101,37 +109,30 @@ func constructActionTable*(origTable: ActionMap): ActionMap = newTable[realk] = v return newTable -proc parseConfigLine(line: string, nmap: var ActionMap, lemap: var ActionMap, - compose: var Table[string, string]) = +proc parseConfigLine[T](line: string, config: var T) = if line.len == 0 or line[0] == '#': return let cmd = line.split(' ') if cmd.len == 3: if cmd[0] == "nmap": - nmap[getRealKey(cmd[1])] = parseEnum[TwtAction]("ACTION_" & cmd[2]) + config.nmap[getRealKey(cmd[1])] = parseEnum[TwtAction]("ACTION_" & cmd[2]) elif cmd[0] == "lemap": - lemap[getRealKey(cmd[1])] = parseEnum[TwtAction]("ACTION_" & cmd[2]) + config.lemap[getRealKey(cmd[1])] = parseEnum[TwtAction]("ACTION_" & cmd[2]) elif cmd[0] == "comp": - compose[getRealKey(cmd[1])] = cmd[2] + config.cmap[getRealKey(cmd[1])] = cmd[2] -proc staticReadKeymap(): (ActionMap, ActionMap, Table[string, string]) = - let config = staticRead"../res/config" - var nmap: ActionMap - var lemap: ActionMap - var compose: Table[string, string] - for line in config.split('\n'): - parseConfigLine(line, nmap, lemap, compose) +proc staticReadConfig(): StaticConfig = + let default = staticRead"../res/config" + for line in default.split('\n'): + parseConfigLine(line, result) - nmap = constructActionTable(nmap) - lemap = constructActionTable(lemap) - return (nmap, lemap, compose) + result.nmap = constructActionTable(result.nmap) + result.lemap = constructActionTable(result.lemap) -const (normalActionMap, linedActionMap, composeMap) = staticReadKeymap() -normalActionRemap = normalActionMap -linedActionRemap = linedActionMap -composeRemap = composeMap.toRadixTree() +const defaultConfig = staticReadConfig() +var gconfig* = getConfig(defaultConfig) -proc readConfig*(filename: string): bool = +proc readConfig(filename: string) = var f: File let status = f.open(filename, fmRead) var nmap: ActionMap @@ -140,11 +141,13 @@ proc readConfig*(filename: string): bool = if status: var line: TaintedString while f.readLine(line): - parseConfigLine(line, nmap, lemap, compose) + parseConfigLine(line, gconfig) + + gconfig.nmap = constructActionTable(nmap) + gconfig.lemap = constructActionTable(lemap) + gconfig.cmap = compose.toRadixTree() - normalActionRemap = constructActionTable(nmap) - linedActionRemap = constructActionTable(lemap) - composeRemap = compose.toRadixTree() - return true - else: - return false +proc readConfig*() = + when defined(debug): + readConfig("res" / "config") + readConfig(getConfigDir() / "twt" / "config") diff --git a/src/io/buffer.nim b/src/io/buffer.nim index 31c02aa9..5eb2c71b 100644 --- a/src/io/buffer.nim +++ b/src/io/buffer.nim @@ -26,16 +26,19 @@ type BufferCell = object of Cell rune*: Rune -# xterm supports max 2 characters per cell by default. might make the tuple a -# seq in the future but for now it's fine like this + BufferRow = seq[BufferCell] + DisplayCell = object of Cell - runes*: tuple[a: Rune, b: Rune] + runes*: seq[Rune] + + DisplayRow = seq[DisplayCell] Buffer* = ref BufferObj BufferObj = object title*: string - lines*: seq[seq[BufferCell]] - display*: seq[DisplayCell] + lines*: seq[BufferRow] + display*: DisplayRow + prevdisplay*: DisplayRow hovertext*: string width*: int height*: int @@ -73,10 +76,10 @@ func generateFullOutput*(buffer: Buffer): string = result &= '\n' x = 0 - if cell.runes.a != Rune(0): - result &= $cell.runes.a - if cell.runes.b != Rune(0): - result &= $cell.runes.b + for r in cell.runes: + if r != Rune(0): + result &= $r + inc x func lastLine*(buffer: Buffer): int = @@ -89,6 +92,15 @@ func width(line: seq[BufferCell]): int = for c in line: result += c.rune.width() +func cellWidthOverlap*(buffer: Buffer, x: int, y: int): int = + let row = y * buffer.width + var ox = x + while buffer.display[row + ox].runes.len == 0 and ox > 0: + dec ox + return buffer.display[row + ox].runes.width() + +func currentCellWidth*(buffer: Buffer): int = buffer.cellWidthOverlap(buffer.cursorx - buffer.fromx, buffer.cursory - buffer.fromy) + func currentLineWidth*(buffer: Buffer): int = return buffer.lines[buffer.cursory].width() @@ -214,19 +226,22 @@ proc cursorUp*(buffer: Buffer) = buffer.redraw = true proc cursorRight*(buffer: Buffer) = - if buffer.cursorx < buffer.currentLineWidth() - 1: - inc buffer.cursorx + let cellwidth = buffer.currentCellWidth() + let lw = buffer.currentLineWidth() + if buffer.cursorx < lw - 1: + buffer.cursorx = min(lw - 1, buffer.cursorx + cellwidth) buffer.xend = buffer.cursorx if buffer.cursorx - buffer.width >= buffer.fromx: inc buffer.fromx buffer.redraw = true proc cursorLeft*(buffer: Buffer) = + let cellwidth = buffer.currentCellWidth() if buffer.fromx > buffer.cursorx: buffer.fromx = buffer.cursorx buffer.redraw = true elif buffer.cursorx > 0: - dec buffer.cursorx + buffer.cursorx = max(0, buffer.cursorx - cellwidth) if buffer.fromx > buffer.cursorx: buffer.fromx = buffer.cursorx buffer.redraw = true @@ -448,40 +463,40 @@ proc setDisplayText(buffer: Buffer, x: int, y: int, text: seq[Rune]) = var n = 0 while i < text.len: if text[i].width() == 0: - buffer.display[pos + i - n].runes.b = text[i] inc n - else: - buffer.display[pos + i - n].runes.a = text[i] + buffer.display[pos + i - n].runes.add(text[i]) inc i proc reshape*(buffer: Buffer) = buffer.display = newSeq[DisplayCell](buffer.width * buffer.height) +proc clearDisplay*(buffer: Buffer) = + var i = 0 + while i < buffer.display.len: + buffer.display[i].runes.setLen(0) + inc i + proc refreshDisplay*(buffer: Buffer) = var y = 0 + buffer.prevdisplay = buffer.display + buffer.clearDisplay() for line in buffer.lines[buffer.fromy..buffer.lastVisibleLine()]: var w = 0 var i = 0 - var n = 0 while w < buffer.fromx and i < line.len: w += line[i].rune.width() inc i let dls = y * buffer.width var j = 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: - buffer.display[dls + j].runes.b = line[i].rune - else: - buffer.display[dls + j].runes.a = line[i].rune + inc n + buffer.display[dls + j - n].runes.add(line[i].rune) + j += line[i].rune.width() inc i - inc j - - while j < buffer.width: - buffer.display[dls + j].runes.a = Rune(0) - buffer.display[dls + j].runes.b = Rune(0) - inc j inc y @@ -494,6 +509,8 @@ proc renderPlainText*(buffer: Buffer, text: string) = buffer.setText(0, y, line.toRunes()) inc y line = "" + elif text[i] == '\r': + discard elif text[i] == '\t': line &= ' '.repeat(8) else: diff --git a/src/io/display.nim b/src/io/display.nim index 6f7be014..f5c9f645 100644 --- a/src/io/display.nim +++ b/src/io/display.nim @@ -335,7 +335,7 @@ proc inputLoop(attrs: TermAttributes, buffer: Buffer): bool = buffer.setLocation(parseUri(url)) return true of ACTION_LINE_INFO: - statusMsg("line " & $buffer.cursory & "/" & $buffer.lastLine() & " col " & $(buffer.cursorx + 1) & "/" & $buffer.currentLineWidth(), buffer.width) + statusMsg("line " & $buffer.cursory & "/" & $buffer.lastLine() & " col " & $(buffer.cursorx + 1) & "/" & $buffer.currentLineWidth() & " cell width: " & $buffer.currentCellWidth(), buffer.width) nostatus = true of ACTION_FEED_NEXT: feedNext = true diff --git a/src/io/twtio.nim b/src/io/twtio.nim index 8a8bef1c..26c5be02 100644 --- a/src/io/twtio.nim +++ b/src/io/twtio.nim @@ -25,13 +25,13 @@ template printesc*(s: string) = stdout.write($r) proc getNormalAction*(s: string): TwtAction = - if normalActionRemap.hasKey(s): - return normalActionRemap[s] + if gconfig.nmap.hasKey(s): + return gconfig.nmap[s] return NO_ACTION proc getLinedAction*(s: string): TwtAction = - if linedActionRemap.hasKey(s): - return linedActionRemap[s] + if gconfig.lemap.hasKey(s): + return gconfig.lemap[s] return NO_ACTION type LineState = object @@ -151,16 +151,16 @@ proc insertCompose(state: var LineState, c: char) = else: cs = state.s.substr(0, state.compa - 1).toRunes() state.comps = state.s.substr(state.compa) - if state.comps.len > 0 and composeRemap.hasPrefix(state.comps): + if state.comps.len > 0 and gconfig.cmap.hasPrefix(state.comps): state.compa = state.comps.len - state.compn = composeRemap{state.comps} + state.compn = gconfig.cmap{state.comps} state.s = state.comps state.comps = "" state.feedNext = true else: cs &= state.comps.toRunes() state.compa = 0 - state.compn = composeRemap + state.compn = gconfig.cmap state.comps = "" state.insertCharseq(cs) @@ -168,7 +168,7 @@ proc insertCompose(state: var LineState, c: char) = proc readLine*(current: var string, minlen: int, maxlen: int): bool = var state: LineState state.news = current.toRunes() - state.compn = composeRemap + state.compn = gconfig.cmap state.cursor = state.news.len state.minlen = minlen state.maxlen = maxlen @@ -293,7 +293,7 @@ proc readLine*(current: var string, minlen: int, maxlen: int): bool = state.cursor = state.news.len of ACTION_LINED_COMPOSE_TOGGLE: state.comp = not state.comp - state.compn = composeRemap + state.compn = gconfig.cmap state.compa = 0 state.comps = "" of ACTION_FEED_NEXT: diff --git a/src/main.nim b/src/main.nim index 78d24e8d..8394b5ab 100644 --- a/src/main.nim +++ b/src/main.nim @@ -42,9 +42,7 @@ proc main*() = if paramCount() != 1: eprint "Invalid parameters. Usage:\ntwt <url>" quit(1) - if not readConfig("res/config"): - #eprint "Failed to read keymap, fallback to default" - discard + readConfig() let attrs = getTermAttributes() let buffer = newBuffer(attrs) let uri = parseUri(paramStr(1)) |