diff options
Diffstat (limited to 'twtio.nim')
-rw-r--r-- | twtio.nim | 267 |
1 files changed, 75 insertions, 192 deletions
diff --git a/twtio.nim b/twtio.nim index acb4add7..db811f40 100644 --- a/twtio.nim +++ b/twtio.nim @@ -1,21 +1,22 @@ import terminal import tables -import strutils import unicode import twtstr import config +import radixtree template print*(s: varargs[string, `$`]) = for x in s: stdout.write(x) template printesc*(s: string) = - for ruby in s: - if ($ruby)[0].isControlChar(): - stdout.write(($($ruby)[0].getControlLetter()).ansiFgColor(fgBlue).ansiStyle(styleBright).ansiReset()) + for r in s.runes: + if r.isControlChar(): + stdout.write(('^' & $($r)[0].getControlLetter()) + .ansiFgColor(fgBlue).ansiStyle(styleBright).ansiReset()) else: - stdout.write($ruby) + stdout.write($r) template eprint*(s: varargs[string, `$`]) = {.cast(noSideEffect).}: var a = false @@ -40,181 +41,31 @@ proc getLinedAction*(s: string): TwtAction = return linedActionRemap[s] return NO_ACTION -const breakWord = [ - Rune('\n'), Rune('/'), Rune('\\'), Rune(' '), Rune('&'), Rune('=') -] - -#proc readLine*(prompt: string, current: var string, termwidth: int): bool = -# var new = current -# print(prompt) -# let maxlen = termwidth - prompt.len -# printesc(new) -# var s = "" -# var feedNext = false -# var escNext = false -# var cursor = new.runeLen -# var shift = 0 -# while true: -# var rl = new.runeLen() -# -# if cursor < shift: -# shift = cursor -# elif cursor - shift > maxlen: -# shift += cursor - maxlen -# -# if not feedNext: -# s = "" -# else: -# feedNext = false -# let c = getch() -# s &= c -# var action = getLinedAction(s) -# if escNext: -# action = NO_ACTION -# case action -# of ACTION_LINED_CANCEL: -# return false -# of ACTION_LINED_SUBMIT: -# current = new -# return true -# of ACTION_LINED_BACKSPACE: -# if cursor > 0: -# print(' '.repeat(rl - cursor + 1)) -# print('\b'.repeat(rl - cursor + 1)) -# print("\b \b") -# new = new.runeSubstr(0, cursor - 1) & new.runeSubstr(cursor) -# rl = new.runeLen() -# cursor -= 1 -# printesc(new.runeSubstr(cursor)) -# print('\b'.repeat(rl - cursor)) -# of ACTION_LINED_ESC: -# escNext = true -# of ACTION_LINED_CLEAR: -# print('\r') -# print(' '.repeat(termwidth)) -# print('\r') -# new = new.runeSubstr(cursor) -# rl = new.runeLen() -# printesc(prompt) -# printesc(new.maxString(maxlen + 1)) -# print('\r') -# printesc(prompt) -# cursor = 0 -# of ACTION_LINED_KILL: -# print(' '.repeat(rl - cursor + 1)) -# print('\b'.repeat(rl - cursor + 1)) -# new = new.runeSubstr(0, cursor) -# of ACTION_LINED_BACK: -# if cursor > 0: -# if cursor < maxlen: -# print('\b') -# dec cursor -# of ACTION_LINED_FORWARD: -# if cursor < rl: -# if cursor + 1 < maxlen: -# var rune: Rune -# new.fastRuneAt(cursor, rune, false) -# printesc($rune) -# elif cursor + 1 == maxlen: -# print('$') -# inc cursor -# of ACTION_LINED_PREV_WORD: -# while cursor > 0: -# print('\b') -# cursor -= 1 -# var rune: Rune -# new.fastRuneAt(cursor, rune, false) -# if rune in breakWord: -# break -# of ACTION_LINED_NEXT_WORD: -# while cursor < rl: -# var rune: Rune -# new.fastRuneAt(cursor, rune, false) -# printesc($rune) -# inc cursor -# if cursor < rl: -# new.fastRuneAt(cursor, rune, false) -# if rune in breakWord: -# break -# of ACTION_LINED_KILL_WORD: -# var chars = 0 -# while cursor > chars: -# inc chars -# var rune: Rune -# new.fastRuneAt(cursor - chars, rune, false) -# if rune in breakWord: -# break -# if chars > 0: -# print(' '.repeat(rl - cursor + 1)) -# print('\b'.repeat(rl - cursor + 1)) -# print("\b \b".repeat(chars)) -# new = new.runeSubstr(0, cursor - chars) & new.runeSubstr(cursor) -# rl = new.runeLen() -# cursor -= chars -# printesc(new.runeSubstr(cursor)) -# print('\b'.repeat(rl - cursor)) -# of ACTION_FEED_NEXT: -# feedNext = true -# elif validateUtf8(s) == -1: -# var cs = "" -# for c in s: -# if not c.isControlChar(): -# cs &= c -# elif escNext: -# cs &= c -# escNext = false -# escNext = false -# if cs.len == 0: -# continue -# if rl + 1 < maxlen: -# print(' '.repeat(rl - cursor + 1)) -# print('\b'.repeat(rl - cursor + 1)) -# new = new.runeSubstr(0, cursor) & cs & new.runeSubstr(cursor) -# rl = new.runeLen() -# if cursor - shift > maxlen: -# shift += maxlen - cursor -# if shift == 0: -# printesc(new.runeSubstr(cursor, min(maxlen - cursor - 1, rl))) -# print('\b'.repeat(max(min(maxlen - cursor - 2, rl - cursor - 1), 0))) -# else: -# print('\r') -# print(' '.repeat(termwidth)) -# print('\r') -# print(prompt) -# print(new.runeSubstr(shift, min(maxlen - 1, rl - shift))) -# if maxlen < rl - shift: -# print(new.runeSubstr(shift, maxlen - 1)) -# print('\b'.repeat(maxlen - cursor + shift)) -# else: -# print(new.runeSubstr(shift, rl - shift)) -# print('\b'.repeat(rl + shift - cursor)) -# inc cursor -# else: -# feedNext = true - proc readLine*(prompt: string, current: var string, termwidth: int): bool = - var new = current - print(prompt) + var news = current.toRunes() let maxlen = termwidth - prompt.len - printesc(new) var s = "" var feedNext = false var escNext = false - var cursor = new.runeLen + var comp = false + var compi: uint16 = 0 + var compa = 0 + var comps = "" + var cursor = news.len var shift = 0 while true: - var rl = new.runeLen() - print('\r') - print(' '.repeat(termwidth)) - print('\r') - printesc(prompt & new) - print('\r') - cursorForward(prompt.len + cursor) - + let rl = news.len if cursor < shift: - shift = cursor - elif cursor - shift > maxlen: - shift += cursor - maxlen + shift = max(cursor - 1, 0) + else: + while news.substr(shift, shift + cursor).width() > maxlen - 1: + shift += news[^1].width() + + eraseLine() + printesc(prompt & $news.substr(shift, shift + maxlen - 1)) + + print('\r') + cursorForward(prompt.len + news.substr(shift, cursor).width()) if not feedNext: s = "" @@ -229,21 +80,22 @@ proc readLine*(prompt: string, current: var string, termwidth: int): bool = of ACTION_LINED_CANCEL: return false of ACTION_LINED_SUBMIT: - current = new + current = $news return true of ACTION_LINED_BACKSPACE: if cursor > 0: - new = new.runeSubstr(0, cursor - 1) & new.runeSubstr(cursor) - rl = new.runeLen() + news = news.substr(0, cursor - 1) & news.substr(cursor) dec cursor + of ACTION_LINED_DELETE: + if cursor > 0 and cursor < rl: + news = news.substr(0, cursor) & news.substr(cursor + 1) of ACTION_LINED_ESC: escNext = true of ACTION_LINED_CLEAR: - new = new.runeSubstr(cursor) - rl = new.runeLen() + news = news.substr(cursor) cursor = 0 of ACTION_LINED_KILL: - new = new.runeSubstr(0, cursor) + news = news.substr(0, cursor) of ACTION_LINED_BACK: if cursor > 0: dec cursor @@ -253,32 +105,64 @@ proc readLine*(prompt: string, current: var string, termwidth: int): bool = of ACTION_LINED_PREV_WORD: while cursor > 0: dec cursor - var rune: Rune - new.fastRuneAt(cursor, rune, false) - if rune in breakWord: + if news[cursor].breaksWord(): break of ACTION_LINED_NEXT_WORD: while cursor < rl: - var rune: Rune inc cursor if cursor < rl: - new.fastRuneAt(cursor, rune, false) - if rune in breakWord: + if news[cursor].breaksWord(): break of ACTION_LINED_KILL_WORD: var chars = 0 while cursor > chars: inc chars - var rune: Rune - new.fastRuneAt(cursor - chars, rune, false) - if rune in breakWord: + if news[cursor - chars].breaksWord(): break if chars > 0: - new = new.runeSubstr(0, cursor - chars) & new.runeSubstr(cursor) - rl = new.runeLen() + news = news.substr(0, cursor - chars) & news.substr(cursor) cursor -= chars + of ACTION_LINED_COMPOSE_ON: + comp = true + compi = 0 + compa = 0 + comps = "" + of ACTION_LINED_COMPOSE_OFF: + comp = false + compi = 0 + compa = 0 + comps = "" + of ACTION_LINED_COMPOSE_TOGGLE: + comp = not comp + compi = 0 + compa = 0 + comps = "" of ACTION_FEED_NEXT: feedNext = true + elif comp: + comps &= c + let n = composeRemap.getPrefix(comps, compi) + if n != compi: + compi = n + compa += comps.len + comps = "" + if composeRemap.hasPrefix(comps, compi) and composeRemap.nodes[n].children.len > 0: + feedNext = true + else: + var cs = "" + if composeRemap.nodes[compi].leaf: + cs = composeRemap.nodes[compi].value + else: + cs = s.substr(0, compa - 1) + comps = s.substr(compa) + if not composeRemap.hasPrefix(comps, 0): + cs &= comps + comps = "" + + news = news.substr(0, cursor) & cs.toRunes() & news.substr(cursor) + cursor += cs.runeLen() + compi = 0 + compa = 0 elif validateUtf8(s) == -1: var cs = "" for c in s: @@ -290,8 +174,7 @@ proc readLine*(prompt: string, current: var string, termwidth: int): bool = escNext = false if cs.len == 0: continue - new = new.runeSubstr(0, cursor) & cs & new.runeSubstr(cursor) - rl = new.runeLen() - inc cursor + news = news.substr(0, cursor) & cs.toRunes() & news.substr(cursor) + cursor += cs.runeLen() else: feedNext = true |