From 1ca5e7d9747491ba24577fc4f9bce346aecf9209 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sat, 7 Mar 2026 17:24:35 -0500 Subject: [PATCH] feat(zsh): prospectively migrate back --- config/bash/bashrc | 29 --------- config/bash/inputrc | 26 -------- config/claude/skills/canola/SKILL.md | 67 ++++++++++++++++++++ config/nvim/lua/plugins/dev.lua | 23 ++++--- config/nvim/nvim-pack-lock.json | 6 +- config/tmux/tmux.conf | 2 +- config/zsh/zshrc | 57 +++++++++++++++++ flake.lock | 42 ++++++------- home/modules/shell.nix | 94 +++++++++++----------------- home/modules/terminal.nix | 2 +- hosts/xps15/configuration.nix | 12 ++-- 11 files changed, 208 insertions(+), 152 deletions(-) delete mode 100644 config/bash/bashrc delete mode 100644 config/bash/inputrc create mode 100644 config/claude/skills/canola/SKILL.md create mode 100644 config/zsh/zshrc diff --git a/config/bash/bashrc b/config/bash/bashrc deleted file mode 100644 index 2c5d91a..0000000 --- a/config/bash/bashrc +++ /dev/null @@ -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 diff --git a/config/bash/inputrc b/config/bash/inputrc deleted file mode 100644 index 797a442..0000000 --- a/config/bash/inputrc +++ /dev/null @@ -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 diff --git a/config/claude/skills/canola/SKILL.md b/config/claude/skills/canola/SKILL.md new file mode 100644 index 0000000..c273590 --- /dev/null +++ b/config/claude/skills/canola/SKILL.md @@ -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/ 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" diff --git a/config/nvim/lua/plugins/dev.lua b/config/nvim/lua/plugins/dev.lua index b2ada8d..70884ae 100644 --- a/config/nvim/lua/plugins/dev.lua +++ b/config/nvim/lua/plugins/dev.lua @@ -102,12 +102,12 @@ return { end, }, keymaps = { - [''] = false, - [''] = false, - [''] = false, - [''] = 'actions.refresh', - [''] = { 'actions.select', opts = { vertical = true } }, - [''] = { + [''] = false, + [''] = false, + [''] = false, + [''] = 'actions.refresh', + [''] = { 'actions.select', opts = { vertical = true } }, + [''] = { 'actions.select', opts = { horizontal = true }, }, @@ -121,7 +121,6 @@ return { end, }, }) - -- TODO: better way to do this allowing vim.g.canola as that's it local refresh = require('canola.actions').refresh local orig_refresh = refresh.callback refresh.callback = function(...) @@ -153,7 +152,11 @@ return { { 'barrettruth/pending.nvim', 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, cmd = 'Pending', keys = { { 'P', 'Pending' } }, @@ -183,7 +186,7 @@ return { commands = { build = { 'g++', - '-std=c++23', + '-std=c++20', '-O2', '-Wall', '-Wextra', @@ -202,7 +205,7 @@ return { run = { '{binary}' }, debug = { 'g++', - '-std=c++23', + '-std=c++20', '-g3', '-fsanitize=address,undefined', '-fno-omit-frame-pointer', diff --git a/config/nvim/nvim-pack-lock.json b/config/nvim/nvim-pack-lock.json index e3fa81d..3a742f3 100644 --- a/config/nvim/nvim-pack-lock.json +++ b/config/nvim/nvim-pack-lock.json @@ -28,6 +28,10 @@ "rev": "f2634758455cfa52a8acea6f142dcd6271a1bf57", "src": "https://github.com/monaqa/dial.nvim" }, + "fzf-lua": { + "rev": "1eba927866251bae1b61dffc5b673b8dbd0f3f48", + "src": "https://github.com/ibhagwan/fzf-lua" + }, "guard-collection": { "rev": "edf6c86c06badc972964dadb7fd469022690cbf0", "src": "https://github.com/nvimdev/guard-collection" @@ -109,4 +113,4 @@ "src": "https://github.com/tpope/vim-sleuth" } } -} +} \ No newline at end of file diff --git a/config/tmux/tmux.conf b/config/tmux/tmux.conf index ba518c2..73a15b7 100644 --- a/config/tmux/tmux.conf +++ b/config/tmux/tmux.conf @@ -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-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 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 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 diff --git a/config/zsh/zshrc b/config/zsh/zshrc new file mode 100644 index 0000000..c06c9a8 --- /dev/null +++ b/config/zsh/zshrc @@ -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 diff --git a/flake.lock b/flake.lock index 3b64586..2b68dcd 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1772760623, - "narHash": "sha256-033mHW/9iSGX4/rb7+HMpQFF9KSJKYKhe6XSC7CYWf8=", + "lastModified": 1772841847, + "narHash": "sha256-Qre73BGBcw1YlhBTTT+T/rVoqVtlCgHYYExUreIJoYs=", "owner": "ryoppippi", "repo": "claude-code-overlay", - "rev": "2320cb504db68e273f264f0d1a7f76af8c4b6e54", + "rev": "871c9fa0d37c0d6b3bdbf30341a8d08a75b1793b", "type": "github" }, "original": { @@ -46,11 +46,11 @@ ] }, "locked": { - "lastModified": 1772633327, - "narHash": "sha256-jl+DJB2DUx7EbWLRng+6HNWW/1/VQOnf0NsQB4PlA7I=", + "lastModified": 1772845525, + "narHash": "sha256-Dp5Ir2u4jJDGCgeMRviHvEQDe+U37hMxp6RSNOoMMPc=", "owner": "nix-community", "repo": "home-manager", - "rev": "5a75730e6f21ee624cbf86f4915c6e7489c74acc", + "rev": "27b93804fbef1544cb07718d3f0a451f4c4cd6c0", "type": "github" }, "original": { @@ -87,11 +87,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1772755493, - "narHash": "sha256-+LM56fjXkZqx7IXMq4eWJeDW4d93/UWgrif6c9TOlvo=", + "lastModified": 1772842024, + "narHash": "sha256-rP+FjAOPqvAJO+hhVSEP3lxkrP6txFgM5O9QOo9Xekc=", "owner": "nix-community", "repo": "neovim-nightly-overlay", - "rev": "c5ec84c53a477099c10a33d20e3702d2ccf7b856", + "rev": "fb3e5603c475739c421d3e941c608bc20986ef18", "type": "github" }, "original": { @@ -103,11 +103,11 @@ "neovim-src": { "flake": false, "locked": { - "lastModified": 1772752529, - "narHash": "sha256-KdHMemEfY5XO1MsmRKlRG95YWTsw3B47eOripGTeazc=", + "lastModified": 1772822087, + "narHash": "sha256-uaecQjyj20yqMHcNNAnJzTsgi3rjDfx2mh9bD9TNPks=", "owner": "neovim", "repo": "neovim", - "rev": "7a8d31687940b40ab82081ffe2fac90bbb6e4e19", + "rev": "34a59e30dbe23bab59bc6b39a4b235c5b2862e60", "type": "github" }, "original": { @@ -149,11 +149,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1772674223, - "narHash": "sha256-/suKbHSaSmuC9UY7G0VRQ3aO+QKqxAQPQ19wG7QNkF8=", + "lastModified": 1772736753, + "narHash": "sha256-au/m3+EuBLoSzWUCb64a/MZq6QUtOV8oC0D9tY2scPQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "66d9241e3dc2296726dc522e62dbfe89c7b449f3", + "rev": "917fec990948658ef1ccd07cef2a1ef060786846", "type": "github" }, "original": { @@ -165,11 +165,11 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1772674223, - "narHash": "sha256-/suKbHSaSmuC9UY7G0VRQ3aO+QKqxAQPQ19wG7QNkF8=", + "lastModified": 1772736753, + "narHash": "sha256-au/m3+EuBLoSzWUCb64a/MZq6QUtOV8oC0D9tY2scPQ=", "owner": "nixos", "repo": "nixpkgs", - "rev": "66d9241e3dc2296726dc522e62dbfe89c7b449f3", + "rev": "917fec990948658ef1ccd07cef2a1ef060786846", "type": "github" }, "original": { @@ -211,11 +211,11 @@ "nixpkgs": "nixpkgs_4" }, "locked": { - "lastModified": 1772772172, - "narHash": "sha256-OCEb6jXTvhnMTMqMLleYChekDO/zh+VtunBAS0WevPM=", + "lastModified": 1772858378, + "narHash": "sha256-VPRlTud1REOz0GPjq3XQNjk5GpH/xNbeadiul4gkPGA=", "owner": "0xc000022070", "repo": "zen-browser-flake", - "rev": "5f8f34c0dd56808ecbfa35697353c455e4a416b3", + "rev": "42e1e9a1cb5b507789a51193113d56f8f1bb08d9", "type": "github" }, "original": { diff --git a/home/modules/shell.nix b/home/modules/shell.nix index a6e613c..521a10c 100644 --- a/home/modules/shell.nix +++ b/home/modules/shell.nix @@ -28,6 +28,7 @@ in with pkgs; [ awscli2 + pure-prompt tree typos jq @@ -43,6 +44,8 @@ in librsvg imagemagick graphite-cli + luarocks + jupyter ] ++ lib.optionals hostConfig.isLinux [ xclip ] ++ lib.optionals rust [ rustup ] @@ -113,9 +116,6 @@ in (lib.mkIf claude { CLAUDE_CONFIG_DIR = "${config.xdg.configHome}/claude"; }) - { - INPUTRC = "${repoDir}/config/bash/inputrc"; - } ]; home.sessionPath = lib.mkMerge [ @@ -198,73 +198,50 @@ in } ''; - programs.bash = { + programs.zsh = { 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"; nv = "nvim"; }; - bashrcExtra = '' - [[ $- == *i* ]] || return 0 - ''; - initExtra = lib.mkAfter '' - [ -f "$HOME/.config/nix/config/bash/bashrc" ] && . "$HOME/.config/nix/config/bash/bashrc" - ''; - }; - programs.starship = { - enable = true; - settings = { - format = lib.concatStrings [ - "$directory" - "$git_branch" - "$git_status" - "$cmd_duration" - "$line_break" - "$character" + syntaxHighlighting.enable = true; + + autosuggestion = { + enable = true; + strategy = [ + "history" + "completion" ]; - 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) "; - }; }; + + initContent = '' + fpath+=("${pkgs.pure-prompt}/share/zsh/site-functions") + source "$XDG_CONFIG_HOME/nix/config/zsh/zshrc" + ''; }; - home.activation.removeZshFiles = lib.hm.dag.entryAfter [ "writeBoundary" ] '' - for f in "$HOME/.zshenv" "$HOME/.zshenv.bak"; do - [ -e "$f" ] && rm "$f" || true - done + home.activation.removeZshenvBridge = lib.hm.dag.entryAfter [ "writeBoundary" ] '' + [ -L "$HOME/.zshenv" ] && rm "$HOME/.zshenv" || true ''; programs.fzf = { enable = true; + enableZshIntegration = true; defaultCommand = "rg --files --hidden"; defaultOptions = [ "--bind=ctrl-a:select-all" @@ -280,15 +257,18 @@ in programs.eza = { enable = true; + enableZshIntegration = true; git = true; }; programs.zoxide = { enable = true; + enableZshIntegration = true; }; programs.direnv = { enable = true; + enableZshIntegration = true; nix-direnv.enable = true; config.global = { hide_env_diff = true; diff --git a/home/modules/terminal.nix b/home/modules/terminal.nix index ef127e8..810437d 100644 --- a/home/modules/terminal.nix +++ b/home/modules/terminal.nix @@ -9,7 +9,7 @@ programs.ghostty = { enable = true; settings = { - font-family = "Jetbrains Mono"; + font-family = "Zen Mono"; font-codepoint-map = "U+f101-U+f25c=nonicons"; font-feature = "-calt"; font-size = 20; diff --git a/hosts/xps15/configuration.nix b/hosts/xps15/configuration.nix index 06a4747..87fb017 100644 --- a/hosts/xps15/configuration.nix +++ b/hosts/xps15/configuration.nix @@ -96,7 +96,7 @@ in "storage" "power" ]; - shell = pkgs.bash; + shell = pkgs.zsh; }; programs.chromium = { @@ -112,12 +112,12 @@ in }; }; - programs.bash = { + programs.zsh = { enable = true; - shellAliases = { - g = "git"; - nv = "nvim"; - }; + shellInit = '' + export ZDOTDIR="$HOME/.config/zsh" + export THEME="midnight" + ''; }; programs.hyprland = { enable = true;