about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--doc/config.md41
-rw-r--r--res/chawan.html4
-rw-r--r--res/config.toml12
-rw-r--r--src/local/container.nim85
4 files changed, 120 insertions, 22 deletions
diff --git a/doc/config.md b/doc/config.md
index 996f0c16..1140f8d9 100644
--- a/doc/config.md
+++ b/doc/config.md
@@ -840,8 +840,45 @@ open the current buffer's contents as HTML.</td>
 </tr>
 
 <tr>
-<td>`pager.centerLine()`</td>
-<td>Center screen around the current line.</td>
+<td>`pager.lowerPage(n = pager.cursory)`</td>
+<td>Move cursor to line n, then scroll up so that the cursor is on the
+top line on the screen. (`zt` in vim.)</td>
+</tr>
+
+<tr>
+<td>`pager.lowerPageBegin(n = pager.cursory)`</td>
+<td>Move cursor to the first non-blank character of line n, then scroll up
+so that the cursor is on the top line on the screen. (`z<CR>` in vi.)</td>
+</tr>
+
+<tr>
+<td>`pager.centerLine(n = pager.cursory)`</td>
+<td>Center screen around line n. (`zz` in vim.)</td>
+</tr>
+
+<tr>
+<td>`pager.centerLineBegin(n = pager.cursory)`</td>
+<td>Center screen around line n, and move the cursor to the line's first
+non-blank character. (`z.` in vi.)</td>
+</tr>
+
+<tr>
+<td>`pager.raisePage(n = pager.cursory)`</td>
+<td>Move cursor to line n, then scroll down so that the cursor is on the
+top line on the screen. (zb in vim.)</td>
+</tr>
+
+<tr>
+<td>`pager.lowerPageBegin(n = pager.cursory)`</td>
+<td>Move cursor to the first non-blank character of line n, then scroll up
+so that the cursor is on the last line on the screen. (`z^` in vi.)</td>
+</tr>
+
+<tr>
+<td>`pager.nextPageBegin(n = pager.cursory)`</td>
+<td>If n was given, move to the screen before the nth line and raise the page.
+Otherwise, go to the previous screen's last line and raise the page. (`z+`
+in vi.)</td>
 </tr>
 
 <tr>
diff --git a/res/chawan.html b/res/chawan.html
index 81f9bbea..b73a4347 100644
--- a/res/chawan.html
+++ b/res/chawan.html
@@ -46,7 +46,9 @@ the meta key may be called Alt or Escape.)
 <li><b>C-z</b>: suspend the browser
 <li><b>M-C-c</b>: cancel loading
 <li><b>H</b>, <b>M</b>, <b>L</b>: move cursor to the Highest/Middle/Lowest rows
-<li><b>z</b>: center on current column
+<li><b>zz, z.</b>: center on current line (and move to beginning)
+<li><b>zt, z-</b>: center on current line (and move to beginning)
+<li><b>zb, zC-m</b>: center on current line (and move to beginning)
 <li><b>w</b>, <b>b</b>: move cursor to next/previous word
 <li><b>v</b>: toggle page source view
 <li><b>0</b>: cursor to first cell on line
diff --git a/res/config.toml b/res/config.toml
index c69d8b66..fed898e9 100644
--- a/res/config.toml
+++ b/res/config.toml
@@ -113,10 +113,18 @@ U = 'pager.reload()'
 r = 'pager.redraw()'
 R = 'pager.reshape()'
 M-C-c = 'pager.cancel()'
-g = 'pager.cursorFirstLine()'
+gg = 'pager.cursorFirstLine()'
 G = 'n => n ? pager.gotoLine(n) : pager.cursorLastLine()'
 M-g = 'pager.gotoLine()'
-z = 'pager.centerLine()'
+'z.' = 'n => pager.centerLineBegin(n)'
+'zC-m' = 'n => pager.raisePageBegin(n)'
+'zC-j' = 'n => pager.raisePageBegin(n)'
+'z-' = 'n => pager.lowerPageBegin(n)'
+zz = 'n => pager.centerLine(n)'
+'zt' = 'n => pager.raisePage(n)'
+'zb' = 'n => pager.lowerPage(n)'
+'z+' = 'n => pager.nextPageBegin(n)'
+'z^' = 'n => pager.previousPageBegin(n)'
 C-g = 'pager.lineInfo()'
 v = 'pager.toggleSource()'
 D = 'pager.discardBuffer()'
diff --git a/src/local/container.nim b/src/local/container.nim
index 6a11e02a..9667d84b 100644
--- a/src/local/container.nim
+++ b/src/local/container.nim
@@ -460,16 +460,76 @@ proc setCursorY(container: Container, y: int, refresh = true) {.jsfunc.} =
   if refresh:
     container.sendCursorPosition()
 
-proc centerLine(container: Container) {.jsfunc.} =
+proc setCursorXY(container: Container, x, y: int, refresh = true) {.jsfunc.} =
+  container.setCursorY(y, refresh)
+  container.setCursorX(x, refresh)
+
+proc cursorLineTextStart(container: Container) {.jsfunc.} =
+  if container.numLines == 0: return
+  var x = 0
+  for r in container.currentLine.runes:
+    if not r.isWhitespace():
+      break
+    x += r.twidth(x)
+  container.setCursorX(x)
+
+# zb
+proc lowerPage(container: Container, n = 0) {.jsfunc.} =
+  if n != 0:
+    container.setCursorY(n - 1)
+  container.setFromY(container.cursory - container.height + 1)
+
+# z-
+proc lowerPageBegin(container: Container, n = 0) {.jsfunc.} =
+  container.lowerPage(n)
+  container.cursorLineTextStart()
+
+# zz
+proc centerLine(container: Container, n = 0) {.jsfunc.} =
+  if n != 0:
+    container.setCursorY(n - 1)
   container.setFromY(container.cursory - container.height div 2)
 
+# z.
+proc centerLineBegin(container: Container, n = 0) {.jsfunc.} =
+  container.centerLine(n)
+  container.cursorLineTextStart()
+
+# zt
+proc raisePage(container: Container, n = 0) {.jsfunc.} =
+  if n != 0:
+    container.setCursorY(n - 1)
+  container.setFromY(container.cursory)
+
+# z^M
+proc raisePageBegin(container: Container, n = 0) {.jsfunc.} =
+  container.raisePage(n)
+  container.cursorLineTextStart()
+
+# z+
+proc nextPageBegin(container: Container, n = 0) {.jsfunc.} =
+  if n == 0:
+    container.setCursorY(container.fromy + container.height)
+  else:
+    container.setCursorY(n - 1)
+  container.cursorLineTextStart()
+  container.raisePage()
+
+# z^
+proc previousPageBegin(container: Container, n = 0) {.jsfunc.} =
+  if n == 0:
+    container.setCursorY(container.fromy - 1)
+  else:
+    container.setCursorY(n - container.height) # +- 1 cancels out
+  container.cursorLineTextStart()
+  container.lowerPage()
+
 proc centerColumn(container: Container) {.jsfunc.} =
   container.setFromX(container.cursorx - container.width div 2)
 
-proc setCursorXY(container: Container, x, y: int, refresh = true) {.jsfunc.} =
+proc setCursorXYCenter(container: Container, x, y: int, refresh = true) {.jsfunc.} =
   let fy = container.fromy
-  container.setCursorY(y, refresh)
-  container.setCursorX(x, refresh)
+  container.setCursorXY(x, y, refresh)
   if fy != container.fromy:
     container.centerLine()
 
@@ -500,15 +560,6 @@ proc cursorRight(container: Container, n = 1) {.jsfunc.} =
 proc cursorLineBegin(container: Container) {.jsfunc.} =
   container.setCursorX(0)
 
-proc cursorLineTextStart(container: Container) {.jsfunc.} =
-  if container.numLines == 0: return
-  var x = 0
-  for r in container.currentLine.runes:
-    if not r.isWhitespace():
-      break
-    x += r.twidth(x)
-  container.setCursorX(x)
-
 proc cursorLineEnd(container: Container) {.jsfunc.} =
   container.setCursorX(container.currentLineWidth() - 1)
 
@@ -716,14 +767,14 @@ proc cursorNextLink*(container: Container) {.jsfunc.} =
     .findNextLink(container.cursorx, container.cursory)
     .then(proc(res: tuple[x, y: int]) =
       if res.x > -1 and res.y != -1:
-        container.setCursorXY(res.x, res.y))
+        container.setCursorXYCenter(res.x, res.y))
 
 proc cursorPrevLink*(container: Container) {.jsfunc.} =
   container.iface
     .findPrevLink(container.cursorx, container.cursory)
     .then(proc(res: tuple[x, y: int]) =
       if res.x > -1 and res.y != -1:
-        container.setCursorXY(res.x, res.y))
+        container.setCursorXYCenter(res.x, res.y))
 
 proc clearSearchHighlights*(container: Container) =
   for i in countdown(container.highlights.high, 0):
@@ -732,7 +783,7 @@ proc clearSearchHighlights*(container: Container) =
 
 proc onMatch(container: Container, res: BufferMatch, refresh: bool) =
   if res.success:
-    container.setCursorXY(res.x, res.y, refresh)
+    container.setCursorXYCenter(res.x, res.y, refresh)
     if container.hlon:
       container.clearSearchHighlights()
       let ex = res.x + res.str.twidth(res.x) - 1
@@ -812,7 +863,7 @@ proc onload*(container: Container, res: LoadResult) =
       ).then(proc(res: Opt[tuple[x, y: int]]) =
         if res.isSome:
           let res = res.get
-          container.setCursorXY(res.x, res.y))
+          container.setCursorXYCenter(res.x, res.y))
 
 proc load(container: Container) =
   container.setLoadInfo("Connecting to " & container.location.host & "...")