aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim
diff options
context:
space:
mode:
authorneeshy <60193883+neeshy@users.noreply.github.com>2025-02-09 16:23:30 -0500
committerGitHub <noreply@github.com>2025-02-09 13:23:30 -0800
commit59a171fd99a7452c8840eee55783fb6746994637 (patch)
tree426c9455c6f6a250e015a460dd232ed26d603b9f /runtime/lua/vim
parentac207c3ac20026baa2a4561f5365c2af6a38a357 (diff)
downloadrneovim-59a171fd99a7452c8840eee55783fb6746994637.tar.gz
rneovim-59a171fd99a7452c8840eee55783fb6746994637.tar.bz2
rneovim-59a171fd99a7452c8840eee55783fb6746994637.zip
fix(defaults): improve visual search mappings #32378
Problem: The behavior of the visual search mappings aren't consistent with their normal mode counterparts. - The count isn't considered - Searching with an empty selection will match every character in the buffer - Searching backwards only jumps back when the cursor is positioned at the start of the selection. Solution: - Issue `n` `v:count1` times - Error out and exit visual mode when the selection is empty - Detect when the cursor is not at the start of the selection, and adjust the count accordingly Also, use the search register instead of the more error-prone approach of feeding the entire search string as an expression
Diffstat (limited to 'runtime/lua/vim')
-rw-r--r--runtime/lua/vim/_defaults.lua48
1 files changed, 37 insertions, 11 deletions
diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua
index b1e5687d74..afcc2cfc73 100644
--- a/runtime/lua/vim/_defaults.lua
+++ b/runtime/lua/vim/_defaults.lua
@@ -32,27 +32,53 @@ do
---
--- See |v_star-default| and |v_#-default|
do
- local function _visual_search(cmd)
- assert(cmd == '/' or cmd == '?')
- local chunks =
- vim.fn.getregion(vim.fn.getpos('.'), vim.fn.getpos('v'), { type = vim.fn.mode() })
+ local function _visual_search(forward)
+ assert(forward == 0 or forward == 1)
+ local pos = vim.fn.getpos('.')
+ local vpos = vim.fn.getpos('v')
+ local mode = vim.fn.mode()
+ local chunks = vim.fn.getregion(pos, vpos, { type = mode })
local esc_chunks = vim
.iter(chunks)
:map(function(v)
- return vim.fn.escape(v, cmd == '/' and [[/\]] or [[?\]])
+ return vim.fn.escape(v, [[\]])
end)
:totable()
local esc_pat = table.concat(esc_chunks, [[\n]])
- local search_cmd = ([[%s\V%s%s]]):format(cmd, esc_pat, '\n')
- return '\27' .. search_cmd
+ if #esc_pat == 0 then
+ vim.api.nvim_echo({ { 'E348: No string under cursor' } }, true, { err = true })
+ return '<Esc>'
+ end
+ local search = [[\V]] .. esc_pat
+
+ vim.fn.setreg('/', search)
+ vim.fn.histadd('/', search)
+ vim.v.searchforward = forward
+
+ -- The count has to be adjusted when searching backwards and the cursor
+ -- isn't positioned at the beginning of the selection
+ local count = vim.v.count1
+ if forward == 0 then
+ local _, line, col, _ = unpack(pos)
+ local _, vline, vcol, _ = unpack(vpos)
+ if
+ line > vline
+ or mode == 'v' and line == vline and col > vcol
+ or mode == 'V' and col ~= 1
+ or mode == '\22' and col > vcol
+ then
+ count = count + 1
+ end
+ end
+ return '<Esc>' .. count .. 'n'
end
vim.keymap.set('x', '*', function()
- return _visual_search('/')
- end, { desc = ':help v_star-default', expr = true, replace_keycodes = false })
+ return _visual_search(1)
+ end, { desc = ':help v_star-default', expr = true })
vim.keymap.set('x', '#', function()
- return _visual_search('?')
- end, { desc = ':help v_#-default', expr = true, replace_keycodes = false })
+ return _visual_search(0)
+ end, { desc = ':help v_#-default', expr = true })
end
--- Map Y to y$. This mimics the behavior of D and C. See |Y-default|