about summary refs log tree commit diff stats
path: root/doc/cha-api.5
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-04-26 19:35:21 +0200
committerbptato <nincsnevem662@gmail.com>2024-04-26 19:45:53 +0200
commit601ad98818f3b966686181445339c52f74f75979 (patch)
tree3f245aacb085ccbee7e7b7c5efbf5b7cd318a5c1 /doc/cha-api.5
parent83dae4a87a78190262317eca15cbb5d25989d41b (diff)
downloadchawan-601ad98818f3b966686181445339c52f74f75979.tar.gz
doc: include auto-generated manpages in repository
The 100kb or so doesn't hurt as much as not having manual pages at all
without pandoc (+ not auto-updating them through make all) does.
Diffstat (limited to 'doc/cha-api.5')
-rw-r--r--doc/cha-api.5828
1 files changed, 828 insertions, 0 deletions
diff --git a/doc/cha-api.5 b/doc/cha-api.5
new file mode 100644
index 00000000..4d0c228b
--- /dev/null
+++ b/doc/cha-api.5
@@ -0,0 +1,828 @@
+'\" t
+.\" Automatically generated by Pandoc 2.17.1.1
+.\"
+.\" Define V font for inline verbatim, using C font in formats
+.\" that render this, and otherwise B font.
+.ie "\f[CB]x\f[]"x" \{\
+. ftr V B
+. ftr VI BI
+. ftr VB B
+. ftr VBI BI
+.\}
+.el \{\
+. ftr V CR
+. ftr VI CI
+. ftr VB CB
+. ftr VBI CBI
+.\}
+.TH "cha-api" "5" "" "" "Chawan\[cq]s command API"
+.hy
+.SH Chawan\[cq]s command API
+.PP
+As described in \f[B]cha-config\f[R](5), keypress combinations can be
+bound to actions.
+.PP
+An action can be either a JavaScript expression, or a command defined in
+the \f[V][cmd]\f[R] section of config.toml.
+For example, the following works:
+.IP
+.nf
+\f[C]
+gpn = \[aq]n => pager.alert(n)\[aq] # e.g. 2gpn prints \[ga]2\[aq] to the status line
+\f[R]
+.fi
+.PP
+Note however, that JavaScript functions must be called with an
+appropriate \f[V]this\f[R] value.
+Unfortunately, this also means that the following does not work:
+.IP
+.nf
+\f[C]
+gpn = \[aq]pager.alert\[aq] # broken!!!
+\f[R]
+.fi
+.PP
+To work around this limitation, actions have to wrap the target function
+in a closure, as above.
+However, this has very poor reusability; for more complex actions, you
+would have to copy and paste the entire function every time you re-bind
+it or call it from a different function.
+.PP
+To fix this, it is possible to define a command in the \f[V][cmd]\f[R]
+section:
+.IP
+.nf
+\f[C]
+[cmd.my.namespace]
+showNumber = \[aq]n => pager.alert(n)\[aq]
+\f[R]
+.fi
+.PP
+\f[V]my.namespace\f[R] can be anything you want; it is to avoid
+collisions when including multiple configs.
+Avoid setting it to \f[V]pager\f[R] or \f[V]line\f[R], because these are
+used by the default config.
+.PP
+Now you can call \f[V]cmd.my.namespace.showNumber()\f[R] from any other
+function, or just include it in an action:
+.IP
+.nf
+\f[C]
+\[aq]gpn\[aq] = \[aq]cmd.my.namespace.showNumber\[aq]
+\f[R]
+.fi
+.SS Interfaces
+.SS Client
+.PP
+The global object (\f[V]globalThis\f[R]) implements the \f[V]Client\f[R]
+interface.
+Documented functions of this are:
+.PP
+Following properties (functions/getters) are defined by \f[V]Pager\f[R]:
+.PP
+.TS
+tab(@);
+lw(28.0n) lw(38.5n) lw(3.5n).
+T{
+Property
+T}@T{
+Description
+T}@T{
+T}
+_
+T{
+\f[V]quit()\f[R]
+T}@T{
+Exit the browser.
+T}@T{
+T}
+T{
+\f[V]suspend()\f[R]
+T}@T{
+Temporarily suspend the browser, by delivering the client process a
+SIGTSTP signal.
+Note: this suspends the entire process group.
+T}@T{
+T}
+.TE
+.PP
+\f[V]Client\f[R] also implements various web standards normally
+available on the \f[V]Window\f[R] object on websites, e.g.\ fetch().
+Note however that it does \f[I]not\f[R] give access to JS objects in
+buffers, so e.g.\ \f[V]globalThis.document\f[R] is not available.
+.SS Pager
+.PP
+\f[V]Pager\f[R] is a separate interface from \f[V]Client\f[R] that gives
+access to the pager (i.e.\ browser chrome).
+It is accessible as \f[V]globalThis.pager\f[R], or simply
+\f[V]pager\f[R].
+.PP
+Following properties (functions/getters) are defined by \f[V]Pager\f[R]:
+.PP
+.TS
+tab(@);
+lw(28.0n) lw(38.5n) lw(3.5n).
+T{
+Property
+T}@T{
+Description
+T}@T{
+T}
+_
+T{
+\f[V]load(url)\f[R]
+T}@T{
+Put the specified address into the URL bar, and optionally load it.
+Note that this performs auto-expansion of URLs, so Chawan will expand
+any matching omni-rules (e.g.\ search), try to open schemeless URLs with
+the default scheme/local files, etc.
+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.\ \f[V]pager.load(\[dq]about:chawann\[dq])\f[R]), the URL is loaded
+directly.
+T}@T{
+T}
+T{
+\f[V]loadSubmit(url)\f[R]
+T}@T{
+Act as if \f[V]url\f[R] had been input into the address bar.
+Same as \f[V]pager.load(url + \[dq]n\[dq])\f[R].
+T}@T{
+T}
+T{
+\f[V]gotoURL(url)\f[R]
+T}@T{
+Go to the specified URL immediately (without a prompt).
+This differs from \f[V]load\f[R] and \f[V]loadSubmit\f[R] in that it
+\f[I]does not\f[R] try to correct the URL.
+Use this for loading automatically retrieved (i.e.\ non-user-provided)
+URLs.
+T}@T{
+T}
+T{
+\f[V]dupeBuffer()\f[R]
+T}@T{
+Duplicate the current buffer by loading its source to a new buffer.
+T}@T{
+T}
+T{
+\f[V]discardBuffer()\f[R]
+T}@T{
+Discard the current buffer, and move back to its previous sibling
+buffer, or if that doesn\[cq]t exist, to its parent.
+If the current buffer is a root buffer (i.e.\ it has no parent), move to
+the next sibling buffer instead.
+T}@T{
+T}
+T{
+\f[V]discardTree()\f[R]
+T}@T{
+Discard all child buffers of the current buffer.
+T}@T{
+T}
+T{
+\f[V]reload()\f[R]
+T}@T{
+Open a new buffer with the current buffer\[cq]s URL, replacing the
+current buffer.
+T}@T{
+T}
+T{
+\f[V]reshape()\f[R]
+T}@T{
+Reshape the current buffer (=render the current page anew.)
+T}@T{
+T}
+T{
+\f[V]redraw()\f[R]
+T}@T{
+Redraw screen contents.
+Useful if something messed up the display.
+T}@T{
+T}
+T{
+\f[V]toggleSource()\f[R]
+T}@T{
+If viewing an HTML buffer, open a new buffer with its source.
+Otherwise, open the current buffer\[cq]s contents as HTML.
+T}@T{
+T}
+T{
+\f[V]lineInfo()\f[R]
+T}@T{
+Display information about the current line.
+T}@T{
+T}
+T{
+\f[V]searchForward()\f[R]
+T}@T{
+Search for a string in the current buffer.
+T}@T{
+T}
+T{
+\f[V]searchBackward()\f[R]
+T}@T{
+Search for a string, backwards.
+T}@T{
+T}
+T{
+\f[V]isearchForward()\f[R]
+T}@T{
+Incremental-search for a string, highlighting the first result.
+T}@T{
+T}
+T{
+\f[V]isearchBackward()\f[R]
+T}@T{
+Incremental-search and highlight the first result, backwards.
+T}@T{
+T}
+T{
+\f[V]gotoLine(n?)\f[R]
+T}@T{
+Go to the line passed as the first argument.
+If no arguments were specified, an input window for entering a line is
+shown.
+T}@T{
+T}
+T{
+\f[V]searchNext(n = 1)\f[R]
+T}@T{
+Jump to the nth next search result.
+T}@T{
+T}
+T{
+\f[V]searchPrev(n = 1)\f[R]
+T}@T{
+Jump to the nth previous search result.
+T}@T{
+T}
+T{
+\f[V]peek()\f[R]
+T}@T{
+Display an alert message of the current URL.
+T}@T{
+T}
+T{
+\f[V]peekCursor()\f[R]
+T}@T{
+Display an alert message of the URL or title under the cursor.
+Multiple calls allow cycling through the two.
+(i.e.\ by default, press u once -> title, press again -> URL)
+T}@T{
+T}
+T{
+\f[V]ask(prompt)\f[R]
+T}@T{
+Ask the user for confirmation.
+Returns a promise which resolves to a boolean value indicating whether
+the user responded with yes.
+Can be used to implement an exit prompt like this:
+\f[V]q = \[aq]pager.ask(\[dq]Do you want to exit Chawan?\[dq]).then(x => x ? pager.quit() : void(0))\[aq]\f[R]
+T}@T{
+T}
+T{
+\f[V]askChar(prompt)\f[R]
+T}@T{
+Ask the user for any character.
+Like \f[V]pager.ask\f[R], but the return value is a character.
+T}@T{
+T}
+T{
+\f[V]saveLink()\f[R]
+T}@T{
+Save URL pointed to by the cursor.
+T}@T{
+T}
+T{
+\f[V]saveSource()\f[R]
+T}@T{
+Save the source of the current buffer.
+T}@T{
+T}
+T{
+\f[V]extern(cmd, options = {setenv: true, suspend: true, wait: false})\f[R]
+T}@T{
+Run an external command \f[V]cmd\f[R].
+The \f[V]$CHA_URL\f[R] and \f[V]$CHA_CHARSET\f[R] variables are set when
+\f[V]options.setenv\f[R] is true.
+\f[V]options.suspend\f[R] suspends the pager while the command is being
+executed, and \f[V]options.wait\f[R] makes it so the user must press a
+key before the pager is resumed.
+Returns true if the command exit successfully, false otherwise.
+Warning: this has a bug where the output is written to stdout even if
+suspend is true.
+Redirect to /dev/null in the command if this is not desired.
+(This will be fixed in the future.)
+T}@T{
+T}
+T{
+\f[V]externCapture(cmd)\f[R]
+T}@T{
+Like extern(), but redirect the command\[cq]s stdout string into the
+result.
+null is returned if the command wasn\[cq]t executed successfully, or if
+the command returned a non-zero exit value.
+T}@T{
+T}
+T{
+\f[V]externInto(cmd, ins)\f[R]
+T}@T{
+Like extern(), but redirect \f[V]ins\f[R] into the command\[cq]s
+standard input stream.
+\f[V]true\f[R] is returned if the command exits successfully, otherwise
+the return value is \f[V]false\f[R].
+T}@T{
+T}
+T{
+\f[V]externFilterSource(cmd, buffer = null, contentType = null)\f[R]
+T}@T{
+Redirects the specified (or if \f[V]buffer\f[R] is null, the current)
+buffer\[cq]s source into \f[V]cmd\f[R].
+Then, it pipes the output into a new buffer, with the content type
+\f[V]contentType\f[R] (or, if \f[V]contentType\f[R] is null, the
+original buffer\[cq]s content type).
+Returns \f[V]undefined\f[R].
+(It should return a promise; TODO.)
+T}@T{
+T}
+T{
+\f[V]buffer\f[R]
+T}@T{
+Getter for the currently displayed buffer.
+Returns a \f[V]Buffer\f[R] object; see below.
+T}@T{
+T}
+.TE
+.SS Buffer
+.PP
+Each buffer is exposed as an object that implements the \f[V]Buffer\f[R]
+interface.
+To get a reference to the currently displayed buffer, use
+\f[V]pager.buffer\f[R].
+.PP
+Important: there exists a quirk of questionable value on pager, where
+accessing properties that do not exist on the pager will dispatch those
+to the current buffer (\f[V]pager.buffer\f[R]).
+So if you see e.g.\ \f[V]pager.url\f[R], that is actually equivalent to
+\f[V]pager.buffer.url\f[R], because \f[V]Pager\f[R] has no \f[V]url\f[R]
+getter.
+.PP
+Following properties (functions/getters) are defined by
+\f[V]Buffer\f[R]:
+.PP
+.TS
+tab(@);
+lw(28.0n) lw(38.5n) lw(3.5n).
+T{
+Property
+T}@T{
+Description
+T}@T{
+T}
+_
+T{
+\f[V]cursorUp(n = 1)\f[R]
+T}@T{
+Move the cursor upwards by n lines, or if n is unspecified, by 1.
+T}@T{
+T}
+T{
+\f[V]cursorDown(n = 1)\f[R]
+T}@T{
+Move the cursor downwards by n lines, or if n is unspecified, by 1.
+T}@T{
+T}
+T{
+\f[V]cursorLeft(n = 1)\f[R]
+T}@T{
+Move the cursor to the left by n cells, or if n is unspecified, by 1.
+T}@T{
+T}
+T{
+\f[V]cursorRight(n = 1)\f[R]
+T}@T{
+Move the cursor to the right by n cells, or if n is unspecified, by 1.
+T}@T{
+T}
+T{
+\f[V]cursorLineBegin()\f[R]
+T}@T{
+Move the cursor to the first cell of the line.
+T}@T{
+T}
+T{
+\f[V]cursorLineTextStart()\f[R]
+T}@T{
+Move the cursor to the first non-blank character of the line.
+T}@T{
+T}
+T{
+\f[V]cursorLineEnd()\f[R]
+T}@T{
+Move the cursor to the last cell of the line.
+T}@T{
+T}
+T{
+\f[V]cursorNextWord()\f[R], \f[V]cursorNextViWord()\f[R],
+\f[V]cursorNextBigWord()\f[R]
+T}@T{
+Move the cursor to the beginning of the next word.
+T}@T{
+T}
+T{
+\f[V]cursorPrevWord()\f[R], \f[V]cursorPrevViWord()\f[R],
+\f[V]cursorPrevBigWord()\f[R]
+T}@T{
+Move the cursor to the end of the previous word.
+T}@T{
+T}
+T{
+\f[V]cursorWordEnd()\f[R], \f[V]cursorViWordEnd()\f[R],
+\f[V]cursorBigWordEnd()\f[R]
+T}@T{
+Move the cursor to the end of the current word, or if already there, to
+the end of the next word.
+T}@T{
+T}
+T{
+\f[V]cursorWordBegin()\f[R], \f[V]cursorViWordBegin()\f[R],
+\f[V]cursorBigWordBegin()\f[R]
+T}@T{
+Move the cursor to the beginning of the current word, or if already
+there, to the end of the previous word.
+T}@T{
+T}
+T{
+\f[V]cursorNextLink()\f[R], \f[V]cursorPrevLink()\f[R]
+T}@T{
+Move the cursor to the beginning of the next/previous clickable element.
+T}@T{
+T}
+T{
+\f[V]cursorPrevParagraph(n = 1)\f[R]
+T}@T{
+Move the cursor to the beginning of the nth next paragraph.
+T}@T{
+T}
+T{
+\f[V]cursorNextParagraph(n = 1)\f[R]
+T}@T{
+Move the cursor to the end of the nth previous paragraph.
+T}@T{
+T}
+T{
+\f[V]cursorNthLink(n = 1)\f[R]
+T}@T{
+Move the cursor to the nth link of the document.
+T}@T{
+T}
+T{
+\f[V]cursorRevNthLink(n = 1)\f[R]
+T}@T{
+Move the cursor to the nth link of the document, counting backwards from
+the document\[cq]s last line.
+T}@T{
+T}
+T{
+\f[V]pageUp(n = 1)\f[R], \f[V]pageDown(n = 1)\f[R],
+\f[V]pageLeft(n = 1)\f[R], \f[V]pageRight(n = 1)\f[R]
+T}@T{
+Scroll up/down/left/right by n pages.
+T}@T{
+T}
+T{
+\f[V]halfPageDown(n = 1)\f[R]
+T}@T{
+Scroll forwards by n half pages.
+T}@T{
+T}
+T{
+\f[V]halfPageUp(n = 1)\f[R]
+T}@T{
+Scroll backwards by n half pages.
+T}@T{
+T}
+T{
+\f[V]halfPageLeft(n = 1)\f[R]
+T}@T{
+Scroll to the left by n half pages.
+T}@T{
+T}
+T{
+\f[V]halfPageUp(n = 1)\f[R]
+T}@T{
+Scroll to the right by n half pages.
+T}@T{
+T}
+T{
+\f[V]scrollUp(n = 1)\f[R], \f[V]scrollDown(n = 1)\f[R],
+\f[V]scrollLeft(n = 1)\f[R], \f[V]scrollRight(n = 1)\f[R]
+T}@T{
+Scroll up/down/left/right by n lines.
+T}@T{
+T}
+T{
+\f[V]click()\f[R]
+T}@T{
+Click the HTML element currently under the cursor.
+T}@T{
+T}
+T{
+\f[V]cursorFirstLine()\f[R], \f[V]cursorLastLine()\f[R]
+T}@T{
+Move to the first/last line in the buffer.
+T}@T{
+T}
+T{
+\f[V]cursorTop()\f[R]
+T}@T{
+Move to the first line on the screen.
+(Equivalent to H in vi.)
+T}@T{
+T}
+T{
+\f[V]cursorMiddle()\f[R]
+T}@T{
+Move to the line in the middle of the screen.
+(Equivalent to M in vi.)
+T}@T{
+T}
+T{
+\f[V]cursorBottom()\f[R]
+T}@T{
+Move to the last line on the screen.
+(Equivalent to L in vi.)
+T}@T{
+T}
+T{
+\f[V]lowerPage(n = this.cursory)\f[R]
+T}@T{
+Move cursor to line n, then scroll up so that the cursor is on the top
+line on the screen.
+(\f[V]zt\f[R] in vim.)
+T}@T{
+T}
+T{
+\f[V]lowerPageBegin(n = this.cursory)\f[R]
+T}@T{
+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.
+(\f[V]z<CR>\f[R] in vi.)
+T}@T{
+T}
+T{
+\f[V]centerLine(n = this.cursory)\f[R]
+T}@T{
+Center screen around line n.\ (\f[V]zz\f[R] in vim.)
+T}@T{
+T}
+T{
+\f[V]centerLineBegin(n = this.cursory)\f[R]
+T}@T{
+Center screen around line n, and move the cursor to the line\[cq]s first
+non-blank character.
+(\f[V]z.\f[R] in vi.)
+T}@T{
+T}
+T{
+\f[V]raisePage(n = this.cursory)\f[R]
+T}@T{
+Move cursor to line n, then scroll down so that the cursor is on the top
+line on the screen.
+(zb in vim.)
+T}@T{
+T}
+T{
+\f[V]lowerPageBegin(n = this.cursory)\f[R]
+T}@T{
+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.
+(\f[V]z\[ha]\f[R] in vi.)
+T}@T{
+T}
+T{
+\f[V]nextPageBegin(n = this.cursory)\f[R]
+T}@T{
+If n was given, move to the screen before the nth line and raise the
+page.
+Otherwise, go to the previous screen\[cq]s last line and raise the page.
+(\f[V]z+\f[R] in vi.)
+T}@T{
+T}
+T{
+\f[V]cursorLeftEdge()\f[R], \f[V]cursorMiddleColumn()\f[R],
+\f[V]cursorRightEdge()\f[R]
+T}@T{
+Move to the first/middle/last column on the screen.
+T}@T{
+T}
+T{
+\f[V]centerColumn()\f[R]
+T}@T{
+Center screen around the current column.
+T}@T{
+T}
+T{
+\f[V]findNextMark(x = this.cursorx, y = this.cursory)\f[R]
+T}@T{
+Find the next mark after \f[V]x\f[R], \f[V]y\f[R], if any; and return
+its id (or null if none were found.)
+T}@T{
+T}
+T{
+\f[V]findPrevMark(x = this.cursorx, y = this.cursory)\f[R]
+T}@T{
+Find the previous mark before \f[V]x\f[R], \f[V]y\f[R], if any; and
+return its id (or null if none were found.)
+T}@T{
+T}
+T{
+\f[V]setMark(id, x = this.cursorx, y = this.cursory)\f[R]
+T}@T{
+Set a mark at (x, y) using the name \f[V]id\f[R].
+Returns true if no other mark exists with \f[V]id\f[R].
+If one already exists, it will be overridden and the function returns
+false.
+T}@T{
+T}
+T{
+\f[V]clearMark(id)\f[R]
+T}@T{
+Clear the mark with the name \f[V]id\f[R].
+Returns true if the mark existed, false otherwise.
+T}@T{
+T}
+T{
+\f[V]gotoMark(id)\f[R]
+T}@T{
+If the mark \f[V]id\f[R] exists, jump to its position and return true.
+Otherwise, do nothing and return false.
+T}@T{
+T}
+T{
+\f[V]gotoMarkY(id)\f[R]
+T}@T{
+If the mark \f[V]id\f[R] exists, jump to the beginning of the line at
+its Y position and return true.
+Otherwise, do nothing and return false.
+T}@T{
+T}
+T{
+\f[V]getMarkPos(id)\f[R]
+T}@T{
+If the mark \f[V]id\f[R] exists, return its position as an array where
+the first element is the X position and the second element is the Y
+position.
+If the mark does not exist, return null.
+T}@T{
+T}
+T{
+\f[V]markURL()\f[R]
+T}@T{
+Convert URL-like strings to anchors on the current page.
+T}@T{
+T}
+T{
+\f[V]url\f[R]
+T}@T{
+Getter for the buffer\[cq]s URL.
+Note: this returns a \f[V]URL\f[R] object, not a string.
+T}@T{
+T}
+T{
+\f[V]hoverTitle\f[R], \f[V]hoverLink\f[R], \f[V]hoverImage\f[R]
+T}@T{
+Getter for the string representation of the element title/link/image
+currently under the cursor.
+Returns the empty string if no title is found.
+T}@T{
+T}
+.TE
+.SS LineEdit
+.PP
+The line editor at the bottom of the screen is exposed to the JavaScript
+context as \f[V]globalThis.line\f[R], or simply \f[V]line\f[R], and
+implements the \f[V]LineEdit\f[R] interface.
+.PP
+Note that there is no single \f[V]LineEdit\f[R] object; a new one is
+created every time the line editor is opened, and when the line editor
+is closed, \f[V]globalThis.line\f[R] simply returns \f[V]null\f[R].
+.PP
+Following properties (functions/getters) are defined by
+\f[V]LineEdit\f[R]:
+.PP
+.TS
+tab(@);
+l l l.
+T{
+Property
+T}@T{
+Description
+T}@T{
+T}
+_
+T{
+\f[V]submit()\f[R]
+T}@T{
+Submit line
+T}@T{
+T}
+T{
+\f[V]cancel()\f[R]
+T}@T{
+Cancel operation
+T}@T{
+T}
+T{
+\f[V]backspace()\f[R]
+T}@T{
+Delete character before cursor
+T}@T{
+T}
+T{
+\f[V]delete()\f[R]
+T}@T{
+Delete character after cursor
+T}@T{
+T}
+T{
+\f[V]clear()\f[R]
+T}@T{
+Clear text before cursor
+T}@T{
+T}
+T{
+\f[V]kill()\f[R]
+T}@T{
+Clear text after cursor
+T}@T{
+T}
+T{
+\f[V]clearWord()\f[R]
+T}@T{
+Delete word before cursor
+T}@T{
+T}
+T{
+\f[V]killWord()\f[R]
+T}@T{
+Delete word after cursor
+T}@T{
+T}
+T{
+\f[V]backward()\f[R]
+T}@T{
+Move cursor back by one character
+T}@T{
+T}
+T{
+\f[V]forward()\f[R]
+T}@T{
+Move cursor forward by one character
+T}@T{
+T}
+T{
+\f[V]prevWord()\f[R]
+T}@T{
+Move cursor to the previous word by one character
+T}@T{
+T}
+T{
+\f[V]nextWord()\f[R]
+T}@T{
+Move cursor to the previous word by one character
+T}@T{
+T}
+T{
+\f[V]begin()\f[R]
+T}@T{
+Move cursor to the previous word by one character
+T}@T{
+T}
+T{
+\f[V]end()\f[R]
+T}@T{
+Move cursor to the previous word by one character
+T}@T{
+T}
+T{
+\f[V]escape()\f[R]
+T}@T{
+Ignore keybindings for next character
+T}@T{
+T}
+T{
+\f[V]prevHist()\f[R]
+T}@T{
+Jump to the previous history entry
+T}@T{
+T}
+T{
+\f[V]nextHist()\f[R]
+T}@T{
+Jump to the next history entry
+T}@T{
+T}
+.TE