# Configuration
Chawan supports custom keybindings and user stylesheets. The configuration
format is very similar to the toml format, with the following exceptions:
* Table arrays can be cleared like this:
```
omnirule = []
[[omnirule]] # this is accepted
```
This allows users to disable default table array rules. Note that these
declarations must be placed at the beginning of the file.
* Inline tables may span across multiple lines. Rationale: the toml specified
behavior is counter-intuitive.
Chawan will look for a config file in the ~/.config/chawan/ directory called
`config.toml`. See the default configuration in the res/ folder for the default
configuration.
**Table of contents**
* [Start](#start)
* [External](#external)
* [Network](#network)
* [Display](#display)
* [Omnirule](#omnirule)
* [Siteconf](#siteconf)
* [Stylesheets](#stylesheets)
* [Keybindings](#keybindings)
* [Pager actions](#pager-actions)
* [Line-editing actions](#line-editing-actions)
## Start
Start-up options are to be placed in the `[start]` section.
Following is a list of start-up options:
<table>
<tr>
<th>**Name**</th>
<th>**Value**</th>
<th>**Function**</th>
</tr>
<tr>
<td>visual-home</td>
<td>url</td>
<td>Page opened when cha is called with the -V option (and no other pages are
passed as arguments.)</td>
</tr>
<tr>
<td>run-script</td>
<td>JavaScript code</td>
<td>Script cha runs on start. Pages will not be loaded until this function
exits. (setTimeout & friends do not block loading, though.)</td>
</tr>
<tr>
<td>headless</td>
<td>boolean</td>
<td>Whether cha should always start in headless mode. Enabled when cha is
called with -r.</td>
</tr>
</table>
## External
External options are to be placed in the `[external]` section.
Following is a list of external options:
<table>
<tr>
<th>**Name**</th>
<th>**Value**</th>
<th>**Function**</th>
</tr>
<tr>
<td>tmpdir</td>
<td>path</td>
<td>Directory used to save temporary files.</td>
</tr>
<tr>
<td>editor</td>
<td>shell command</td>
<td>External editor command. %s is substituted for the file name, %d for
the line number.</td>
</tr>
</table>
## Network
Network options are to be placed in the `[network]` section.
<table>
<tr>
<th>**Name**</th>
<th>**Value**</th>
<th>**Function**</th>
</tr>
<tr>
<td>max-redirect</td>
<td>number</td>
<td>Maximum number of redirections to follow.</td>
</tr>
<tr>
<td>prepend-https</td>
<td>boolean</td>
<td>Whether or not cha should attempt loading "raw" URLs without a scheme as
https (e.g. wikipedia.org as https://wikipedia.org.)</td>
</tr>
</table>
## Display
Display options are to be placed in the `[display]` section.
Following is a list of display options:
<table>
<tr>
<th>**Name**</th>
<th>**Value**</th>
<th>**Function**</th>
</tr>
<tr>
<td>color-mode</td>
<td>"monochrome"/"ansi"/"8bit"/"24bit"/"auto"</td>
<td>Set the color mode. "auto" for automatic detection, "monochrome"
for black on white, "ansi" for ansi colors, "24bit" for true colors. "8bit"
is currently unimplemented (and falls back to ansi).</td>
</tr>
<tr>
<td>format-mode</td>
<td>"auto"/["bold", "italic", "underline", "reverse", "strike", "overline",
"blink"]</td>
<td>Specifies output formatting modes. Accepts the string "auto" or an array
of specific attributes. An empty array (`[]`) disables formatting
completely.</td>
</tr>
<tr>
<td>no-format-mode
<td>["bold", "italic", "underline", "reverse", "strike", "overline", "blink"]
<td>Disable specified formatting modes.</td>
</tr>
<tr>
<td>emulate-overline</td>
<td>boolean</td>
<td>When set to true and the overline formatting attribute is not enabled,
overlines are substituted by underlines on the previous line.</td>
</tr>
<tr>
<td>alt-screen</td>
<td>"auto"/boolean</td>
<td>Enable/disable the alternative screen.</td>
</tr>
<tr>
<td>highlight-color</td>
<td>color</td>
<td>Set the highlight color. Both hex values and CSS color names are
accepted.</td>
</tr>
<tr>
<td>double-width-ambiguous</td>
<td>boolean</td>
<td>Assume the terminal displays characters in the East Asian Ambiguous
category as double-width characters. Useful when e.g. ○ occupies two
cells.</td>
</tr>
<tr>
<td>minimum-contrast</td>
<td>number</td>
<td>Specify the minimum difference between the luminance (Y) of the background
and the foreground. -1 disables this function (i.e. allows black letters on
black background, etc).</td>
</tr>
<tr>
<td>force-clear</td>
<td>boolean</td>
<td>Force the screen to be completely cleared every time it is redrawn.</td>
</tr>
</table>
## Omnirule
The omni-bar (by default opened with C-l) can be used to perform searches using
omni-rules. These are to be placed in the table array `[[omnirule]]`.
Examples:
```
# Search using DuckDuckGo Lite. (Bound to C-k by default.)
[[omnirule]]
match = '^ddg:'
substitute-url = '(x) => "https://lite.duckduckgo.com/lite/?kp=-1&kd=-1&q=" + x.substring(4)'
# Search using wikipedia, Firefox-style.
[[omnirule]]
match = '^@wikipedia'
substitute-url = '(x) => "https://en.wikipedia.org/wiki/Special:Search?search=" + x.replace(/@wikipedia/, "")'
```
Omnirule options:
<table>
<tr>
<th>**Name**</th>
<th>**Value**</th>
<th>**Function**</th>
</tr>
<tr>
<td>match</td>
<td>regex</td>
<td>Regular expression used to match the input string. Note that websites
passed as arguments are matched as well.</td>
</tr>
<tr>
<td>substitute</td>
<td>JavaScript function</td>
<td>A JavaScript function cha will pass the input string to. If a new string is
returned, it will be parsed instead of the old one.</td>
</tr>
</table>
## Siteconf
Configuration options can be specified for individual sites. Entries are to be
placed in the table array `[[siteconf]]`.
Examples:
```
# Enable cookies on the orange website for log-in.
[[siteconf]]
url = '^https://news\.ycombinator\.com/.*'
cookie = true
# Redirect npr.org to text.npr.org.
[[siteconf]]
host = '^(www\.)?npr\.org$'
rewrite-url = '''
(x) => {
x.host = "text.npr.org";
x.pathname = x.pathname.replace(/(.*)\/.*/, "$1").replace(/.*\//, "");
/* No need to return; URL objects are passed by reference. */
}
'''
```
Siteconf options:
<table>
<tr>
<th>**Name**</th>
<th>**Value**</th>
<th>**Function**</th>
</tr>
<tr>
<td>url</td>
<td>regex</td>
<td>Regular expression used to match the URL. Either this or the `host` option
must be specified.</td>
</tr>
<tr>
<td>host</td>
<td>regex</td>
<td>Regular expression used to match the host part of the URL (i.e. domain
name/ip address.) Either this or the `url` option must be specified.</td>
</tr>
<tr>
<td>rewrite-url</td>
<td>JavaScript function</td>
<td>A JavaScript function cha will pass the URL to. If a new URL is returned,
it will replace the old one.</td>
</tr>
<tr>
<td>cookie</td>
<td>boolean</td>
<td>Whether loading cookies should be allowed for this URL. By default, this is
false for all websites.</td>
</tr>
<tr>
<td>third-party-cookie</td>
<td>regex/array of regexes</td>
<td>Domains for which third-party cookies are allowed on this domain. Note:
this only works for buffers which share the same cookie jar.</td>
</tr>
<tr>
<td>share-cookie-jar</td>
<td>host</td>
<td>Cookie jar to use for this domain. Useful for e.g. sharing cookies with
subdomains.</td>
</tr>
<tr>
<td>referer-from</td>
<td>boolean</td>
<td>Whether or not we should send a Referer header when opening requests
originating from this domain. Simplified example: if you click a link on a.com
that refers to b.com, and referer-from is true, b.com is sent "a.com" as the
Referer header.
Defaults to false.
</td>
</tr>
</table>
## Stylesheets
User stylesheets are to be placed in the `[css]` section.
There are two ways to import user stylesheets:
1. Include a user stylesheet using the format `include = 'path-to-user.css'`.
To include multiple stylesheets, use `include = ['first-stylesheet.css,
second-stylesheet.css']`.
Relative paths are interpreted relative to the config directory.
2. Place your stylesheet directly in your configuration file using `inline =
"""your-style"""`.
## Keybindings
Keybindings are to be placed in these sections:
* for pager interaction: `[page]`
* for line editing: `[line]`
Keybindings are configured using the syntax
'<keybinding>' = '<action>'
Where `<keybinding>` is a combination of unicode characters with or without
modifiers. Modifiers are the prefixes `C-` and `M-`, which add control or
escape to the keybinding respectively (essentially making `M-` the same as
`C-[`). Modifiers can be escaped with the `\` sign.
```Examples:
'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
is typed in. A list of built-in pager functions can be found below.
### Pager actions
<table>
<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>
<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 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.
'C-a' = 'line.begin()'
# Escape+D deletes everything after the cursor until it reaches a word-breaking
# character.
'M-d' = 'line.killWord()'
# Control+W deletes everything before the cursor until it reaches a space.
'C-w' = 'line.clearWord(x => x == " ")'
```