about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-12-15 17:35:41 +0100
committerbptato <nincsnevem662@gmail.com>2022-12-15 17:35:41 +0100
commit5be29f675fc27974ff256cb2094ccd0854e19b07 (patch)
treef7ff0acf57a2440b681fc5e90b4a74e0943e106c
parente86bcfd40f699b88c984c4f79adc8647796353ae (diff)
downloadchawan-5be29f675fc27974ff256cb2094ccd0854e19b07.tar.gz
Add discardTree, update docs
-rw-r--r--doc/config.md395
-rw-r--r--res/config.toml4
-rw-r--r--src/buffer/container.nim4
-rw-r--r--src/display/pager.nim53
4 files changed, 367 insertions, 89 deletions
diff --git a/doc/config.md b/doc/config.md
index 95b55f92..d64d0d59 100644
--- a/doc/config.md
+++ b/doc/config.md
@@ -371,7 +371,7 @@ escape to the keybinding respectively (essentially making `M-` the same as
 `C-[`). Modifiers can be escaped with the `\` sign.
 
 ```Examples:
-'C-M-j' = 'pager.changeLocation()' # change URL when Control, Escape and j are pressed
+'C-M-j' = 'pager.load()' # change URL when Control, Escape and j are pressed
 'gg' = 'pager.cursorFirstLine()' # go to the first line of the page when g is pressed twice
 ```
 An action is a JavaScript function called by chawan every time the keybinding
@@ -380,78 +380,341 @@ is typed in. A list of built-in pager functions can be found below.
 ### Pager actions
 
 <table>
-<tr><th>**Name**<th>**Function**
-<tr><td>`pager.quit()`<td>Exit the browser
-<tr><td>`pager.cursorUp()`<td>Move the cursor to the previous line
-<tr><td>`pager.cursorDown()`<td>Move cursor to the next line
-<tr><td>`pager.cursorLeft()`<td>Move cursor to the previous cell
-<tr><td>`pager.cursorRight()`<td>Move cursor to the next cell
-<tr><td>`pager.cursorLineBegin()`<td>Move cursor to the first cell of the line
-<tr><td>`pager.cursorLineEnd()`<td>Move cursor to the last cell of the line
-<tr><td>`pager.cursorNextWord()`<td>Move cursor to the beginning of the next word
-<tr><td>`pager.cursorPrevWord()`<td>Move cursor to the end of the previous word
-<tr><td>`pager.cursorNextLink()`<td>Move cursor to the beginning of the next clickable element
-<tr><td>`pager.cursorPrevLink()`<td>Move cursor to the beginning of the previous clickable element
-<tr><td>`pager.pageDown()`<td>Move screen down by one page
-<tr><td>`pager.pageUp()`<td>Move screen up by one page
-<tr><td>`pager.pageLeft()`<td>Move screen to the left by one page
-<tr><td>`pager.pageRight()`<td>Move screen to the right by one page
-<tr><td>`pager.halfPageDown()`<td>Move screen down by half a page
-<tr><td>`pager.halfPageUp()`<td>Move screen up by half a page
-<tr><td>`pager.scrollDown()`<td>Move screen down by one line
-<tr><td>`pager.scrollUp()`<td>Move screen up by one line
-<tr><td>`pager.scrollLeft()`<td>Move screen to the left by one line
-<tr><td>`pager.scrollRight()`<td>Move screen to the right by one line
-<tr><td>`pager.click()`<td>Click element currently under cursor
-<tr><td>`pager.changeLocation()`<td>Go to URL
-<tr><td>`pager.dupeBuffer()`<td>Duplicate the current buffer
-<tr><td>`pager.reload()`<td>Reload page
-<tr><td>`pager.reshape()`<td>Reshape buffer (=render page anew)
-<tr><td>`pager.redraw()`<td>Redraw buffer (=redraw screen)
-<tr><td>`pager.toggleSource()`<td>Source view
-<tr><td>`pager.cursorFirstLine()`<td>Move cursor to the first line of the buffer
-<tr><td>`pager.cursorLastLine()`<td>Move cursor to the last line of the buffer
-<tr><td>`pager.cursorTop()`<td>Move cursor to the first line of the page
-<tr><td>`pager.cursorMiddle()`<td>Move cursor to the middle of the page
-<tr><td>`pager.cursorBottom()`<td>Move cursor to the last line of the page
-<tr><td>`pager.centerLine()`<td>Center screen around line
-<tr><td>`pager.lineInfo()`<td>Display information about line
-<tr><td>`pager.searchForward()`<td>Search for a string in the current buffer
-<tr><td>`pager.searchBackward()`<td>Search for a string, backwards
-<tr><td>`pager.isearchForward()`<td>Search for a string and highlight the first result
-<tr><td>`pager.isearchBackward()`<td>Search and highlight the first result, backwards
-<tr><td>`pager.searchPrev()`<td>Jump to the next search result
-<tr><td>`pager.searchNext()`<td>Jump to the previous search result
-<tr><td>`pager.peek()`<td>Display an alert of the current URL
-<tr><td>`pager.peekCursor()`<td>Display an alert of the URL under the cursor
+
+<tr>
+<th>**Name**</th>
+<th>**Function**</th>
+</tr>
+
+<tr>
+<td>`pager.quit()`</td>
+<td>Exit the browser.</td>
+</tr>
+
+<tr>
+<td>`pager.cursorUp()`</td>
+<td>Move the cursor to the previous line.</td>
+</tr>
+<tr>
+<td>`pager.cursorDown()`</td>
+<td>Move cursor to the next line.</td>
+</tr>
+
+<tr>
+<td>`pager.cursorLeft()`</td>
+<td>Move the cursor to the previous cell.</td>
+</tr>
+
+<tr>
+<td>`pager.cursorRight()`</td>
+<td>Move the cursor to the next cell.</td>
+</tr>
+
+<tr>
+<td>`pager.cursorLineBegin()`</td>
+<td>Move the cursor to the first cell of the line.</td>
+</tr>
+
+<tr>
+<td>`pager.cursorLineEnd()`</td>
+<td>Move the cursor to the last cell of the line.</td>
+</tr>
+
+<tr>
+<td>`pager.cursorNextWord()`</td>
+<td>Move the cursor to the beginning of the next word.</td>
+</tr>
+
+<tr>
+<td>`pager.cursorPrevWord()`</td>
+<td>Move the cursor to the end of the previous word.</td>
+</tr>
+
+<tr>
+<td>`pager.cursorNextLink()`</td>
+<td>Move the cursor to the beginning of the next clickable element.</td>
+</tr>
+
+<tr>
+<td>`pager.cursorPrevLink()`</td>
+<td>Move the cursor to the beginning of the previous clickable element.</td>
+</tr>
+
+<tr>
+<td>`pager.pageDown()`</td>
+<td>Scroll down by one page.</td>
+</tr>
+
+<tr>
+<td>`pager.pageUp()`</td>
+<td>Scroll up by one page.</td>
+</tr>
+
+<tr>
+<td>`pager.pageLeft()`</td>
+<td>Scroll to the left by one page.</td>
+</tr>
+
+<tr>
+<td>`pager.pageRight()`</td>
+<td>Scroll to the right by one page.</td>
+</tr>
+
+<tr>
+<td>`pager.halfPageDown()`</td>
+<td>Scroll forwards by half a page.</td>
+</tr>
+
+<tr>
+<td>`pager.halfPageUp()`</td>
+<td>Scroll backwards by half a page.</td>
+</tr>
+
+<tr>
+<td>`pager.scrollDown()`</td>
+<td>Scroll forwards by one line.</td>
+</tr>
+
+<tr>
+<td>`pager.scrollUp()`</td>
+<td>Scroll backwards by one line.</td>
+</tr>
+
+<tr>
+<td>`pager.scrollLeft()`</td>
+<td>Scroll to the left by one column.</td>
+</tr>
+
+<tr>
+<td>`pager.scrollRight()`</td>
+<td>Scroll to the right by one column.</td>
+</tr>
+
+<tr>
+<td>`pager.click()`</td>
+<td>Click the HTML element currently under the cursor.</td>
+</tr>
+
+<tr>
+<td>`pager.load(url)`</td>
+<td>Go to the specified URL. Opens a prompt with the current URL when no
+parameters are specified; otherwise, the string passed is displayed in
+the prompt. If this string ends with a newline
+(e.g. `pager.load("about:cha\n")`), the URL is loaded directly.</td>
+</tr>
+
+<tr>
+<td>`pager.dupeBuffer()`</td>
+<td>Duplicate the current buffer by loading its source to a new buffer.</td>
+</tr>
+
+<tr>
+<td>`pager.discardBuffer()`</td>
+<td>Discard the current buffer, and move back to its parent. If the current
+buffer is a root buffer (i.e. it has no parent), move to the first child
+buffer instead.</td>
+</tr>
+
+<tr>
+<td>`pager.reload()`</td>
+<td>Open a new buffer with the current buffer's URL, replacing the current
+buffer.</td>
+</tr>
+
+<tr>
+<td>`pager.reshape()`</td>
+<td>Reshape the current buffer (=render the current page anew.)</td>
+</tr>
+
+<tr>
+<td>`pager.redraw()`</td>
+<td>Redraw screen contents. Useful if something messed up the display.</td>
+</tr>
+
+<tr>
+<td>`pager.toggleSource()`</td>
+<td>If viewing a HTML buffer, open a new buffer with its source. Otherwise,
+open the current buffer's contents as HTML.</td>
+</tr>
+
+<tr>
+<td>`pager.cursorFirstLine()`</td>
+<td>Move to the beginning in the buffer.</td>
+</tr>
+
+<tr>
+<td>`pager.cursorLastLine()`</td>
+<td>Move to the last line in the buffer.</td>
+</tr>
+
+<tr>
+<td>`pager.cursorTop()`</td>
+<td>Move to the first line on the screen. (Equivalent to H in vi.)</td>
+</tr>
+
+<tr>
+<td>`pager.cursorMiddle()`</td>
+<td>Move to the middle of the screen. (Equivalent to M in vi.)</td>
+</tr>
+
+<tr>
+<td>`pager.cursorBottom()`</td>
+<td>Move to the last line on the screen. (Equivalent to L in vi.)</td>
+</tr>
+
+<tr>
+<td>`pager.centerLine()`</td>
+<td>Center screen around the current line.</td>
+</tr>
+
+<tr>
+<td>`pager.lineInfo()`</td>
+<td>Display information about the current line.</td>
+</tr>
+
+<tr>
+<td>`pager.searchForward()`</td>
+<td>Search for a string in the current buffer.</td>
+</tr>
+
+<tr>
+<td>`pager.searchBackward()`</td>
+<td>Search for a string, backwards.</td>
+</tr>
+
+<tr>
+<td>`pager.isearchForward()`</td>
+<td>Incremental-search for a string, highlighting the first result.</td>
+</tr>
+
+<tr>
+<td>`pager.isearchBackward()`</td>
+<td>Incremental-search and highlight the first result, backwards.</td>
+</tr>
+
+<tr>
+<td>`pager.searchNext()`</td>
+<td>Jump to the next search result.</td>
+</tr>
+
+<tr>
+<td>`pager.searchPrev()`</td>
+<td>Jump to the previous search result.</td>
+</tr>
+
+<tr>
+<td>`pager.peek()`</td>
+<td>Display an alert message of the current URL.</td>
+</tr>
+
+<tr>
+<td>`pager.peekCursor()`</td>
+<td>Display an alert message of the URL under the cursor.</td>
+</tr>
+
 </table>
 
+
 ### Line-editing actions
 
 <table>
-<tr><th>**Name**<th>**Function**
-<tr><td>`line.submit()`<td>Submit line
-<tr><td>`line.cancel()`<td>Cancel operation
-<tr><td>`line.backspace()`<td>Delete character before cursor
-<tr><td>`line.delete()`<td>Delete character after cursor
-<tr><td>`line.clear()`<td>Clear text before cursor
-<tr><td>`line.kill()`<td>Clear text after cursor
-<tr><td>`line.clearWord(bounds)`<td>Delete word before cursor
-<tr><td>`line.killWord(bounds)`<td>Delete word after cursor
-<tr><td>`line.backward()`<td>Move cursor back by one character
-<tr><td>`line.forward()`<td>Move cursor forward by one character
-<tr><td>`line.prevWord(bounds)`<td>Move cursor to the previous word by one character
-<tr><td>`line.nextWord(bounds)`<td>Move cursor to the previous word by one character
-<tr><td>`line.begin()`<td>Move cursor to the previous word by one character
-<tr><td>`line.end()`<td>Move cursor to the previous word by one character
-<tr><td>`line.escape()`<td>Ignore keybindings for next character
-<tr><td>`line.prevHist()`<td>Jump to the previous history entry
-<tr><td>`line.nextHist()`<td>Jump to the next history entry
+
+<tr>
+<th>**Name**</th>
+<th>**Function**</th>
+</tr>
+
+<tr>
+<td>`line.submit()`</td>
+<td>Submit line</td>
+</tr>
+
+<tr>
+<td>`line.cancel()`</td>
+<td>Cancel operation</td>
+</tr>
+
+<tr>
+<td>`line.backspace()`</td>
+<td>Delete character before cursor</td>
+</tr>
+
+<tr>
+<td>`line.delete()`</td>
+<td>Delete character after cursor</td>
+</tr>
+
+<tr>
+<td>`line.clear()`</td>
+<td>Clear text before cursor</td>
+</tr>
+
+<tr>
+<td>`line.kill()`</td>
+<td>Clear text after cursor</td>
+</tr>
+
+<tr>
+<td>`line.clearWord(bounds)`</td>
+<td>Delete word before cursor</td>
+</tr>
+
+<tr>
+<td>`line.killWord(bounds)`</td>
+<td>Delete word after cursor</td>
+</tr>
+
+<tr>
+<td>`line.backward()`</td>
+<td>Move cursor back by one character</td>
+</tr>
+
+<tr>
+<td>`line.forward()`</td>
+<td>Move cursor forward by one character</td>
+</tr>
+
+<tr>
+<td>`line.prevWord(bounds)`</td>
+<td>Move cursor to the previous word by one character</td>
+</tr>
+
+<tr>
+<td>`line.nextWord(bounds)`</td>
+<td>Move cursor to the previous word by one character</td>
+</tr>
+
+<tr>
+<td>`line.begin()`</td>
+<td>Move cursor to the previous word by one character</td>
+</tr>
+
+<tr>
+<td>`line.end()`</td>
+<td>Move cursor to the previous word by one character</td>
+</tr>
+
+<tr>
+<td>`line.escape()`</td>
+<td>Ignore keybindings for next character</td>
+</tr>
+
+<tr>
+<td>`line.prevHist()`</td>
+<td>Jump to the previous history entry</td>
+</tr>
+
+<tr>
+<td>`line.nextHist()`</td>
+<td>Jump to the next history entry</td>
+</tr>
+
 </table>
 
-Some entries have an optional `bounds` parameter. If passed, this must be a
-JavaScript function that expects one parameter (the current unicode character),
-and returns true if the passed character should count as a word boundary.
+Some of these entries have an optional `bounds` parameter. If passed, this
+must be a JavaScript function that expects one parameter (the current
+unicode character), and returns true if the passed character should count
+as a word boundary.
 
 ```Examples:
 # Control+A moves the cursor to the beginning of the line.
diff --git a/res/config.toml b/res/config.toml
index 7918bea3..17bfc574 100644
--- a/res/config.toml
+++ b/res/config.toml
@@ -71,7 +71,7 @@ M-b = 'pager.load("~/.w3m/bookmark.html\n")'
 U = 'pager.reload()'
 r = 'pager.redraw()'
 R = 'pager.reshape()'
-M-D = 'pager.cancel()'
+M-C-c = 'pager.cancel()'
 1G = 'pager.cursorFirstLine()'
 g = 'pager.cursorFirstLine()'
 G = 'pager.cursorLastLine()'
@@ -79,7 +79,7 @@ z = 'pager.centerLine()'
 C-g = 'pager.lineInfo()'
 v = 'pager.toggleSource()'
 D = 'pager.discardBuffer()'
-M-d = 'pager.discardBuffer(true)'
+M-d = 'pager.discardTree()'
 ',' = 'pager.prevBuffer()'
 'M-,' = 'pager.prevSiblingBuffer()'
 '.' = 'pager.nextBuffer()'
diff --git a/src/buffer/container.nim b/src/buffer/container.nim
index 8084c068..7a3534be 100644
--- a/src/buffer/container.nim
+++ b/src/buffer/container.nim
@@ -63,6 +63,8 @@ type
     clear*: bool
 
   Container* = ref object
+    parent* {.jsget.}: Container
+    children* {.jsget.}: seq[Container]
     config*: BufferConfig
     iface*: BufferInterface
     attrs: WindowAttributes
@@ -72,11 +74,9 @@ type
     title*: string
     hovertext*: string
     source*: BufferSource
-    children*: seq[Container]
     pos: CursorPosition
     bpos: seq[CursorPosition]
     highlights: seq[Highlight]
-    parent*: Container
     process* {.jsget.}: Pid
     loadinfo*: string
     lines: SimpleFlexibleGrid
diff --git a/src/display/pager.nim b/src/display/pager.nim
index 9c3e664b..9ce058f2 100644
--- a/src/display/pager.nim
+++ b/src/display/pager.nim
@@ -62,19 +62,28 @@ type
 
 func attrs(pager: Pager): WindowAttributes = pager.term.attrs
 
-iterator containers*(pager: Pager): Container =
+func getRoot(container: Container): Container =
+  var c = container
+  while c.parent != nil: c = c.parent
+
+iterator all_children(parent: Container): Container {.inline.} =
+  var stack = newSeqOfCap[Container](parent.children.len)
+  for i in countdown(parent.children.high, 0):
+    stack.add(parent.children[i])
+  while stack.len > 0:
+    let c = stack.pop()
+    yield c
+    for i in countdown(c.children.high, 0):
+      stack.add(c.children[i])
+
+iterator containers*(pager: Pager): Container {.inline.} =
   if pager.container != nil:
-    var c = pager.container
-    while c.parent != nil: c = c.parent
-    var stack: seq[Container]
-    stack.add(c)
-    while stack.len > 0:
-      c = stack.pop()
+    let root = getRoot(pager.container)
+    yield root
+    for c in root.all_children:
       yield c
-      for i in countdown(c.children.high, 0):
-        stack.add(c.children[i])
 
-proc setContainer*(pager: Pager, c: Container) =
+proc setContainer*(pager: Pager, c: Container) {.jsfunc.} =
   pager.container = c
   pager.redraw = true
 
@@ -404,7 +413,7 @@ proc alert*(pager: Pager, msg: string) {.jsfunc.} =
 proc lineInfo(pager: Pager) {.jsfunc.} =
   pager.alert(pager.container.lineInfo())
 
-proc deleteContainer(pager: Pager, container: Container, prevlevel = false) =
+proc deleteContainer(pager: Pager, container: Container) =
   container.cancel()
   if container.sourcepair != nil:
     container.sourcepair.sourcepair = nil
@@ -419,10 +428,7 @@ proc deleteContainer(pager: Pager, container: Container, prevlevel = false) =
       parent.children.insert(child, n + 1)
     parent.children.delete(n)
     if container == pager.container:
-      if prevlevel or n == 0:
-        pager.setContainer(parent)
-      else:
-        pager.setContainer(parent.children[n - 1])
+      pager.setContainer(parent)
   elif container.children.len > 0:
     let parent = container.children[0]
     parent.parent = nil
@@ -441,12 +447,21 @@ proc deleteContainer(pager: Pager, container: Container, prevlevel = false) =
   pager.unreg.add((container.process, SocketStream(container.iface.stream)))
   pager.dispatcher.forkserver.removeChild(container.process)
 
-proc discardBuffer(pager: Pager, prevlevel = false) {.jsfunc.} =
-  if pager.container == nil or pager.container.parent == nil and
-      pager.container.children.len == 0:
+proc discardBuffer(pager: Pager, container = none(Container)) {.jsfunc.} =
+  let c = container.get(pager.container)
+  if c == nil or c.parent == nil and c.children.len == 0:
     pager.alert("Cannot discard last buffer!")
   else:
-    pager.deleteContainer(pager.container, prevlevel)
+    pager.deleteContainer(c)
+
+proc discardTree(pager: Pager, container = none(Container)) {.jsfunc.} =
+  let container = container.get(pager.container)
+  if container != nil:
+    for c in container.all_children:
+      pager.deleteContainer(c)
+    pager.discardBuffer(some(container))
+  else:
+    pager.alert("Cannot discard last buffer!")
 
 proc toggleSource*(pager: Pager) {.jsfunc.} =
   if pager.container.sourcepair != nil: