feat(zsh): prospectively migrate back

This commit is contained in:
Barrett Ruth 2026-03-07 17:24:35 -05:00
parent ed8e5bf7fd
commit 1ca5e7d974
Signed by: barrett
GPG key ID: A6C96C9349D2FC81
11 changed files with 208 additions and 152 deletions

View file

@ -1,29 +0,0 @@
_tf="${XDG_STATE_HOME:-$HOME/.local/state}/theme"
THEME="$(cat "$_tf" 2>/dev/null)" || THEME="midnight"
export THEME
unset _tf
shopt -s autocd cdspell dirspell globstar histappend
HISTFILE="${XDG_STATE_HOME:-$HOME/.local/state}/bash_history"
HISTSIZE=50000
HISTFILESIZE=50000
HISTCONTROL=ignoreboth:erasedups
export GPG_TTY=$(tty)
export FZF_COMPLETION_TRIGGER=';'
export FZF_TMUX=1
fzf-config-widget() {
local selected
selected="$(rg --files --hidden "$HOME"/.config | sed "s|$HOME|~|" | \
FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --scheme=path" "-m") \
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))" || return
selected="${selected//$'\n'/ }"
READLINE_LINE="${READLINE_LINE:0:READLINE_POINT}${selected}${READLINE_LINE:READLINE_POINT}"
READLINE_POINT=$((READLINE_POINT + ${#selected}))
}
bind -m vi-insert -x '"\C-e": fzf-config-widget'
bind -m vi-command -x '"\C-e": fzf-config-widget'
[ -r "$OPAMROOT/opam-init/init.sh" ] && . "$OPAMROOT/opam-init/init.sh" > /dev/null 2> /dev/null

View file

@ -1,26 +0,0 @@
set editing-mode vi
set show-mode-in-prompt on
set vi-cmd-mode-string "\1\e[2 q\2"
set vi-ins-mode-string "\1\e[6 q\2"
set completion-ignore-case on
set colored-stats on
set show-all-if-ambiguous on
$if mode=vi
set keymap vi-command
"\C-l": clear-screen
"\C-p": previous-history
"\C-n": next-history
"\C-j": backward-char
"\C-k": forward-char
"\e[3~": delete-char
set keymap vi-insert
"\C-l": clear-screen
"\C-p": previous-history
"\C-n": next-history
"\C-j": backward-char
"\C-k": forward-char
"\e[3~": delete-char
$endif

View file

@ -0,0 +1,67 @@
---
name: canola
description: This skill should be used when starting a canola.nvim issue fix
session, processing upstream oil.nvim issues, or when the user invokes /canola.
version: 0.3.0
---
# Canola Issue Fix Session
## Repo rules (non-negotiable)
- ALL PRs target `barrettruth/canola.nvim` (remote `origin`) — NEVER `stevearc/oil.nvim`
- Upstream (`stevearc/oil.nvim`) is READ-ONLY: fetch, diff, view — never push or open PRs
- Always pass `--repo barrettruth/canola.nvim` explicitly to every `gh pr` command
## Phase 1: Research (parallel, 2 issues at a time)
Process at most 2 issues per session. Spawn one Agent(subagent_type=general,
worktree=true) per issue using EnterWorktree so each agent works in an
isolated git worktree. Each agent receives: issue number, description, and
instructions to find:
- Root cause (which files, which functions, line numbers)
- Whether a test already covers it
- Whether the fix has side effects in other adapters or modes
- What upstream's latest state is
## Phase 2: Plan mode — present BEFORE implementing
Call EnterPlanMode immediately after research completes.
For each issue, present the FULL picture:
- Problem statement (2-3 sentences, not just the title)
- Root cause (files + line numbers)
- **Expected behavior** — what the correct outcome looks like, step by step,
so the user knows exactly what to verify after the fix
- Solution A: description, tradeoffs, risks
- Solution B: description, tradeoffs, risks
- Recommended solution and why
- Config surface change? (yes/no) → vimdoc needed?
Do NOT write any code or edit any files during plan mode.
Do NOT exit plan mode until the user has approved an approach for every issue.
Call ExitPlanMode only after receiving explicit approval.
## Phase 3: Implement (one at a time, after plan mode exits)
For each approved issue:
1. Write `/tmp/minimal_init.lua` — self-contained repro
2. Give user step-by-step instructions to confirm bug reproduces
3. Implement fix
4. Give user the pre-laid-out expected behavior from Phase 2 as a checklist
to verify the fix works (no surprises — user already knows what to expect)
5. /gc — conventional commit on fix/<short> branch
6. /pr — push, create PR targeting `barrettruth/canola.nvim` with Problem/Solution body
7. Update doc/upstream.md — status → fixed, add PR + commit link
8. /gc + push the upstream.md change on same branch
## Subagent Research Prompt Template
"Research upstream oil.nvim issue #NNN for the canola.nvim fork.
Read: doc/upstream.md entry for this issue, then trace the relevant
source files to find the root cause. Return:
- Affected files and functions (with line numbers)
- Root cause in 2-3 sentences
- Expected correct behavior (step by step)
- Risky areas (other code that touches the same path)
- Whether existing tests cover this behavior"

View file

@ -102,12 +102,12 @@ return {
end, end,
}, },
keymaps = { keymaps = {
['<C-h>'] = false, ['<c-h>'] = false,
['<C-t>'] = false, ['<c-t>'] = false,
['<C-l>'] = false, ['<c-l>'] = false,
['<C-r>'] = 'actions.refresh', ['<c-r>'] = 'actions.refresh',
['<C-s>'] = { 'actions.select', opts = { vertical = true } }, ['<c-s>'] = { 'actions.select', opts = { vertical = true } },
['<C-x>'] = { ['<c-x>'] = {
'actions.select', 'actions.select',
opts = { horizontal = true }, opts = { horizontal = true },
}, },
@ -121,7 +121,6 @@ return {
end, end,
}, },
}) })
-- TODO: better way to do this allowing vim.g.canola as that's it
local refresh = require('canola.actions').refresh local refresh = require('canola.actions').refresh
local orig_refresh = refresh.callback local orig_refresh = refresh.callback
refresh.callback = function(...) refresh.callback = function(...)
@ -153,7 +152,11 @@ return {
{ {
'barrettruth/pending.nvim', 'barrettruth/pending.nvim',
before = function() before = function()
vim.g.pending = { debug = false } vim.g.pending = {
debug = true,
-- TODO: use date formats/personal rice
data_path = (os.getenv('XDG_STATE_HOME') or (os.getenv('HOME') .. '/.local/state')) .. '/nvim/pending/tasks.json',
}
end, end,
cmd = 'Pending', cmd = 'Pending',
keys = { { '<leader>P', '<cmd>Pending<cr>' } }, keys = { { '<leader>P', '<cmd>Pending<cr>' } },
@ -183,7 +186,7 @@ return {
commands = { commands = {
build = { build = {
'g++', 'g++',
'-std=c++23', '-std=c++20',
'-O2', '-O2',
'-Wall', '-Wall',
'-Wextra', '-Wextra',
@ -202,7 +205,7 @@ return {
run = { '{binary}' }, run = { '{binary}' },
debug = { debug = {
'g++', 'g++',
'-std=c++23', '-std=c++20',
'-g3', '-g3',
'-fsanitize=address,undefined', '-fsanitize=address,undefined',
'-fno-omit-frame-pointer', '-fno-omit-frame-pointer',

View file

@ -28,6 +28,10 @@
"rev": "f2634758455cfa52a8acea6f142dcd6271a1bf57", "rev": "f2634758455cfa52a8acea6f142dcd6271a1bf57",
"src": "https://github.com/monaqa/dial.nvim" "src": "https://github.com/monaqa/dial.nvim"
}, },
"fzf-lua": {
"rev": "1eba927866251bae1b61dffc5b673b8dbd0f3f48",
"src": "https://github.com/ibhagwan/fzf-lua"
},
"guard-collection": { "guard-collection": {
"rev": "edf6c86c06badc972964dadb7fd469022690cbf0", "rev": "edf6c86c06badc972964dadb7fd469022690cbf0",
"src": "https://github.com/nvimdev/guard-collection" "src": "https://github.com/nvimdev/guard-collection"

View file

@ -54,9 +54,9 @@ unbind C-u; bind C-u if -F '#{pane_in_mode}' { send-keys -X halfpage-up } { copy
unbind /; bind / if -F '#{pane_in_mode}' { send-keys -X cancel } { copy-mode ; command-prompt -p '/' { send -X search-forward -- '%%' } } unbind /; bind / if -F '#{pane_in_mode}' { send-keys -X cancel } { copy-mode ; command-prompt -p '/' { send -X search-forward -- '%%' } }
unbind ?; bind ? if -F '#{pane_in_mode}' { send-keys -X cancel } { copy-mode ; command-prompt -p '?' { send -X search-backward -- '%%' } } unbind ?; bind ? if -F '#{pane_in_mode}' { send-keys -X cancel } { copy-mode ; command-prompt -p '?' { send -X search-backward -- '%%' } }
bind -T copy-mode-vi WheelDownPane select-pane \; send-keys -X scroll-down
bind -T copy-mode-vi v send-keys -X begin-selection bind -T copy-mode-vi v send-keys -X begin-selection
bind -T copy-mode-vi y send-keys -X copy-pipe 'test -n "$WAYLAND_DISPLAY" && wl-copy || xclip -in -sel c' bind -T copy-mode-vi y send-keys -X copy-pipe 'test -n "$WAYLAND_DISPLAY" && wl-copy || xclip -in -sel c'
# TODO: breaks all the time
bind -n DoubleClick1Pane select-pane \; copy-mode -M \; send-keys -X select-word \; run-shell -d 0.3 \; send-keys -X copy-pipe-and-cancel 'test -n "$WAYLAND_DISPLAY" && wl-copy || xclip -in -sel c' bind -n DoubleClick1Pane select-pane \; copy-mode -M \; send-keys -X select-word \; run-shell -d 0.3 \; send-keys -X copy-pipe-and-cancel 'test -n "$WAYLAND_DISPLAY" && wl-copy || xclip -in -sel c'
bind -n TripleClick1Pane select-pane \; copy-mode -M \; send-keys -X select-line \; run-shell -d 0.3 \; send-keys -X copy-pipe-and-cancel 'test -n "$WAYLAND_DISPLAY" && wl-copy || xclip -in -sel c' bind -n TripleClick1Pane select-pane \; copy-mode -M \; send-keys -X select-line \; run-shell -d 0.3 \; send-keys -X copy-pipe-and-cancel 'test -n "$WAYLAND_DISPLAY" && wl-copy || xclip -in -sel c'
bind -T copy-mode-vi DoubleClick1Pane select-pane \; send-keys -X select-word \; run-shell -d 0.3 \; send-keys -X copy-pipe 'test -n "$WAYLAND_DISPLAY" && wl-copy || xclip -in -sel c' \; send-keys -X clear-selection bind -T copy-mode-vi DoubleClick1Pane select-pane \; send-keys -X select-word \; run-shell -d 0.3 \; send-keys -X copy-pipe 'test -n "$WAYLAND_DISPLAY" && wl-copy || xclip -in -sel c' \; send-keys -X clear-selection

57
config/zsh/zshrc Normal file
View file

@ -0,0 +1,57 @@
autoload -U compinit && compinit -d "$XDG_STATE_HOME/zcompdump" -u
zmodload zsh/complist
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-za-z}'
export GPG_TTY=$(tty)
export THEME="${THEME:-midnight}"
setopt auto_cd
unsetopt beep notify
unset completealiases
bindkey -v
bindkey '^[[3~' delete-char
bindkey '^P' up-line-or-history
bindkey '^N' down-line-or-history
bindkey '^J' backward-char
bindkey '^K' forward-char
export PURE_PROMPT_SYMBOL=">"
export PURE_PROMPT_VICMD_SYMBOL="<"
export PURE_GIT_UP_ARROW="^"
export PURE_GIT_DOWN_ARROW="v"
export PURE_GIT_STASH_SYMBOL="="
export PURE_CMD_MAX_EXEC_TIME=5
export PURE_GIT_PULL=0
export PURE_GIT_UNTRACKED_DIRTY=1
zstyle ':prompt:pure:git:stash' show yes
autoload -Uz promptinit && promptinit
prompt pure
autoload -Uz add-zle-hook-widget
function _cursor_shape() {
case $KEYMAP in
vicmd) echo -ne '\e[2 q' ;;
viins|main) echo -ne '\e[6 q' ;;
esac
}
function _cursor_init() { echo -ne '\e[6 q'; }
add-zle-hook-widget zle-keymap-select _cursor_shape
add-zle-hook-widget zle-line-init _cursor_init
export FZF_COMPLETION_TRIGGER=\;
export FZF_TMUX=1
fzf-config-widget() {
local file="$(FZF_CTRL_T_COMMAND="fd --type file --hidden . \"$XDG_CONFIG_HOME\"/nix | sed \"s|$HOME|~|g\"" __fzf_select)"
[ -n "$file" ] || { zle reset-prompt; return; }
file="${file/#\\~/~}"
LBUFFER+="$file"
zle reset-prompt
}
zle -N fzf-config-widget
bindkey '^E' fzf-config-widget
[[ ! -r "$OPAMROOT/opam-init/init.zsh" ]] || source "$OPAMROOT/opam-init/init.zsh" > /dev/null 2> /dev/null

42
flake.lock generated
View file

@ -5,11 +5,11 @@
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1772760623, "lastModified": 1772841847,
"narHash": "sha256-033mHW/9iSGX4/rb7+HMpQFF9KSJKYKhe6XSC7CYWf8=", "narHash": "sha256-Qre73BGBcw1YlhBTTT+T/rVoqVtlCgHYYExUreIJoYs=",
"owner": "ryoppippi", "owner": "ryoppippi",
"repo": "claude-code-overlay", "repo": "claude-code-overlay",
"rev": "2320cb504db68e273f264f0d1a7f76af8c4b6e54", "rev": "871c9fa0d37c0d6b3bdbf30341a8d08a75b1793b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -46,11 +46,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1772633327, "lastModified": 1772845525,
"narHash": "sha256-jl+DJB2DUx7EbWLRng+6HNWW/1/VQOnf0NsQB4PlA7I=", "narHash": "sha256-Dp5Ir2u4jJDGCgeMRviHvEQDe+U37hMxp6RSNOoMMPc=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "5a75730e6f21ee624cbf86f4915c6e7489c74acc", "rev": "27b93804fbef1544cb07718d3f0a451f4c4cd6c0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -87,11 +87,11 @@
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_2"
}, },
"locked": { "locked": {
"lastModified": 1772755493, "lastModified": 1772842024,
"narHash": "sha256-+LM56fjXkZqx7IXMq4eWJeDW4d93/UWgrif6c9TOlvo=", "narHash": "sha256-rP+FjAOPqvAJO+hhVSEP3lxkrP6txFgM5O9QOo9Xekc=",
"owner": "nix-community", "owner": "nix-community",
"repo": "neovim-nightly-overlay", "repo": "neovim-nightly-overlay",
"rev": "c5ec84c53a477099c10a33d20e3702d2ccf7b856", "rev": "fb3e5603c475739c421d3e941c608bc20986ef18",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -103,11 +103,11 @@
"neovim-src": { "neovim-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1772752529, "lastModified": 1772822087,
"narHash": "sha256-KdHMemEfY5XO1MsmRKlRG95YWTsw3B47eOripGTeazc=", "narHash": "sha256-uaecQjyj20yqMHcNNAnJzTsgi3rjDfx2mh9bD9TNPks=",
"owner": "neovim", "owner": "neovim",
"repo": "neovim", "repo": "neovim",
"rev": "7a8d31687940b40ab82081ffe2fac90bbb6e4e19", "rev": "34a59e30dbe23bab59bc6b39a4b235c5b2862e60",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -149,11 +149,11 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1772674223, "lastModified": 1772736753,
"narHash": "sha256-/suKbHSaSmuC9UY7G0VRQ3aO+QKqxAQPQ19wG7QNkF8=", "narHash": "sha256-au/m3+EuBLoSzWUCb64a/MZq6QUtOV8oC0D9tY2scPQ=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "66d9241e3dc2296726dc522e62dbfe89c7b449f3", "rev": "917fec990948658ef1ccd07cef2a1ef060786846",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -165,11 +165,11 @@
}, },
"nixpkgs_3": { "nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1772674223, "lastModified": 1772736753,
"narHash": "sha256-/suKbHSaSmuC9UY7G0VRQ3aO+QKqxAQPQ19wG7QNkF8=", "narHash": "sha256-au/m3+EuBLoSzWUCb64a/MZq6QUtOV8oC0D9tY2scPQ=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "66d9241e3dc2296726dc522e62dbfe89c7b449f3", "rev": "917fec990948658ef1ccd07cef2a1ef060786846",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -211,11 +211,11 @@
"nixpkgs": "nixpkgs_4" "nixpkgs": "nixpkgs_4"
}, },
"locked": { "locked": {
"lastModified": 1772772172, "lastModified": 1772858378,
"narHash": "sha256-OCEb6jXTvhnMTMqMLleYChekDO/zh+VtunBAS0WevPM=", "narHash": "sha256-VPRlTud1REOz0GPjq3XQNjk5GpH/xNbeadiul4gkPGA=",
"owner": "0xc000022070", "owner": "0xc000022070",
"repo": "zen-browser-flake", "repo": "zen-browser-flake",
"rev": "5f8f34c0dd56808ecbfa35697353c455e4a416b3", "rev": "42e1e9a1cb5b507789a51193113d56f8f1bb08d9",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -28,6 +28,7 @@ in
with pkgs; with pkgs;
[ [
awscli2 awscli2
pure-prompt
tree tree
typos typos
jq jq
@ -43,6 +44,8 @@ in
librsvg librsvg
imagemagick imagemagick
graphite-cli graphite-cli
luarocks
jupyter
] ]
++ lib.optionals hostConfig.isLinux [ xclip ] ++ lib.optionals hostConfig.isLinux [ xclip ]
++ lib.optionals rust [ rustup ] ++ lib.optionals rust [ rustup ]
@ -113,9 +116,6 @@ in
(lib.mkIf claude { (lib.mkIf claude {
CLAUDE_CONFIG_DIR = "${config.xdg.configHome}/claude"; CLAUDE_CONFIG_DIR = "${config.xdg.configHome}/claude";
}) })
{
INPUTRC = "${repoDir}/config/bash/inputrc";
}
]; ];
home.sessionPath = lib.mkMerge [ home.sessionPath = lib.mkMerge [
@ -198,73 +198,50 @@ in
} }
''; '';
programs.bash = { programs.zsh = {
enable = true; enable = true;
shellAliases = lib.mkIf (!hostConfig.isNixOS) { dotDir = "${config.xdg.configHome}/zsh";
completionInit = "";
history = {
path = "${config.xdg.stateHome}/zsh_history";
size = 2000;
save = 2000;
ignoreDups = true;
ignoreAllDups = true;
ignoreSpace = true;
extended = true;
append = true;
};
shellAliases = {
g = "git"; g = "git";
nv = "nvim"; nv = "nvim";
}; };
bashrcExtra = ''
[[ $- == *i* ]] || return 0
'';
initExtra = lib.mkAfter ''
[ -f "$HOME/.config/nix/config/bash/bashrc" ] && . "$HOME/.config/nix/config/bash/bashrc"
'';
};
programs.starship = { syntaxHighlighting.enable = true;
autosuggestion = {
enable = true; enable = true;
settings = { strategy = [
format = lib.concatStrings [ "history"
"$directory" "completion"
"$git_branch"
"$git_status"
"$cmd_duration"
"$line_break"
"$character"
]; ];
add_newline = true;
continuation_prompt = "[>>](purple) ";
character = {
success_symbol = "[>](bold purple)";
error_symbol = "[>](bold red)";
};
directory = {
style = "bold blue";
truncation_length = 0;
truncate_to_repo = false;
};
git_branch = {
format = "[$branch]($style) ";
style = "242";
};
git_status = {
format = "[$all_status$ahead_behind]($style) ";
style = "242";
modified = "*";
ahead = "^";
behind = "v";
stashed = "=";
deleted = "-";
diverged = "^v";
conflicted = "m";
renamed = "->";
};
cmd_duration = {
min_time = 5000;
format = "[$duration]($style) ";
};
};
}; };
home.activation.removeZshFiles = lib.hm.dag.entryAfter [ "writeBoundary" ] '' initContent = ''
for f in "$HOME/.zshenv" "$HOME/.zshenv.bak"; do fpath+=("${pkgs.pure-prompt}/share/zsh/site-functions")
[ -e "$f" ] && rm "$f" || true source "$XDG_CONFIG_HOME/nix/config/zsh/zshrc"
done '';
};
home.activation.removeZshenvBridge = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
[ -L "$HOME/.zshenv" ] && rm "$HOME/.zshenv" || true
''; '';
programs.fzf = { programs.fzf = {
enable = true; enable = true;
enableZshIntegration = true;
defaultCommand = "rg --files --hidden"; defaultCommand = "rg --files --hidden";
defaultOptions = [ defaultOptions = [
"--bind=ctrl-a:select-all" "--bind=ctrl-a:select-all"
@ -280,15 +257,18 @@ in
programs.eza = { programs.eza = {
enable = true; enable = true;
enableZshIntegration = true;
git = true; git = true;
}; };
programs.zoxide = { programs.zoxide = {
enable = true; enable = true;
enableZshIntegration = true;
}; };
programs.direnv = { programs.direnv = {
enable = true; enable = true;
enableZshIntegration = true;
nix-direnv.enable = true; nix-direnv.enable = true;
config.global = { config.global = {
hide_env_diff = true; hide_env_diff = true;

View file

@ -9,7 +9,7 @@
programs.ghostty = { programs.ghostty = {
enable = true; enable = true;
settings = { settings = {
font-family = "Jetbrains Mono"; font-family = "Zen Mono";
font-codepoint-map = "U+f101-U+f25c=nonicons"; font-codepoint-map = "U+f101-U+f25c=nonicons";
font-feature = "-calt"; font-feature = "-calt";
font-size = 20; font-size = 20;

View file

@ -96,7 +96,7 @@ in
"storage" "storage"
"power" "power"
]; ];
shell = pkgs.bash; shell = pkgs.zsh;
}; };
programs.chromium = { programs.chromium = {
@ -112,12 +112,12 @@ in
}; };
}; };
programs.bash = { programs.zsh = {
enable = true; enable = true;
shellAliases = { shellInit = ''
g = "git"; export ZDOTDIR="$HOME/.config/zsh"
nv = "nvim"; export THEME="midnight"
}; '';
}; };
programs.hyprland = { programs.hyprland = {
enable = true; enable = true;