Add navigation mode feature plan documentation
Introduce a comprehensive plan for a custom navigation mode in Neovim, detailing user experience, technical implementation, and visual feedback options.
This commit is contained in:
parent
d2ff40df16
commit
8e2b71c7f1
|
|
@ -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
|
||||||
|
- `<Esc>` - 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', '<Esc>', 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', '<Esc>')
|
||||||
|
|
||||||
|
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 `<Esc>`
|
||||||
|
- [ ] No residual mappings after exit
|
||||||
|
- [ ] Works across different buffers
|
||||||
|
- [ ] Visual feedback is clear
|
||||||
|
- [ ] Common navigation pairs work (c, d, m, f, q)
|
||||||
Loading…
Reference in New Issue