diff --git a/NAVIGATION_MODE_PLAN.md b/NAVIGATION_MODE_PLAN.md new file mode 100644 index 0000000..608f3cd --- /dev/null +++ b/NAVIGATION_MODE_PLAN.md @@ -0,0 +1,216 @@ +# 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)