diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 00000000..50205cb8 --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,156 @@ +# Migration Checklist - Neovim Config Refactor + +## Current State ✅ +- [x] Working Python LSP (pyright) +- [x] Working Flutter LSP (dartls) +- [x] Lazy-loaded language profiles +- [x] Common plugins loaded globally +- [x] ~1200 line init.lua (needs refactoring) + +## Phase 1: Understand Your Config (Before Refactoring) +- [ ] Read through entire `init.lua` - understand every line +- [ ] List all plugins you actually use (vs installed) +- [ ] Identify startup bottlenecks: `nvim --startuptime startup.log` +- [ ] Document your most-used keybindings +- [ ] Run `:checkhealth` to verify everything works + +## Phase 2: Extract Configuration (Low Risk) +- [ ] Create `lua/config/options.lua` - Move all `vim.opt` settings +- [ ] Create `lua/config/keymaps.lua` - Move global keymaps +- [ ] Create `lua/config/autocmds.lua` - Move global autocmds +- [ ] Update `init.lua` to require these modules +- [ ] Test: Restart nvim, verify everything works + +## Phase 3: Reorganize Plugins (Medium Risk) +- [ ] Create `lua/plugins/core/` directory structure +- [ ] Move UI plugins to `core/ui.lua` +- [ ] Move editor plugins to `core/editor.lua` +- [ ] Move git plugins to `core/git.lua` +- [ ] Move completion to `core/completion.lua` +- [ ] Test after EACH move - don't batch them! + +## Phase 4: Refactor LSP (High Risk - Do Last!) +- [ ] Create `lua/plugins/lsp/init.lua` for mason setup +- [ ] Create `lua/plugins/lsp/servers.lua` for general servers (lua_ls) +- [ ] Move language-specific LSP to their lang files +- [ ] Create `lua/util/lsp.lua` for shared utilities +- [ ] Test each language: Python, Flutter, Svelte + +## Phase 5: Cleanup +- [ ] Remove unused plugins (check with `:Lazy`) +- [ ] Remove duplicate code +- [ ] Add comments explaining WHY, not WHAT +- [ ] Update README.md with your structure +- [ ] Profile startup time - compare before/after + +## Testing Checklist (Run After Each Phase) +- [ ] Python: Open .py file, verify pyright loads, test completion +- [ ] Flutter: Open .dart file, verify dartls loads, test completion +- [ ] Svelte: Open .svelte file, verify svelte-ls loads +- [ ] Git: Open a git repo, test gitsigns +- [ ] Telescope: Test fuzzy finding (sf) +- [ ] LSP: Test go-to-definition, hover, rename +- [ ] Formatting: Test format-on-save +- [ ] Sessions: Test session save/restore + +## Rollback Plan +```bash +# Before starting, create a backup branch +cd ~/.config/nvim +git checkout -b refactor-backup +git checkout -b refactor-attempt + +# If something breaks: +git checkout refactor-backup +``` + +## Performance Targets +| Metric | Before | Target | After | +|--------|--------|--------|-------| +| Startup time | ? ms | <100ms | ? ms | +| Plugins loaded on startup | ? | <30 | ? | +| Time to first edit | ? ms | <200ms | ? ms | + +Measure with: +```bash +nvim --startuptime startup.log +# Check the last line for total time +``` + +## When NOT to Refactor +- [ ] You don't understand why your current config works +- [ ] You're in the middle of a project deadline +- [ ] Your startup time is already <50ms +- [ ] You haven't backed up your config + +## When TO Refactor +- [x] Your init.lua is >500 lines (yours is 1200!) +- [x] You have duplicate code across files +- [x] You're adding a 4th+ language (you have 3) +- [x] Startup time is >200ms +- [x] You want to understand how Neovim works + +## Expected Benefits +- Faster startup (lazy-loading) +- Easier to add new languages (template) +- Easier to debug (modular) +- Easier to share/document +- Better understanding of Neovim + +## Expected Challenges +- LSP loading timing issues (we already solved this!) +- Plugin dependency conflicts +- Breaking changes in lazy.nvim API +- Time investment (plan 4-6 hours) + +--- + +## Quick Win: Do This First (30 minutes) + +1. **Extract options** (lowest risk, immediate clarity): +```lua +-- lua/config/options.lua +vim.g.mapleader = ' ' +vim.g.maplocalleader = ' ' +vim.g.have_nerd_font = true +vim.opt.number = true +vim.opt.relativenumber = true +-- ... all your vim.opt settings +``` + +2. **Extract keymaps**: +```lua +-- lua/config/keymaps.lua +-- Escape closes floating windows +vim.keymap.set('n', '', function() + -- ... your escape logic +end) +``` + +3. **Update init.lua**: +```lua +-- NEW init.lua (first 3 lines!) +require('config.options') +require('config.keymaps') +-- ... rest stays the same for now +``` + +This alone will make your init.lua 200 lines shorter and much clearer! + +--- + +## Resources to Keep Handy +- [Lazy.nvim Spec](https://lazy.folke.io/spec) +- [:help lua-guide](https://neovim.io/doc/user/lua-guide.html) +- [Your ORGANIZATION.md](./ORGANIZATION.md) +- [Kickstart.nvim](https://github.com/nvim-lua/kickstart.nvim) (reference only) + +--- + +**Remember:** Refactoring is optional. Your current setup WORKS. Only refactor if: +1. You want to learn more about Neovim +2. You want to add many more languages +3. Your startup time bothers you +4. You enjoy organizing code + +Good luck! 🚀 diff --git a/ORGANIZATION.md b/ORGANIZATION.md new file mode 100644 index 00000000..debe8763 --- /dev/null +++ b/ORGANIZATION.md @@ -0,0 +1,389 @@ +# Neovim Configuration Organization Guide + +## Current Structure (What You Have) + +``` +~/.config/nvim/ +├── init.lua # Main entry point (1200 lines - TOO LARGE!) +├── lua/ +│ ├── custom/ +│ │ └── plugins/ +│ │ ├── init.lua # Common plugins (all filetypes) +│ │ ├── flutter.lua # Flutter-specific (lazy-loaded) +│ │ ├── python.lua # Python-specific (lazy-loaded) +│ │ ├── svelte.lua # Svelte-specific (lazy-loaded) +│ │ └── session.lua # Session management +│ └── kickstart/ +│ ├── health.lua +│ └── plugins/ +│ ├── autopairs.lua +│ ├── debug.lua +│ ├── gitsigns.lua +│ ├── indent_line.lua +│ ├── lint.lua +│ └── neo-tree.lua +``` + +## Problems with Current Setup + +1. **`init.lua` is massive (1200 lines)** - Should be split into modules +2. **LSP setup is duplicated** - Language-specific LSP code is in `init.lua` instead of language files +3. **Unclear separation** - What belongs in `custom/` vs `kickstart/`? +4. **No clear loading strategy** - Which plugins load when? + +--- + +## Recommended Structure (Optimal Organization) + +``` +~/.config/nvim/ +├── init.lua # THIN entry point (~50 lines) +│ +├── lua/ +│ ├── config/ +│ │ ├── options.lua # Vim options (set, opt) +│ │ ├── keymaps.lua # Global keymaps +│ │ ├── autocmds.lua # Global autocmds +│ │ └── lazy.lua # Lazy.nvim bootstrap +│ │ +│ ├── plugins/ +│ │ ├── core/ +│ │ │ ├── ui.lua # UI plugins (always loaded) +│ │ │ ├── editor.lua # Editor enhancements (always loaded) +│ │ │ ├── git.lua # Git tools (always loaded) +│ │ │ └── completion.lua # Completion engine (always loaded) +│ │ │ +│ │ ├── lsp/ +│ │ │ ├── init.lua # LSP infrastructure (mason, lspconfig) +│ │ │ ├── servers.lua # General LSP servers (lua_ls, etc.) +│ │ │ └── keymaps.lua # LSP keymaps (shared) +│ │ │ +│ │ └── lang/ +│ │ ├── python.lua # Python: LSP + formatters + linters +│ │ ├── flutter.lua # Flutter: LSP + debugging + tools +│ │ ├── svelte.lua # Svelte: LSP + formatters +│ │ ├── go.lua # Future: Go support +│ │ └── rust.lua # Future: Rust support +│ │ +│ └── util/ +│ ├── lsp.lua # Shared LSP utilities +│ └── init.lua # Shared helper functions +``` + +--- + +## How This Works: Lazy-Loading Strategy + +### 1. **Core Plugins (Always Loaded)** +```lua +-- lua/plugins/core/editor.lua +return { + { 'echasnovski/mini.pairs' }, -- Autopairs + { 'folke/which-key.nvim' }, -- Keybinding helper + { 'nvim-telescope/telescope.nvim' }, -- Fuzzy finder +} +``` + +### 2. **LSP Infrastructure (Loaded Early)** +```lua +-- lua/plugins/lsp/init.lua +return { + 'neovim/nvim-lspconfig', + dependencies = { 'mason.nvim', 'mason-lspconfig.nvim' }, + config = function() + -- Setup mason, but don't configure language servers here + require('mason').setup() + require('mason-lspconfig').setup() + end, +} +``` + +### 3. **Language-Specific (Lazy-Loaded by FileType)** +```lua +-- lua/plugins/lang/python.lua +return { + -- Mason tools + { + 'WhoIsSethDaniel/mason-tool-installer.nvim', + ft = 'python', + config = function() + require('mason-tool-installer').setup({ + ensure_installed = { 'pyright', 'ruff' } + }) + end, + }, + + -- LSP setup + { + 'neovim/nvim-lspconfig', + ft = 'python', + config = function() + -- Start pyright via autocmd + vim.api.nvim_create_autocmd('FileType', { + pattern = 'python', + callback = function(args) + local capabilities = require('blink.cmp').get_lsp_capabilities() + vim.lsp.start({ + name = 'pyright', + cmd = { vim.fn.stdpath('data') .. '/mason/bin/pyright-langserver', '--stdio' }, + root_dir = vim.fs.root(args.buf, { 'pyproject.toml', 'setup.py', '.git' }), + capabilities = capabilities, + }) + end, + }) + end, + }, + + -- Formatters + { + 'stevearc/conform.nvim', + ft = 'python', + config = function() + require('conform').formatters_by_ft.python = { 'ruff_format', 'ruff_organize_imports' } + end, + }, +} +``` + +--- + +## Migration Plan (Step-by-Step) + +### Phase 1: Extract Configuration from init.lua +```lua +-- NEW init.lua (50 lines instead of 1200!) +require('config.options') -- Vim settings +require('config.keymaps') -- Global keymaps +require('config.autocmds') -- Global autocmds +require('config.lazy') -- Bootstrap lazy.nvim and load plugins +``` + +### Phase 2: Organize Plugins by Loading Strategy + +**Always Loaded (Core):** +- `lua/plugins/core/ui.lua` - colorscheme, statusline, bufferline +- `lua/plugins/core/editor.lua` - telescope, which-key, autopairs, neo-tree +- `lua/plugins/core/git.lua` - gitsigns, fugitive +- `lua/plugins/core/completion.lua` - blink.cmp + +**Lazy-Loaded by FileType:** +- `lua/plugins/lang/python.lua` - ft = 'python' +- `lua/plugins/lang/flutter.lua` - ft = { 'dart', 'flutter' } +- `lua/plugins/lang/svelte.lua` - ft = 'svelte' + +**Lazy-Loaded by Command:** +- Debugging tools - cmd = { 'DapContinue', 'DapToggleBreakpoint' } +- Session management - cmd = { 'SessionSave', 'SessionLoad' } + +### Phase 3: Fix LSP Loading Issue + +**Problem:** You discovered that language-specific LSP configs in lazy-loaded files don't work because `nvim-lspconfig` is already loaded by `init.lua`. + +**Solution:** Two approaches: + +#### Option A: Centralized LSP Setup (Simpler) +```lua +-- lua/plugins/lsp/servers.lua +local M = {} + +M.setup_python = function() + -- Python LSP setup +end + +M.setup_flutter = function() + -- Flutter LSP setup +end + +-- Autocmds to trigger setup +vim.api.nvim_create_autocmd('FileType', { + pattern = 'python', + once = true, + callback = M.setup_python, +}) +``` + +#### Option B: Per-Language Setup (Cleaner but Complex) +```lua +-- lua/plugins/lang/python.lua +return { + { + 'WhoIsSethDaniel/mason-tool-installer.nvim', + ft = 'python', + config = function() + -- Install tools + require('mason-tool-installer').setup({ ensure_installed = { 'pyright', 'ruff' }}) + + -- Setup LSP via autocmd (since lspconfig is already loaded) + vim.api.nvim_create_autocmd('FileType', { + pattern = 'python', + callback = function(args) + require('util.lsp').start_server('pyright', args.buf, { + settings = { python = { analysis = { typeCheckingMode = 'basic' }}} + }) + end, + }) + end, + }, +} + +-- lua/util/lsp.lua (shared utility) +local M = {} + +M.start_server = function(name, bufnr, opts) + local clients = vim.lsp.get_clients({ bufnr = bufnr, name = name }) + if #clients > 0 then return end + + local capabilities = require('blink.cmp').get_lsp_capabilities() + vim.lsp.start(vim.tbl_deep_extend('force', { + name = name, + capabilities = capabilities, + }, opts)) +end + +return M +``` + +--- + +## Loading Performance Best Practices + +### 1. Use Lazy-Loading Triggers + +```lua +-- ❌ BAD: Loads immediately on startup +{ 'some/plugin' } + +-- ✅ GOOD: Loads only when needed +{ 'some/plugin', ft = 'python' } -- When opening .py files +{ 'some/plugin', cmd = 'SomeCommand' } -- When running :SomeCommand +{ 'some/plugin', keys = 'x' } -- When pressing x +{ 'some/plugin', event = 'VeryLazy' } -- After startup (low priority) +``` + +### 2. Profile Your Startup Time + +```bash +# Measure startup time +nvim --startuptime startup.log + +# Find slow plugins +grep "sourcing" startup.log | sort -k2 -n +``` + +### 3. Use `:Lazy` to Monitor Loading + +- Green plugins = loaded +- Gray plugins = not loaded yet (lazy) +- See what triggered loading + +--- + +## Recommended Final Structure + +``` +~/.config/nvim/ +├── init.lua # ~50 lines: require config modules +│ +├── lua/ +│ ├── config/ +│ │ ├── options.lua # set.number, opt.clipboard, etc. +│ │ ├── keymaps.lua # Global keymaps only +│ │ ├── autocmds.lua # Global autocmds only +│ │ └── lazy.lua # Bootstrap lazy.nvim +│ │ +│ ├── plugins/ +│ │ ├── core/ +│ │ │ ├── ui.lua # Colorscheme, statusline, etc. +│ │ │ ├── editor.lua # Telescope, which-key, autopairs +│ │ │ ├── git.lua # Gitsigns, fugitive +│ │ │ └── completion.lua # blink.cmp +│ │ │ +│ │ ├── lsp/ +│ │ │ ├── init.lua # Mason, lspconfig setup +│ │ │ ├── servers.lua # lua_ls and other general servers +│ │ │ └── keymaps.lua # LSP keymaps (on_attach) +│ │ │ +│ │ └── lang/ +│ │ ├── python.lua # ft = 'python' +│ │ ├── flutter.lua # ft = 'dart' +│ │ └── svelte.lua # ft = 'svelte' +│ │ +│ └── util/ +│ ├── lsp.lua # Shared LSP helpers +│ └── init.lua # Shared utility functions +│ +├── ORGANIZATION.md # This file +├── MIGRATION.md # Step-by-step migration guide +└── README.md # Your custom README +``` + +--- + +## Key Principles + +1. **Thin `init.lua`** - Just require modules, no logic +2. **Separate concerns** - Options, keymaps, autocmds, plugins +3. **Lazy-load everything possible** - Use `ft`, `cmd`, `keys`, `event` +4. **Language files are independent** - Each lang/ file is self-contained +5. **Share common code** - Use `util/` for helpers +6. **Profile regularly** - Use `:Lazy profile` and `--startuptime` + +--- + +## Learning Resources + +### Understanding Neovim Configuration +- `:help lua-guide` - Official Lua guide +- `:help options` - All vim options +- `:help api` - Lua API reference + +### Lazy-Loading +- `:help lazy.nvim` - Lazy.nvim documentation +- `:Lazy profile` - See what's slow +- `:Lazy` - Interactive plugin manager + +### LSP +- `:help lsp` - LSP overview +- `:help vim.lsp.start()` - Start LSP servers +- `:LspInfo` - See active LSP clients + +### Performance +- `nvim --startuptime startup.log` - Measure startup +- `:profile start profile.log | profile func * | profile file *` - Profile runtime + +--- + +## Next Steps + +1. **Commit current working state** ✅ (You're doing this now) +2. **Read through this guide** to understand the concepts +3. **Try the migration in a branch** (don't break your working config!) +4. **Migrate incrementally**: + - Step 1: Extract options/keymaps from init.lua + - Step 2: Move plugins to core/ structure + - Step 3: Refactor language-specific configs +5. **Test after each step** - Make sure everything still works +6. **Profile before and after** - Measure improvements + +--- + +## Questions to Consider + +1. **Do you need kickstart/ folder anymore?** + - If you understand the code, merge it into your own structure + +2. **How many languages will you support?** + - 3-5 languages: Current structure is fine + - 10+ languages: Consider more sophisticated loading + +3. **Do you want to share your config?** + - Yes: Document everything, make it modular + - No: Optimize for your own workflow + +4. **How often will you add new languages?** + - Frequently: Build a template system + - Rarely: Current per-file approach works + +--- + +**Remember:** This is YOUR config. Start with what works, refactor when you understand WHY you're refactoring. Don't cargo-cult someone else's structure!