about summary refs log tree commit diff stats
path: root/src/io/buffer.nim
diff options
context:
space:
mode:
Diffstat (limited to 'src/io/buffer.nim')
-rw-r--r--src/io/buffer.nim146
1 files changed, 81 insertions, 65 deletions
diff --git a/src/io/buffer.nim b/src/io/buffer.nim
index 2cdc1a77..ec61999b 100644
--- a/src/io/buffer.nim
+++ b/src/io/buffer.nim
@@ -177,7 +177,7 @@ func currentCellOrigin(buffer: Buffer): int =
   return buffer.cellOrigin(buffer.acursorx, buffer.acursory)
 
 #TODO counter-intuitive naming?
-func currentCell(buffer: Buffer): FixedCell =
+func currentDisplayCell(buffer: Buffer): FixedCell =
   let row = (buffer.cursory - buffer.fromy) * buffer.width
   return buffer.display[row + buffer.currentCellOrigin()]
 
@@ -186,13 +186,13 @@ func cell(buffer: Buffer): FixedCell =
   return buffer.display[row + buffer.acursorx]
 
 func currentRune(buffer: Buffer): Rune =
-  let cell = buffer.currentCell()
+  let cell = buffer.currentDisplayCell()
   if cell.runes.len == 0:
     return Rune(' ')
   return cell.runes[0]
 
 func getCursorLink(buffer: Buffer): Element =
-  let nodes = buffer.currentCell().nodes
+  let nodes = buffer.currentDisplayCell().nodes
   for node in nodes:
     if node.nodeType == ELEMENT_NODE:
       let elem = Element(node)
@@ -205,6 +205,20 @@ func currentLineWidth*(buffer: Buffer): int =
     return 0
   return buffer.lines[buffer.cursory].width()
 
+func currentLine(buffer: Buffer): string =
+  return buffer.lines[buffer.cursory].str
+
+func currentCursorBytes(buffer: Buffer): int =
+  let line = buffer.currentLine
+  var w = 0
+  var i = 0
+  let cc = buffer.fromx + buffer.cursorx
+  while i < line.len and w < cc:
+    var r: Rune
+    fastRuneAt(line, i, r)
+    w += r.width()
+  return i
+
 func maxScreenWidth*(buffer: Buffer): int =
   for line in buffer.lines[buffer.fromy..buffer.lastVisibleLine - 1]:
     result = max(line.width(), result)
@@ -279,7 +293,6 @@ proc refreshDisplay*(buffer: Buffer) =
 
     inc y
 
-
 proc restoreCursorX(buffer: Buffer) =
   buffer.cursorx = max(min(buffer.currentLineWidth() - 1, buffer.xend), 0)
 
@@ -354,6 +367,25 @@ proc cursorLeft*(buffer: Buffer) =
 
   buffer.xend = buffer.cursorx
 
+proc setCursorX*(buffer: Buffer, x: int) =
+  var b = buffer.currentCursorBytes()
+  var w = buffer.fromx + buffer.cursorx
+  while b < buffer.currentLine.len and w < x:
+    var r: Rune
+    fastRuneAt(buffer.currentLine, b, r)
+    w += r.width()
+  while b > 0 and w > x:
+    let (r, o) = lastRune(buffer.currentLine, b)
+    w -= r.width()
+    b -= o
+
+  if w - buffer.fromx <= buffer.width:
+    buffer.cursorx = w - buffer.fromx
+  else:
+    buffer.fromx = w - buffer.width
+    buffer.cursorx = w - buffer.fromx
+    buffer.redraw = true
+
 proc cursorLineBegin*(buffer: Buffer) =
   buffer.cursorx = 0
   buffer.xend = 0
@@ -368,82 +400,66 @@ proc cursorLineEnd*(buffer: Buffer) =
   buffer.redraw = buffer.fromx > 0
 
 proc cursorNextWord*(buffer: Buffer) =
-  let llen = buffer.currentLineWidth() - 1
-  if llen >= 0:
-    while not buffer.currentRune().breaksWord():
-      if buffer.cursorx >= llen:
-        break
-      buffer.cursorRight()
+  var r: Rune
+  var b = buffer.currentCursorBytes()
+  var x = buffer.fromx + buffer.cursorx
+  while b < buffer.currentLine.len:
+    let pb = b
+    fastRuneAt(buffer.currentLine, b, r)
+    if r.breaksWord():
+      b = pb
+      break
+    x += r.width()
 
-    while buffer.currentRune().breaksWord():
-      if buffer.cursorx >= llen:
-        break
-      buffer.cursorRight()
+  while b < buffer.currentLine.len:
+    let pb = b
+    fastRuneAt(buffer.currentLine, b, r)
+    if not r.breaksWord():
+      b = pb
+      break
+    x += r.width()
 
-  if buffer.cursorx >= buffer.currentLineWidth() - 1:
+  if b < buffer.currentLine.len:
+    buffer.setCursorX(x)
+  else:
     if buffer.cursory < buffer.numLines - 1:
       buffer.cursorDown()
       buffer.cursorLineBegin()
+    else:
+      buffer.cursorLineEnd()
 
 proc cursorPrevWord*(buffer: Buffer) =
-  if buffer.currentLineWidth() > 0:
-    while not buffer.currentRune().breaksWord():
-      if buffer.cursorx == 0:
+  var b = buffer.currentCursorBytes()
+  var x = buffer.fromx + buffer.cursorx
+  if buffer.currentLine.len > 0:
+    var r: Rune
+    while b >= 0:
+      let (r, o) = lastRune(buffer.currentLine, b)
+      if r.breaksWord():
         break
-      buffer.cursorLeft()
+      b -= o
+      x -= r.width()
 
-    while buffer.currentRune().breaksWord():
-      if buffer.cursorx == 0:
+    while b >= 0:
+      let (r, o) = lastRune(buffer.currentLine, b)
+      if not r.breaksWord():
         break
-      buffer.cursorLeft()
+      b -= o
+      x -= r.width()
+  else:
+    b = -1
 
-  if buffer.cursorx == 0:
+  if b >= 0:
+    buffer.setCursorX(x)
+  else:
     if buffer.cursory > 0:
       buffer.cursorUp()
       buffer.cursorLineEnd()
-
-#TODO this is sloooooow
-#proc cursorRightOverflow(buffer: Buffer) =
-#  buffer.cursorRight()
-#  if buffer.cursorx >= buffer.currentLineWidth() - 1 and buffer.cursory < buffer.numLines - 1:
-#    buffer.cursorDown()
-#    buffer.cursorLineBegin()
-#  buffer.refreshDisplay()
-#
-#proc cursorLeftOverflow(buffer: Buffer) =
-#  buffer.cursorLeft()
-#  if buffer.cursorx <= 0 and buffer.cursory > 0:
-#    buffer.cursorUp()
-#    buffer.cursorLineEnd()
-#  buffer.refreshDisplay()
+    else:
+      buffer.cursorLineBegin()
 
 proc cursorNextLink*(buffer: Buffer) =
   #TODO
-  #let ocx = buffer.cursorx
-  #let ocy = buffer.cursory
-  #let ofx = buffer.fromx
-  #let ofy = buffer.fromy
-  #let elem = buffer.getCursorLink()
-  #if elem != nil:
-  #  while buffer.getCursorLink() == elem:
-  #    buffer.cursorRightOverflow()
-  #    if buffer.cursorx >= buffer.currentLineWidth() - 1 and
-  #        buffer.cursory >= buffer.numLines - 1:
-  #      buffer.cursorx = ocx
-  #      buffer.cursory = ocy
-  #      buffer.fromx = ofx
-  #      buffer.fromy = ofy
-  #      break
-
-  #while buffer.getCursorLink() == nil:
-  #  buffer.cursorRightOverflow()
-  #  if buffer.cursorx >= buffer.currentLineWidth() - 1 and
-  #      buffer.cursory >= buffer.numLines - 1:
-  #    buffer.cursorx = ocx
-  #    buffer.cursory = ocy
-  #    buffer.fromx = ofx
-  #    buffer.fromy = ofy
-  #    break
   discard
 
 proc cursorPrevLink*(buffer: Buffer) =
@@ -668,7 +684,7 @@ proc updateCursor(buffer: Buffer) =
     buffer.cursory = 0
 
 proc updateHover(buffer: Buffer) =
-  let nodes = buffer.currentCell().nodes
+  let nodes = buffer.currentDisplayCell().nodes
   if nodes != buffer.prevnodes:
     for node in nodes:
       var elem: Element
@@ -875,7 +891,7 @@ proc inputLoop(attrs: TermAttributes, buffer: Buffer): bool =
         buffer.setLocation(parseUri(url))
         return true
     of ACTION_LINE_INFO:
-      buffer.setStatusMessage("line " & $(buffer.cursory + 1) & "/" & $buffer.numLines & " col " & $(buffer.cursorx + 1) & "/" & $buffer.currentLineWidth() & " cell width: " & $buffer.currentCell().width())
+      buffer.setStatusMessage("line " & $(buffer.cursory + 1) & "/" & $buffer.numLines & " col " & $(buffer.cursorx + 1) & "/" & $buffer.currentLineWidth() & " cell width: " & $buffer.currentDisplayCell().width())
       nostatus = true
     of ACTION_FEED_NEXT:
       feedNext = true