edamame 0.1.2

A fast TUI Markdown editor and viewer
Documentation
# Configuration

Every setting edamame reads, what it defaults to, and where to change it.

Most people never need this page — the settings overlay covers the common options. Reach it from the command palette: **`Ctrl-P` → "Open settings"**.

---

## Where config lives

edamame follows the XDG convention on **every** platform, macOS included:

```
$XDG_CONFIG_HOME/edamame/     # if XDG_CONFIG_HOME is set to an absolute path
~/.config/edamame/            # otherwise
```

Inside it:

| File | Purpose |
|---|---|
| `config.toml` | Everything on this page |
| `keybindings.toml` | Key overrides — see [keybindings.md](keybindings.md) |
| `themes/` | Your custom themes — see [themes.md](themes.md) |
| `export/` | Custom stylesheets for HTML export |

All four are created on first run and **never overwritten afterwards**. The shipped `config.toml` is heavily commented, so reading it is often faster than reading this page.

To find the folder from inside edamame: `Ctrl-P` → "Open settings" → the first row is "Open config folder". The second, "Open config.toml", opens the file in `$VISUAL` / `$EDITOR`.

### When something is wrong with your config

Nothing about config loading is fatal. A missing file means defaults. A file that doesn't parse means defaults plus a warning. An unrecognized key is kept in the file and reported. Warnings appear in a modal at startup, naming the file and the key — so a typo tells you rather than silently doing nothing.

Saving from inside edamame **preserves your comments, blank lines, and section order** — settings are written surgically, not round-tripped.

---

## Appearance

| Key | Type | Default | Where |
|---|---|---|---|
| `theme` | string | `"Edamame"` | Theme picker |
| `appearance` | `"dark"` \| `"light"` | `"dark"` | Theme picker |

```toml
theme = "Edamame"
appearance = "dark"
```

`theme` is a built-in name or the filename stem of a file in `themes/`. See [themes.md](themes.md) for the full list and how to write your own.

`appearance` filters the theme picker to matching themes and decides which counterpart is previewed when you flip modes. It does not itself change colors.

Change both from the theme picker: `Ctrl-P` → "Switch theme". There is no default chord for it, and no Appearance row in the settings overlay.

> On a first run in a terminal without 24-bit color, edamame seeds `theme = "256 Dark"` instead, because most themes quantize badly. If you later launch an existing config in such a terminal it substitutes an indexed-color theme **for that session only** — your `config.toml` keeps the theme you chose, so a config shared with a capable machine is never clobbered.

---

## `[editor]`

### Layout and display

| Key | Type | Default | Where |
|---|---|---|---|
| `line_wrap` | bool | `true` | file only |
| `code_block_wrap` | bool | `false` | file only |
| `preserve_blank_lines` | bool | `true` | file only |
| `show_line_numbers` | bool | `false` | overlay, palette |
| `big_h1` | bool | `false` | overlay, palette |
| `syntax_highlighting` | bool | `true` | overlay |
| `max_width_enabled` | bool | `false` | overlay, palette |
| `max_width_cols` | integer | `100` | overlay |

`line_wrap` wraps long lines at the terminal width. `code_block_wrap` is separate because wrapped code is often harder to read than clipped code.

`preserve_blank_lines` renders runs of blank lines as written. Standard Markdown collapses them to one; this keeps your spacing.

`big_h1` renders H1 titles as four-row block characters. It falls back to normal rendering when the title is wider than the viewport or contains non-ASCII characters.

`syntax_highlighting` colors fenced code blocks. The language comes only from the opening fence — edamame never guesses — so a fence with no language, or one naming a language it doesn't ship, renders as plain code. Token colors are theme fields (`syntax_keyword`, `syntax_string`, and the rest), so a custom theme can restyle or flatten them; see [themes.md](themes.md).

`max_width_cols` caps the content column and centers it, which helps on very wide terminals. Values below **20** are clamped up. The status and hint rows always span the full width. No effect when the terminal is already narrower than the cap.

### Cursor and movement

| Key | Type | Default | Where |
|---|---|---|---|
| `visual_line_nav` | bool | `true` | overlay, palette |
| `cursor_blink` | bool | `true` | overlay, palette |
| `cursor_blink_ms` | integer | `530` | file only |
| `mouse_scroll_lines` | integer | `1` | overlay |

`visual_line_nav` makes `↑`/`↓` move by visual rows, so the cursor keeps its screen column across a wrapped line. Set `false` to move by logical lines.

`cursor_blink_ms` is the half-period — the cursor toggles every this many milliseconds.

`mouse_scroll_lines` is lines per wheel tick, and also governs trackpad scrolling (where `1` usually feels best). Keyboard scrolling always steps one line and ignores this.

### Saving

| Key | Type | Default | Where |
|---|---|---|---|
| `autosave_enabled` | bool | `false` | overlay, palette |
| `autosave_idle_ms` | integer | `5000` | file only |

Autosave is a debounce, not a timer: every keystroke resets the clock, so a burst of typing produces one save at the end. A successful save flashes "Autosaved". **Buffers with no filename never autosave** — there is nowhere to write. Autosave is also suspended during diff review.

`autosave_idle_ms` must be **strictly between 1000 and 600000** (10 minutes). Anything outside that range is rejected at load with a warning and the default is used — so `0` can't quietly turn autosave into save-on-every-keystroke.

### External changes

| Key | Type | Default | Where |
|---|---|---|---|
| `diff_on_change` | bool | `true` | overlay, palette |
| `show_diff_intro` | bool | `true` | file only |

`diff_on_change` decides what happens when something else writes the file you have open **and your buffer is clean**: `true` opens diff review so you see each change; `false` reloads silently.

A buffer with unsaved edits always prompts, regardless of this setting. edamame never silently discards your work. See [editing.md](editing.md#when-the-file-changes-underneath-you).

`show_diff_intro` shows the explainer when diff review opens. The modal's "Don't show this again" flips it off; set it back to `true` here to bring it back — it is not in the settings overlay.

### Startup prompts

| Key | Type | Default | Where |
|---|---|---|---|
| `show_welcome` | bool | `true` | welcome modal |
| `check_for_updates` | bool | `true` | settings overlay, welcome modal |
| `last_update_check` | integer | `0` | written by edamame |
| `update_notified_for` | string | `""` | written by edamame |
| `last_version_seen` | string | `""` | written by edamame |
| `seen_terminal_fingerprints` | list of string | `[]` | written by edamame |

`seen_terminal_fingerprints` is used by edamame to record which terminals have already shown the capabilities notice, so it fires once per new terminal rather than every launch.

`check_for_updates` is used by edamame to govern the automatic release check at startup. It runs at most once every 24 hours — and not before the first-run welcome screen has been answered, so turning it off there stops the first check too. It is silent unless there is a new release. Turning it off disables the automatic check.

`last_update_check` and `update_notified_for` are used by edamame to know when the last update check was conducted and whether it already notified you about a specific release.

`last_version_seen` records the version that last ran. This is used by edamame to show you release notes for a specific version only once. The notes are read from the changelog built into the binary — no network is involved, and this is unrelated to the update check above. To read the notes again at any time, press **Release notes** on the About page.

---

## `[modal]`

| Key | Type | Default | Where |
|---|---|---|---|
| `handler` | `"default"` \| `"vim"` | `"default"` | overlay, palette, welcome |

```toml
[modal]
handler = "vim"
```

`"vim"` turns on modal editing — see [vim-mode.md](vim-mode.md).

Note that an unrecognized value is accepted without complaint and behaves as `"default"`, so check your spelling if vim mode doesn't appear.

---

## `[table]`

| Key | Type | Default | Where |
|---|---|---|---|
| `show_buttons` | bool | `true` | overlay, palette |
| `row_striping` | bool | `true` | file only |
| `warn_on_width_injection` | bool | `true` | file only |

`show_buttons` draws the mouse handles on tables — `⠿` to drag rows and columns into a new order, `⇔` to resize a column, `✕` to delete a row or column. They're inert without mouse support, so edamame forces this off on a terminal that has none.

`warn_on_width_injection` controls the confirmation shown the first time a column resize would write a `<!-- tui-columns: [...] -->` comment into your Markdown. That comment is how column widths persist; the modal's "Continue and don't ask again" flips this off.

---

## `[images]`

| Key | Type | Default | Where |
|---|---|---|---|
| `enabled` | `"ask"` \| `"always"` \| `"never"` | `"ask"` | overlay |
| `remote_policy` | `"ask"` \| `"always"` \| `"never"` | `"ask"` | overlay |
| `max_width` | integer | `100` | file only |
| `max_height` | integer | `24` | file only |

`enabled` is the master switch. `"ask"` prompts the first time you open a document containing images.

`remote_policy` separately governs `http(s)://` image URLs — the same idea as an email client's "load remote images", and for the same reason: it stops a document tracking you the moment you open it. It has no effect when `enabled` is `"never"`.

`max_width` / `max_height` are ceilings in terminal cells. Images scale to fit inside that box, keeping their aspect ratio.

> **Images need 24-bit color** as well as a supporting terminal. Below that, edamame declines to render them regardless of these settings — for that session only, so a config shared with a capable terminal keeps working. See [editing.md](editing.md#images) and [terminal-compatibility.md](terminal-compatibility.md#images-and-diagrams).

---

## `[diagrams]`

| Key | Type | Default | Where |
|---|---|---|---|
| `enabled` | `"ask"` \| `"always"` \| `"never"` | `"ask"` | overlay |

Controls rendering of ` ```mermaid ` blocks. Deliberately independent of `[images]` so you can opt into one without the other. Same 24-bit color requirement.

---

## `[export.html]`

| Key | Type | Default |
|---|---|---|
| `stylesheet` | string | `"builtin"` |
| `inline_images` | bool | `false` |
| `diagrams` | bool | `true` |

These are the values the export modal opens with — for a custom target as well as for HTML, since a custom export converts the HTML these settings describe. Whatever you pick in that modal is written back here.

`stylesheet` is either the literal `"builtin"` or a path to a `.css` file. Drop stylesheets into the `export/` folder beside `config.toml` and they appear in the modal's picker. A `default.css.example` is written there on first run to copy from.

`inline_images` base64-embeds local images into the HTML so the file is self-contained. Off by default, partly because it makes large files and partly because an embedded file leaves your machine when you share the export — only images inside the document's own directory tree are ever inlined.

`diagrams` renders diagrams as SVG and inlines them into the export. If off, the raw Mermaid source is outputted instead.

See [editing.md](editing.md#exporting).

---

## `[[export.custom]]`

| Key | Type | Default |
|---|---|---|
| `name` | string | — |
| `command` | array of strings | — |
| `extension` | string | — |

An array of tables: repeat the block once per converter. Each entry adds a format to the export modal's Format list (beside HTML); choosing it renders the document to HTML using `[export.html]` above and then runs `command` over the result.

`name` is what the format will be listed as in the export modal's Format list.

`command` is an argv list, not a command line — it is executed directly, never through a shell, so quoting, globbing and `$VAR` don't apply. Use `["sh", "-c", "…"]` if you want them. Two placeholders are substituted anywhere in the list: `{html}` is the rendered intermediate file (a temp file, removed afterwards) and `{out}` is the file to write. A converter that writes to standard output instead is also handled — omit `{out}` and edamame captures and writes the output. The command runs with the document's directory as its working directory, so relative image paths resolve as they do in the document.

`extension` sets the output extension. `notes/guide.md` with `extension = "pdf"` writes `notes/guide.pdf`.

All three fields are required in practice. An entry missing one is left out of the export modal's Format list, with a startup warning that names its position.

```toml
[[export.custom]]
name      = "PDF (weasyprint)"
command   = ["weasyprint", "{html}", "{out}"]
extension = "pdf"

[[export.custom]]
name      = "DOCX"
command   = ["pandoc", "{html}", "-o", "{out}"]
extension = "docx"
```

The first entry adds "PDF (weasyprint)" to the Format list in the export modal, beside "HTML". Pick it and the rest of the form is unchanged — because the HTML your converter reads is the HTML those options describe, the stylesheet in particular. Choose your stylesheet with the final format in mind: for print, a `@page` rule in a custom `.css` is usually what you want.

Everything else works as it does for HTML — the output lands beside your document under the extension you configured, you're asked before overwriting, and the converter runs in the background so edamame stays responsive. If it fails, the modal shows you the error.

You can configure as many as you like; each becomes another row in the Format list. An entry that couldn't work — no name, no command, no extension — is left out of that list with a warning naming it, rather than becoming a format that fails once you've filled in the form. Your `config.toml` is left untouched, so the block stays there for you to correct.

---

## `[dev]`

| Key | Type | Default |
|---|---|---|
| `logging` | bool | `false` |

Writes `tracing` logs to your XDG data directory (e.g. `~/.local/share/edamame/`). When off, the subscriber is never installed and logging calls cost nothing. Useful when reporting a bug.

---

## Full example

A complete `config.toml` with non-default choices throughout:

```toml
theme = "Tokyo Night"
appearance = "dark"

[editor]
show_line_numbers = true
max_width_enabled = true
max_width_cols = 90
autosave_enabled = true
autosave_idle_ms = 3000
big_h1 = true
syntax_highlighting = true
cursor_blink = false

[modal]
handler = "vim"

[table]
row_striping = false

[images]
enabled = "always"
remote_policy = "never"

[diagrams]
enabled = "always"

[export.html]
inline_images = true

[[export.custom]]
name      = "PDF (weasyprint)"
command   = ["weasyprint", "{html}", "{out}"]
extension = "pdf"
```