From 1acbcbc5f043eb976adf17b5f6643376bd09cdb5 Mon Sep 17 00:00:00 2001 From: Andrew Radev Date: Tue, 2 Sep 2025 20:51:43 +0200 Subject: [PATCH] runtime(vimgoto): Implement jumping to autoloaded functions Also refactor the script slightly. closes: #18193 Co-authored-by: dkearns Signed-off-by: Andrew Radev Signed-off-by: Christian Brabandt --- runtime/autoload/vimgoto.vim | 125 ++++++++++++++++++++++++++--------- 1 file changed, 94 insertions(+), 31 deletions(-) diff --git a/runtime/autoload/vimgoto.vim b/runtime/autoload/vimgoto.vim index ffeab0af4b..121af4ef32 100644 --- a/runtime/autoload/vimgoto.vim +++ b/runtime/autoload/vimgoto.vim @@ -3,11 +3,12 @@ vim9script # Language: Vim9 script # Contributers: @lacygoill # Shane-XB-Qian -# Last Change: 2025 Aug 13 +# Andrew Radev +# Last Change: 2025 Sep 02 # -# Vim Script to handle -# :import, :packadd and :colorscheme -# lines and allows to easily jump to it using gf +# Vim Script to handle jumping to the targets of several types of Vim commands +# (:import, :packadd, :runtime, :colorscheme), and to autoloaded functions of +# the style #. # # see runtime/ftplugin/vim.vim @@ -20,6 +21,11 @@ export def Find(editcmd: string) #{{{2 return endif + if curline =~ '^\s*\%(:\s*\)\=ru\%[ntime]!\=' + HandleRuntimeLine(editcmd, curline, expand('')) + return + endif + if curline =~ '^\s*\%(:\s*\)\=colo\%[rscheme]\s' HandleColoLine(editcmd, curline) return @@ -30,6 +36,20 @@ export def Find(editcmd: string) #{{{2 return endif + var curfunc = FindCurfunc() + + if stridx(curfunc, '#') >= 0 + var parts = split(curfunc, '#') + var path = $"autoload/{join(parts[0 : -2], '/')}.vim" + var resolved_path = globpath(&runtimepath, path) + + if resolved_path != '' + var function_pattern: string = $'^\s*\%(:\s*\)\=fun\%[ction]!\=\s\+\zs{curfunc}(' + resolved_path->Open(editcmd, function_pattern) + endif + return + endif + try execute 'normal! ' .. editcmd catch @@ -45,14 +65,8 @@ def HandlePackaddLine(editcmd: string, curline: string) #{{{2 ->substitute('^vim-\|\.vim$', '', 'g') if plugin == '' - try - execute 'normal! ' .. editcmd .. 'zv' - catch - Error(v:exception) - return - endtry + Fallback(editcmd) else - var split: string = editcmd[0] == 'g' ? 'edit' : editcmd[1] == 'g' ? 'tabedit' : 'split' var files: list = getcompletion($'plugin/{plugin}', 'runtime') ->map((_, fname: string) => fname->findfile(&rtp)->fnamemodify(':p')) ->filter((_, path: string): bool => filereadable(path)) @@ -60,7 +74,33 @@ def HandlePackaddLine(editcmd: string, curline: string) #{{{2 echo 'Could not find any plugin file for ' .. string(plugin) return endif - files->Open(split) + files->Open(editcmd) + endif +enddef + +def HandleRuntimeLine(editcmd: string, curline: string, cfile: string) #{{{2 + var fname: string + var where_pat: string = '\%(START\|OPT\|PACK\|ALL\)' + + if cfile == 'runtime' || cfile =~# $'^{where_pat}$' + # then the cursor was not on one of the filenames, jump to the first file: + var fname_pat: string = $'\s*\%(:\s*\)\=ru\%[ntime]\%(!\s*\|\s\+\)\%({where_pat}\s\+\)\=\zs\S\+\>\ze' + fname = curline->matchstr(fname_pat) + else + fname = cfile + endif + + if fname == '' + Fallback(editcmd) + else + var file: string = fname + ->findfile(&rtp) + ->fnamemodify(':p') + if file == '' || !filereadable(file) + echo 'Could not be found in the runtimepath: ' .. string(fname) + return + endif + file->Open(editcmd) endif enddef @@ -69,14 +109,8 @@ def HandleColoLine(editcmd: string, curline: string) #{{{2 var colo: string = curline->matchstr(pat) if colo == '' - try - execute 'normal! ' .. editcmd .. 'zv' - catch - Error(v:exception) - return - endtry + Fallback(editcmd) else - var split: string = editcmd[0] == 'g' ? 'edit' : editcmd[1] == 'g' ? 'tabedit' : 'split' var files: list = getcompletion($'colors/{colo}', 'runtime') ->map((_, fname: string) => fname->findfile(&rtp)->fnamemodify(':p')) ->filter((_, path: string): bool => filereadable(path)) @@ -84,7 +118,7 @@ def HandleColoLine(editcmd: string, curline: string) #{{{2 echo 'Could not find any colorscheme file for ' .. string(colo) return endif - files->Open(split) + files->Open(editcmd) endif enddef @@ -136,27 +170,34 @@ def HandleImportLine(editcmd: string, curline: string) #{{{2 execute how_to_split .. ' ' .. filepath enddef -def Open(what: any, how: string) #{{{2 +def Open(target: any, editcmd: string, search_pattern: string = '') #{{{2 + var split: string = editcmd[0] == 'g' ? 'edit' : editcmd[1] == 'g' ? 'tabedit' : 'split' var fname: string - if what->typename() == 'list' - if what->empty() + var cmd: string + + if target->typename() == 'list' + if target->empty() return endif - fname = what[0] + fname = target[0] else - if what->typename() != 'string' + if target->typename() != 'string' return endif - fname = what + fname = target endif - execute $'{how} {fname}' - cursor(1, 1) + if search_pattern != '' + var escaped_pattern = escape(search_pattern, '\#'' ') + cmd = $'+silent\ call\ search(''{escaped_pattern}'')' + endif + + execute $'{split} {cmd} {fname}' # If there are several files to open, put them into an arglist. - if what->typename() == 'list' - && what->len() > 1 - var arglist: list = what + if target->typename() == 'list' + && target->len() > 1 + var arglist: list = target ->copy() ->map((_, f: string) => f->fnameescape()) execute $'arglocal {arglist->join()}' @@ -170,4 +211,26 @@ def Error(msg: string) #{{{2 echohl NONE enddef +def Fallback(editcmd: string) #{{{2 + try + execute 'normal! ' .. editcmd .. 'zv' + catch + Error(v:exception) + endtry +enddef + +def FindCurfunc(): string #{{{2 + var curfunc = '' + var saved_iskeyword = &iskeyword + + try + set iskeyword+=# + curfunc = expand('') + finally + &iskeyword = saved_iskeyword + endtry + + return curfunc +enddef + # vim: sw=4 et