From 505ecb2e0e3336e632bb2e96e363d94c457229a2 Mon Sep 17 00:00:00 2001 From: Matt Menefee Date: Sun, 17 May 2026 15:52:05 -0600 Subject: [PATCH 1/2] Add NeoVim migration plan Document the phased migration from MacVim + Vundle + Vimscript to Neovim with its native conventions and ecosystem. The plan is split into 7 phases ordered by dependency so each phase can land independently and leave a working editor: 1. Minimum cutover (also closes #64) 2. Remove Vim-only quirks 3. Replace Vundle with lazy.nvim (foundational for 4-7) 4. Replace syntastic with built-in LSP + nvim-lint 5. File navigation and search (telescope, oil/nvim-tree, ripgrep) 6. Treesitter and completion (nvim-cmp) 7. Convert init.vim to init.lua Each phase is tracked in its own GitHub issue (#67-#73). --- PLAN.md | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 PLAN.md diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..31ee3a8 --- /dev/null +++ b/PLAN.md @@ -0,0 +1,284 @@ +# NeoVim Migration Plan + +Migration from MacVim + Vundle + Vimscript to Neovim with its native +conventions and ecosystem. Phased to allow stopping at any phase boundary and +still having a working editor. + +Scope: `home/.vimrc`, `home/.config/nvim/`, `Brewfile`, `init.zsh`, `.zshrc` +alias, and `README.md`. + +--- + +## Phase 1 — Minimum cutover (this PR) + +**Goal:** Stop launching MacVim. Start launching Neovim. Keep every plugin, +keybinding, and behavior identical. No Lua, no plugin manager changes, no +linter changes. + +**Also addresses:** [#64][issue-64] (undodir workaround cleanup) by dropping +the explicit `undodir`/`mkdir` block — Neovim defaults to +`~/.local/state/nvim/undo//`, which is outside the homesick castle and +auto-created. + +### Changes + +1. Create `home/.config/nvim/init.vim` containing the full former `.vimrc` + contents, **minus** the `undodir` block. + - First line: `set runtimepath^=~/.vim runtimepath+=~/.vim/after` so Vundle + continues finding `~/.vim/bundle/`. + - Second line: `let &packpath = &runtimepath`. +2. Delete `home/.vimrc` entirely (no MacVim fallback to maintain). +3. Update `home/.zshrc` alias: `alias vim='nvim'` (was `alias vim='mvim -v'`). +4. Update `init.zsh` bootstrap: `nvim +PluginInstall +qall` (was + `vim +BundleInstall +qall`). +5. Remove `brew 'macvim'` from `Brewfile`. +6. Update `README.md`: + - Replace "Vim via Vundle" framing with "Neovim via Vundle (transitional)". + - Update the bootstrap step that says "installs Vundle plugins for MacVim". + +### Manual cleanup (per-machine, not in repo) + +- [ ] `rm -rf ~/.vim/undo` (the workaround directory from #63 is no longer + written to) +- [ ] `brew uninstall macvim` after confirming the alias swap works +- [ ] Verify `homesick link dotfiles` produces no `.un~` symlinks on a fresh + run (closes #64) + +### Acceptance + +- `nvim` opens with all 30+ plugins loaded from `~/.vim/bundle/` +- `vim` alias resolves to `nvim` +- No `.un~` files appear next to source files in the castle +- README accurately describes the current state + +--- + +## Phase 2 — Neovim-compat hygiene (small, opportunistic) + +**Goal:** Remove Vim-only quirks that are no-ops or warnings under Neovim. +Tiny PR, mechanical changes. + +### Changes + +- Remove `set pastetoggle=` — Neovim handles paste automatically via + bracketed-paste and the option is deprecated. +- Remove the explicit `set nocompatible` (Neovim is always non-compatible). +- Audit `set rtp+=~/.vim/bundle/Vundle.vim` and the `vundle#begin()` call — + these still work but flag for Phase 3. +- Remove `Plugin 'matchit.zip'` — Neovim ships matchit and loads it + automatically. + +### Acceptance + +- `nvim --headless +qall` produces no deprecation warnings related to our + config + +--- + +## Phase 3 — Plugin manager: Vundle → lazy.nvim + +**Goal:** Replace Vundle. This is the **foundational phase** for everything +that comes after, because most modern Neovim plugins assume a Lua-capable +manager (lazy.nvim, packer.nvim, etc.). + +### Why lazy.nvim + +- De-facto standard in 2025; actively maintained +- Lazy-loads by default → faster startup +- Lockfile (`lazy-lock.json`) → reproducible installs +- UI for plugin management (`:Lazy`) + +### Changes + +- Bootstrap `lazy.nvim` into `~/.local/share/nvim/lazy/lazy.nvim` from + `init.vim` (the bootstrap snippet from lazy.nvim docs). +- Convert every `Plugin '...'` line to a `lazy.nvim` spec in a new + `home/.config/nvim/lua/plugins.lua` (still keep `init.vim` as entry point — + Lua conversion comes in Phase 7). +- Drop `Plugin 'VundleVim/Vundle.vim'` and the `call vundle#begin()` / + `call vundle#end()` block. +- Remove the `~/.vim/bundle/` directory and the `set rtp+=~/.vim/...` line. +- Commit `lazy-lock.json` so machines stay in sync. +- Update `init.zsh`: `nvim --headless "+Lazy! sync" +qa`. +- Update `README.md` to describe lazy.nvim instead of Vundle. + +### Plugins to drop during conversion + +- `jQuery` — obsolete +- `Markdown` (vim-scripts version) — replace with `preservim/vim-markdown` or + defer to treesitter in Phase 6 +- `Rename` — vim-eunuch already provides `:Rename` +- `vim-coffee-script` — assess actual usage; likely dead + +### Acceptance + +- `~/.vim/bundle/` is gone +- `:Lazy` opens the management UI +- `lazy-lock.json` is committed +- Startup time measurable improvement (`nvim --startuptime /tmp/start.log`) + +--- + +## Phase 4 — Diagnostics: syntastic → built-in LSP + nvim-lint + +**Goal:** Replace synchronous, slow `syntastic` with Neovim's async-native +diagnostics stack. + +### Why + +- `syntastic` blocks the UI on save (it shells out and waits) +- Neovim has `vim.diagnostic` and `vim.lsp` built in since 0.5 +- LSP gives go-to-definition, hover docs, rename, etc. — free upside + +### Changes + +- Add `neovim/nvim-lspconfig` and `williamboman/mason.nvim` for managing LSP + servers +- Add `mfussenegger/nvim-lint` for the non-LSP linters you currently use via + syntastic: + - `eslint` (JS) → mostly replaced by `eslint-lsp` now + - `scss_lint`, `haml_lint`, `pyyaml`, `language_check` → keep via nvim-lint +- Add `lewis6991/gitsigns.nvim` to replace `airblade/vim-gitgutter` (also + async, with `vim.diagnostic`-style sign column) +- Remove `Plugin 'scrooloose/syntastic'` and `Plugin 'myint/syntastic-extras'` +- Remove all the `let g:syntastic_*` config blocks +- Configure LSP servers for the languages in your stack: + - Ruby: `ruby_lsp` or `solargraph` + - JS/TS: `ts_ls` + - Terraform: `terraformls` + - YAML: `yamlls` + - Bash: `bashls` + +### Acceptance + +- Save no longer pauses +- `` diagnostic keymaps (jump to next error, hover, etc.) work +- `:LspInfo` shows attached servers for each language + +--- + +## Phase 5 — File navigation and search + +**Goal:** Replace tree/search plugins with their modern Neovim equivalents. + +### Changes + +- Replace `scrooloose/nerdtree` with `nvim-tree/nvim-tree.lua` OR + `stevearc/oil.nvim` (oil.nvim is the modern choice — edits the filesystem + as a buffer) +- Replace `rking/ag.vim` and `gabesoft/vim-ags` with + `nvim-telescope/telescope.nvim` (live grep, file find, buffer list, LSP + pickers) +- Switch `the_silver_searcher` (ag) → `ripgrep` (rg) in `Brewfile` — + telescope and most modern tooling expect rg +- Update all `s`, `a`, `a` mappings to call + telescope pickers +- Update `let g:NERDTreeHijackNetrw=1`, `let NERDTreeShowHidden=1`, and the + startup-NERDTree autocmd → equivalent nvim-tree/oil setup + +### Acceptance + +- `s` on a word opens telescope grep results +- `` or equivalent opens a fuzzy file picker +- Tree explorer of choice opens on startup + +--- + +## Phase 6 — Treesitter + completion + +**Goal:** Modern syntax highlighting and structural editing, plus real +completion. + +### Changes + +- Add `nvim-treesitter/nvim-treesitter` with parsers for: ruby, javascript, + typescript, tsx, html, scss, yaml, markdown, lua, vim, vimdoc, bash, + dockerfile, terraform, python +- Drop these syntax/ftplugin plugins (treesitter handles them): + - `pangloss/vim-javascript` + - `jelera/vim-javascript-syntax` + - `mtscout6/vim-cjsx` + - `mxw/vim-jsx` (and the `let g:jsx_ext_required = 0` line) + - `vim-coffee-script` (if not already dropped) +- Add `hrsh7th/nvim-cmp` + sources (`cmp-nvim-lsp`, `cmp-buffer`, `cmp-path`) + → replaces `ervandew/supertab` +- Add `nvim-treesitter/nvim-treesitter-textobjects` → richer text objects, + may eventually replace `textobj-rubyblock`/`textobj-user` +- Optional: `windwp/nvim-autopairs` replacing `Raimondi/delimitMate` + +### Acceptance + +- Ruby/JS/etc. syntax highlighting visibly richer +- Tab triggers a completion menu sourced from LSP +- `:TSUpdate` keeps parsers fresh + +--- + +## Phase 7 — Convert `init.vim` to `init.lua` + +**Goal:** Pure Lua config. This is mostly mechanical translation, done last +so the previous phases stabilize first. + +### Changes + +- Create `home/.config/nvim/init.lua` and a `lua/` directory structure: + ``` + home/.config/nvim/ + init.lua + lua/ + options.lua -- everything that was set xxx + keymaps.lua -- everything that was map/nnoremap/etc. + autocmds.lua -- everything that was autocmd + plugins.lua -- lazy.nvim spec (moved from Phase 3) + lsp.lua -- LSP config (moved from Phase 4) + after/ + ftplugin/ + markdown.lua -- replaces the inline au BufRead *.md blocks + gitcommit.lua -- replaces the inline gitcommit autocmd + ``` +- Delete `home/.config/nvim/init.vim` +- Use `vim.opt`, `vim.keymap.set`, `vim.api.nvim_create_autocmd` instead of + their Vimscript equivalents +- Move filetype-specific behavior out of giant `au BufRead` blocks into + `after/ftplugin/.lua` files (Neovim convention) + +### Acceptance + +- `home/.config/nvim/init.vim` no longer exists +- `:checkhealth` reports green across the board +- All keybindings still work + +--- + +## Out of scope (intentionally) + +- Replacing `tpope/vim-fugitive` (still the best git plugin; no compelling + successor) +- Replacing `vim-rails`, `vim-eunuch`, `vim-abolish`, `vim-repeat`, + `vim-endwise`, `vim-surround` (all still maintained by tpope and work + natively in nvim) +- Replacing `thoughtbot/vim-rspec` — could move to `vim-test` or + `nvim-neotest/neotest` in a future phase but not necessary + +--- + +## Issue tracking + +| Phase | Issue | +|-------|-------| +| 1 | [#67][issue-67] (also closes [#64][issue-64]) | +| 2 | [#68][issue-68] | +| 3 | [#69][issue-69] | +| 4 | [#70][issue-70] | +| 5 | [#71][issue-71] | +| 6 | [#72][issue-72] | +| 7 | [#73][issue-73] | + +[issue-64]: https://github.com/mattmenefee/dotfiles/issues/64 +[issue-67]: https://github.com/mattmenefee/dotfiles/issues/67 +[issue-68]: https://github.com/mattmenefee/dotfiles/issues/68 +[issue-69]: https://github.com/mattmenefee/dotfiles/issues/69 +[issue-70]: https://github.com/mattmenefee/dotfiles/issues/70 +[issue-71]: https://github.com/mattmenefee/dotfiles/issues/71 +[issue-72]: https://github.com/mattmenefee/dotfiles/issues/72 +[issue-73]: https://github.com/mattmenefee/dotfiles/issues/73 From 9b63f25050eb64f42c4d2e06442d48ac82c822dc Mon Sep 17 00:00:00 2001 From: Matt Menefee Date: Sun, 17 May 2026 16:00:56 -0600 Subject: [PATCH 2/2] Cut over from MacVim to Neovim (Phase 1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 of the Neovim migration: stop launching MacVim, start launching Neovim, with the smallest reasonable diff. Modernizing the plugin manager, linter stack, search, and Lua conversion are deferred to later phases (#68-#73). The previous setup ran `mvim -v` against `~/.vimrc` with ~30 Vundle plugins. Most carry over unchanged; the exceptions are called out below. Changes: - Move `home/.vimrc` to `home/.config/nvim/init.vim` and prepend the Neovim → Vim runtimepath shim so Vundle continues finding `~/.vim/bundle/`. - Drop the explicit `undodir` block — Neovim's default `~/.local/state/nvim/undo//` is already outside the homesick castle and auto-created (closes #64). - Drop `set pastetoggle=` — option removed in Neovim 0.10 (bracketed-paste handles this automatically). - Drop `ervandew/supertab` plugin — incompatible with Neovim 0.12's Lua-callback default mappings; tab completion will be restored via nvim-cmp in Phase 6 (#72). - Drop `flazz/vim-colorschemes` plugin — abandoned 6 years ago with no explicit Neovim support. Switch the active colorscheme from `railscasts` (a community port from that collection) to `new-railscasts` from the already-installed `carakan/new-railscasts-theme` plugin, which is actively maintained and has dedicated markdown / error-state styling. Enable `termguicolors` since the new colorscheme is gui-defined. - Switch `vim` alias to `nvim` in `home/.zshrc`. - Switch bootstrap to `nvim +PluginInstall +qall` in `init.zsh`. - Remove `brew 'macvim'` from `Brewfile`. - Update `README.md` to describe the transitional Neovim + Vundle state and link to `PLAN.md`. Closes #64. Implements #67. --- Brewfile | 1 - README.md | 17 ++++++++++------- home/{.vimrc => .config/nvim/init.vim} | 19 ++++++++----------- home/.zshrc | 2 +- init.zsh | 2 +- 5 files changed, 20 insertions(+), 21 deletions(-) rename home/{.vimrc => .config/nvim/init.vim} (94%) diff --git a/Brewfile b/Brewfile index 0b20d52..1e81309 100644 --- a/Brewfile +++ b/Brewfile @@ -3,7 +3,6 @@ # Terminal tools cask 'iterm2' brew 'bash' -brew 'macvim' brew 'neovim' brew 'the_silver_searcher' brew 'zsh' diff --git a/README.md b/README.md index d686c58..5863663 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ # dotfiles Personal macOS development environment managed with [Homesick][homesick_link]. -Configures Zsh (with [Oh My Zsh][oh_my_zsh_link]), Vim via [Vundle][vundle_link], -Ruby development tools via [rbenv][rbenv_link], and a curated set of -[Homebrew][homebrew_link] packages for web development. Uses -[mise][mise_link] for managing non-Ruby tool versions. +Configures Zsh (with [Oh My Zsh][oh_my_zsh_link]), Neovim (still using +[Vundle][vundle_link] for now — migration in progress), Ruby development +tools via [rbenv][rbenv_link], and a curated set of [Homebrew][homebrew_link] +packages for web development. Uses [mise][mise_link] for managing non-Ruby +tool versions. ## Getting Started @@ -76,15 +77,16 @@ Ruby development tools via [rbenv][rbenv_link], and a curated set of - **[zsh-syntax-highlighting][zsh_sh_link]** — highlights commands as you type - **[zsh-autosuggestions][zsh_as_link]** — suggests commands from history as you type -1. Install [Vundle][vundle_link] and run the Vim plugin installer +1. Install [Vundle][vundle_link] and run the Neovim plugin installer ```shell $ cd ~/.homesick/repos/dotfiles $ zsh init.zsh ``` - This installs Vundle plugins for MacVim. Neovim (also in the Brewfile) - uses a separate configuration. + This installs Vundle plugins for Neovim from `~/.config/nvim/init.vim`. + Vundle is transitional — see [`PLAN.md`](PLAN.md) for the migration to + [lazy.nvim][lazy_link]. 1. Set up Git config @@ -122,6 +124,7 @@ Oh My Zsh is configured to auto-update daily via `zstyle` settings in `.zshrc`. [rbenv_link]: https://github.com/rbenv/rbenv [rbenv_default_gems_link]: https://github.com/rbenv/rbenv-default-gems [vundle_link]: https://github.com/VundleVim/Vundle.vim +[lazy_link]: https://github.com/folke/lazy.nvim [mise_link]: https://mise.jdx.dev/ [omz_bundler]: https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/bundler [omz_docker]: https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/docker diff --git a/home/.vimrc b/home/.config/nvim/init.vim similarity index 94% rename from home/.vimrc rename to home/.config/nvim/init.vim index 44b63c2..44a95e9 100644 --- a/home/.vimrc +++ b/home/.config/nvim/init.vim @@ -1,3 +1,7 @@ +" Make Neovim load plugins from ~/.vim/bundle (Vundle's default location). +set runtimepath^=~/.vim runtimepath+=~/.vim/after +let &packpath = &runtimepath + " RULE #1: Don't put any lines in your vimrc that you don't understand " Ensure that legacy compatibility mode is off @@ -25,13 +29,11 @@ Plugin 'textobj-user' Plugin 'DrawIt' Plugin 'Markdown' Plugin 'Rename' -Plugin 'ervandew/supertab' Plugin 'pangloss/vim-javascript' Plugin 'scrooloose/nerdcommenter' Plugin 'scrooloose/nerdtree' Plugin 'scrooloose/syntastic' Plugin 'myint/syntastic-extras' -Plugin 'flazz/vim-colorschemes' Plugin 'tpope/vim-rails' Plugin 'tpope/vim-eunuch' Plugin 'vim-coffee-script' @@ -88,20 +90,14 @@ set autoindent set autoread set autowrite set confirm -set pastetoggle= set shortmess=atI set visualbell " stop Vim from beeping at me " set cursorline " Highlight the current line " Maintain the undo history even after the file is closed. -" Without an explicit undodir, Vim writes .un~ files next to the source — which -" inside the homesick castle means symlinks back into ~/Library, etc. The // -" suffix encodes the full path in the filename so undo histories don't collide. +" Neovim's default undodir (~/.local/state/nvim/undo//) lives outside the +" homesick castle and is auto-created, so no explicit undodir is needed. set undofile -set undodir=~/.vim/undo// -if !isdirectory(expand(&undodir)) - call mkdir(expand(&undodir), 'p') -endif " Softtabs, 2 spaces set tabstop=2 @@ -139,7 +135,8 @@ syntax on " are both of these necessary? filetype plugin indent on -colorscheme railscasts +set termguicolors +colorscheme new-railscasts map QQ :q map WW :wall diff --git a/home/.zshrc b/home/.zshrc index ea22bf8..cb9dab0 100644 --- a/home/.zshrc +++ b/home/.zshrc @@ -20,7 +20,7 @@ alias be="bundle exec" alias bi="bundle install -j 8" alias bo="bundle outdated" alias bu="bundle update" -alias vim='mvim -v' +alias vim='nvim' alias rrr="bin/rspec" alias rrrore="bin/rspec spec --tag @open_source_risk --tag @flaky --format documentation --format RSpec::Instafail" alias rrroresys="bin/rspec spec/system --tag @open_source_risk --tag @flaky --format documentation --format RSpec::Instafail" diff --git a/init.zsh b/init.zsh index 6bdb7c0..29e69cd 100644 --- a/init.zsh +++ b/init.zsh @@ -11,4 +11,4 @@ # Vundle install cd ~/.homesick/repos/dotfiles/ -vim +BundleInstall +qall +nvim +PluginInstall +qall