]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
runtime(vimgoto): Implement jumping to autoloaded functions
authorAndrew Radev <andrey.radev@gmail.com>
Tue, 2 Sep 2025 18:51:43 +0000 (20:51 +0200)
committerChristian Brabandt <cb@256bit.org>
Tue, 2 Sep 2025 18:51:43 +0000 (20:51 +0200)
Also refactor the script slightly.

closes: #18193

Co-authored-by: dkearns <dougkearns@gmail.com>
Signed-off-by: Andrew Radev <andrey.radev@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/autoload/vimgoto.vim

index ffeab0af4b54ab1098ff74fbafb05506c1e81c73..121af4ef32bee79a6f2e76f58845eecc4a69a22f 100644 (file)
@@ -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 <path>#<function_name>.
 #
 # 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('<cfile>'))
+        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<string> = 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<string> = 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<string>'
-        if what->empty()
+    var cmd: string
+
+    if target->typename() == 'list<string>'
+        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<string>'
-            && what->len() > 1
-        var arglist: list<string> = what
+    if target->typename() == 'list<string>'
+            && target->len() > 1
+        var arglist: list<string> = 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('<cword>')
+    finally
+        &iskeyword = saved_iskeyword
+    endtry
+
+    return curfunc
+enddef
+
 # vim: sw=4 et