diff --git a/docs/chezmoi/index.mdx b/docs/chezmoi/index.mdx
index 99c9b66..2704976 100644
--- a/docs/chezmoi/index.mdx
+++ b/docs/chezmoi/index.mdx
@@ -52,7 +52,6 @@ The repo is a [chezmoi](https://chezmoi.io) source directory. It lives at `~/.lo
- herdr-nvim/
- hunk/
- hypr/
- - iris/
- kitty/
- lazydocker/
- lazygit/
diff --git a/docs/shell/atuin.mdx b/docs/shell/atuin.mdx
index bffa566..010f4d8 100644
--- a/docs/shell/atuin.mdx
+++ b/docs/shell/atuin.mdx
@@ -1,9 +1,9 @@
---
title: atuin
-description: Shell history search for bash with a daemon, directory-scoped up-arrow, tmux popups, and a cyberdream theme.
+description: Shell history search with a daemon, directory-scoped up-arrow, tmux popups, a cyberdream theme, and the atuin AI inline command generator.
---
-[atuin](https://atuin.sh) replaces shell history search in bash. fish and zsh do not use it: [iris](/shell/iris) wraps both and takes up, down, and ctrl-r itself, so the two fought over the same keys.
+[atuin](https://atuin.sh) replaces shell history search in fish, bash, and zsh. It also provides `atuin ai inline`, a natural-language command generator that the fish config binds to keys.
| Source (repo) | Target | Notes |
| --- | --- | --- |
@@ -15,9 +15,12 @@ chezmoi runs in symlink mode, but `private_` files are written as real files, so
## Installation
-`atuin` is listed in `.chezmoidata/packages.yaml` for pacman and Homebrew. bash also expects atuin's standalone installer layout in `~/.atuin/bin`: it runs `. "$HOME/.atuin/bin/env"` just before `atuin init`.
+`atuin` is listed in `.chezmoidata/packages.yaml` for pacman and Homebrew. The shells also expect atuin's standalone installer layout in `~/.atuin/bin`:
-That line does not check that the file exists, so a machine without `~/.atuin/bin` prints a sourcing error at shell start.
+- fish: `conf.d/atuin.env.fish` sources `~/.atuin/bin/env.fish`.
+- bash and zsh: `. "$HOME/.atuin/bin/env"` just before `atuin init`.
+
+Neither line checks that the file exists, so a machine without `~/.atuin/bin` prints a sourcing error at shell start.
### atuin-receipt.json
@@ -37,21 +40,51 @@ The receipt that atuin's [cargo-dist](https://opensource.axo.dev/cargo-dist/) in
| Shell | Where | What |
| --- | --- | --- |
+| fish | `config.fish`, interactive only | `atuin init fish \| source`, `atuin ai init fish \| source`, and the `?` binding |
+| fish | `functions/fish_user_key_bindings.fish` | ctrl-w runs `atuin ai inline` |
| bash | end of `~/.bashrc` | `eval "$(atuin init bash)"` |
+| zsh | end of `~/.zshrc` | `eval "$(atuin init zsh)"` |
+
+In fish, `40-tools.fish` sources hishtory before atuin, but atuin's init runs later in `config.fish` and takes ctrl-r. zsh also loads `suv init zsh` (suvadu) if installed.
### Key bindings
| Key | Shells | Action |
| --- | --- | --- |
-| ctrl-r | bash | Interactive search (`_atuin_search`) |
-| up | bash | Search opened from the up arrow. `filter_mode_shell_up_key_binding = "directory"` limits it to history from the current directory |
+| ctrl-r | all | Interactive search (`_atuin_search`) |
+| up | all | Search opened from the up arrow. `filter_mode_shell_up_key_binding = "directory"` limits it to history from the current directory |
+| ? | fish, vi normal mode | On an empty buffer, runs `atuin ai inline --hook` |
+| ctrl-w | fish, insert and normal mode | `atuin ai inline`, then repaint |
| ctrl+shift+p | kitty | [`atuin-pick`](/shell/scripts#atuin-pick): directory-filtered search in a split, running the pick in a fresh fish |
Under tmux, atuin's `[tmux]` settings open the search in a tmux popup (80% wide, 60% tall) instead of inline.
## AI inline
-`atuin ai` is enabled in the config (`[ai] enabled = true`), but no shell loads `atuin ai init` or binds a key to it any more: the fish integration (? and ctrl-w) was removed with the move to iris. Run `atuin ai inline` by hand to use it.
+Commit `a82921c` ("add Atuin AI inline integration and keybinding") added the ctrl-w bind to `fish_user_key_bindings.fish` and the following to `config.fish`:
+
+1. `atuin ai init fish | source`, in the interactive block next to `atuin init fish`.
+2. A copy of the `_atuin_ai_question_mark` function that `atuin ai init fish` prints, and `bind "?" _atuin_ai_question_mark`.
+
+The config also sets `[ai] enabled = true`.
+
+`_atuin_ai_question_mark` works like this:
+
+- **Buffer empty (or just `?`):** clears the line, prints OSC `133;C` to `/dev/tty` to close the terminal's semantic prompt zone (so shell-integrated terminals do not erase the TUI during a prompt reflow), then runs `atuin ai inline --hook` with stdout and stderr swapped. The TUI draws on the terminal, and the result comes back tagged:
+
+ | Output prefix | Effect |
+ | --- | --- |
+ | `__atuin_ai_print__:` | Print the text, repaint |
+ | `__atuin_ai_cancel__` | Repaint only |
+ | `__atuin_ai_execute__:` | Put the command on the line and execute it |
+ | `__atuin_ai_insert__:` | Put the command on the line for editing |
+ | anything else, non-empty | Put it on the line for editing |
+
+- **Buffer not empty:** inserts a literal `?` under emacs bindings. Under vi or hybrid bindings, which this config uses, it does nothing.
+
+`bind "?"` in `config.fish` has no `-M` flag, so it applies to fish's `default` mode, which is vi **normal** mode here. In insert mode ? types a question mark. To ask for a command, press Esc and then ? on an empty line, or press ctrl-w from either mode. The ctrl-w bind calls `atuin ai inline` without `--hook` and replaces fish's default ctrl-w word deletion.
+
+bash and zsh do not load `atuin ai init`.
## Configuration
diff --git a/docs/shell/bash-zsh.mdx b/docs/shell/bash-zsh.mdx
index cc8f478..cad50ea 100644
--- a/docs/shell/bash-zsh.mdx
+++ b/docs/shell/bash-zsh.mdx
@@ -1,9 +1,9 @@
---
title: bash and zsh
-description: Secondary shells that share fish's aliases, starship prompt, and cd-style helper functions; zsh also runs under iris like fish.
+description: Secondary shells that share fish's aliases, starship prompt, atuin history, and cd-style helper functions.
---
-bash and zsh are set up so a shell other than fish feels the same: the same aliases, the same starship prompt, ports of the fish helpers that have to change the shell's own directory (`zsh/functions/` also ports `czs` and `y`), and the same picker key bindings. zsh matches fish most closely: it runs under [iris](/shell/iris), activates mise and zoxide, and has the ctrl-z job picker. bash keeps atuin for history.
+bash and zsh are set up so a shell other than fish feels the same: the same aliases, the same starship prompt, atuin history, ports of the fish helpers that have to change the shell's own directory, and the same picker key bindings.
| Source (repo) | Target |
| --- | --- |
@@ -38,30 +38,24 @@ Interactive shells only (`[[ $- != *i* ]] && return`). In order:
## ~/.zshrc
-1. **History.** `HISTFILE=~/.zsh_history`, `HISTSIZE=10000`, `SAVEHIST=10000`, `setopt SHARE_HISTORY HIST_IGNORE_DUPS HIST_IGNORE_SPACE`. `HIST_IGNORE_SPACE` keeps lines that start with a space out of history, as fish does; the ctrl-z binding's hidden ` __jobs_bind_fg` relies on it.
+1. **History.** `HISTFILE=~/.zsh_history`, `HISTSIZE=10000`, `SAVEHIST=10000`, `setopt SHARE_HISTORY HIST_IGNORE_DUPS`.
2. **Completion.** `autoload -Uz compinit && compinit`.
-3. The same PATH, Go, Android, and `GITHUB_TOKEN` blocks as `.bashrc`, including `GHQ_ROOT` and `CODE_ROOT`, plus `eval "$(mise activate zsh)"` if mise is installed (fish activates mise in `40-tools.fish`; the Go block's `GOROOT` comes from it).
+3. The same PATH, Go, Android, and `GITHUB_TOKEN` blocks as `.bashrc`, including `GHQ_ROOT` and `CODE_ROOT`.
4. Sources `~/.config/shell/aliases.sh`.
5. Sources every `~/.config/zsh/functions/*.zsh`.
6. Sources `~/.config/zsh/keybinds.zsh`.
7. `eval "$(suv init zsh)"` if suvadu is installed.
8. Sources `~/.config/envman/load.sh` if it is non-empty.
9. `eval "$(starship init zsh)"` if starship is installed.
-10. Prints quickshell's wallpaper-generated terminal color sequences (`~/.local/state/quickshell/user/generated/terminal/sequences.txt`) if present, as fish does.
-11. `eval "$(zoxide init zsh)"` if zoxide is installed (`z`, `zi`), alongside the zoxide fallback in `functions/cd.zsh`.
-12. `eval "$(tv init zsh)"` if `tv` is installed (ctrl-t smart autocomplete).
-13. **iris.** If iris is installed, `eval "$(iris init zsh)"`: in an interactive zsh on a tty it `exec`s iris, which starts a second zsh in its pty that runs `.zshrc` again; there the init installs iris's line, cwd, and command hooks. Inside iris (`IRIS_PID` set) it also runs `unsetopt PROMPT_SP`: zsh's partial-line marker pads the line with spaces and a carriage return before each prompt, and iris read that echo as a typed space, so every prompt opened with a stale query and inserted a stray first suggestion on the next key. `IRIS_RESCUE=1 zsh` starts a plain zsh. See [iris](/shell/iris).
-14. **Syntax highlighting.** Sources the first `zsh-syntax-highlighting.zsh` found in `/usr/share/zsh/plugins/zsh-syntax-highlighting/`, `/opt/homebrew/share/zsh-syntax-highlighting/`, or `/usr/local/share/zsh-syntax-highlighting/`. It stays last, because it wraps every zle widget defined before it.
-
-atuin is not used in zsh: under iris it fought for up and ctrl-r, as in fish.
+10. `eval "$(tv init zsh)"` if `tv` is installed (ctrl-t smart autocomplete).
+11. **Syntax highlighting.** Sources the first `zsh-syntax-highlighting.zsh` found in `/usr/share/zsh/plugins/zsh-syntax-highlighting/`, `/opt/homebrew/share/zsh-syntax-highlighting/`, or `/usr/local/share/zsh-syntax-highlighting/`. The comment says this must stay last, because it wraps every zle widget defined before it.
+12. **atuin.** Sources `~/.atuin/bin/env` and runs `eval "$(atuin init zsh)"`. These lines come after the syntax-highlighting block, so despite the comment, syntax highlighting is not actually last. atuin loads after tv, so it keeps ctrl-r.
## zsh key bindings
`keybinds.zsh` ports `fish_user_key_bindings.fish` to zle. Unlike fish, zsh uses the **emacs** keymap: `bindkey -e` pins it so that `$EDITOR=nvim` does not switch zsh into vi mode. `unsetopt flow_control` frees ctrl-q and ctrl-s from the terminal.
-A generic widget `_zle-run` is registered as `run-` for `purple`, `clip-last`, `omp-session`, `yy`, and `lazygit`. It clears the pending display (`zle -I`), runs the command with the tty on stdin, then `zle reset-prompt`. Widgets run in the shell process, so directory changes made by `gho` and `yy` persist.
-
-Widgets never fire `preexec`/`precmd`, so every widget that runs a program wraps it in `_iris_busy start` / `_iris_busy stop`, which send iris the same `IRIS_CMD_START` / `IRIS_CMD_STOP` messages its own hooks do (a no-op outside iris). Without them iris kept handling keys as if the prompt were idle while tv, yazi, or lazygit owned the screen, swallowing arrows and tab. See [fish](/shell/fish#key-bindings) for the same helper there.
+A generic widget `_zle-run` is registered as `run-` for `purple`, `clip-last`, `omp`, `yy`, and `lazygit`. It clears the pending display (`zle -I`), runs the command with the tty on stdin, then `zle reset-prompt`. Widgets run in the shell process, so directory changes made by `gho` and `yy` persist.
The tv pickers have their own widgets, because `tv --inline` opens on the line below the prompt and leaves the cursor there on exit. `zle -I` followed by `zle reset-prompt` redraws the prompt where zle last drew it, wiping anything printed below; `zle -I` alone draws a fresh prompt under the output.
@@ -69,8 +63,7 @@ The tv pickers have their own widgets, because `tv --inline` opens on the line b
| --- | --- | --- |
| `tv-git-files` | `tv git-files --inline` | `\033[A`, `reset-prompt` |
| `gho-inline` | `gho` | cwd unchanged: `\033[A`, `reset-prompt`. After a cd: nothing, so the new prompt lands below onefetch |
-| `pj-inline` | `_zle-pj`: `pj` with `PJ_STATE` set to a temp file | `open` (cancelled): `\033[A`, `reset-prompt`. `ran`: nothing, so the task output stays. Empty (no task sources): `reset-prompt` |
-| `jobs-fg` | `_zle-jobs`: with one job, that job; with several, `tv jobs --inline` with `TV_JOBS` set to a temp file holding the job table built from `$jobstates`/`$jobtexts` | Cancelled: `\033[A`, `reset-prompt`. Picked: `zle push-input`, then the line ` __jobs_bind_fg ` is accepted; `__jobs_bind_fg` erases that echoed line and runs `fg` quietly. Typed text returns at the next prompt |
+| `pj-inline`, `pj-down` | `_zle-pj`: `pj` with `PJ_STATE` set to a temp file (`PJ_QUIET=1` for `pj-down`) | `open` (cancelled): `\033[A`, `reset-prompt`. `ran`: nothing, so the task output stays. Empty (no task sources): `reset-prompt` |
| Key | Action |
| --- | --- |
@@ -81,7 +74,7 @@ The tv pickers have their own widgets, because `tv --inline` opens on the line b
| ctrl-o | `gho-inline` (`ghq-repos` cable, cd) |
| ctrl-p | `pj-inline` (`pj` cable) |
| ctrl-t | tv smart autocomplete (from `tv init zsh`) |
-| ctrl-z | `jobs-fg`: `fg` the only background job, or pick one from the `jobs` cable ([television](/tools/television#jobs)); nothing with no jobs. While a job runs, ctrl-z is the tty's suspend, so the key toggles |
+| down | `pj-down`: `PJ_QUIET=1 pj` on an empty prompt, otherwise `down-line-or-history` (bound to `^[[B` and `^[OB`) |
| ctrl-a | `omp-session`: resume or start omp for the current repo ([Scripts](/shell/scripts#omp-session)) |
| ctrl-g | `lazygit` |
| ctrl-q | `exit` |
@@ -89,7 +82,7 @@ The tv pickers have their own widgets, because `tv --inline` opens on the line b
ctrl-c is the tty interrupt character, so `bindkey '^C'` would never fire. The binding is a `TRAPINT` function instead. At the prompt it runs `zle .kill-buffer`, prints the clear sequence, and runs `zle .reset-prompt`. While a command is running, SIGINT keeps its normal behavior (returns `128+SIGINT`).
-ctrl-h/j/k/l belong to kitty ([kitty](/terminal/kitty)) and are not bound here. Under iris, tab, shift-tab, ctrl-r, up, and down belong to iris; up/down keep zsh's defaults outside it. The cables are described on the [television](/tools/television) page.
+The fish-only binds ctrl-w (atuin AI) and ? have no zsh equivalent. ctrl-h/j/k/l belong to kitty ([kitty](/terminal/kitty)) and are not bound here. The cables are described on the [television](/tools/television) page.
## bash key bindings
@@ -100,6 +93,7 @@ The tv pickers have their own widgets, because `tv --inline` opens on the line b
| ctrl-o | Macro `\C-x1\C-x2\C-x3\C-x0` (below): pick from the `ghq-repos` cable and cd |
| ctrl-e | `_kb_git_files`: `tv git-files --inline`, then `_kb_up` |
| ctrl-p | `_kb_pj`: `pj` with `PJ_STATE` set to a temp file; `_kb_up` only when the state is `open` (cancelled) |
+| down | `PJ_QUIET=1 _kb_pj` on an empty prompt, otherwise `history-search-forward` |
| ctrl-t | `_kb_tv_autocomplete`: runs `tv --autocomplete-prompt … --inline` on the text left of the cursor, `_kb_up`, and inserts the picks there, each `printf %q`-quoted |
`bind -x` runs in the shell process, so a `cd` persists, but readline keeps drawing the prompt it started with. ctrl-o is therefore a macro:
@@ -109,6 +103,8 @@ The tv pickers have their own widgets, because `tv --inline` opens on the line b
3. `\C-x3` runs `_kb_gho_show` (`clear`, then `onefetch` in git repos); readline redraws the prompt below the output.
4. `\C-x0` runs `_kb_restore`, which puts the typed text back.
+down (`\e[B` and `\eOB`) is the macro `\C-x4\C-x5`. `bind -x` cannot call readline functions, so `_kb_down` (`\C-x4`) rebinds `\C-x5` to `history-search-forward` when the line is non-empty, or runs `PJ_QUIET=1 _kb_pj` and rebinds `\C-x5` to `redraw-current-line`.
+
## Shared aliases: aliases.sh
`~/.config/shell/aliases.sh` is rendered from `.chezmoidata/aliases.yaml`. Each YAML `section` becomes a comment, and each item becomes `alias =''`. The template then appends shell-specific extras that are not in the YAML:
diff --git a/docs/shell/fish.mdx b/docs/shell/fish.mdx
index aa68095..a3141c5 100644
--- a/docs/shell/fish.mdx
+++ b/docs/shell/fish.mdx
@@ -3,7 +3,7 @@ title: fish
description: The primary interactive shell — conf.d layout, environment, vi-mode key bindings, the cyberdream theme, completions, and every autoloaded function.
---
-fish is the primary interactive shell. The config is split into autoloaded files: `conf.d/` for startup snippets, `functions/` for one function per file, `completions/` for completion scripts, and `themes/` for the color theme. `config.fish` runs last and holds the prompt setup and the [iris](/shell/iris) launch.
+fish is the primary interactive shell. The config is split into autoloaded files: `conf.d/` for startup snippets, `functions/` for one function per file, `completions/` for completion scripts, and `themes/` for the color theme. `config.fish` runs last and holds the prompt and atuin setup.
| Source (repo) | Target |
| --- | --- |
@@ -19,7 +19,7 @@ None of these files are templates. chezmoi runs in symlink mode, so each target
## Installation
-`fish` is in `.chezmoidata/packages.yaml` under `packages.arch.pacman` and `packages.darwin.brew`. `.chezmoiscripts/run_onchange_before_10-packages.sh.tmpl` installs it with pacman on Arch and Homebrew on macOS. The tools that fish initializes (starship, zoxide, fzf, eza, gum, yazi) come from the same manifest. mise, television, hishtory, envman, iris, and the Bun, Go, Android, and Foundry toolchains are not in the manifest; fish initializes each one only if it is present.
+`fish` is in `.chezmoidata/packages.yaml` under `packages.arch.pacman` and `packages.darwin.brew`. `.chezmoiscripts/run_onchange_before_10-packages.sh.tmpl` installs it with pacman on Arch and Homebrew on macOS. The tools that fish initializes (starship, zoxide, atuin, fzf, eza, gum, yazi) come from the same manifest. mise, television, hishtory, envman, and the Bun, Go, Android, and Foundry toolchains are not in the manifest; fish initializes each one only if it is present.
### Plugins
@@ -43,6 +43,7 @@ fish sources `conf.d/*.fish` in name order and then `config.fish`. The numbered
| `30-ssh-agent.fish` | One ssh-agent shared across shells |
| `40-tools.fish` | mise, television, starship, zoxide, entire, hishtory, unsloth |
| `50-terminal-title.fish` | tmux/screen window name from `$PWD` |
+| `atuin.env.fish` | Sources `~/.atuin/bin/env.fish` (puts atuin's install dir on `PATH`) |
| `inir-env.fish` | `INIR_VENV` and `ILLOGICAL_IMPULSE_VIRTUAL_ENV` → `~/.local/state/quickshell/.venv` |
| `inir-path.fish` | Prepends `~/.local/bin` to `PATH` if missing |
| `nvm.fish` | nvm.fish plugin events and default-version activation |
@@ -132,7 +133,7 @@ Interactive shells without `SSH_AUTH_SOCK` source `~/.ssh/agent.env.fish` and pr
5. Source `~/.hishtory/config.fish` if present.
6. Activate the unsloth studio venv (`~/.unsloth/studio/unsloth_studio/bin/activate.fish`) if present.
-Under [iris](/shell/iris), ctrl-r never reaches fish: iris takes it to switch its menu between spec and history mode.
+atuin is initialized later, in `config.fish`, and binds ctrl-r itself.
### 50-terminal-title.fish
@@ -168,14 +169,10 @@ The header comment says the file should stay empty, but it holds the following:
2. **Bottom-pinned prompt.** In interactive shells with `FISH_BOTTOM_PROMPT=1`, `tput cup $LINES 0` moves the cursor to the last row. The comment calls `1` the default, but `10-env.fish` sets `0`, so the prompt stays at the top unless you export `FISH_BOTTOM_PROMPT=1`.
3. `fish_add_path ~/.grok/bin` (grok installer block).
4. Sources `~/.config/envman/load.fish` if it is non-empty.
-5. `fish_add_path ~/.cmux/bin` and `~/.cache/.bun/bin`.
-6. Sources the first readable `~/.config/herdr/plugins/github/herdr-automatic-rename-*/shell/hook.fish`. This is herdr's automatic pane-rename hook ([herdr](/terminal/herdr)).
-7. `brew shellenv fish` for `/home/linuxbrew/.linuxbrew`.
-8. **iris.** If iris is installed: in an interactive fish that iris is not already running (no `IRIS_PID`, no `IRIS_RESCUE`), export `fish_features=no-query-term`, then `iris init fish | source`. The first half of the init `exec`s iris from an interactive fish; iris starts a second fish inside its pty, which runs this whole config again, and there the second half installs iris's cwd and command hooks and turns off fish autosuggestions. `IRIS_RESCUE=1 fish` starts a plain fish. See [iris](/shell/iris).
-
- `no-query-term` turns off fish's terminal capability query. In kitty that query switches on kitty's keyboard protocol, which sends keys as `CSI u` escape sequences iris cannot parse, so its menu never opened. Feature flags are read at startup, so the export has to happen before `exec iris`; the fish iris starts inherits it.
-
-atuin is not used in fish: it fought iris for up and ctrl-r. bash still initializes it ([atuin](/shell/atuin)).
+5. **atuin.** Interactive shells run `atuin init fish | source` and `atuin ai init fish | source`. See [atuin](/shell/atuin).
+6. `fish_add_path ~/.cmux/bin` and `~/.cache/.bun/bin`.
+7. Sources the first readable `~/.config/herdr/plugins/github/herdr-automatic-rename-*/shell/hook.fish`. This is herdr's automatic pane-rename hook ([herdr](/terminal/herdr)).
+8. A copy of the `_atuin_ai_question_mark` function that `atuin ai init fish` emits, followed by `bind "?" _atuin_ai_question_mark`.
## Key bindings
@@ -184,14 +181,16 @@ atuin is not used in fish: it fought iris for up and ctrl-rctrl-e | `_tv_inline git-files`, then repaint: pick a file in the repo and open it in nvim ([television](/tools/television#git-files)) |
-| ctrl-f | `_bind_run yy`: yazi, then cd to the directory yazi exited in |
-| ctrl-b | `_bind_run purple` (an external command; this repo does not provide it) |
-| ctrl-y | `_bind_run clip-last`: re-run the last command and copy its output |
+| ctrl-f | `yy`: yazi, then cd to the directory yazi exited in |
+| ctrl-b | `purple`, then repaint (an external command; this repo does not provide it) |
+| ctrl-y | `clip-last`: re-run the last command and copy its output |
| ctrl-o | `_gho_bind`: `gho` (pick a ghq repo or Obsidian vault from the `ghq-repos` cable and cd into it), then repaint |
| ctrl-p | `_pj_bind`: `pj`, the task runner on the `pj` cable ([Scripts](/shell/scripts#pj)), then repaint |
-| ctrl-a | `_bind_run omp-session`: resume or start omp for the current repo by branch and session age, opening the `omp-sessions` cable only when nothing qualifies ([Scripts](/shell/scripts#omp-session)) |
+| ctrl-a | `omp-session`, then repaint: resume or start omp for the current repo by branch and session age, opening the `omp-sessions` cable only when nothing qualifies ([Scripts](/shell/scripts#omp-session)) |
+| ctrl-w | `atuin ai inline`: natural-language command overlay |
| ctrl-z | `_jobs_bind`: with one background job, `fg` it; with several, pick one from the `jobs` cable ([television](/tools/television#jobs)) and `fg` that; with none, nothing. While a job holds the terminal, ctrl-z is still the tty's suspend, so the key toggles suspend and resume |
-| ctrl-g | `_bind_run lazygit` |
+| ctrl-g | `lazygit` |
+| down | `_pj_bind_down`: opens the `pj` cable on an idle, empty prompt, otherwise fish's `down-or-search` |
| ctrl-c | Clears the command line, runs `clear` (screen and kitty scrollback), repaints |
| ctrl-q | `exit` |
@@ -199,12 +198,12 @@ Bindings added by tool init scripts:
| Key | Mode | Action | Source |
| --- | --- | --- | --- |
-| up / down | default and insert | fish presets (`up-or-search`, `down-or-search`); under iris the keys never reach fish | fish |
+| ctrl-r | default and insert | `_atuin_search` | `atuin init fish` |
+| up | default and insert | `_atuin_bind_up` (atuin history, directory filter) | `atuin init fish` |
+| ? | default (vi normal) | `_atuin_ai_question_mark`: on an empty buffer, opens `atuin ai inline` | `config.fish` |
| ctrl-t | insert | `tv_smart_autocomplete` | `tv init fish` |
-Under iris, tab, shift-tab, ctrl-r, up, and down belong to iris and never reach fish, so fish's tab completion, history keys, and the `tv init fish` ctrl-r history binding are shadowed. Every other key above reaches fish.
-
-A program started by a key binding never fires `fish_preexec`/`fish_postexec`, so iris would keep handling keys as if the prompt were idle while tv, yazi, or lazygit owned the screen: it swallowed arrows and tab and could draw its menu over them. Every binding that runs a program therefore tells iris with `_iris_busy start` / `_iris_busy stop`, the same `IRIS_CMD_START` / `IRIS_CMD_STOP` messages iris's own hooks send (a no-op outside iris). `_bind_run CMD` wraps a command that way and repaints; `_tv_inline`, `_gho_bind`, and `_pj_bind` call `_iris_busy` themselves.
+`_pj_bind_down` hands the key to `down-or-search` when the buffer is non-empty, the completion pager is open, or history search is active. Otherwise it runs `_pj_bind --quiet` (`PJ_QUIET=1`), so pressing down outside a project does nothing and prints no error.
The pickers run `tv --inline`, which opens on the line below the prompt and leaves the cursor there when it exits. The wrappers put the prompt back before `commandline -f repaint`, writing the cursor moves to `/dev/tty`:
@@ -212,14 +211,14 @@ The pickers run `tv --inline`, which opens on the line below the prompt and leav
| --- | --- | --- |
| `_tv_inline ARGS` | `tv ARGS --inline` | `\033[A` (cursor up), returns tv's status |
| `_gho_bind` | `gho` | `\033[A` if the cwd did not change; `\n` after a cd, so the prompt lands below onefetch |
-| `_pj_bind` | `pj` with `PJ_STATE` set to a temp file | `\033[A` for `open` (cancelled) or empty (no task sources); `\n` for `ran` (the task printed output) |
+| `_pj_bind [--quiet]` | `pj` with `PJ_STATE` set to a temp file | `\033[A` for `open` (cancelled) or empty (no task sources); `\n` for `ran` (the task printed output) |
| `_jobs_bind` | `fg` of the only job, or `jobs` with `TV_JOBS` set to a temp file holding the job table | `\033[A` (via `_tv_inline`) when the picker is cancelled |
`_jobs_bind` runs `fg` by replacing the command line with ` __jobs_bind_fg ` (leading space: kept out of history) and executing it, not from inside the binding. A binding runs while fish's reader still owns the terminal with extended keys on, so a job started with `&` that had never held the terminal got ctrl-z and ctrl-c as escape sequences instead of signals. `__jobs_bind_fg` erases the echoed prompt line (`\033[A\033[2K` on `/dev/tty`) and runs `fg` with its "Send job … to foreground" message sent to `/dev/null`, so resuming leaves nothing on screen. Text already typed is put back at the next prompt by a one-shot `fish_prompt` handler.
`omp-session` (ctrl-a) does its own `\033[A` when its `omp-sessions` picker is cancelled, so the binding only repaints.
-zsh and bash bind ctrl-o, ctrl-e, ctrl-p, and ctrl-t the same way, and zsh also ctrl-z ([bash and zsh](/shell/bash-zsh)). Inside television, ctrl-e runs the channel's `edit` action and ctrl-h its `goto_parent_dir` action (`television/config.toml`). The config and cables are on the [television](/tools/television) page.
+zsh and bash bind ctrl-o, ctrl-e, ctrl-p, down, and ctrl-t the same way ([bash and zsh](/shell/bash-zsh)). Inside television, ctrl-e runs the channel's `edit` action and ctrl-h its `goto_parent_dir` action (`television/config.toml`). The config and cables are on the [television](/tools/television) page.
:::note
Under kitty, ctrl-g (lazygit overlay), ctrl-y (yazi split), and ctrl-h/j/k/l (split navigation) are mapped in `kitty.conf` and never reach fish. The fish binds for those keys only apply in other terminals. See [kitty](/terminal/kitty).
@@ -272,10 +271,9 @@ Every file in `functions/` is autoloaded by name. Several also exist as POSIX sc
| `_nvm_version_activate` | nvm.fish internal: sets `nvm_current_version` and prepends its `bin` to `PATH` |
| `_nvm_version_deactivate` | nvm.fish internal: removes a version's `bin` from `PATH` |
| `_gho_bind` | ctrl-o handler: `gho`, then cursor fix and repaint (see [Key bindings](#key-bindings)) |
-| `_pj_bind` | ctrl-p handler: `pj` with `PJ_STATE`, then cursor fix and repaint |
+| `_pj_bind` | ctrl-p handler: `pj` with `PJ_STATE`, then cursor fix and repaint. `--quiet` sets `PJ_QUIET=1` |
| `_jobs_bind` | ctrl-z handler: `fg` the only job or pick one from the `jobs` cable (see [Key bindings](#key-bindings)) |
-| `_bind_run` | Runs `$argv` between `_iris_busy start` and `stop`, then repaints. Used by the ctrl-a, ctrl-b, ctrl-f, ctrl-g, and ctrl-y bindings |
-| `_iris_busy` | `start`/`stop`: writes `IRIS_CMD_START` / `IRIS_CMD_STOP:0` to `$IRIS_FD` so iris stands down while a binding's program runs. No-op outside iris |
+| `_pj_bind_down` | Down-arrow handler: `_pj_bind --quiet` on an empty idle prompt, else `down-or-search` |
| `_tv_inline` | `tv $argv --inline`, then moves the cursor up one line on `/dev/tty` |
| `ai` | `gum choose` among `claude`, `opencode`, `codex`, `hermes`, `fractal`. `claude` runs with `--dangerously-skip-permissions` |
| `c` | `clear` with no argument, `cd ` with one |
@@ -304,7 +302,7 @@ Every file in `functions/` is autoloaded by name. Several also exist as POSIX sc
| `y` | yazi with `--cwd-file`, then cd to the directory yazi exited in |
| `yy` | Same as `y`. Used by the ctrl-f bind |
-Functions defined inside `conf.d/` and `config.fish` rather than `functions/`: `q` (20-aliases), `terminal_title` (50-terminal-title), the `pnpmf*` helpers and `__pnpm_pick_pkg` (pnpm-filter), the `_nvm_install`/`_nvm_update`/`_nvm_uninstall` event handlers (nvm), and `starship_transient_prompt_func` and `starship_transient_rprompt_func` (config.fish). Under iris, `iris init fish` adds `_iris_fish_prompt`, `_iris_fish_preexec`, and `_iris_fish_postexec`.
+Functions defined inside `conf.d/` and `config.fish` rather than `functions/`: `q` (20-aliases), `terminal_title` (50-terminal-title), the `pnpmf*` helpers and `__pnpm_pick_pkg` (pnpm-filter), the `_nvm_install`/`_nvm_update`/`_nvm_uninstall` event handlers (nvm), and `starship_transient_prompt_func`, `starship_transient_rprompt_func`, and `_atuin_ai_question_mark` (config.fish).
:::warning[gh-sonr-org-migrate]
`functions/gh-sonr-org-migrate.fish` is a script, not a function definition. Running `gh-sonr-org-migrate` in fish autoloads the file, which runs the whole fish migration flow. Because the file defines no function of that name, fish then falls through to the bash port at `~/.local/bin/gh-sonr-org-migrate` and starts a second run. Cancel the second run at its first `gum` prompt, or call the bash script by its full path.
diff --git a/docs/shell/index.mdx b/docs/shell/index.mdx
index 3b411fe..bbdc17e 100644
--- a/docs/shell/index.mdx
+++ b/docs/shell/index.mdx
@@ -1,11 +1,11 @@
---
title: Shell
-description: fish, bash, and zsh with shared aliases, the starship prompt, iris and atuin, and the ~/.local/bin scripts.
+description: fish, bash, and zsh with shared aliases, the starship prompt, atuin history, and the ~/.local/bin scripts.
sidebar:
label: Overview
---
-fish is the main interactive shell. fish and zsh both run under [iris](/shell/iris) for an inline completion menu; bash uses atuin for history. All three share aliases, the prompt, and ports of the cd-style helper functions. General-purpose tools are POSIX or bash scripts in `~/.local/bin`, so each has a single implementation that all three shells call.
+fish is the main interactive shell. bash and zsh are set up to feel the same: they share aliases, the prompt, atuin history, and ports of the cd-style helper functions. General-purpose tools are POSIX or bash scripts in `~/.local/bin`, so each has a single implementation that all three shells call.
| Page | Covers |
| --- | --- |
@@ -14,8 +14,7 @@ fish is the main interactive shell. fish and zsh both run under [iris](/shell/ir
| [Aliases](/shell/aliases) | Every alias from `.chezmoidata/aliases.yaml` plus the fish-only and shell-specific ones |
| [Scripts](/shell/scripts) | Every general-purpose executable in `~/.local/bin` (`pj`, `ghn`, `gop`, `mtime-sort`, `atuin-pick`, …) |
| [Starship](/shell/starship) | `~/.config/starship.toml`: format, modules, symbols, cyberdream palette |
-| [iris](/shell/iris) | `~/.config/iris/config.toml`: the inline completion menu that wraps fish and zsh, zoxide `cd`, key ownership |
-| [atuin](/shell/atuin) | `~/.config/atuin`: bash history search settings, cyberdream theme |
+| [atuin](/shell/atuin) | `~/.config/atuin`: history search settings, AI inline integration, cyberdream theme |
## Shared across shells
@@ -23,11 +22,10 @@ fish is the main interactive shell. fish and zsh both run under [iris](/shell/ir
| --- | --- | --- | --- |
| Aliases | `conf.d/20-aliases.fish` (hand-maintained) | `~/.config/shell/aliases.sh` (rendered from YAML) | same as bash |
| Prompt | starship + transient prompt | starship | starship |
-| History | fish's own history, browsed through iris (hishtory also sourced if installed) | atuin | zsh's own history, browsed through iris, plus suvadu if installed |
-| Completion menu | iris | bash completion | iris |
-| Key bindings | vi mode plus custom binds | atuin defaults plus picker keys | emacs keymap plus ports of the fish binds |
+| History | atuin (hishtory also sourced if installed) | atuin | atuin, plus suvadu if installed |
+| Key bindings | vi mode plus custom binds | atuin defaults only | emacs keymap plus ports of the fish binds |
| cd-style helpers | `functions/*.fish` | `~/.config/bash/functions/*.bash` | `~/.config/zsh/functions/*.zsh` |
-| Directory jumping | `cd` wrapper with zoxide fallback, `zoxide init` | `cd` wrapper | `cd` wrapper with zoxide fallback, `zoxide init` |
+| Directory jumping | `cd` wrapper with zoxide fallback, `zoxide init` | `cd` wrapper | `cd` wrapper |
## Theme
diff --git a/docs/shell/iris.mdx b/docs/shell/iris.mdx
deleted file mode 100644
index 2a0e0e1..0000000
--- a/docs/shell/iris.mdx
+++ /dev/null
@@ -1,66 +0,0 @@
----
-title: iris
-description: Inline completion menu that wraps fish and zsh in its own pty, with zoxide cd suggestions, and how the shells' bindings coexist with it.
----
-
-[iris](https://github.com/versenilvis/iris) draws an IntelliSense-style completion menu inline in the terminal. It runs the shell inside its own pty and reads keys before the shell does. fish and zsh start it; bash does not.
-
-| Source (repo) | Target | Notes |
-| --- | --- | --- |
-| `dot_config/iris/config.toml` | `~/.config/iris/config.toml` | symlink |
-
-iris is the AUR package `iris-autocomplete`, not in `.chezmoidata/packages.yaml`. State and history live in `~/.local/share/iris` (not in the repo); `state.toml` remembers the last menu mode.
-
-## Startup
-
-`config.fish` ends with the iris block and `.zshrc` runs `iris init zsh` just before zsh-syntax-highlighting; both skip it where iris is not installed. The init script has two halves:
-
-1. In an interactive shell without `IRIS_PID`, it exports `IRIS_ACTIVE_SHELL` and `exec`s `iris`, which starts a second copy of that shell inside its pty. That shell runs the whole config again.
-2. Inside iris (`IRIS_PID` and `IRIS_FD` set), it installs hooks that report the cwd, the current line (zsh), and command start/stop to iris over `$IRIS_FD`. fish also loses its autosuggestions.
-
-`IRIS_RESCUE=1 fish` or `IRIS_RESCUE=1 zsh` skips the `exec` and gives a plain shell, for when iris itself misbehaves.
-
-Two shell settings change for iris:
-
-| Shell | Setting | Why |
-| --- | --- | --- |
-| fish | `fish_features=no-query-term`, exported before `exec iris` | fish's terminal query turns on kitty's keyboard protocol in kitty, which encodes keys as `CSI u` escapes; iris cannot parse them, so the menu never opened in kitty (it did in tmux, which lacks the protocol) |
-| zsh | `unsetopt PROMPT_SP` inside iris | zsh's partial-line marker pads each prompt with spaces and a carriage return; iris read the echo as a typed space, so prompts opened with a stale query and inserted a stray suggestion (`4channels`) on the next key |
-
-### Key bindings that run programs
-
-iris only knows a command is running from the shell's preexec/postexec hooks, and programs started by key bindings never fire those. While tv, yazi, or lazygit ran from a binding, iris kept treating the screen as an idle prompt: it swallowed arrows and tab (Down never reached a tv picker) and could draw its menu on top. Every such binding now wraps the program in `_iris_busy start` / `_iris_busy stop`, which send `IRIS_CMD_START` and `IRIS_CMD_STOP:0` on `$IRIS_FD`, the same messages the hooks send ([fish](/shell/fish#key-bindings), [zsh](/shell/bash-zsh#zsh-key-bindings)).
-
-The old down → `pj` binding is gone from fish, zsh, and bash: it opened the `pj` picker inside iris's pty and the two fought over the screen. `pj` stays on ctrl-p.
-
-## Config
-
-Every key from iris's sample config is listed, so `iris config show` and the file agree. Changes from the defaults:
-
-| Key | Value | Why |
-| --- | --- | --- |
-| `core.shell` | `""` | Auto-detect. `IRIS_ACTIVE_SHELL`, exported by `iris init `, decides which shell starts, so one config serves fish and zsh |
-| `core.mode` | `"spec"` | Every shell opens with Fig-style completions (subcommands, flags, paths). The default `"last"` restores whatever mode the last shell ended in, so one stray ctrl-r left every new shell showing history |
-| `core.atuin-history` | `0` | Shell history only; atuin is not used under iris |
-| `updater.check-on-startup` | `false` | The package manager owns updates; `iris update` would replace a pacman-owned binary |
-| `zoxide.extend-cd` | `true` | `cd ` suggests directories from zoxide's database, not just the current directory |
-
-AI suggestions stay off (`ai.enabled = false`). The Groq provider reads `GROQ_API_KEY` from the environment (`conf.d/secrets.fish`) through `api_key_env`; no key is stored in the file. `debug` stays off because iris then logs every keystroke.
-
-## Keys
-
-iris consumes these keys; the shell never sees them while iris runs:
-
-| Key | iris action |
-| --- | --- |
-| tab | Accept the selected suggestion (replaces the shell's tab completion) |
-| shift-tab | Hide or show the menu for this shell session |
-| ctrl-r | Switch between spec and history mode for this shell session (shadows `tv init`'s history binding) |
-| up / down | Move the selection in the menu; on a closed menu, browse iris's history (`navigate-closed = "history"`, the default) |
-| right | Accept ghost text |
-
-Every other key in [fish's](/shell/fish#key-bindings) and [zsh's](/shell/bash-zsh#zsh-key-bindings) bindings (ctrl-a, ctrl-e, ctrl-o, ctrl-p, ctrl-z, ctrl-c, …) and fish vi mode's esc still reach the shell.
-
-## When the menu appears
-
-Like Fig, the menu opens by itself about 20 ms after each keystroke on a non-empty line (`ghost-text = 1`: menu plus inline ghost text) and closes on an empty line or while a command runs. It only appears in shells that iris started, so shells opened before iris was set up (for example long-running herdr or tmux panes) show nothing until they are reopened.
diff --git a/docs/shell/meta.ts b/docs/shell/meta.ts
index ebed2ba..af6c4b1 100644
--- a/docs/shell/meta.ts
+++ b/docs/shell/meta.ts
@@ -3,5 +3,5 @@ import { defineMeta } from "blume";
export default defineMeta({
title: "Shell",
icon: "terminal",
- pages: ["index", "fish", "bash-zsh", "aliases", "scripts", "starship", "iris", "atuin"],
+ pages: ["index", "fish", "bash-zsh", "aliases", "scripts", "starship", "atuin"],
});
diff --git a/docs/shell/scripts.mdx b/docs/shell/scripts.mdx
index e2940bd..e04249a 100644
--- a/docs/shell/scripts.mdx
+++ b/docs/shell/scripts.mdx
@@ -314,9 +314,9 @@ A task runner that searches every task source in the project and lets you pick o
**Run.** cds into the task's directory and `exec`s the runner. Extra arguments given to `pj` travel to the task through `$PJ_EXTRA` (shell-quoted), with `--` inserted for `npm run`, `mise`, and `devbox`. Tasks named `dev`, `start`, `serve`, `watch`, or namespaced variants like `dev:web` are wrapped in `openlogs` (found on `PATH`, via `mise which`, or in mise's node installs) for a live log tail. Without openlogs they run unwrapped, with a note.
-**Env.** `PJ_STATE=FILE` makes `pj` write `open` to `FILE` before launching the picker, and `pj --run` writes `ran`; the file stays empty when there are no task sources. The key bindings read it to tell no tasks, a cancelled picker, and a task that printed output apart and redraw the prompt to match. `pj` itself does no cursor handling, so typing `pj` behaves like any command.
+**Env.** `PJ_QUIET=1` suppresses the "no task sources found" error (exit status stays 1). The down bindings use it. `PJ_STATE=FILE` makes `pj` write `open` to `FILE` before launching the picker, and `pj --run` writes `ran`; the file stays empty when there are no task sources. The key bindings read it to tell no tasks, a cancelled picker, and a task that printed output apart and redraw the prompt to match. `pj` itself does no cursor handling, so typing `pj` behaves like any command.
-**Launched by:** ctrl-p in fish, zsh, and bash.
+**Launched by:** ctrl-p, and down on an empty prompt, in fish, zsh, and bash.
**Needs:** `bash`, `tv`, `mtime-sort`, `jq`, `python3` 3.11+ (for `tomllib`), plus whichever runners the project uses.
diff --git a/docs/tools/television.mdx b/docs/tools/television.mdx
index b1848a6..96e4e47 100644
--- a/docs/tools/television.mdx
+++ b/docs/tools/television.mdx
@@ -70,14 +70,14 @@ Every custom cable except `agents` (a fixed list, see [agents](#agents)), `omp-s
| --- | --- | --- |
| [`ghq-repos`](#ghq-repos) | `cable/ghq-repos.toml` | ctrl-o (`gho`) |
| [`git-files`](#git-files) | `cable/git-files.toml` | ctrl-e |
-| [`pj`](#pj) | `cable/pj.toml` | ctrl-p (`pj`) |
+| [`pj`](#pj) | `cable/pj.toml` | ctrl-p, down on an empty prompt (`pj`) |
| [`files`](#files) | `cable/files.toml` | `tv`, ctrl-t autocomplete |
| [`obsidian`](#obsidian) | `cable/obsidian.toml` | `tv obsidian` |
| [`agents`](#agents) | `cable/agents.toml` | `tv agents` |
| [`omp-sessions`](#omp-sessions) | `cable/omp-sessions.toml` | `tv omp-sessions`, ctrl-a (`omp-session`) when it has nothing to resume |
-| [`jobs`](#jobs) | `cable/jobs.toml` | ctrl-z in fish (`_jobs_bind`) and zsh (`jobs-fg`) with two or more background jobs |
+| [`jobs`](#jobs) | `cable/jobs.toml` | ctrl-z in fish (`_jobs_bind`) with two or more background jobs |
-The keys are bound in fish (`fish_user_key_bindings.fish`), zsh (`keybinds.zsh`), and bash (`keybinds.bash`); bash has no ctrl-a or ctrl-z binding. See [fish](/shell/fish#key-bindings) and [bash and zsh](/shell/bash-zsh). Under [iris](/shell/iris), the bindings tell iris a picker is running (`_iris_busy`), or iris would swallow the arrow keys meant for tv.
+The keys are bound in fish (`fish_user_key_bindings.fish`), zsh (`keybinds.zsh`), and bash (`keybinds.bash`); bash has no ctrl-a binding, and ctrl-z is fish only. See [fish](/shell/fish#key-bindings) and [bash and zsh](/shell/bash-zsh).
### ghq-repos
@@ -161,7 +161,7 @@ The preview runs `omp-session --preview`: title, last-write time and cwd, then t
### jobs
-The current shell's background jobs, stopped or running, newest first. tv runs as a child process and cannot read the shell's job table, so the ctrl-z binding (`_jobs_bind` in [fish](/shell/fish#key-bindings), `jobs-fg` in [zsh](/shell/bash-zsh#zsh-key-bindings)) writes it to a temp file named by `$TV_JOBS` and the source just `cat`s that file; opened any other way the list is empty. Entries are `% `; enter prints the id and the binding runs `fg %`.
+The current fish shell's background jobs, stopped or running, newest first. tv runs as a child process and cannot read the shell's job table, so `_jobs_bind` ([fish](/shell/fish#key-bindings)) writes it to a temp file named by `$TV_JOBS` and the source just `cat`s that file; opened any other way the list is empty. Entries are `% `; enter prints the id and the binding runs `fg %`.
The preview finds the job's processes by process group (procps `ps -g` matches sessions, so it filters `ps -e -o pgid,pid`) and shows the first process's cwd and start time, then `ps --forest` with PID, STAT (`T` = stopped), elapsed time, CPU, RSS, and arguments. The preview script avoids `{`/`}` because tv would parse them as templates and leave `{split:…}` unexpanded.
@@ -170,4 +170,4 @@ The preview finds the job's processes by process group (procps `ps -g` matches s
| enter | Print the job id; `_jobs_bind` runs `fg` on it |
| ctrl-d | `kill` then `reload_source`: SIGTERM to the job's process group, then SIGCONT so a stopped job receives it. Once the group is gone (polled up to 1 s) the row is removed from `$TV_JOBS`, so the reloaded list drops it; a job that ignores SIGTERM stays listed. Fish reports the termination at the next prompt |
-**Needs:** `ps`, fish or zsh.
+**Needs:** `ps`, fish.
diff --git a/dot_config/bash/keybinds.bash b/dot_config/bash/keybinds.bash
index f6458e0..669a6ff 100644
--- a/dot_config/bash/keybinds.bash
+++ b/dot_config/bash/keybinds.bash
@@ -1,7 +1,7 @@
# ~/.config/bash/keybinds.bash — readline ports of the television keys in
# fish_user_key_bindings.fish / zsh keybinds.zsh:
# ctrl-o → gho (ghq-repos cable, cd) ctrl-e → tv git-files (nvim)
-# ctrl-p → pj (pj cable)
+# ctrl-p → pj (pj cable) down → pj on an empty prompt
# ctrl-t → tv smart autocomplete (tv init bash ships no ctrl-t)
# Keys owned by kitty.conf never reach the shell: ctrl-h/j/k/l (pass_keys.py).
#
@@ -19,12 +19,12 @@ _kb_git_files() {
}
bind -x '"\C-e": _kb_git_files'
-# ctrl-p. pj reports through $PJ_STATE: `open` = cancelled, `ran` = a task
-# printed output, empty = no task sources.
+# ctrl-p, and down on an empty prompt. pj reports through $PJ_STATE: `open`
+# = cancelled, `ran` = a task printed output, empty = no task sources.
_kb_pj() {
local state
state=$(mktemp) || return
- PJ_STATE=$state pj /dev/tty
+
+ # Run atuin ai inline, swapping stdout and stderr
+ set -l output (atuin ai inline --hook 3>&1 1>&2 2>&3 | string collect)
+
+ if string match --quiet '__atuin_ai_print__:*' "$output"
+ echo (string replace "__atuin_ai_print__:" "" -- "$output" | string collect)
+ commandline -f repaint
+ else if test "$output" = "__atuin_ai_cancel__"
+ commandline -f repaint
+ else if string match --quiet '__atuin_ai_execute__:*' "$output"
+ # Execute the command immediately
+ set -l cmd (string replace "__atuin_ai_execute__:" "" -- "$output" | string collect)
+ commandline -r "$cmd"
+ commandline -f repaint
+ commandline -f execute
+ else if string match --quiet '__atuin_ai_insert__:*' "$output"
+ # Insert the command for editing
+ set -l cmd (string replace "__atuin_ai_insert__:" "" -- "$output" | string collect)
+ commandline -r "$cmd"
+ commandline -f repaint
+ else if test -n "$output"
+ # Default: insert for editing
+ commandline -r "$output"
+ commandline -f repaint
+ else
+ commandline -f repaint
+ end
+ else if not contains -- "$fish_key_bindings" fish_vi_key_bindings fish_hybrid_key_bindings
+ # Not at empty prompt, just insert the question mark
+ commandline -i "?"
end
- iris init fish | source
end
+
+# Set up keybindings
+bind "?" _atuin_ai_question_mark
+
+eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv fish)"
diff --git a/dot_config/fish/functions/_bind_run.fish b/dot_config/fish/functions/_bind_run.fish
deleted file mode 100644
index c26174c..0000000
--- a/dot_config/fish/functions/_bind_run.fish
+++ /dev/null
@@ -1,6 +0,0 @@
-function _bind_run --description 'run a command from a key binding (iris-aware), then repaint'
- _iris_busy start
- $argv
- _iris_busy stop
- commandline -f repaint
-end
diff --git a/dot_config/fish/functions/_gho_bind.fish b/dot_config/fish/functions/_gho_bind.fish
index ce0b8da..3518ae6 100644
--- a/dot_config/fish/functions/_gho_bind.fish
+++ b/dot_config/fish/functions/_gho_bind.fish
@@ -1,8 +1,6 @@
function _gho_bind --description 'ctrl-o: gho (tv --inline), then redraw the prompt in the right place'
set -l before $PWD
- _iris_busy start
gho
- _iris_busy stop
if test "$PWD" = "$before"
# Cancelled (or the nvim action ran): tv --inline left the cursor on
# the line below the prompt; step back so repaint redraws in place.
diff --git a/dot_config/fish/functions/_iris_busy.fish b/dot_config/fish/functions/_iris_busy.fish
deleted file mode 100644
index 20b6ba5..0000000
--- a/dot_config/fish/functions/_iris_busy.fish
+++ /dev/null
@@ -1,15 +0,0 @@
-function _iris_busy --description 'tell iris a key binding is running a program (start|stop)'
- # iris (~/.config/iris) learns a command is running from fish_preexec /
- # fish_postexec, which never fire for programs a key binding starts. Without
- # this, iris keeps treating the screen as an idle prompt while tv, yazi or
- # lazygit run: it swallows up/down/tab and can draw its menu over them.
- # Same messages as iris's own hooks; a no-op outside iris.
- set -q IRIS_FD; or return 0
- switch "$argv[1]"
- case start
- printf 'IRIS_CMD_START\x00' >&$IRIS_FD 2>/dev/null
- case stop
- printf 'IRIS_CMD_STOP:0\x00' >&$IRIS_FD 2>/dev/null
- end
- return 0
-end
diff --git a/dot_config/fish/functions/_pj_bind.fish b/dot_config/fish/functions/_pj_bind.fish
index 9e65325..bc265d7 100644
--- a/dot_config/fish/functions/_pj_bind.fish
+++ b/dot_config/fish/functions/_pj_bind.fish
@@ -1,13 +1,14 @@
-function _pj_bind --description 'ctrl-p: pj (tv --inline), then redraw the prompt in the right place'
+function _pj_bind --description 'ctrl-p / down: pj (tv --inline), then redraw the prompt in the right place'
# pj reports through $PJ_STATE: `open` = the picker was cancelled and
# left the cursor on the line below the prompt; empty = no task sources,
# nothing drawn — but fish's repaint after an external command still
# lands one line low, so both step back up. `ran` = a task printed
# output: new line, prompt below it.
set -lx PJ_STATE (mktemp)
- _iris_busy start
+ if contains -- --quiet $argv
+ set -lx PJ_QUIET 1
+ end
pj
- _iris_busy stop
set -l state (cat $PJ_STATE)
switch "$state"
case open ''
diff --git a/dot_config/fish/functions/_pj_bind_down.fish b/dot_config/fish/functions/_pj_bind_down.fish
new file mode 100644
index 0000000..948aa39
--- /dev/null
+++ b/dot_config/fish/functions/_pj_bind_down.fish
@@ -0,0 +1,21 @@
+function _pj_bind_down --description "down arrow: pj tv cable on an idle empty prompt, else fish's down-or-search"
+ # Mirror of atuin's up binding (atuin owns up, this owns down). Everything
+ # that legitimately needs the arrow keys keeps them:
+ # - non-empty buffer → multiline cursor movement / forward history search
+ # - paging mode → tab-completion pager navigation (tab on an empty
+ # line opens the pager with an empty buffer)
+ # - search mode → history-search navigation
+ # down-or-search is fish's own input function, called as a command exactly
+ # the way atuin's _atuin_bind_up calls up-or-search.
+ set -l buf (commandline | string collect)
+ if test -n "$buf"; or commandline --paging-mode; or commandline --search-mode
+ down-or-search
+ return
+ end
+
+ # _pj_bind runs ~/.local/bin/pj (also ctrl-p), which opens the `pj` tv
+ # cable. --quiet (PJ_QUIET) keeps it silent when the tree has no task
+ # source at all, so down is a no-op outside projects instead of printing
+ # an error per press.
+ _pj_bind --quiet
+end
diff --git a/dot_config/fish/functions/_tv_inline.fish b/dot_config/fish/functions/_tv_inline.fish
index 2ce7ff9..af2b544 100644
--- a/dot_config/fish/functions/_tv_inline.fish
+++ b/dot_config/fish/functions/_tv_inline.fish
@@ -3,10 +3,8 @@ function _tv_inline --description 'tv --inline below the prompt, cursor back on
# its own first row when it exits; step back up so the following
# `commandline -f repaint` redraws the prompt in place instead of one line
# lower. /dev/tty keeps the move out of callers that capture stdout (gho).
- _iris_busy start
tv $argv --inline
set -l st $status
- _iris_busy stop
printf '\033[A' >/dev/tty
return $st
end
diff --git a/dot_config/fish/functions/fish_user_key_bindings.fish b/dot_config/fish/functions/fish_user_key_bindings.fish
index 71e99c3..9206e5d 100644
--- a/dot_config/fish/functions/fish_user_key_bindings.fish
+++ b/dot_config/fish/functions/fish_user_key_bindings.fish
@@ -10,29 +10,33 @@ function fish_user_key_bindings
# Keys owned by kitty.conf never reach fish and are NOT bound here:
# ctrl-g → lazygit overlay, ctrl-y → yazi vsplit,
# ctrl-h/j/k/l → vim-aware split nav (pass_keys.py).
- # ctrl-e: tv git-files (bat preview, enter opens nvim). ctrl-o and
- # ctrl-p also open tv cables — same keys in zsh and bash. tv runs
+ # ctrl-e: tv git-files (bat preview, enter opens nvim). ctrl-o, ctrl-p
+ # and down also open tv cables — same keys in zsh and bash. tv runs
# --inline below the prompt; _tv_inline/_gho_bind/_pj_bind put the
# prompt back in place (or below any output) afterwards. ctrl-a:
# omp-session resumes or starts omp for the repo (same in zsh); when it
# opens the omp-sessions cable and it is cancelled, it steps back up.
- # Every binding that runs a program tells iris via _iris_busy
- # (_bind_run, _tv_inline, _gho_bind, _pj_bind), or iris would keep
- # its prompt key handling while tv/yazi/lazygit own the screen.
bind -M $mode ctrl-e '_tv_inline git-files; commandline -f repaint'
- bind -M $mode ctrl-b '_bind_run purple'
- bind -M $mode ctrl-y '_bind_run clip-last'
+ bind -M $mode ctrl-b purple repaint
+ bind -M $mode ctrl-y clip-last
bind -M $mode ctrl-o _gho_bind
bind -M $mode ctrl-p _pj_bind
- bind -M $mode ctrl-a '_bind_run omp-session'
+ bind -M $mode ctrl-a 'omp-session; commandline -f repaint'
+ bind -M $mode ctrl-w 'atuin ai inline; commandline -f repaint'
# ctrl-z at the prompt: fg the only background job, or pick one from
# the jobs tv cable when there are several (_jobs_bind).
bind -M $mode ctrl-z _jobs_bind
+ # Arrow keys: atuin owns up (bound from config.fish, survives the
+ # fish_vi_key_bindings reset above because that only erases presets),
+ # down opens the pj tv cable — but only on an idle, empty prompt; see
+ # _pj_bind_down.
+ bind -M $mode down _pj_bind_down
+
# ctrl-f: yazi (cd's to yazi's exit dir on quit).
- bind -M $mode ctrl-f '_bind_run yy'
- bind -M $mode ctrl-g '_bind_run lazygit'
+ bind -M $mode ctrl-f 'yy; commandline -f repaint'
+ bind -M $mode ctrl-g 'lazygit; commandline -f repaint'
# ctrl-c routes through the clear wrapper (kitty scrollback + prompt
# pinned to the bottom) AND wipes any text typed on the command line.
diff --git a/dot_config/iris/config.toml b/dot_config/iris/config.toml
deleted file mode 100644
index 0eb047c..0000000
--- a/dot_config/iris/config.toml
+++ /dev/null
@@ -1,73 +0,0 @@
-# iris (https://github.com/versenilvis/iris): inline completion menu that wraps
-# the shell in its own pty. Started from fish and zsh (`iris init ` in
-# config.fish / .zshrc). `iris config show` prints the merged result; missing
-# keys fall back to iris's defaults.
-
-[core]
-version = 1 # config schema version
-shell = "" # auto-detect; `iris init ` exports IRIS_ACTIVE_SHELL, which wins anyway
-shell-login = false # run shell as a login shell (also: iris --shell-login)
-# Every shell opens in spec mode: Fig-style completions (subcommands, flags,
-# paths) pop up as you type. ctrl+r still flips to history for that session;
-# "last" would carry a stray ctrl+r into every later shell.
-mode = "spec" # "last", "spec", or "history"
-debug = false # verbose logging to iris.log (also: iris -d); logs every keystroke
-expand-alias = true # expand aliases before matching
-auto-execute = false # run suggestion immediately instead of inserting it
-atuin-history = 0 # shell history only: atuin is not used under iris
-atuin-db-path = "" # path to atuin's history.db, empty = use default
-cobra-probe-enabled = true # fall back to probing cobra binaries for completions
-# Menu closed: up/down browse iris's own history (Fig-style). No shell binds
-# up/down; handing them to the shell ran the old down -> pj picker inside
-# iris's pty, and the two fought over the screen.
-navigate-closed = "history"
-
-[ui]
-style = "modern" # "modern" or "classic"
-ghost-text = 1 # 0 = off, 1 = menu + ghost text, 2 = ghost text only
-hidden-files = false # include dotfiles in suggestions
-max-suggestions = 100 # max suggestions ranked before display
-max-height = 6 # max visible rows in the menu
-max-width = 0 # menu width: columns (80) or a share ("80%"), 0 = default
-nerd-fonts = true # use nerd-font icons (Victor Mono Nerd Font)
-
-# ctrl+r, tab, shift+tab, up and down never reach the shell while iris runs;
-# tv's own ctrl-r history binding (`tv init`) is shadowed by toggle-mode.
-[keybindings]
-toggle-mode = "ctrl+r" # switch spec/history mode
-toggle-menu = "shift+tab" # show or hide the suggestion menu
-select = "tab" # accept the selected suggestion
-navigate-up = "up" # select up (menu open)
-navigate-down = "down" # select down (menu open)
-navigate-right = "right" # accept ghost text
-
-[git]
-filter-active-branch = true # exclude current branch from suggestions
-deduplicate-branches = true # merge same-name local/remote branches
-
-# Installed from the AUR (iris-autocomplete): pacman/paru owns updates, so iris
-# neither checks nor installs on its own.
-[updater]
-check-on-startup = false
-channel = "stable"
-check-interval = "24h"
-auto-update = 0
-
-[zoxide]
-extend-cd = true # complete `cd` from zoxide's database (conf.d/40-tools.fish runs `zoxide init fish`)
-
-[ai]
-enabled = false
-provider = "groq" # "groq" or "ollama"
-debounce_ms = 400 # ms to wait before querying the AI
-
-[ai.providers.groq]
-endpoint = "https://api.groq.com/openai/v1/chat/completions"
-api_key_env = "GROQ_API_KEY" # read from the environment, never stored here
-model = "llama-3.3-70b-versatile"
-timeout_ms = 3000
-
-[ai.providers.ollama]
-endpoint = "http://localhost:11434/v1/chat/completions"
-model = "qwen2.5-coder"
-timeout_ms = 5000
diff --git a/dot_config/zsh/functions/czs.zsh b/dot_config/zsh/functions/czs.zsh
deleted file mode 100644
index a094476..0000000
--- a/dot_config/zsh/functions/czs.zsh
+++ /dev/null
@@ -1,35 +0,0 @@
-# czs: chezmoi re-add drifted files, then commit + push the source repo.
-# Port of functions/czs.fish. Optional targets scope the status view and the
-# re-add (e.g. `czs ~/.config/fish`); no args = all managed files.
-czs() {
- local drift src ahead
- drift=$(chezmoi status "$@") || return
-
- if [[ -n $drift ]]; then
- print -r -- $drift
- # re-add takes the local (destination) contents as truth for modified
- # files; templates are never overwritten, non-file entries are ignored.
- chezmoi re-add "$@" || return
- else
- echo "chs: in sync — nothing to re-add"
- fi
-
- # Commit + sync the source repo (~/.local/share/chezmoi).
- src=$(chezmoi source-path)
- if [[ -n $(git -C $src status --porcelain) ]]; then
- git -C $src add -A &&
- git -C $src commit --quiet -m 'chs: re-add drifted files' || return
- echo "chs: committed $(git -C $src rev-parse --short HEAD)"
- fi
-
- # Push anything unpushed: this commit and leftovers from a failed push.
- # --autostash tolerates post-commit hooks re-dirtying the tree mid-sync.
- ahead=$(git -C $src rev-list --count @{upstream}..HEAD 2>/dev/null || echo 0)
- if (( ahead > 0 )); then
- git -C $src pull --rebase --autostash --quiet &&
- git -C $src push --quiet &&
- echo "chs: pushed $ahead commit(s) to $(git -C $src remote get-url origin)"
- else
- echo "chs: remote up to date"
- fi
-}
diff --git a/dot_config/zsh/functions/y.zsh b/dot_config/zsh/functions/y.zsh
deleted file mode 100644
index 67ec71e..0000000
--- a/dot_config/zsh/functions/y.zsh
+++ /dev/null
@@ -1,2 +0,0 @@
-# y: same as yy (fish has both names) — yazi, then cd to its exit directory.
-y() { yy "$@"; }
diff --git a/dot_config/zsh/keybinds.zsh b/dot_config/zsh/keybinds.zsh
index 1a39e0e..da679d1 100644
--- a/dot_config/zsh/keybinds.zsh
+++ b/dot_config/zsh/keybinds.zsh
@@ -5,20 +5,6 @@
bindkey -e # pin emacs keymap ($EDITOR containing "vi" would pick viins)
unsetopt flow_control # free ^Q/^S in zle so the ctrl-q exit bind fires
-# iris (~/.config/iris) learns a command is running from the preexec/precmd
-# hooks, which never fire for programs a widget starts. Without this, iris
-# keeps treating the screen as an idle prompt while tv, yazi or lazygit run:
-# it swallows up/down/tab and can draw its menu over them. Same messages as
-# iris's own hooks; a no-op outside iris. fish: functions/_iris_busy.fish.
-_iris_busy() {
- [[ -n $IRIS_FD ]] || return 0
- case $1 in
- start) print -u $IRIS_FD -N -r -- IRIS_CMD_START 2>/dev/null ;;
- stop) print -u $IRIS_FD -N -r -- IRIS_CMD_STOP:0 2>/dev/null ;;
- esac
- return 0
-}
-
# Generic runner: widget `run-` executes (function or binary) with
# the tty as stdin, then repaints — fish's `commandline -f repaint`.
# cwd changes from gho/yy persist: widgets run in the shell process.
@@ -27,9 +13,7 @@ _iris_busy() {
_zle-run() {
local cmd=${WIDGET#run-}
zle -I
- _iris_busy start
$cmd /dev/tty
zle reset-prompt
}
@@ -60,9 +42,7 @@ zle -N tv-git-files _zle-tv-git-files
_zle-gho() {
local before=$PWD
zle -I
- _iris_busy start
gho /dev/tty
zle reset-prompt
@@ -70,15 +50,23 @@ _zle-gho() {
}
zle -N gho-inline _zle-gho
-# ctrl-p: pj. pj reports through $PJ_STATE: `open` = cancelled, `ran` = a task
-# printed output, empty = no task sources.
+# ctrl-p, and down on an idle empty prompt (fish's _pj_bind_down; otherwise
+# normal history / multiline movement). pj reports through $PJ_STATE: `open`
+# = cancelled, `ran` = a task printed output, empty = no task sources
+# (PJ_QUIET keeps down silent outside projects).
_zle-pj() {
+ if [[ $WIDGET == pj-down && -n $BUFFER ]]; then
+ zle down-line-or-history
+ return
+ fi
local state
state=$(mktemp) || return
zle -I
- _iris_busy start
- PJ_STATE=$state pj /dev/tty; zle reset-prompt ;;
ran) ;;
@@ -87,48 +75,7 @@ _zle-pj() {
rm -f $state
}
zle -N pj-inline _zle-pj
-
-# ctrl-z at the prompt (fish's _jobs_bind): fg the only job, or pick one from
-# the `jobs` tv cable, which reads the job table from $TV_JOBS (records:
-# "% ", id, process group). While a job holds the
-# terminal ctrl-z is still the tty's suspend, so the key toggles.
-# fg runs as a real command line (push-input keeps typed text for the next
-# prompt); __jobs_bind_fg erases that echoed line and fg's "[1] continued"
-# notice. The leading space keeps it out of history (HIST_IGNORE_SPACE).
-__jobs_bind_fg() {
- printf '\033[A\033[2K\r' >/dev/tty
- fg %$1 2>/dev/null
-}
-_zle-jobs() {
- local -a ids recs
- local id pick file
- ids=(${(On)${(k)jobstates}})
- (( $#ids )) || return 0
- for id in $ids; do
- recs+=("$(printf '%%%s %-9s %s\t%s\t%s' $id ${jobstates[$id]%%:*} \
- "${jobtexts[$id]}" $id ${${jobstates[$id]#*:*:}%%=*})")
- done
- if (( $#ids == 1 )); then
- pick=$ids[1]
- else
- file=$(mktemp) || return
- print -rl -- $recs >$file
- zle -I
- _iris_busy start
- pick=$(TV_JOBS=$file tv jobs --inline /dev/tty
- rm -f $file
- if [[ -z $pick ]]; then
- zle reset-prompt
- return
- fi
- fi
- zle push-input
- BUFFER=" __jobs_bind_fg $pick"
- zle accept-line
-}
-zle -N jobs-fg _zle-jobs
+zle -N pj-down _zle-pj
bindkey '^E' tv-git-files
bindkey '^B' run-purple
@@ -141,7 +88,8 @@ bindkey '^A' run-omp-session
# ctrl-f: yazi; yy cd's to yazi's exit dir on quit.
bindkey '^F' run-yy
bindkey '^G' run-lazygit
-bindkey '^Z' jobs-fg
+bindkey '^[[B' pj-down
+bindkey '^[OB' pj-down
# ctrl-q mirrors ctrl-d's preset (`exit`) — quit the shell.
_zle-exit() { exit }
diff --git a/dot_local/bin/executable_pj b/dot_local/bin/executable_pj
index ddff877..a563670 100755
--- a/dot_local/bin/executable_pj
+++ b/dot_local/bin/executable_pj
@@ -14,6 +14,8 @@
# Usage: pj [extra args…] extra args are forwarded to the picked task
#
# Env:
+# PJ_QUIET=1 suppress the "no task sources" error — the down-arrow
+# bindings use this, where an empty tree is the normal case.
# PJ_STATE=FILE key bindings pass a path; pj writes `open` to it when the
# picker opens and `pj --run` writes `ran`, so the binding
# can tell "no tasks" / "cancelled" / "task printed output"
@@ -390,7 +392,7 @@ while :; do
done
if [ ${#recs[@]} -eq 0 ]; then
- echo "pj: no task sources found in this tree" >&2
+ [ -n "${PJ_QUIET-}" ] || echo "pj: no task sources found in this tree" >&2
exit 1
fi
diff --git a/dot_zshrc b/dot_zshrc
index 897fbf3..a090a3a 100644
--- a/dot_zshrc
+++ b/dot_zshrc
@@ -4,9 +4,7 @@
HISTFILE="$HOME/.zsh_history"
HISTSIZE=10000
SAVEHIST=10000
-# HIST_IGNORE_SPACE: a leading space keeps a line out of history, as in fish
-# (the ctrl-z binding's hidden ` __jobs_bind_fg` relies on it).
-setopt SHARE_HISTORY HIST_IGNORE_DUPS HIST_IGNORE_SPACE
+setopt SHARE_HISTORY HIST_IGNORE_DUPS
# Completion
autoload -Uz compinit && compinit
@@ -22,10 +20,6 @@ export GOPATH="$HOME/.local/share/go"
export GOBIN="$GOPATH/bin"
case ":$PATH:" in *":$GOBIN:"*) ;; *) PATH="$GOBIN:$PATH" ;; esac
-# mise: tool shims and env (GOROOT above comes from it), as fish's
-# conf.d/40-tools.fish does for every fish.
-command -v mise >/dev/null 2>&1 && eval "$(mise activate zsh)"
-
# Repo roots (ghq) — same as fish's conf.d/10-env.fish; the ghq-repos tv
# cable (ctrl-o) lists this root.
export GHQ_ROOT="$HOME/Code"
@@ -71,33 +65,10 @@ command -v suv >/dev/null 2>&1 && eval "$(suv init zsh)"
# Prompt — starship, consistent with fish
command -v starship >/dev/null 2>&1 && eval "$(starship init zsh)"
-# Material You terminal colors generated from the wallpaper (quickshell),
-# replayed like fish's conf.d/40-tools.fish.
-_qs_seq="$HOME/.local/state/quickshell/user/generated/terminal/sequences.txt"
-[ -f "$_qs_seq" ] && cat "$_qs_seq"
-unset _qs_seq
-
-# zoxide: `z` / `zi`, plus the cd wrapper's fallback (functions/cd.zsh).
-command -v zoxide >/dev/null 2>&1 && eval "$(zoxide init zsh)"
-
-# television: ctrl-t smart autocomplete (its ctrl-r is shadowed by iris's
-# mode toggle, as in fish)
+# television: ctrl-t smart autocomplete (its ctrl-r is taken over by atuin
+# below, as in fish)
command -v tv >/dev/null 2>&1 && eval "$(tv init zsh)"
-# iris (~/.config/iris/config.toml): inline completion menu, same as fish.
-# The init's first half `exec`s iris from an interactive zsh on a tty; iris
-# starts a second zsh in its pty, which runs this file again, and there the
-# second half installs the line/cwd/command hooks. `IRIS_RESCUE=1 zsh` skips
-# it. Placed before syntax highlighting, which must stay last.
-if command -v iris >/dev/null 2>&1; then
- eval "$(iris init zsh)"
- # Inside iris: PROMPT_SP pads the line with spaces + CR before each prompt
- # (the inverse `%` partial-line marker). iris reads that echo as a typed
- # space, so every prompt opened with a stale query and a stray first
- # suggestion (`4channels`) got inserted on the next key.
- [[ -n $IRIS_PID ]] && unsetopt PROMPT_SP
-fi
-
# Fish-style syntax highlighting (zsh-users/zsh-syntax-highlighting).
# MUST stay last in .zshrc: it wraps every zle widget defined above
# (keybinds, compinit, suv/starship hooks).
@@ -109,6 +80,10 @@ for _zsh_hl in \
done
unset _zsh_hl
+. "$HOME/.atuin/bin/env"
+
+eval "$(atuin init zsh)"
+
# >>> termium >>>
case ":$PATH:" in *:'/home/prad/.local/bin':*) ;; *) export PATH='/home/prad/.local/bin':"$PATH" ;; esac
# <<< termium <<<
diff --git a/television/cable/jobs.toml b/television/cable/jobs.toml
index 3151dc1..540a1bc 100644
--- a/television/cable/jobs.toml
+++ b/television/cable/jobs.toml
@@ -1,11 +1,11 @@
[metadata]
name = "jobs"
description = """
-The current shell's background jobs (stopped or running). tv runs in a child
-process and cannot see the shell's job table, so the ctrl-z binding (fish
-_jobs_bind, zsh jobs-fg) writes it to the file named by $TV_JOBS; enter prints
-the job id and the binding runs `fg %`; ctrl-d kills the job. Opened any
-other way, the list is empty.
+The current fish shell's background jobs (stopped or running). tv runs in a
+child process and cannot see the shell's job table, so the ctrl-z binding
+(_jobs_bind) writes it to the file named by $TV_JOBS; enter prints the job id
+and the binding runs `fg %`; ctrl-d kills the job. Opened any other way,
+the list is empty.
"""
requirements = ["ps"]
diff --git a/television/cable/pj.toml b/television/cable/pj.toml
index d8b24ab..c11c654 100644
--- a/television/cable/pj.toml
+++ b/television/cable/pj.toml
@@ -4,8 +4,8 @@ description = """
Project tasks from every task source between the cwd and the git toplevel
(package.json, Makefile, justfile, mise, devbox, pyproject), tasks of the most
recently modified manifest first. Enter runs the task. Discovery, preview and
-run live in ~/.local/bin/pj; `pj` (ctrl-p in fish, zsh and bash) opens this
-cable with its own scan.
+run live in ~/.local/bin/pj; `pj` (ctrl-p, and down on an empty prompt in fish,
+zsh and bash) opens this cable with its own scan.
"""
requirements = ["pj", "mtime-sort"]