about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--doc/config.md24
-rw-r--r--res/config.toml22
-rw-r--r--src/local/container.nim59
-rw-r--r--src/local/pager.nim16
-rw-r--r--src/server/buffer.nim24
5 files changed, 82 insertions, 63 deletions
diff --git a/doc/config.md b/doc/config.md
index 8796ccfe..ad1807c5 100644
--- a/doc/config.md
+++ b/doc/config.md
@@ -703,23 +703,23 @@ Note: this does not suspend buffer processes.</td>
 </tr>
 
 <tr>
-<td>`pager.scrollDown()`</td>
-<td>Scroll forwards by one line.</td>
+<td>`pager.scrollDown(n = 1)`</td>
+<td>Scroll forwards by n lines.</td>
 </tr>
 
 <tr>
-<td>`pager.scrollUp()`</td>
-<td>Scroll backwards by one line.</td>
+<td>`pager.scrollUp(n = 1)`</td>
+<td>Scroll backwards by n lines.</td>
 </tr>
 
 <tr>
-<td>`pager.scrollLeft()`</td>
-<td>Scroll to the left by one column.</td>
+<td>`pager.scrollLeft(n = 1)`</td>
+<td>Scroll to the left by n columns.</td>
 </tr>
 
 <tr>
-<td>`pager.scrollRight()`</td>
-<td>Scroll to the right by one column.</td>
+<td>`pager.scrollRight(n = 1)`</td>
+<td>Scroll to the right by n columns.</td>
 </tr>
 
 <tr>
@@ -857,13 +857,13 @@ shown.</td>
 </tr>
 
 <tr>
-<td>`pager.searchNext()`</td>
-<td>Jump to the next search result.</td>
+<td>`pager.searchNext(n = 1)`</td>
+<td>Jump to the nth next search result.</td>
 </tr>
 
 <tr>
-<td>`pager.searchPrev()`</td>
-<td>Jump to the previous search result.</td>
+<td>`pager.searchPrev(n = 1)`</td>
+<td>Jump to the nth previous search result.</td>
 </tr>
 
 <tr>
diff --git a/res/config.toml b/res/config.toml
index 89b42cbe..fbda89b6 100644
--- a/res/config.toml
+++ b/res/config.toml
@@ -77,9 +77,9 @@ b = 'pager.cursorPrevWord()'
 w = 'pager.cursorNextWord()'
 '[' = 'pager.cursorPrevLink()'
 ']' = 'pager.cursorNextLink()'
-H = 'pager.cursorTop()'
-M = 'pager.cursorMiddle()'
-L = 'pager.cursorBottom()'
+H = 'n => pager.cursorTop(n ?? 1)'
+M = '() => pager.cursorMiddle()'
+L = 'n => pager.cursorBottom(n ?? 1)'
 ';' = 'pager.cursorLeftEdge()'
 '+' = 'pager.cursorMiddleColumn()'
 '@' = 'pager.cursorRightEdge()'
@@ -91,12 +91,12 @@ C-b = 'pager.pageUp()'
 'M-[5~' = 'pager.pageUp()'
 '>' = 'pager.pageRight()'
 '<' = 'pager.pageLeft()'
-C-e = 'pager.scrollDown()'
-C-y = 'pager.scrollUp()'
-J = 'pager.scrollDown()'
-K = 'pager.scrollUp()'
-'('= 'pager.scrollLeft()'
-')' = 'pager.scrollRight()'
+C-e = 'n => pager.scrollDown(n ?? 1)'
+C-y = 'n => pager.scrollUp(n ?? 1)'
+J = 'n => pager.scrollDown(n ?? 1)'
+K = 'n => pager.scrollUp(n ?? 1)'
+'('= 'n => pager.scrollLeft(n ?? 1)'
+')' = 'n => pager.scrollRight(n ?? 1)'
 C-m = 'pager.click()'
 C-j = 'pager.click()'
 M-u = 'pager.dupeBuffer()'
@@ -123,8 +123,8 @@ M-d = 'pager.discardTree()'
 M-c = 'pager.command()'
 '/' = 'pager.isearchForward()'
 '?' = 'pager.isearchBackward()'
-n = 'pager.searchNext()'
-N = 'pager.searchPrev()'
+n = 'n => pager.searchNext(n ?? 1)'
+N = 'n => pager.searchPrev(n ?? 1)'
 c = 'pager.peek()'
 u = 'pager.peekCursor()'
 C-w = '''
diff --git a/src/local/container.nim b/src/local/container.nim
index 37a78faf..465d7b87 100644
--- a/src/local/container.nim
+++ b/src/local/container.nim
@@ -610,14 +610,16 @@ proc cursorLastLine*(container: Container) {.jsfunc.} =
   else:
     container.setCursorY(container.numLines - 1)
 
-proc cursorTop(container: Container) {.jsfunc.} =
-  container.setCursorY(container.fromy)
+proc cursorTop(container: Container, i = 1) {.jsfunc.} =
+  let i = clamp(i - 1, 0, container.height - 1)
+  container.setCursorY(container.fromy + i)
 
 proc cursorMiddle(container: Container) {.jsfunc.} =
   container.setCursorY(container.fromy + (container.height - 2) div 2)
 
-proc cursorBottom(container: Container) {.jsfunc.} =
-  container.setCursorY(container.fromy + container.height - 1)
+proc cursorBottom(container: Container, i = 1) {.jsfunc.} =
+  let i = clamp(i, 0, container.height)
+  container.setCursorY(container.fromy + container.height - i)
 
 proc cursorLeftEdge(container: Container) {.jsfunc.} =
   container.setCursorX(container.fromx)
@@ -628,29 +630,30 @@ proc cursorMiddleColumn(container: Container) {.jsfunc.} =
 proc cursorRightEdge(container: Container) {.jsfunc.} =
   container.setCursorX(container.fromx + container.width - 1)
 
-proc scrollDown(container: Container) {.jsfunc.} =
+proc scrollDown(container: Container, n = 1) {.jsfunc.} =
   if container.fromy + container.height < container.numLines:
-    container.setFromY(container.fromy + 1)
+    container.setFromY(container.fromy + n)
     if container.fromy > container.cursory:
-      container.cursorDown()
+      container.cursorDown(container.fromy - container.cursory)
   else:
-    container.cursorDown()
+    container.cursorDown(n)
 
-proc scrollUp(container: Container) {.jsfunc.} =
+proc scrollUp(container: Container, n = 1) {.jsfunc.} =
   if container.fromy > 0:
-    container.setFromY(container.fromy - 1)
+    container.setFromY(container.fromy - n)
     if container.fromy + container.height <= container.cursory:
-      container.cursorUp()
+      container.cursorUp(container.cursory - container.fromy -
+        container.height + 1)
   else:
-    container.cursorUp()
+    container.cursorUp(n)
 
-proc scrollRight(container: Container) {.jsfunc.} =
-  if container.fromx + container.width < container.maxScreenWidth():
-    container.setFromX(container.fromx + 1)
+proc scrollRight(container: Container, n = 1) {.jsfunc.} =
+  if container.fromx + container.width + n <= container.maxScreenWidth():
+    container.setFromX(container.fromx + n)
 
-proc scrollLeft(container: Container) {.jsfunc.} =
-  if container.fromx > 0:
-    container.setFromX(container.fromx - 1)
+proc scrollLeft(container: Container, n = 1) {.jsfunc.} =
+  if container.fromx - n >= 0:
+    container.setFromX(container.fromx - n)
 
 proc alert(container: Container, msg: string) =
   container.triggerEvent(ContainerEvent(t: ALERT, msg: msg))
@@ -742,25 +745,29 @@ proc onMatch(container: Container, res: BufferMatch, refresh: bool) =
     container.needslines = true
     container.hlon = false
 
-proc cursorNextMatch*(container: Container, regex: Regex, wrap, refresh: bool):
-    EmptyPromise {.discardable.} =
+proc cursorNextMatch*(container: Container, regex: Regex, wrap, refresh: bool,
+    n: int): EmptyPromise {.discardable.} =
   if container.select.open:
-    container.select.cursorNextMatch(regex, wrap)
+    #TODO
+    for _ in 0 ..< n:
+      container.select.cursorNextMatch(regex, wrap)
     return newResolvedPromise()
   else:
     return container.iface
-      .findNextMatch(regex, container.cursorx, container.cursory, wrap)
+      .findNextMatch(regex, container.cursorx, container.cursory, wrap, n)
       .then(proc(res: BufferMatch) =
         container.onMatch(res, refresh))
 
-proc cursorPrevMatch*(container: Container, regex: Regex, wrap, refresh: bool):
-    EmptyPromise {.discardable.} =
+proc cursorPrevMatch*(container: Container, regex: Regex, wrap, refresh: bool,
+    n: int): EmptyPromise {.discardable.} =
   if container.select.open:
-    container.select.cursorPrevMatch(regex, wrap)
+    #TODO
+    for _ in 0 ..< n:
+      container.select.cursorPrevMatch(regex, wrap)
     return newResolvedPromise()
   else:
     return container.iface
-      .findPrevMatch(regex, container.cursorx, container.cursory, wrap)
+      .findPrevMatch(regex, container.cursorx, container.cursory, wrap, n)
       .then(proc(res: BufferMatch) =
         container.onMatch(res, refresh))
 
diff --git a/src/local/pager.nim b/src/local/pager.nim
index 79511f86..eb3f0ca0 100644
--- a/src/local/pager.nim
+++ b/src/local/pager.nim
@@ -141,21 +141,21 @@ proc getter(ctx: JSContext, pager: Pager, s: string): Option[JSValue]
         return some(fun)
       return some(val)
 
-proc searchNext(pager: Pager) {.jsfunc.} =
+proc searchNext(pager: Pager, n = 1) {.jsfunc.} =
   if pager.regex.isSome:
     let wrap = pager.config.search.wrap
     if not pager.reverseSearch:
-      pager.container.cursorNextMatch(pager.regex.get, wrap, true)
+      pager.container.cursorNextMatch(pager.regex.get, wrap, true, n)
     else:
-      pager.container.cursorPrevMatch(pager.regex.get, wrap, true)
+      pager.container.cursorPrevMatch(pager.regex.get, wrap, true, n)
 
-proc searchPrev(pager: Pager) {.jsfunc.} =
+proc searchPrev(pager: Pager, n = 1) {.jsfunc.} =
   if pager.regex.isSome:
     let wrap = pager.config.search.wrap
     if not pager.reverseSearch:
-      pager.container.cursorPrevMatch(pager.regex.get, wrap, true)
+      pager.container.cursorPrevMatch(pager.regex.get, wrap, true, n)
     else:
-      pager.container.cursorNextMatch(pager.regex.get, wrap, true)
+      pager.container.cursorNextMatch(pager.regex.get, wrap, true, n)
 
 proc getLineHist(pager: Pager, mode: LineMode): LineHistory =
   if pager.linehist[mode] == nil:
@@ -778,9 +778,9 @@ proc updateReadLineISearch(pager: Pager, linemode: LineMode) =
         pager.container.hlon = true
         let wrap = pager.config.search.wrap
         return if linemode == ISEARCH_F:
-          pager.container.cursorNextMatch(pager.iregex.get, wrap, false)
+          pager.container.cursorNextMatch(pager.iregex.get, wrap, false, 1)
         else:
-          pager.container.cursorPrevMatch(pager.iregex.get, wrap, false)
+          pager.container.cursorPrevMatch(pager.iregex.get, wrap, false, 1)
     of FINISH:
       pager.regex = pager.checkRegex(pager.iregex)
       pager.reverseSearch = linemode == ISEARCH_B
diff --git a/src/server/buffer.nim b/src/server/buffer.nim
index 4ab09c20..d6c00ef9 100644
--- a/src/server/buffer.nim
+++ b/src/server/buffer.nim
@@ -463,16 +463,20 @@ proc findNextLink*(buffer: Buffer, cursorx, cursory: int): tuple[x, y: int] {.pr
       inc i
   return (-1, -1)
 
-proc findPrevMatch*(buffer: Buffer, regex: Regex, cursorx, cursory: int, wrap: bool): BufferMatch {.proxy.} =
+proc findPrevMatch*(buffer: Buffer, regex: Regex, cursorx, cursory: int,
+    wrap: bool, n: int): BufferMatch {.proxy.} =
   if cursory >= buffer.lines.len: return
   var y = cursory
   let b = buffer.cursorBytes(y, cursorx)
   let res = regex.exec(buffer.lines[y].str, 0, b)
+  var numfound = 0
   if res.success and res.captures.len > 0:
     let cap = res.captures[^1]
     let x = buffer.lines[y].str.width(0, cap.s)
     let str = buffer.lines[y].str.substr(cap.s, cap.e - 1)
-    return BufferMatch(success: true, x: x, y: y, str: str)
+    inc numfound
+    if numfound >= n:
+      return BufferMatch(success: true, x: x, y: y, str: str)
   dec y
   while true:
     if y < 0:
@@ -485,21 +489,27 @@ proc findPrevMatch*(buffer: Buffer, regex: Regex, cursorx, cursory: int, wrap: b
       let cap = res.captures[^1]
       let x = buffer.lines[y].str.width(0, cap.s)
       let str = buffer.lines[y].str.substr(cap.s, cap.e - 1)
-      return BufferMatch(success: true, x: x, y: y, str: str)
+      inc numfound
+      if numfound >= n:
+        return BufferMatch(success: true, x: x, y: y, str: str)
     if y == cursory:
       break
     dec y
 
-proc findNextMatch*(buffer: Buffer, regex: Regex, cursorx, cursory: int, wrap: bool): BufferMatch {.proxy.} =
+proc findNextMatch*(buffer: Buffer, regex: Regex, cursorx, cursory: int,
+    wrap: bool, n: int): BufferMatch {.proxy.} =
   if cursory >= buffer.lines.len: return
   var y = cursory
   let b = buffer.cursorBytes(y, cursorx + 1)
   let res = regex.exec(buffer.lines[y].str, b, buffer.lines[y].str.len)
+  var numfound = 0
   if res.success and res.captures.len > 0:
     let cap = res.captures[0]
     let x = buffer.lines[y].str.width(0, cap.s)
     let str = buffer.lines[y].str.substr(cap.s, cap.e - 1)
-    return BufferMatch(success: true, x: x, y: y, str: str)
+    inc numfound
+    if numfound >= n:
+      return BufferMatch(success: true, x: x, y: y, str: str)
   inc y
   while true:
     if y > buffer.lines.high:
@@ -512,7 +522,9 @@ proc findNextMatch*(buffer: Buffer, regex: Regex, cursorx, cursory: int, wrap: b
       let cap = res.captures[0]
       let x = buffer.lines[y].str.width(0, cap.s)
       let str = buffer.lines[y].str.substr(cap.s, cap.e - 1)
-      return BufferMatch(success: true, x: x, y: y, str: str)
+      inc numfound
+      if numfound >= n:
+        return BufferMatch(success: true, x: x, y: y, str: str)
     if y == cursory:
       break
     inc y