From 4162cdc9802c55fcea40b811d0eb49515aae6ed2 Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Mon, 25 Mar 2024 17:38:53 +0100 Subject: [PATCH] Add basic control of cursor position in text input mode Using the arrow keys, the cursor can be moved left or right. --- src/core.nim | 5 ++++- src/draw.nim | 16 ++++++++++------ src/nimmm.nim | 31 ++++++++++++++++++++++++------- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/core.nim b/src/core.nim index 882cda3..167011b 100644 --- a/src/core.nim +++ b/src/core.nim @@ -12,10 +12,13 @@ type ModeInfo* = object case mode*: Mode - of MdNormal, MdSearch: discard + of MdNormal: discard + of MdSearch: + searchCursorPos*: int = 0 of MdInputText: promptText*: string input*: string = "" + textCursorPos*: int = 0 callbackText*: proc (input: string) of MdInputBool: promptBool*: string diff --git a/src/draw.nim b/src/draw.nim index e350514..2a2adab 100644 --- a/src/draw.nim +++ b/src/draw.nim @@ -168,13 +168,15 @@ proc drawFooter(index: int, lenEntries: int, lenSelected: int, hidden: bool, nb.print(offsetErrMsg, y, " " & errMsg, c8(clrRed), c8(clrBlack)) nb.cursor = (TB_HIDE_CURSOR, TB_HIDE_CURSOR) -proc drawInputFooter(prompt: string, query: string, nb: var Nimbox) = +proc drawInputFooter(prompt: string, query: string, cursorPos: int, + nb: var Nimbox) = let y = nb.height() - 1 - offset = prompt.len + 1 + offset = prompt.wcswidth + 1 + cursorPos = offset + query[0..cursorPos - 1].wcswidth nb.print(0, y, prompt, c8(clrYellow), c8(clrBlack)) nb.print(offset, y, query, c8(clrYellow), c8(clrBlack)) - nb.cursor = (offset + query.wcswidth, y) + nb.cursor = (cursorPos, y) proc errMsg(err: ErrorKind): string = case err @@ -215,10 +217,12 @@ proc redraw*(s: State, nb: var Nimbox) = s.showHidden, s.currentSearchQuery != "", errMsg, nb) of MdSearch: - drawInputFooter("search:", s.currentSearchQuery, nb) + drawInputFooter("search:", s.currentSearchQuery, + s.modeInfo.searchCursorPos, nb) of MdInputText: - drawInputFooter(s.modeInfo.promptText, s.modeInfo.input, nb) + drawInputFooter(s.modeInfo.promptText, s.modeInfo.input, + s.modeInfo.textCursorPos, nb) of MdInputBool: - drawInputFooter(s.modeInfo.promptBool, "", nb) + drawInputFooter(s.modeInfo.promptBool, "", 0, nb) nb.present() diff --git a/src/nimmm.nim b/src/nimmm.nim index 358f790..f3399a8 100644 --- a/src/nimmm.nim +++ b/src/nimmm.nim @@ -128,7 +128,8 @@ type PrComplete, proc processInputTextMode(event: nimbox.Event, - input: var string): ProcessInputTextModeResult = + input: var string, + cursorPos: var int): ProcessInputTextModeResult = ## common input processing for MdInputText and MdSearch case event.kind of EventType.Key: @@ -136,14 +137,28 @@ proc processInputTextMode(event: nimbox.Event, of Symbol.Escape: return PrCanceled of Symbol.Backspace: - if input.len > 0: - input.setLen(input.high) + if cursorPos > 0: + let (_, runeLen) = lastRune(input, cursorPos - 1) + input = input[0..cursorPos - 1 - runeLen] & input.substr(cursorPos) + cursorPos -= runeLen of Symbol.Enter: return PrComplete of Symbol.Space: - input.add(" ") + let inserted = " " + input.insert(inserted, cursorPos) + cursorPos += inserted.len of Symbol.Character: - input.add($event.ch.Rune) + let inserted = $event.ch.Rune + input.insert(inserted, cursorPos) + cursorPos += inserted.len + of Symbol.Left: + if cursorPos > 0: + let (_, runeLen) = lastRune(input, cursorPos - 1) + cursorPos -= runeLen + of Symbol.Right: + if cursorPos < input.len: + let runeLen = runeLenAt(input, cursorPos) + cursorPos += runeLen else: discard of EventType.Mouse, EventType.Resize, EventType.None: @@ -208,7 +223,8 @@ proc mainLoop(nb: var Nimbox, enable256Colors: bool) = discard # Input text mode: Ignore keymap of MdInputText: - case processInputTextMode(event, s.modeInfo.input) + case processInputTextMode(event, s.modeInfo.input, + s.modeInfo.textCursorPos) of PrCanceled: s.modeInfo = ModeInfo(mode: MdNormal) of PrComplete: @@ -220,7 +236,8 @@ proc mainLoop(nb: var Nimbox, enable256Colors: bool) = discard # Incremental search mode: Ignore keymap of MdSearch: - case processInputTextMode(event, s.currentSearchQuery) + case processInputTextMode(event, s.currentSearchQuery, + s.modeInfo.searchCursorPos) of PrCanceled: s.resetTab() of PrComplete: