mirror of
https://github.com/neovim/neovim.git
synced 2026-04-28 10:14:06 +00:00
feat(help): super K (":help!") guesses tag at cursor #36205
Problem:
`K` in help files may fail in some noisy text. Example:
(`fun(config: vim.lsp.ClientConfig): boolean`)
^cursor
Solution:
- `:help!` (bang, no args) activates DWIM behavior: tries `<cWORD>`,
then trims punctuation until a valid tag is found.
- Set `keywordprg=:help!` by default.
- Does not affect `CTRL-]`, that is still fully "tags" based.
This commit is contained in:
@@ -10,6 +10,34 @@ local mkdir = t.mkdir
|
||||
local rmdir = n.rmdir
|
||||
local write_file = t.write_file
|
||||
|
||||
local cursor = n.api.nvim_win_set_cursor
|
||||
|
||||
local function buf_word()
|
||||
local word = n.fn.expand('<cWORD>')
|
||||
local bufname = n.fn.fnamemodify(n.fn.bufname('%'), ':t')
|
||||
return { word, bufname }
|
||||
end
|
||||
|
||||
local function open_helptag()
|
||||
-- n.exec [[:normal! K]]
|
||||
n.exec [[:help!]]
|
||||
local rv = buf_word()
|
||||
if n.fn.winnr('$') > 1 then
|
||||
n.command('close')
|
||||
end
|
||||
return rv
|
||||
end
|
||||
|
||||
local function set_lines(text)
|
||||
n.exec_lua(
|
||||
[[
|
||||
vim.cmd'%delete _'
|
||||
vim.api.nvim_paste(vim.text.indent(-1, ...), false, -1)
|
||||
]],
|
||||
text
|
||||
)
|
||||
end
|
||||
|
||||
describe(':help', function()
|
||||
before_each(clear)
|
||||
|
||||
@@ -121,6 +149,136 @@ describe(':help', function()
|
||||
check_tag([[help \|]], [[*/\bar*]])
|
||||
end)
|
||||
|
||||
it('":help!" (bang + no args) guesses the best tag near cursor', function()
|
||||
n.command('helptags ++t $VIMRUNTIME/doc')
|
||||
-- n.command('enew')
|
||||
-- n.command('set filetype=help')
|
||||
-- n.command [[set keywordprg=:help]]
|
||||
|
||||
-- Failure modes:
|
||||
set_lines 'xxxxxxxxx'
|
||||
cursor(0, { 1, 4 })
|
||||
t.matches('E149: Sorry, no help for xxxxxxxxx', t.pcall_err(n.exec, [[:help!]]))
|
||||
|
||||
-- Success:
|
||||
|
||||
set_lines 'some plain text'
|
||||
cursor(0, { 1, 5 }) -- on 'plain'
|
||||
eq({ '*ft-plaintex-syntax*', 'syntax.txt' }, open_helptag())
|
||||
|
||||
set_lines ':help command'
|
||||
cursor(0, { 1, 4 })
|
||||
eq({ '*:help*', 'helphelp.txt' }, open_helptag())
|
||||
|
||||
set_lines ' :help command'
|
||||
cursor(0, { 1, 5 })
|
||||
eq({ '*:command*', 'map.txt' }, open_helptag())
|
||||
|
||||
set_lines 'v:version name'
|
||||
cursor(0, { 1, 5 })
|
||||
eq({ '*v:version*', 'vvars.txt' }, open_helptag())
|
||||
cursor(0, { 1, 2 })
|
||||
eq({ '*v:version*', 'vvars.txt' }, open_helptag())
|
||||
|
||||
set_lines "See 'option' for more."
|
||||
cursor(0, { 1, 6 }) -- on 'option'
|
||||
eq({ "*'option'*", 'helphelp.txt' }, open_helptag())
|
||||
|
||||
set_lines ':command-nargs'
|
||||
cursor(0, { 1, 7 }) -- on 'nargs'
|
||||
eq({ '*:command-nargs*', 'map.txt' }, open_helptag())
|
||||
|
||||
set_lines '|("vim.lsp.foldtext()")|'
|
||||
cursor(0, { 1, 10 })
|
||||
eq({ '*vim.lsp.foldtext()*', 'lsp.txt' }, open_helptag())
|
||||
|
||||
set_lines 'nvim_buf_detach_event[{buf}]'
|
||||
cursor(0, { 1, 10 })
|
||||
eq({ '*nvim_buf_detach_event*', 'api.txt' }, open_helptag())
|
||||
|
||||
set_lines '{buf}'
|
||||
cursor(0, { 1, 1 })
|
||||
eq({ '*:buf*', 'windows.txt' }, open_helptag())
|
||||
|
||||
set_lines '(`vim.lsp.ClientConfig`)'
|
||||
cursor(0, { 1, 1 })
|
||||
eq({ '*vim.lsp.ClientConfig*', 'lsp.txt' }, open_helptag())
|
||||
|
||||
set_lines "vim.lsp.enable('clangd')"
|
||||
cursor(0, { 1, 3 })
|
||||
eq({ '*vim.lsp.enable()*', 'lsp.txt' }, open_helptag())
|
||||
|
||||
set_lines "vim.lsp.enable('clangd')"
|
||||
cursor(0, { 1, 6 })
|
||||
eq({ '*vim.lsp.enable()*', 'lsp.txt' }, open_helptag())
|
||||
|
||||
set_lines "vim.lsp.enable('clangd')"
|
||||
cursor(0, { 1, 9 })
|
||||
eq({ '*vim.lsp.enable()*', 'lsp.txt' }, open_helptag())
|
||||
|
||||
set_lines 'assert(vim.lsp.get_client_by_id(client_id))'
|
||||
cursor(0, { 1, 12 })
|
||||
eq({ '*vim.lsp.get_client_by_id()*', 'lsp.txt' }, open_helptag())
|
||||
|
||||
set_lines "vim.api.nvim_create_autocmd('LspAttach', {"
|
||||
cursor(0, { 1, 7 })
|
||||
eq({ '*nvim_create_autocmd()*', 'api.txt' }, open_helptag())
|
||||
|
||||
-- Falls back to <cword> when all trimming fails.
|
||||
set_lines "'@lsp.type.function'"
|
||||
cursor(0, { 1, 2 }) -- on 'lsp'
|
||||
eq({ '*lsp*', 'lsp.txt' }, open_helptag())
|
||||
set_lines "'@lsp.type.function'"
|
||||
cursor(0, { 1, 14 }) -- on 'function'
|
||||
eq({ '*:function*', 'userfunc.txt' }, open_helptag())
|
||||
|
||||
set_lines ' • `@lsp.type.<type>.<ft>` for the type'
|
||||
cursor(0, { 1, 6 }) -- on backtick '`' (byte 6, after 2 spaces + 3-byte '•' + space)
|
||||
eq({ '*lsp*', 'lsp.txt' }, open_helptag())
|
||||
|
||||
set_lines [[
|
||||
- `root_dir` usages akin to >lua
|
||||
root_dir = require'lspconfig.util'.root_pattern(...)
|
||||
<
|
||||
require'lspconfig.util'.root_pattern(...)
|
||||
]]
|
||||
cursor(0, { 2, 17 }) -- on "require"
|
||||
eq({ '*require()*', 'luaref.txt' }, open_helptag())
|
||||
|
||||
set_lines '`:lsp restart`. You'
|
||||
cursor(0, { 1, 6 }) -- on "restart"
|
||||
eq({ '*:restart*', 'gui.txt' }, open_helptag())
|
||||
|
||||
--
|
||||
-- Test with actual helpfiles. This affects getcompletion(…,'help') ...
|
||||
--
|
||||
|
||||
n.command(':help lua')
|
||||
n.feed('gg/package.searchpath<cr>')
|
||||
eq({ "vim.cmd.edit(package.searchpath('jit.p',", 'lua.txt' }, buf_word())
|
||||
-- ^ cursor on "package"
|
||||
n.command(':help!')
|
||||
eq({ '*packages*', 'pack.txt' }, buf_word())
|
||||
|
||||
n.command(':help lsp')
|
||||
n.feed('gg/type.<lt>type><cr>')
|
||||
eq({ '`@lsp.type.<type>.<ft>`', 'lsp.txt' }, buf_word())
|
||||
-- ^ cursor on "type"
|
||||
n.command(':help!')
|
||||
eq({ '*type()*', 'vimfn.txt' }, buf_word())
|
||||
n.feed('<c-o>f<lt>')
|
||||
eq({ '`@lsp.type.<type>.<ft>`', 'lsp.txt' }, buf_word())
|
||||
-- ^ cursor on "<"
|
||||
n.command(':help!')
|
||||
|
||||
n.command(':help lsp')
|
||||
n.feed('gg/codelens.run()|<cr>')
|
||||
eq({ '|vim.lsp.codelens.run()|.', 'lsp.txt' }, buf_word())
|
||||
-- ^ cursor on "codelens"
|
||||
n.command(':help!')
|
||||
eq({ '*vim.lsp.codelens.run()*', 'lsp.txt' }, buf_word())
|
||||
end)
|
||||
|
||||
it('window closed makes cursor return to a valid win/buf #9773', function()
|
||||
n.add_builddir_to_rtp()
|
||||
command('help help')
|
||||
|
||||
Reference in New Issue
Block a user