about summary refs log tree commit diff stats
path: root/src/io
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2021-12-23 16:16:51 +0100
committerbptato <nincsnevem662@gmail.com>2021-12-23 16:16:51 +0100
commitbfd634f845a8669a066ba55836e77d2d203959aa (patch)
tree8f66448b0786691b545469ef7c5783ff3819674b /src/io
parenteb16da9fdff2d483c9143a4caea641e021a9e3af (diff)
downloadchawan-bfd634f845a8669a066ba55836e77d2d203959aa.tar.gz
Fix pager bugs
Diffstat (limited to 'src/io')
-rw-r--r--src/io/buffer.nim77
-rw-r--r--src/io/lineedit.nim87
2 files changed, 98 insertions, 66 deletions
diff --git a/src/io/buffer.nim b/src/io/buffer.nim
index 35325ff7..82b5b46e 100644
--- a/src/io/buffer.nim
+++ b/src/io/buffer.nim
@@ -169,8 +169,6 @@ func numLines*(buffer: Buffer): int = buffer.lines.len
 func lastVisibleLine(buffer: Buffer): int = min(buffer.fromy + buffer.height, buffer.numLines)
 
 func currentLineWidth(buffer: Buffer): int =
-  if buffer.cursory > buffer.lines.len:
-    return 0
   return buffer.lines[buffer.cursory].width()
 
 func maxfromy(buffer: Buffer): int = max(buffer.numLines - buffer.height, 0)
@@ -227,6 +225,37 @@ func currentCursorBytes(buffer: Buffer): int =
     w += r.width()
   return i
 
+func currentWidth(buffer: Buffer): int =
+  let line = buffer.currentLine
+  if line.len == 0: return 0
+  var w = 0
+  var i = 0
+  let cc = buffer.fromx + buffer.cursorx
+  var r: Rune
+  fastRuneAt(line, i, r)
+  while i < line.len and w < cc:
+    fastRuneAt(line, i, r)
+    w += r.width()
+  return r.width()
+
+func prevWidth(buffer: Buffer): int =
+  let line = buffer.currentLine
+  var w = 0
+  var i = 0
+  let cc = buffer.fromx + buffer.cursorx
+  if i >= line.len:
+    assert i == 0
+    return 0
+  var r: Rune
+  var pr: Rune
+  while i < line.len and w < cc:
+    pr = r
+    fastRuneAt(line, i, r)
+    w += r.width()
+  if pr == Rune(0):
+    return 0
+  return pr.width()
+
 func maxScreenWidth*(buffer: Buffer): int =
   for line in buffer.lines[buffer.fromy..buffer.lastVisibleLine - 1]:
     result = max(line.width(), result)
@@ -331,9 +360,8 @@ proc setCursorX(buffer: Buffer, x: int) =
     fastRuneAt(buffer.currentLine, b, r)
     w += r.width()
 
-  b = min(b, max(buffer.currentLine.len - 1, 0))
   while b > 0 and w > x:
-    let (r, o) = lastRune(buffer.currentLine, b)
+    let (r, o) = lastRune(buffer.currentLine, b - 1)
     w -= r.width()
     b -= o
 
@@ -383,27 +411,20 @@ proc cursorUp*(buffer: Buffer) =
     buffer.setCursorY(buffer.cursory - 1)
 
 proc cursorRight*(buffer: Buffer) =
-  let cellwidth = buffer.cell().ow
-  if buffer.cursorx < buffer.currentLineWidth() - 1:
+  let cellwidth = buffer.currentWidth()
+  if buffer.cursorx + cellwidth < buffer.currentLineWidth():
     buffer.setCursorX(buffer.cursorx + cellwidth)
 
 proc cursorLeft*(buffer: Buffer) =
-  let cellwidth = buffer.cell().ow
+  let cellwidth = buffer.currentWidth()
   if buffer.cursorx >= cellwidth:
     buffer.setCursorX(buffer.cursorx - cellwidth)
 
 proc cursorLineBegin*(buffer: Buffer) =
-  buffer.cursorx = 0
-  buffer.xend = 0
-  if buffer.fromx > 0:
-    buffer.fromx = 0
-    buffer.redraw = true
+  buffer.setCursorX(0)
 
 proc cursorLineEnd*(buffer: Buffer) =
-  buffer.cursorx = max(buffer.currentLineWidth() - 1, 0)
-  buffer.xend = buffer.cursorx
-  buffer.fromx = max(buffer.cursorx - buffer.width + 1, 0)
-  buffer.redraw = buffer.redraw or buffer.fromx > 0
+  buffer.setCursorX(max(buffer.currentLineWidth() - 1, 0))
 
 proc cursorNextWord*(buffer: Buffer) =
   var r: Rune
@@ -532,33 +553,19 @@ proc cursorPrevLink*(buffer: Buffer) =
       dec i
 
 proc cursorFirstLine*(buffer: Buffer) =
-  if buffer.fromy > 0:
-    buffer.fromy = 0
-    buffer.redraw = true
-  else:
-    buffer.redraw = false
-
-  buffer.cursory = 0
-  buffer.restoreCursorX()
+  buffer.setCursorY(0)
 
 proc cursorLastLine*(buffer: Buffer) =
-  if buffer.fromy < buffer.numLines - buffer.height:
-    buffer.fromy = buffer.numLines - buffer.height
-    buffer.redraw = true
-  buffer.cursory = buffer.numLines - 1
-  buffer.restoreCursorX()
+  buffer.setCursorY(buffer.numLines - 1)
 
 proc cursorTop*(buffer: Buffer) =
-  buffer.cursory = buffer.fromy
-  buffer.restoreCursorX()
+  buffer.setCursorY(buffer.fromy)
 
 proc cursorMiddle*(buffer: Buffer) =
-  buffer.cursory = min(buffer.fromy + (buffer.height - 2) div 2, buffer.numLines - 1)
-  buffer.restoreCursorX()
+  buffer.setCursorY(min(buffer.fromy + (buffer.height - 2) div 2, buffer.numLines - 1))
 
 proc cursorBottom*(buffer: Buffer) =
-  buffer.cursory = min(buffer.fromy + buffer.height - 1, buffer.numLines - 1)
-  buffer.restoreCursorX()
+  buffer.setCursorY(min(buffer.fromy + buffer.height - 1, buffer.numLines - 1))
 
 proc cursorLeftEdge*(buffer: Buffer) =
   buffer.cursorx = buffer.fromx
diff --git a/src/io/lineedit.nim b/src/io/lineedit.nim
index ab9a1feb..b453bef5 100644
--- a/src/io/lineedit.nim
+++ b/src/io/lineedit.nim
@@ -19,6 +19,40 @@ type LineState = object
   displen: int
   spaces: seq[string]
 
+func lwidth(r: Rune): int =
+  if r.isControlChar():
+    return 2
+  return r.width()
+
+func lwidth(s: string): int =
+  for r in s.runes():
+    result += lwidth(r)
+
+func lwidth(s: seq[Rune]): int =
+  for r in s:
+    result += lwidth(r)
+
+func lwidth(s: seq[Rune], min, max: int): int =
+  var i = min
+  var mi = min(max, s.len)
+  while i < mi:
+    result += lwidth(s[i])
+    inc i
+
+func lwidth(s: seq[Rune], min: int): int =
+  var i = min
+  while i < s.len:
+    result += lwidth(s[i])
+    inc i
+
+template kill(state: LineState, i: int) =
+  state.space(i)
+  state.backward(i)
+
+template kill(state: LineState) =
+  let w = min(state.news.lwidth(state.cursor), state.displen)
+  state.kill(w)
+
 proc backward(state: LineState, i: int) =
   if i > 0:
     if i == 1:
@@ -32,50 +66,39 @@ proc forward(state: LineState, i: int) =
 
 proc begin(state: LineState) =
   print('\r')
-
   state.forward(state.minlen)
 
 proc space(state: LineState, i: int) =
   print(state.spaces[i])
 
-template kill(state: LineState, i: int) =
-  state.space(i)
-  state.backward(i)
-  #print("\e[K")
-
-template kill(state: LineState) =
-  let w = min(state.news.width(state.cursor), state.displen)
-  state.kill(w)
-
 proc redraw(state: var LineState) =
-  var dispw = state.news.width(state.shift, state.shift + state.displen)
+  var dispw = state.news.lwidth(state.shift, state.shift + state.displen)
   if state.shift + state.displen > state.news.len:
     state.displen = state.news.len - state.shift
   while dispw > state.maxlen - 1:
-    dispw -= state.news[state.shift + state.displen - 1].width()
+    dispw -= state.news[state.shift + state.displen - 1].lwidth()
     dec state.displen
 
   state.begin()
   let os = state.news.substr(state.shift, state.shift + state.displen)
   printesc($os)
-  state.space(max(state.maxlen - state.minlen - os.width(), 0))
+  state.space(max(state.maxlen - state.minlen - os.lwidth(), 0))
 
   state.begin()
-  state.forward(state.news.width(state.shift, state.cursor))
+  state.forward(state.news.lwidth(state.shift, state.cursor))
 
 proc zeroShiftRedraw(state: var LineState) =
   state.shift = 0
   state.displen = state.maxlen - 1
-
   state.redraw()
 
 proc fullRedraw(state: var LineState) =
   state.displen = state.maxlen - 1
   if state.cursor > state.shift:
-    var shiftw = state.news.width(state.shift, state.cursor)
+    var shiftw = state.news.lwidth(state.shift, state.cursor)
     while shiftw > state.maxlen - 1:
       inc state.shift
-      shiftw -= state.news[state.shift].width()
+      shiftw -= state.news[state.shift].lwidth()
   else:
     state.shift = max(state.cursor - 1, 0)
 
@@ -88,7 +111,7 @@ proc insertCharseq(state: var LineState, cs: var seq[Rune]) =
   if cs.len == 0:
     return
 
-  if state.cursor >= state.news.len and state.news.width(state.shift, state.cursor) + cs.width() < state.displen:
+  if state.cursor >= state.news.len and state.news.lwidth(state.shift, state.cursor) + cs.lwidth() < state.displen:
     state.news &= cs
     state.cursor += cs.len
     printesc($cs)
@@ -128,18 +151,20 @@ proc readLine*(current: var string, minlen, maxlen: int): bool =
       return true
     of ACTION_LINED_BACKSPACE:
       if state.cursor > 0:
+        let w = state.news[state.cursor - 1].lwidth()
         state.news.delete(state.cursor - 1, state.cursor - 1)
         dec state.cursor
         if state.cursor == state.news.len and state.shift == 0:
-          state.backward(1)
-          state.kill(1)
+          state.backward(w)
+          state.kill(w)
         else:
           state.fullRedraw()
     of ACTION_LINED_DELETE:
       if state.cursor > 0 and state.cursor < state.news.len:
+        let w = state.news[state.cursor - 1].lwidth()
         state.news.delete(state.cursor, state.cursor)
         if state.cursor == state.news.len and state.shift == 0:
-          state.kill(1)
+          state.kill(w)
         else:
           state.fullRedraw()
     of ACTION_LINED_ESC:
@@ -157,16 +182,16 @@ proc readLine*(current: var string, minlen, maxlen: int): bool =
       if state.cursor > 0:
         dec state.cursor
         if state.cursor > state.shift or state.shift == 0:
-          state.backward(state.news[state.cursor].width())
+          state.backward(state.news[state.cursor].lwidth())
         else:
           state.fullRedraw()
     of ACTION_LINED_FORWARD:
       if state.cursor < state.news.len:
         inc state.cursor
-        if state.news.width(state.shift, state.cursor) < state.displen:
+        if state.news.lwidth(state.shift, state.cursor) < state.displen:
           var n = 1
           if state.news.len > state.cursor:
-            n = state.news[state.cursor].width()
+            n = state.news[state.cursor].lwidth()
           state.forward(n)
         else:
           state.fullRedraw()
@@ -178,7 +203,7 @@ proc readLine*(current: var string, minlen, maxlen: int): bool =
           break
       if state.cursor != oc:
         if state.cursor > state.shift or state.shift == 0:
-          state.backward(state.news.width(state.cursor, oc))
+          state.backward(state.news.lwidth(state.cursor, oc))
         else:
           state.fullRedraw()
     of ACTION_LINED_NEXT_WORD:
@@ -190,7 +215,7 @@ proc readLine*(current: var string, minlen, maxlen: int): bool =
             break
 
       if state.cursor != oc:
-        let dw = state.news.width(oc, state.cursor)
+        let dw = state.news.lwidth(oc, state.cursor)
         if oc + dw - state.shift < state.displen:
           state.forward(dw)
         else:
@@ -206,7 +231,7 @@ proc readLine*(current: var string, minlen, maxlen: int): bool =
           dec chars
           break
       if chars > 0:
-        let w = state.news.width(state.cursor - chars, state.cursor)
+        let w = state.news.lwidth(state.cursor - chars, state.cursor)
         state.news.delete(state.cursor - chars, state.cursor - 1)
         state.cursor -= chars
         if state.cursor == state.news.len and state.shift == 0:
@@ -217,14 +242,14 @@ proc readLine*(current: var string, minlen, maxlen: int): bool =
     of ACTION_LINED_BEGIN:
       if state.cursor > 0:
         if state.shift == 0:
-          state.backward(state.news.width(0, state.cursor))
+          state.backward(state.news.lwidth(0, state.cursor))
         else:
           state.fullRedraw()
         state.cursor = 0
     of ACTION_LINED_END:
       if state.cursor < state.news.len:
-        if state.news.width(state.shift, state.news.len) < maxlen:
-          state.forward(state.news.width(state.cursor, state.news.len))
+        if state.news.lwidth(state.shift, state.news.len) < maxlen:
+          state.forward(state.news.lwidth(state.cursor, state.news.len))
         else:
           state.fullRedraw()
         state.cursor = state.news.len
@@ -238,4 +263,4 @@ proc readLine*(current: var string, minlen, maxlen: int): bool =
 
 proc readLine*(prompt: string, current: var string, termwidth: int): bool =
   printesc(prompt)
-  readLine(current, prompt.width(), termwidth - prompt.len)
+  readLine(current, prompt.lwidth(), termwidth - prompt.len)