# 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. 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 = pager.buffer.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. **Deprecated quirk**: If this string ends with a newline (e.g. `pager.load("about:chawan\n")`), the URL is loaded directly. This usage isn't recommended; use loadSubmit instead. |
| `loadSubmit(url)` | Act as if `url` had been entered to the URL bar. `loadSubmit` differs from `gotoURL` in that it also evaluates omni-rules, tries to prepend a scheme, etc. |
| `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.
|
| `traverse(dir)` | Switch to the next buffer in direction `dir`, interpreted as in `Buffer#find`. |
| `nextBuffer()`, `prevBuffer()`, `nextSiblingBuffer()`, `prevSiblingBuffer()`, `parentBuffer()` | Same as `traverse("next")`, `traverse("prev")`, `traverse("next-sibling")`, `traverse("prev-sibling")`, and `traverse("parent")`. |
| `dupeBuffer()` | Duplicate the current buffer by loading its source in a new buffer. |
| `discardBuffer(buffer = pager.buffer, dir = pager.navDirection)` | Discard `buffer`, then move back to the buffer opposite to `dir` (interpreted as in `Buffer#find`). |
| `discardTree()` | Discard all next siblings of the current buffer. This function is deprecated, and may be removed in the future. |
| `addTab(target)` | Open a new tab.
If `target` is a buffer, it is removed from its current tab and added to the newly created tab. Otherwise, `target` is interpreted as a URL to open with `gotoURL`. |
| `prevTab()`, `nextTab()` | Switch to the previous/next tab in the tab list. |
| `discardTab()` | Discard the current tab. |
| `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. |
| `clipboardWrite(s)` | Write `s` to the clipboard (copy). By default, it tries using OSC
52; if that fails, it tries to run `external.copy-cmd` (defaults to
`xsel`).
Returns true if the copy succeeded, false otherwise. (There may be false positives in case OSC 52 is used and the terminal doesn't consume the text.) |
| `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 exited 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. |
| `navDirection` | The direction the user last moved in the buffer list using `traverse`. Possible values are `prev`, `next`, `prev-sibling`, `next-sibling`, `parent`, `any`. |
| `revDirection` | Equivalent to `Pager.oppositeDir(pager.navDirection)`. |
| Property | Description |
|---|---|
| `Pager.oppositeDir(dir)` | Return a string representing the direction opposite to `dir`.
For "next", this is "prev"; for "parent", "next"; for "prev-sibling", "next-sibling"; for "any", it is the same; for the rest, vice versa. |
| 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. |
| `showLinkHints()` | Display link hints on the page. Mainly intended for the built-in
toggleLinkHints command.
Returns an array of objects with `x` representing the x position, `y` the y position of a link. |
| `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. |
| `find(dir)` | Find the next buffer in the list in a specific direction.
Possible values of `dir` are: `prev`, `next`, `prev-sibling`, `next-sibling`, `parent`, `any`. "next" and "prev" return the next/previous buffer respectively. "prev-sibling", "parent" are deprecated aliases for "prev", while "next-sibling" is a deprecated alias for "next". Finally, "any" returns either "prev", or if it's null, "next". |
| `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. |
| `next` | Next buffer in the buffer list. May be `null`. |
| `prev` | Previous buffer in the buffer list. May be `null`. |
| `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. |