# Chawan's command API As described in the [config](config.md) documentation, keypress combinations can be bound to actions. An action can be either a JavaScript expression, or a command defined in the `[cmd]` section of config.toml. For example, the following works: ``` gpn = 'n => pager.alert(n)' # e.g. 2gpn prints `2' to the status line ``` Note however, that JavaScript functions must be called with an appropriate `this` value. Unfortunately, this also means that the following does not work: ``` gpn = 'pager.alert' # broken!!! ``` 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. To fix this, it is possible to define a command in the `[cmd]` section: ```toml [cmd.my.namespace] showNumber = 'n => pager.alert(n)' ``` `my.namespace` can be anything you want; it is to avoid collisions when including multiple configs. Avoid setting it to `pager` or `line`, because these are used by the default config. Now you can call `cmd.my.namespace.showNumber()` from any other function, or just include it in an action: ```toml 'gpn' = 'cmd.my.namespace.showNumber' ``` ## Interfaces ### Client The global object (`globalThis`) implements the `Client` interface. Documented functions of this are:
Property | Description |
---|---|
`quit()` | Exit the browser. |
`suspend()` | Temporarily suspend the browser, by delivering the client process a
SIGTSTP signal. Note: this suspends the entire process group. |
`readFile(path)` | Read a file at `path`. Returns the file's content as a string, or null if the file does not exist. |
`writeFile(path, content)` | Write `content` to the file at `path`. Throws a TypeError if this failed for whatever reason. |
`getenv(name, fallback = null)` | Get an environment variable by `name`. Returns `fallback` if the variable does not exist. |
`setenv(name, value)` | Set an environment variable by `name`. Throws a type error if the operation failed (e.g. because the variable's size exceeded an OS-specified limit.) |
`pager` | The pager object. Implements `Pager`, as described below. |
`line` | The line editor. Implements `LineEdit`, as described below. |
`config` | The config object. A currently incomplete interface for retrieving and setting configuration options. In general, names are the same as in config.toml, except all `-` (ASCII hyphen) characters are stripped and the next character is upper-cased (underscore). e.g. `external.cgi-dir` can be queried as `config.external.cgiDir`, etc. Setting individual options sometimes works, but sometimes they do not get propagated as expected. Consider this an experimental API. Currently, `siteconf`, `protocol` and `omnirule` values are not exposed to JS. The configuration directory itself can be queried as `config.dir`. |
Property | Description |
---|---|
`load(url)` | 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. `pager.load("about:chawan\n")`), the URL is loaded directly. |
`loadSubmit(url)` | Act as if `url` had been input into the address bar. Same as `pager.load(url + "\n")`. |
`gotoURL(url, options = {replace: null, contentType: null, save: false})` | Go to the specified URL immediately (without a prompt). This differs from
`loadSubmit` in that it loads the exact URL as passed (no prepending https,
etc.) When `replace` is set, the new buffer may replace the old one if it loads successfully. When `contentType` is set, the new buffer's content type is forcefully set to that string. When `save` is true, the user is prompted to save the resource instead of displaying it in a buffer. |
`nextBuffer()`, `prevBuffer()`, `nextSiblingBufer()`, `prevSiblingBuffer()`, `parentBuffer()` | Traverse the buffer tree. `nextBuffer()`, `prevBuffer()` do a depth-first traversal; ``nextSiblingBufer()`, `prevSiblingBuffer()` cycle through siblings, and `parentBuffer()` returns to the parent. |
`dupeBuffer()` | Duplicate the current buffer by loading its source to a new buffer. |
`discardBuffer(buffer = pager.buffer, dir = pager.navDirection)` | Discard `buffer`, then move back to the buffer opposite to `dir`. Possible values of `dir` are: "prev", "next", "prev-sibling", "next-sibling", "parent", "first-child", "any". |
`discardTree()` | Discard all child buffers of the current buffer. |
`reload()` | Open a new buffer with the current buffer's URL, replacing the current buffer. |
`reshape()` | Reshape the current buffer (=render the current page anew.) |
`redraw()` | Redraw screen contents. Useful if something messed up the display. |
`toggleSource()` | If viewing an HTML buffer, open a new buffer with its source. Otherwise, open the current buffer's contents as HTML. |
`lineInfo()` | Display information about the current line. |
`searchForward()`, `searchBackward()` | Search forward/backward for a string in the current buffer. |
`isearchForward()`, `isearchBackward()` | Incremental-search forward/backward for a string, highlighting the first result. |
`gotoLine(n?)` | Go to the line passed as the first argument. If no arguments were specified, an input window for entering a line is shown. |
`searchNext(n = 1)`, `searchPrev(n = 1)` | Jump to the nth next/previous search result. |
`peek()` | Display an alert message of the current URL. |
`peekCursor()` | 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) |
`showFullAlert()` | Show the last alert inside the line editor. |
`ask(prompt)` | 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: ``` q = 'pager.ask("Do you want to exit Chawan?").then(x => x ? pager.quit() : void(0))' ``` |
`askChar(prompt)` | Ask the user for any character. Like `pager.ask`, but the return value is a character. |
`extern(cmd, options = {env: { ... }, suspend: true, wait: false})` | Run an external command `cmd`. By default, the `$CHA_URL` and `$CHA_CHARSET` variables are set; change this using the `env` option. `options.suspend` suspends the pager while the command is being executed, and `options.wait` 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.) |
`externCapture(cmd)` | Like extern(), but redirect the command's stdout string into the result. null is returned if the command wasn't executed successfully, or if the command returned a non-zero exit value. |
`externInto(cmd, ins)` | Like extern(), but redirect `ins` into the command's standard input stream. `true` is returned if the command exits successfully, otherwise the return value is `false`. |
`externFilterSource(cmd, buffer = null, contentType = null)` | Redirects the specified (or if `buffer` is null, the current) buffer's
source into `cmd`. Then, it pipes the output into a new buffer, with the content type `contentType` (or, if `contentType` is null, the original buffer's content type). Returns `undefined`. (It should return a promise; TODO.) |
`buffer` | Getter for the currently displayed buffer. Returns a `Buffer` object; see below. |
Property | Description |
---|---|
`cursorUp(n = 1)`, `cursorDown(n = 1)` | Move the cursor upwards/downwards by n lines, or if n is unspecified, by 1. |
`cursorLeft(n = 1)`, `cursorRight(n = 1)` | Move the cursor to the left/right by n cells, or if n is unspecified, by
1. Note: `n` right now represents cells, but really it should represent characters. (The difference is that right now numbered cursorLeft/cursorRight is broken for double-width chars.) |
`cursorLineBegin()`, `cursorLineEnd()` | Move the cursor to the first/last cell of the line. |
`cursorLineTextStart()` | Move the cursor to the first non-blank character of the line. |
`cursorNextWord()`, `cursorNextViWord()`, `cursorNextBigWord()` | Move the cursor to the beginning of the next [word](#word-types). |
`cursorPrevWord()`, `cursorPrevViWord()`, `cursorPrevBigWord()` | Move the cursor to the end of the previous [word](#word-types). |
`cursorWordEnd()`, `cursorViWordEnd()`, `cursorBigWordEnd()` | Move the cursor to the end of the current [word](#word-types), or if already there, to the end of the next word. |
`cursorWordBegin()`, `cursorViWordBegin()`, `cursorBigWordBegin()` | Move the cursor to the beginning of the current [word](#word-types), or if already there, to the end of the previous word. |
`cursorNextLink()`, `cursorPrevLink()` | Move the cursor to the beginning of the next/previous clickable element. |
`cursorLinkNavDown(n = 1)`, `cursorLinkNavUp(n = 1)` | Move the cursor to the beginning of the next/previous clickable element. Buffer scrolls pagewise, wrap to beginning/end if content is less than one page length. |
`cursorNextParagraph(n = 1)`, `cursorPrevParagraph(n = 1)` | Move the cursor to the beginning/end of the nth next/previous paragraph. |
`cursorNthLink(n = 1)` | Move the cursor to the nth link of the document. |
`cursorRevNthLink(n = 1)` | Move the cursor to the nth link of the document, counting backwards from the document's last line. |
`pageUp(n = 1)`, `pageDown(n = 1)`, `pageLeft(n = 1)`, `pageRight(n = 1)` | Scroll up/down/left/right by n pages. |
`halfPageUp(n = 1)`, `halfPageDown(n = 1)`, `halfPageLeft(n = 1)`, `halfPageRight(n = 1)` | Scroll up/down/left/right by n half pages. |
`scrollUp(n = 1)`, `scrollDown(n = 1)`, `scrollLeft(n = 1)`, `scrollRight(n = 1)` | Scroll up/down/left/right by n lines. |
`click()` | Click the HTML element currently under the cursor. |
`cursorFirstLine()`, `cursorLastLine()` | Move to the first/last line in the buffer. |
`cursorTop()`, `cursorMiddle()`, `cursorBottom()` | Move to the first/middle/bottom line on the screen. (Equivalent to H/M/L in vi.) |
`lowerPage(n = this.cursory)` | Move cursor to line n, then scroll up so that the cursor is on the top line on the screen. (`zt` in vim.) |
`lowerPageBegin(n = this.cursory)` | 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 |
`centerLine(n = this.cursory)` | Center screen around line n. (`zz` in vim.) |
`centerLineBegin(n = this.cursory)` | Center screen around line n, and move the cursor to the line's first non-blank character. (`z.` in vi.) |
`raisePage(n = this.cursory)` | Move cursor to line n, then scroll down so that the cursor is on the top line on the screen. (zb in vim.) |
`lowerPageBegin(n = this.cursory)` | 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.) |
`nextPageBegin(n = this.cursory)` | 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.) |
`cursorLeftEdge()`, `cursorMiddleColumn()`, `cursorRightEdge()` | Move to the first/middle/last column on the screen. |
`centerColumn()` | Center screen around the current column. |
`findNextMark(x = this.cursorx, y = this.cursory)`, `findPrevMark(x = this.cursorx, y = this.cursory)` | Find the next/previous mark after/before `x`, `y`, if any; and return its id (or null if none were found.) |
`setMark(id, x = this.cursorx, y = this.cursory)` | Set a mark at (x, y) using the name `id`. Returns true if no other mark exists with `id`. If one already exists, it will be overridden and the function returns false. |
`clearMark(id)` | Clear the mark with the name `id`. Returns true if the mark existed, false otherwise. |
`gotoMark(id)` | If the mark `id` exists, jump to its position and return true. Otherwise, do nothing and return false. |
`gotoMarkY(id)` | If the mark `id` exists, jump to the beginning of the line at its Y position and return true. Otherwise, do nothing and return false. |
`getMarkPos(id)` | If the mark `id` 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. |
`cursorToggleSelection(n = 1, opts = {selectionType: "normal"})` | Start a vim-style visual selection. The cursor is moved to the right
by `n` cells. selectionType may be "normal" (regular selection), "line" (line-based selection) and "column" (column-based selection). |
`getSelectionText()` | Get the currently selected text. Returns a promise, so consumers must `await` it to get the text. |
`markURL()` | Convert URL-like strings to anchors on the current page. |
`toggleImages()` | Toggle display of images in this buffer. |
`saveLink()` | Save URL pointed to by the cursor. |
`saveSource()` | Save the source of this buffer. |
`setCursorX(x)`, `setCursorY(y)`, `setCursorXY(x, y)`, `setCursorXCenter(x)`, `setCursorYCenter(y)`, `setCursorXYCenter(x, y)` | Set the cursor position to `x` and `y` respectively, scrolling the
view if necessary. Variants that end with "Center" will also center the screen around the position if it is outside the screen. |
`url` | Getter for the buffer's URL. Note: this returns a `URL` object, not a string. |
`hoverTitle`, `hoverLink`, `hoverImage` | Getter for the string representation of the element title/link/image currently under the cursor. Returns the empty string if no title is found. |
`cursorx`, `cursory` | The x/y position of the cursor inside the buffer. Note that although the status line is 1-based, these values are 0-based. |
`fromx`, `fromy` | The x/y position of the first line displayed on the screen. |
`numLines` | The number of lines currently loaded in the buffer. |
`width`, `height` | The width and height of the buffer's window (i.e. the visible part of the canvas). |
`process` | The process ID of the buffer. |
`title` | Text from the `title` element, or the buffer's URL if there is no title. |
`parent` | Parent buffer in the buffer tree. May be null. |
`children` | Array of child buffers in the buffer tree. |
`select` | Reference to the current `select` element's widget, or null if no
`select` element is open. This object implements the `Select` interface, which is somewhat compatible with the `Buffer` interface with some exceptions. (TODO: elaborate) |
Property | Description |
---|---|
`submit()` | Submit line. |
`cancel()` | Cancel operation. |
`backspace()` | Delete character before cursor. |
`delete()` | Delete character after cursor. |
`clear()` | Clear text before cursor. |
`kill()` | Clear text after cursor. |
`clearWord()` | Delete word before cursor. |
`killWord()` | Delete word after cursor. |
`backward()`, `forward()` | Move cursor backward/forward by one character. |
`nextWord()`, `prevWord()` | Move cursor to the next/previous word by one character. |
`begin()`, `end()` | Move cursor to the beginning/end of the line. |
`escape()` | Ignore keybindings for next character. |
`nextHist()`, `prevHist()` | Jump to the previous/next history entry. |