-
Notifications
You must be signed in to change notification settings - Fork 0
Replace leap.nvim with lightweight inline 2-character motion plugin #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -132,6 +132,162 @@ end | |||||||||||||
| vim.defer_fn(setup_fast_cursor_move, 500) | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| -------------------------------------------------------------------------------- | ||||||||||||||
| -- Static Leap: lightweight 2-character motion plugin (inline, no dependencies) | ||||||||||||||
| -- Inspired by leap.nvim - press s/S + 2 chars to jump to a match | ||||||||||||||
| -------------------------------------------------------------------------------- | ||||||||||||||
|
|
||||||||||||||
| local leap_ns = vim.api.nvim_create_namespace("static_leap") | ||||||||||||||
| local leap_labels = "sfnjklhodweimbuyvrgtaqpcxz" | ||||||||||||||
|
|
||||||||||||||
| local function leap_get_input() | ||||||||||||||
| local ok, ch = pcall(vim.fn.getcharstr) | ||||||||||||||
| if not ok or ch == "\27" or ch == "" then return nil end | ||||||||||||||
| return ch | ||||||||||||||
| end | ||||||||||||||
|
|
||||||||||||||
| local function leap_find_matches(pattern, backward, case_sensitive) | ||||||||||||||
| local cursor = vim.api.nvim_win_get_cursor(0) | ||||||||||||||
| local cursor_line = cursor[1] | ||||||||||||||
| local cursor_col = cursor[2] | ||||||||||||||
| local top = vim.fn.line("w0") | ||||||||||||||
| local bot = vim.fn.line("w$") | ||||||||||||||
| local matches = {} | ||||||||||||||
|
|
||||||||||||||
| local search_pat = case_sensitive and pattern or pattern:lower() | ||||||||||||||
|
|
||||||||||||||
| if backward then | ||||||||||||||
| for lnum = cursor_line, top, -1 do | ||||||||||||||
| local text = vim.api.nvim_buf_get_lines(0, lnum - 1, lnum, false)[1] or "" | ||||||||||||||
| local search_text = case_sensitive and text or text:lower() | ||||||||||||||
| local line_matches = {} | ||||||||||||||
| local start = 1 | ||||||||||||||
| while true do | ||||||||||||||
| local s = search_text:find(search_pat, start, true) | ||||||||||||||
| if not s then break end | ||||||||||||||
| local col = s - 1 | ||||||||||||||
| if not (lnum == cursor_line and col >= cursor_col) then | ||||||||||||||
| table.insert(line_matches, { lnum = lnum, col = col }) | ||||||||||||||
| end | ||||||||||||||
| start = s + 1 | ||||||||||||||
| end | ||||||||||||||
| -- Closest to cursor first (reverse within line for backward) | ||||||||||||||
| for i = #line_matches, 1, -1 do | ||||||||||||||
| table.insert(matches, line_matches[i]) | ||||||||||||||
| end | ||||||||||||||
| end | ||||||||||||||
| else | ||||||||||||||
| for lnum = cursor_line, bot do | ||||||||||||||
| local text = vim.api.nvim_buf_get_lines(0, lnum - 1, lnum, false)[1] or "" | ||||||||||||||
| local search_text = case_sensitive and text or text:lower() | ||||||||||||||
| local start = 1 | ||||||||||||||
| while true do | ||||||||||||||
| local s = search_text:find(search_pat, start, true) | ||||||||||||||
| if not s then break end | ||||||||||||||
| local col = s - 1 | ||||||||||||||
| if not (lnum == cursor_line and col <= cursor_col) then | ||||||||||||||
| table.insert(matches, { lnum = lnum, col = col }) | ||||||||||||||
| end | ||||||||||||||
| start = s + 1 | ||||||||||||||
| end | ||||||||||||||
| end | ||||||||||||||
| end | ||||||||||||||
|
|
||||||||||||||
| return matches | ||||||||||||||
| end | ||||||||||||||
|
|
||||||||||||||
| local function setup_static_leap() | ||||||||||||||
| vim.api.nvim_set_hl(0, "LeapMatch", { fg = "#000000", bg = "#ccff88", bold = true }) | ||||||||||||||
|
||||||||||||||
| vim.api.nvim_set_hl(0, "LeapMatch", { fg = "#000000", bg = "#ccff88", bold = true }) |
Copilot
AI
Feb 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The operator-pending mode handling may not work correctly. When in operator-pending mode (e.g., after pressing 'd' for delete), this code enters visual mode with 'v' and then moves the cursor. However, entering visual mode while an operator is pending may cancel the operator rather than applying it to the selected range. This should be tested with operators like 'd', 'y', and 'c'. If it doesn't work, consider using a different approach such as setting marks and using motion commands, or checking the v:operator variable and handling it explicitly.
| -- Force inclusive motion in operator-pending mode | |
| if vim.fn.mode(true):match("o") then | |
| vim.cmd("normal! v") | |
| end | |
| -- In operator-pending mode, avoid entering Visual mode, as that would cancel the operator. | |
| -- Instead, just move the cursor so the pending operator uses this motion. |
Copilot
AI
Feb 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same operator-pending mode issue as lines 243-244. The operator may not correctly apply to the selected range when using this approach.
| if vim.fn.mode(true):match("o") then | |
| vim.cmd("normal! v") | |
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The search algorithm has a potential performance issue when searching large visible regions with many matches. For each line, the code searches for all occurrences of the pattern by repeatedly calling
string.findwithstart = s + 1. In the worst case (e.g., searching for a very common two-character pattern like " " (two spaces) in a large file with many spaces), this could result in hundreds of matches being found and labeled. Consider adding a configurable limit on the maximum number of matches to find (e.g., stop after finding 50-100 matches) to prevent performance degradation.