nvim-hlslens
nvim-hlslens copied to clipboard
Hlsearch Lens for Neovim
nvim-hlslens
nvim-hlslens helps you better glance at matched information, seamlessly jump between matched instances.
Table of contents
- Table of contents
- Features
-
Quickstart
- Requirements
- Installation
- Minimal configuration
-
Usage
- 3 ways to start hlslens
- Stop hlslens
-
Documentation
- Setup and description
- Highlight
- Commands
-
Advanced configuration
- Customize configuration
- Customize virtual text
- Integrate with other plugins
- Feedback
- License
Features
- Fully customizable style of virtual text
- Clear highlighting and virtual text when cursor is out of range
- Display search result dynamically while cursor is moving
- Display search result for the current matched instance while searching
- Display search result for some built-in commands that support incsearch (need Neovim 0.8.0)
Need
vim.api.nvim_parse_cmd
to pick up built-in commands in command line mode.
Quickstart
Requirements
- Neovim 0.61 or later
Installation
Install nvim-hlslens with Packer.nvim:
use {'kevinhwang91/nvim-hlslens'}
Minimal configuration
require('hlslens').setup()
local kopts = {noremap = true, silent = true}
vim.api.nvim_set_keymap('n', 'n',
[[<Cmd>execute('normal! ' . v:count1 . 'n')<CR><Cmd>lua require('hlslens').start()<CR>]],
kopts)
vim.api.nvim_set_keymap('n', 'N',
[[<Cmd>execute('normal! ' . v:count1 . 'N')<CR><Cmd>lua require('hlslens').start()<CR>]],
kopts)
vim.api.nvim_set_keymap('n', '*', [[*<Cmd>lua require('hlslens').start()<CR>]], kopts)
vim.api.nvim_set_keymap('n', '#', [[#<Cmd>lua require('hlslens').start()<CR>]], kopts)
vim.api.nvim_set_keymap('n', 'g*', [[g*<Cmd>lua require('hlslens').start()<CR>]], kopts)
vim.api.nvim_set_keymap('n', 'g#', [[g#<Cmd>lua require('hlslens').start()<CR>]], kopts)
vim.api.nvim_set_keymap('n', '<Leader>l', ':noh<CR>', kopts)
Usage
After using Minimal configuration:
Hlslens will add virtual text at the end of the line if the room is enough for virtual text, otherwise, add a floating window to overlay the statusline to display lens.
You can glance at the result provided by lens while searching when incsearch
is on. Hlslens also
supports <C-g>
and <C-t>
to move to the next and previous match.
3 ways to start hlslens
- Press
/
or?
to search text,/s
and/e
offsets are supported - Press
n
orN
to jump to the instance matched by last pattern - Press
*
,#
,g*
org#
to search word nearest to the cursor
run ex command :help search-commands for more information.
Stop hlslens
Hlslens will observe whether nohlsearch
command is accepted.
- Run ex command
nohlsearch
- Map key to
:nohlsearch
, make sure that to use:
instead of<Cmd>
Documentation
Setup and description
{
auto_enable = {
description = [[Enable nvim-hlslens automatically]],
default = true
},
enable_incsearch = {
description = [[When `incsearch` option is on and enable_incsearch is true, add lens
for the current matched instance]],
default = true
},
calm_down = {
description = [[If calm_down is true, clear all lens and highlighting When the cursor is
out of the position range of the matched instance or any texts are changed]],
default = false,
},
nearest_only = {
description = [[Only add lens for the nearest matched instance and ignore others]],
default = false
},
nearest_float_when = {
description = [[When to open the floating window for the nearest lens.
'auto': floating window will be opened if room isn't enough for virtual text;
'always': always use floating window instead of virtual text;
'never': never use floating window for the nearest lens]],
default = 'auto',
},
float_shadow_blend = {
description = [[Winblend of the nearest floating window. `:h winbl` for more details]],
default = 50,
},
virt_priority = {
description = [[Priority of virtual text, set it lower to overlay others.
`:h nvim_buf_set_extmark` for more details]],
default = 100,
},
override_lens = {
description = [[Hackable function for customizing the lens. If you like hacking, you
should search `override_lens` and inspect the corresponding source code.
There's no guarantee that this function will not be changed in the future. If it is
changed, it will be listed in the CHANGES file.
@param render table an inner module for hlslens, use `setVirt` to set virtual text
@param splist table (1,1)-indexed position
@param nearest boolean whether nearest lens
@param idx number nearest index in the plist
@param relIdx number relative index, negative means before current position,
positive means after
]],
default = nil
},
}
Highlight
hi default link HlSearchNear IncSearch
hi default link HlSearchLens WildMenu
hi default link HlSearchLensNear IncSearch
hi default link HlSearchFloat IncSearch
- HlSearchLensNear: highlight the nearest virtual text
- HlSearchLens: highlight virtual text except for the nearest one
- HlSearchNear: highlight the nearest matched instance
- HlSearchFloat: highlight the nearest text for the floating window
Commands
-
HlSearchLensToggle
: Toggle nvim-hlslens enable/disable -
HlSearchLensEnable
: Enable nvim-hlslens -
HlSearchLensDisable
: Disable nvim-hlslens
Advanced configuration
Customize configuration
require('hlslens').setup({
calm_down = true,
nearest_only = true,
nearest_float_when = 'always'
})
Customize virtual text
require('hlslens').setup({
override_lens = function(render, posList, nearest, idx, relIdx)
local sfw = vim.v.searchforward == 1
local indicator, text, chunks
local absRelIdx = math.abs(relIdx)
if absRelIdx > 1 then
indicator = ('%d%s'):format(absRelIdx, sfw ~= (relIdx > 1) and '▲' or '▼')
elseif absRelIdx == 1 then
indicator = sfw ~= (relIdx == 1) and '▲' or '▼'
else
indicator = ''
end
local lnum, col = unpack(posList[idx])
if nearest then
local cnt = #posList
if indicator ~= '' then
text = ('[%s %d/%d]'):format(indicator, idx, cnt)
else
text = ('[%d/%d]'):format(idx, cnt)
end
chunks = {{' ', 'Ignore'}, {text, 'HlSearchLensNear'}}
else
text = ('[%s %d]'):format(indicator, idx)
chunks = {{' ', 'Ignore'}, {text, 'HlSearchLens'}}
end
render.setVirt(0, lnum - 1, col - 1, chunks, nearest)
end
})
Integrate with other plugins
vim-asterisk
-- packer
use 'haya14busa/vim-asterisk'
vim.api.nvim_set_keymap('n', '*', [[<Plug>(asterisk-z*)<Cmd>lua require('hlslens').start()<CR>]], {})
vim.api.nvim_set_keymap('n', '#', [[<Plug>(asterisk-z#)<Cmd>lua require('hlslens').start()<CR>]], {})
vim.api.nvim_set_keymap('n', 'g*', [[<Plug>(asterisk-gz*)<Cmd>lua require('hlslens').start()<CR>]], {})
vim.api.nvim_set_keymap('n', 'g#', [[<Plug>(asterisk-gz#)<Cmd>lua require('hlslens').start()<CR>]], {})
vim.api.nvim_set_keymap('x', '*', [[<Plug>(asterisk-z*)<Cmd>lua require('hlslens').start()<CR>]], {})
vim.api.nvim_set_keymap('x', '#', [[<Plug>(asterisk-z#)<Cmd>lua require('hlslens').start()<CR>]], {})
vim.api.nvim_set_keymap('x', 'g*', [[<Plug>(asterisk-gz*)<Cmd>lua require('hlslens').start()<CR>]], {})
vim.api.nvim_set_keymap('x', 'g#', [[<Plug>(asterisk-gz#)<Cmd>lua require('hlslens').start()<CR>]], {})
nvim-ufo
-- packer
use {'kevinhwang91/nvim-ufo', requires = 'kevinhwang91/promise-async'}
-- simply use a global function to demo
function _G.nN(c)
local ok, msg = pcall(vim.cmd, 'norm!' .. vim.v.count1 .. c)
if not ok then
vim.api.nvim_echo({{msg:match(':(.*)$'), 'ErrorMsg'}}, false, {})
return
end
require('hlslens').start()
require('ufo').peekFoldedLinesUnderCursor()
end
vim.api.nvim_set_keymap('n', 'n', '<Cmd>lua _G.nN("n")<CR>', {})
vim.api.nvim_set_keymap('n', 'N', '<Cmd>lua _G.nN("N")<CR>', {})
vim-visual-multi
-- packer
use 'mg979/vim-visual-multi'
vim.cmd([[
aug VMlens
au!
au User visual_multi_start lua require('vmlens').start()
au User visual_multi_exit lua require('vmlens').exit()
aug END
]])
Add vmlens.lua under your lua path, for instance: ~/.config/nvim/lua/vmlens.lua
local M = {}
local hlslens = require('hlslens')
local config
local lensBak
local overrideLens = function(render, posList, nearest, idx, relIdx)
local _ = relIdx
local lnum, col = unpack(posList[idx])
local text, chunks
if nearest then
text = ('[%d/%d]'):format(idx, #posList)
chunks = {{' ', 'Ignore'}, {text, 'VM_Extend'}}
else
text = ('[%d]'):format(idx)
chunks = {{' ', 'Ignore'}, {text, 'HlSearchLens'}}
end
render.setVirt(0, lnum - 1, col - 1, chunks, nearest)
end
function M.start()
if hlslens then
config = require('hlslens.config')
lensBak = config.override_lens
config.override_lens = overrideLens
hlslens.start()
end
end
function M.exit()
if hlslens then
config.override_lens = lensBak
hlslens.start()
end
end
return M
Feedback
- If you get an issue or come up with an awesome idea, don't hesitate to open an issue in github.
- If you think this plugin is useful or cool, consider rewarding it a star.
License
The project is licensed under a BSD-3-clause license. See LICENSE file for details.