about summary refs log tree commit diff stats
path: root/src/local
diff options
context:
space:
mode:
Diffstat (limited to 'src/local')
-rw-r--r--src/local/container.nim166
1 files changed, 156 insertions, 10 deletions
diff --git a/src/local/container.nim b/src/local/container.nim
index 83ba16f0..fe6e30e5 100644
--- a/src/local/container.nim
+++ b/src/local/container.nim
@@ -655,28 +655,140 @@ proc cursorLineBegin(container: Container) {.jsfunc.} =
 proc cursorLineEnd(container: Container) {.jsfunc.} =
   container.setCursorX(container.currentLineWidth() - 1)
 
-proc cursorNextWord(container: Container) {.jsfunc.} =
+type BreakFunc = proc(r: Rune): BreakCategory {.nimcall.}
+
+proc cursorNextWord(container: Container, breakFunc: BreakFunc) =
   if container.numLines == 0: return
   var r: Rune
   var b = container.currentCursorBytes()
   var x = container.cursorx
+  # meow
+  let currentCat = if b < container.currentLine.len:
+    container.currentLine.runeAt(b).breakFunc()
+  else:
+    BREAK_SPACE
+  if currentCat != BREAK_SPACE:
+    # not in space, skip chars that have the same category
+    while b < container.currentLine.len:
+      let pb = b
+      fastRuneAt(container.currentLine, b, r)
+      if r.breakFunc() != currentCat:
+        b = pb
+        break
+      x += r.twidth(x)
+
+  # skip space
   while b < container.currentLine.len:
     let pb = b
     fastRuneAt(container.currentLine, b, r)
-    if r.breaksWord():
+    if r.breakFunc() != BREAK_SPACE:
       b = pb
       break
     x += r.twidth(x)
 
+  if b < container.currentLine.len:
+    container.setCursorX(x)
+  else:
+    if container.cursory < container.numLines - 1:
+      container.cursorDown()
+      container.cursorLineBegin()
+    else:
+      container.cursorLineEnd()
+
+proc cursorNextWord(container: Container) {.jsfunc.} =
+  container.cursorNextWord(breaksWordCat)
+
+proc cursorNextViWord(container: Container) {.jsfunc.} =
+  container.cursorNextWord(breaksViWordCat)
+
+proc cursorNextBigWord(container: Container) {.jsfunc.} =
+  container.cursorNextWord(breaksBigWordCat)
+
+proc cursorPrevWord(container: Container, breakFunc: BreakFunc) =
+  if container.numLines == 0: return
+  var b = container.currentCursorBytes()
+  var x = container.cursorx
+  if container.currentLine.len > 0:
+    b = min(b, container.currentLine.len - 1)
+    let currentCat = if b >= 0:
+      container.currentLine.runeAt(b).breakFunc()
+    else:
+      BREAK_SPACE
+    if currentCat != BREAK_SPACE:
+      # not in space, skip chars that have the same category
+      while b >= 0:
+        let (r, o) = lastRune(container.currentLine, b)
+        if r.breakFunc() != currentCat:
+          break
+        b -= o
+        x -= r.twidth(x)
+
+    # skip space
+    while b >= 0:
+      let (r, o) = lastRune(container.currentLine, b)
+      if r.breakFunc() != BREAK_SPACE:
+        break
+      b -= o
+      x -= r.twidth(x)
+  else:
+    b = -1
+
+  if b >= 0:
+    container.setCursorX(x)
+  else:
+    if container.cursory > 0:
+      container.cursorUp()
+      container.cursorLineEnd()
+    else:
+      container.cursorLineBegin()
+
+proc cursorPrevWord(container: Container) {.jsfunc.} =
+  container.cursorPrevWord(breaksWordCat)
+
+proc cursorPrevViWord(container: Container) {.jsfunc.} =
+  container.cursorPrevWord(breaksViWordCat)
+
+proc cursorPrevBigWord(container: Container) {.jsfunc.} =
+  container.cursorPrevWord(breaksBigWordCat)
+
+proc cursorWordEnd(container: Container, breakFunc: BreakFunc) =
+  if container.numLines == 0: return
+  var r: Rune
+  var b = container.currentCursorBytes()
+  var x = container.cursorx
+  var px = x
+  # if not in space, move to the right by one
+  if b < container.currentLine.len:
+    let pb = b
+    fastRuneAt(container.currentLine, b, r)
+    if r.breakFunc() == BREAK_SPACE:
+      b = pb
+    else:
+      px = x
+      x += r.twidth(x)
+
+  # skip space
   while b < container.currentLine.len:
     let pb = b
     fastRuneAt(container.currentLine, b, r)
-    if not r.breaksWord():
+    if r.breakFunc() != BREAK_SPACE:
       b = pb
       break
     x += r.twidth(x)
 
   if b < container.currentLine.len:
+    let currentCat = container.currentLine.runeAt(b).breakFunc()
+    while b < container.currentLine.len:
+      let pb = b
+      fastRuneAt(container.currentLine, b, r)
+      if r.breakFunc() != currentCat:
+        b = pb
+        break
+      px = x
+      x += r.twidth(x)
+    x = px
+
+  if b < container.currentLine.len:
     container.setCursorX(x)
   else:
     if container.cursory < container.numLines - 1:
@@ -685,25 +797,50 @@ proc cursorNextWord(container: Container) {.jsfunc.} =
     else:
       container.cursorLineEnd()
 
-proc cursorPrevWord(container: Container) {.jsfunc.} =
+proc cursorWordEnd(container: Container) {.jsfunc.} =
+  container.cursorWordEnd(breaksWordCat)
+
+proc cursorViWordEnd(container: Container) {.jsfunc.} =
+  container.cursorWordEnd(breaksViWordCat)
+
+proc cursorBigWordEnd(container: Container) {.jsfunc.} =
+  container.cursorWordEnd(breaksBigWordCat)
+
+proc cursorWordBegin(container: Container, breakFunc: BreakFunc) =
   if container.numLines == 0: return
   var b = container.currentCursorBytes()
   var x = container.cursorx
+  var px = x
   if container.currentLine.len > 0:
     b = min(b, container.currentLine.len - 1)
-    while b >= 0:
+    if b >= 0:
       let (r, o) = lastRune(container.currentLine, b)
-      if r.breaksWord():
-        break
-      b -= o
-      x -= r.twidth(x)
+      # if not in space, move to the left by one
+      if r.breakFunc() != BREAK_SPACE:
+        b -= o
+        px = x
+        x -= r.twidth(x)
 
+    # skip space
     while b >= 0:
       let (r, o) = lastRune(container.currentLine, b)
-      if not r.breaksWord():
+      if r.breakFunc() != BREAK_SPACE:
         break
       b -= o
       x -= r.twidth(x)
+
+    # move to the last char in the current category
+    if b >= 0:
+      let (r, _) = lastRune(container.currentLine, b)
+      let currentCat = r.breakFunc()
+      while b >= 0:
+        let (r, o) = lastRune(container.currentLine, b)
+        if r.breakFunc() != currentCat:
+          break
+        b -= o
+        px = x
+        x -= r.twidth(x)
+    x = px
   else:
     b = -1
 
@@ -716,6 +853,15 @@ proc cursorPrevWord(container: Container) {.jsfunc.} =
     else:
       container.cursorLineBegin()
 
+proc cursorWordBegin(container: Container) {.jsfunc.} =
+  container.cursorWordBegin(breaksWordCat)
+
+proc cursorViWordBegin(container: Container) {.jsfunc.} =
+  container.cursorWordBegin(breaksViWordCat)
+
+proc cursorBigWordBegin(container: Container) {.jsfunc.} =
+  container.cursorWordBegin(breaksBigWordCat)
+
 proc pageDown(container: Container, n = 1) {.jsfunc.} =
   container.setFromY(container.fromy + container.height * n)
   container.setCursorY(container.cursory + container.height * n)