# Navigation Mode Feature Plan ## Concept A custom navigation mode where keypresses are automatically prefixed with `[` or `]`, making it easier to navigate using Neovim's bracket-based navigation pairs without repeatedly typing brackets. ## User Experience ### Entry - `z[` - Enter navigation mode with `[` prefix active (backward) - `z]` - Enter navigation mode with `]` prefix active (forward) ### In Mode - All letter keys (`a-z`, `A-Z`) get prefixed with current bracket - Examples: - Press `c` → executes `[c` or `]c` (git hunks) - Press `d` → executes `[d` or `]d` (diagnostics) - Press `m` → executes `[m` or `]m` (methods) - Press `f` → executes `[f` or `]f` (functions) - Press `b` → executes `[b` or `]b` (buffers) - Press `q` → executes `[q` or `]q` (quickfix) ### Toggle Prefix - `[` - Switch to `[` prefix (backward navigation) - `]` - Switch to `]` prefix (forward navigation) ### Exit - `` - Exit navigation mode and restore normal mappings ## Technical Implementation ### State Management ```lua local NavMode = { active = false, prefix = '[', -- '[' or ']' } ``` ### Key Remapping Strategy 1. Store original mappings for letters a-z, A-Z 2. On mode entry, create new mappings: `key → prefix .. key` 3. On mode exit, restore original mappings 4. On prefix toggle, update all mappings with new prefix ### Keys to Remap - Lowercase: `a-z` (26 keys) - Uppercase: `A-Z` (26 keys) - Total: 52 keys dynamically remapped ### Common Bracket Navigation Pairs - `[c`/`]c` - Previous/next git hunk (gitsigns) - `[d`/`]d` - Previous/next diagnostic - `[b`/`]b` - Previous/next buffer (custom mapping) - `[q`/`]q` - Previous/next quickfix item - `[l`/`]l` - Previous/next location list item - `[m`/`]m` - Previous/next method (treesitter textobjects) - `[f`/`]f` - Previous/next function (treesitter textobjects) - `[p`/`]p` - Previous/next parameter (treesitter textobjects) - `[t`/`]t` - Previous/next tag ## Implementation Details ### Module Structure Create `lua/navigation-mode.lua`: ```lua local M = {} local state = { active = false, prefix = '[', stored_mappings = {}, } local LETTERS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' function M.enter(prefix) if state.active then return end state.prefix = prefix or '[' state.active = true -- Store original mappings and create prefixed ones for i = 1, #LETTERS do local key = LETTERS:sub(i, i) -- Store original mapping (if exists) -- Create new mapping: key → prefix .. key vim.keymap.set('n', key, state.prefix .. key, { noremap = true, silent = true }) end -- Special mappings for [ and ] to toggle prefix vim.keymap.set('n', '[', function() M.set_prefix('[') end, { noremap = true, silent = true }) vim.keymap.set('n', ']', function() M.set_prefix(']') end, { noremap = true, silent = true }) -- Exit mapping vim.keymap.set('n', '', function() M.exit() end, { noremap = true, silent = true }) -- TODO: Set visual feedback (statusline, notification, etc.) end function M.set_prefix(new_prefix) if not state.active then return end state.prefix = new_prefix -- Remap all letters with new prefix for i = 1, #LETTERS do local key = LETTERS:sub(i, i) vim.keymap.set('n', key, state.prefix .. key, { noremap = true, silent = true }) end -- TODO: Update visual feedback end function M.exit() if not state.active then return end -- Restore original mappings for i = 1, #LETTERS do local key = LETTERS:sub(i, i) vim.keymap.del('n', key) -- Restore stored mapping if it existed end -- Clean up special mappings vim.keymap.del('n', '[') vim.keymap.del('n', ']') vim.keymap.del('n', '') state.active = false -- TODO: Clear visual feedback end return M ``` ### Integration in keymaps.lua ```lua -- Navigation mode vim.keymap.set('n', 'z[', function() require('navigation-mode').enter('[') end, { desc = 'Enter navigation mode (backward)' }) vim.keymap.set('n', 'z]', function() require('navigation-mode').enter(']') end, { desc = 'Enter navigation mode (forward)' }) ``` ## Visual Feedback Options (TODO) Need to decide on one or more: 1. **Statusline indicator**: Show `[NAV ←]` or `[NAV →]` in statusline 2. **Notification**: Brief message on mode entry/exit 3. **Command line**: `echo` message showing current prefix 4. **Cursor highlight**: Change cursor color/shape 5. **Virtual text**: Floating indicator in corner of window ## Open Questions 1. **Mapping conflicts**: How to handle if a letter already has a mapping? - Overwrite temporarily? - Skip that letter? - Warn user? 2. **Buffer-local mappings**: Should mode respect buffer-local mappings? - Store and restore per-buffer? - Global mode only? 3. **Visual feedback**: Which approach is clearest without being intrusive? 4. **Number keys**: Should `0-9` also be prefixed? - Useful for some navigation pairs - But might conflict with counts 5. **Operators**: Should `d`, `c`, `y` still work as operators or only as navigation? - Current plan: They become navigation only while in mode - Trade-off: Can't delete/change while navigating ## Implementation Phases 1. **Core functionality** (essential) - Mode enter/exit - Key remapping for a-z - Prefix toggle - Basic state management 2. **Visual feedback** (important) - Choose and implement feedback mechanism - Ensure clarity when mode is active 3. **Edge cases** (polish) - Handle existing mappings gracefully - Buffer-local mapping preservation - Mode timeout/auto-exit? 4. **Documentation** (completion) - Update README.md with keymaps - Add examples of useful navigation pairs - Consider adding to help docs ## Estimated Complexity - **Core**: ~100-150 lines of Lua - **Visual feedback**: +20-50 lines depending on approach - **Edge case handling**: +30-50 lines - **Total**: 150-250 lines ## Testing Checklist - [ ] Enter mode with `z[` and `z]` - [ ] Verify letter keys are prefixed correctly - [ ] Toggle between `[` and `]` prefix - [ ] Exit cleanly with `` - [ ] No residual mappings after exit - [ ] Works across different buffers - [ ] Visual feedback is clear - [ ] Common navigation pairs work (c, d, m, f, q)