runtime(vim): add gf support for import and packadd in ftplugin
closes: #17881 Signed-off-by: lacygoill <lacygoill@lacygoill.me> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
9340aa1bf8
commit
c0b3c19120
134
runtime/autoload/vim.vim
Normal file
134
runtime/autoload/vim.vim
Normal file
@ -0,0 +1,134 @@
|
||||
vim9script
|
||||
|
||||
# Interface {{{1
|
||||
export def Find(editcmd: string) #{{{2
|
||||
var curline: string = getline('.')
|
||||
|
||||
if curline =~ '^\s*\%(:\s*\)\=packadd!\=\s'
|
||||
HandlePackaddLine(editcmd, curline)
|
||||
return
|
||||
endif
|
||||
|
||||
if curline =~ '^\s*\%(:\s*\)\=import\s'
|
||||
HandleImportLine(editcmd, curline)
|
||||
return
|
||||
endif
|
||||
|
||||
try
|
||||
execute 'normal! ' .. editcmd
|
||||
catch
|
||||
Error(v:exception)
|
||||
endtry
|
||||
enddef
|
||||
#}}}1
|
||||
# Core {{{1
|
||||
def HandlePackaddLine(editcmd: string, curline: string) #{{{2
|
||||
var pat: string = '^\s*packadd!\=\s\+\zs\S\+$'
|
||||
var plugin: string = curline
|
||||
->matchstr(pat)
|
||||
->substitute('^vim-\|\.vim$', '', 'g')
|
||||
|
||||
if plugin == ''
|
||||
try
|
||||
execute 'normal! ' .. editcmd .. 'zv'
|
||||
catch
|
||||
Error(v:exception)
|
||||
return
|
||||
endtry
|
||||
else
|
||||
var split: string = editcmd[0] == 'g' ? 'edit' : editcmd[1] == 'g' ? 'tabedit' : 'split'
|
||||
# In the past, we passed `runtime` to `getcompletion()`, instead of
|
||||
# `cmdline`. But the output was tricky to use, because it contained
|
||||
# paths relative to inconsistent root directories.
|
||||
var files: list<string> = getcompletion($'edit **/plugin/{plugin}.vim', 'cmdline')
|
||||
->filter((_, path: string): bool => filereadable(path))
|
||||
->map((_, fname: string) => fname->fnamemodify(':p'))
|
||||
if empty(files)
|
||||
echo 'Could not find any plugin file for ' .. string(plugin)
|
||||
return
|
||||
endif
|
||||
files->Open(split)
|
||||
endif
|
||||
enddef
|
||||
|
||||
def HandleImportLine(editcmd: string, curline: string) #{{{2
|
||||
var fname: string
|
||||
var import_cmd: string = '^\s*import\s\+\%(autoload\s\+\)\='
|
||||
var import_alias: string = '\%(\s\+as\s\+\w\+\)\=$'
|
||||
var import_string: string = import_cmd .. '\([''"]\)\zs.*\ze\1' .. import_alias
|
||||
var import_expr: string = import_cmd .. '\zs.*\ze' .. import_alias
|
||||
# the script is referred to by its name in a quoted string
|
||||
if curline =~ import_string
|
||||
fname = curline->matchstr(import_string)
|
||||
# the script is referred to by an expression
|
||||
elseif curline =~ import_expr
|
||||
try
|
||||
sandbox fname = curline
|
||||
->matchstr(import_expr)
|
||||
->eval()
|
||||
catch
|
||||
Error(v:exception)
|
||||
return
|
||||
endtry
|
||||
endif
|
||||
|
||||
var filepath: string
|
||||
if fname->isabsolutepath()
|
||||
filepath = fname
|
||||
elseif fname[0] == '.'
|
||||
filepath = (expand('%:h') .. '/' .. fname)->simplify()
|
||||
else
|
||||
var subdir: string = curline =~ '^\s*import\s\+autoload\>' ? 'autoload' : 'import'
|
||||
# Matching patterns in `'wildignore'` can be slow.
|
||||
# Let's set `{nosuf}` to `true` to avoid `globpath()` to be slow.
|
||||
filepath = globpath(&runtimepath, subdir .. '/' .. fname, true, true)
|
||||
->get(0, '')
|
||||
endif
|
||||
|
||||
if !filepath->filereadable()
|
||||
printf('E447: Can''t find file "%s" in path', fname)
|
||||
->Error()
|
||||
return
|
||||
endif
|
||||
|
||||
var how_to_split: string = {
|
||||
gF: 'edit',
|
||||
"\<C-W>F": 'split',
|
||||
"\<C-W>gF": 'tab split',
|
||||
}[editcmd]
|
||||
execute how_to_split .. ' ' .. filepath
|
||||
enddef
|
||||
|
||||
def Open(what: any, how: string) #{{{2
|
||||
var fname: string
|
||||
if what->typename() == 'list<string>'
|
||||
if what->empty()
|
||||
return
|
||||
endif
|
||||
fname = what[0]
|
||||
else
|
||||
if what->typename() != 'string'
|
||||
return
|
||||
endif
|
||||
fname = what
|
||||
endif
|
||||
|
||||
execute $'{how} {fname}'
|
||||
cursor(1, 1)
|
||||
|
||||
# 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
|
||||
->copy()
|
||||
->map((_, f: string) => f->fnameescape())
|
||||
execute $'arglocal {arglist->join()}'
|
||||
endif
|
||||
enddef
|
||||
#}}}1
|
||||
# Util {{{1
|
||||
def Error(msg: string) #{{{2
|
||||
echohl ErrorMsg
|
||||
echomsg msg
|
||||
echohl NONE
|
||||
enddef
|
@ -1063,8 +1063,18 @@ To disable: >
|
||||
<
|
||||
VIM *ft-vim-plugin*
|
||||
|
||||
The Vim filetype plugin defines mappings to move to the start and end of
|
||||
functions with [[ and ]]. Move around comments with ]" and [".
|
||||
The Vim filetype plugin defines the following mappings:
|
||||
|
||||
[[ move to the start of the previous function
|
||||
]] move to the start of the next function
|
||||
][ move to the end of the previous function
|
||||
[] move to the end of the next function
|
||||
]" move to the next (legacy) comment
|
||||
[" move to the previous (legacy) comment
|
||||
gf edit the file under the cursor
|
||||
CTRL-W gf edit the file under the cursor in a new tab
|
||||
CTRL-W f edit the file under the cursor in a new window
|
||||
|
||||
|
||||
The mappings can be disabled with: >
|
||||
let g:no_vim_maps = 1
|
||||
|
@ -1,11 +1,13 @@
|
||||
" Vim filetype plugin
|
||||
" Language: Vim
|
||||
" Maintainer: Doug Kearns <dougkearns@gmail.com>
|
||||
" Last Change: 2025 Mar 05
|
||||
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
|
||||
" Contributors: Riley Bruins <ribru17@gmail.com> ('commentstring'),
|
||||
" @Konfekt
|
||||
" @tpope (s:Help())
|
||||
" @lacygoill
|
||||
" Last Change: 2025 Mar 05
|
||||
" 2025 Aug 06 by Vim Project (add gf maps #17881)
|
||||
|
||||
" Only do this when not done yet for this buffer
|
||||
if exists("b:did_ftplugin")
|
||||
@ -35,6 +37,9 @@ if !exists('*VimFtpluginUndo')
|
||||
silent! xunmap <buffer> ]"
|
||||
silent! nunmap <buffer> ["
|
||||
silent! xunmap <buffer> ["
|
||||
silent! nunmap <buffer> gf
|
||||
silent! nunmap <buffer> <C-W>f
|
||||
silent! nunmap <buffer> <C-W>gf
|
||||
endif
|
||||
unlet! b:match_ignorecase b:match_words b:match_skip b:did_add_maps
|
||||
endfunc
|
||||
@ -139,6 +144,29 @@ if !exists("no_plugin_maps") && !exists("no_vim_maps")
|
||||
xnoremap <silent><buffer> ]" :<C-U>exe "normal! gv"<Bar>call search('\%(^\s*".*\n\)\@<!\%(^\s*"\)', "W")<CR>
|
||||
nnoremap <silent><buffer> [" :call search('\%(^\s*".*\n\)\%(^\s*"\)\@!', "bW")<CR>
|
||||
xnoremap <silent><buffer> [" :<C-U>exe "normal! gv"<Bar>call search('\%(^\s*".*\n\)\%(^\s*"\)\@!', "bW")<CR>
|
||||
|
||||
" Purpose: Handle `:import` and `:packadd` lines in a smarter way. {{{
|
||||
"
|
||||
" `:import` is followed by a filename or filepath. Find it.
|
||||
"
|
||||
" `:packadd` is followed by the name of a package, which we might have
|
||||
" configured in scripts under `~/.vim/plugin`. Find it.
|
||||
"
|
||||
" ---
|
||||
"
|
||||
" We can't handle the `:import` lines simply by setting `'includeexpr'`, because
|
||||
" the option would be ignored if:
|
||||
"
|
||||
" - the name of the imported script is the same as the current one
|
||||
" - `'path'` includes the `.` item
|
||||
"
|
||||
" Indeed, in that case, Vim finds the current file, and simply reloads the
|
||||
" buffer.
|
||||
" }}}
|
||||
" We use the `F` variants, instead of the `f` ones, because they're smarter.
|
||||
nnoremap <silent><buffer> gf :<C-U>call vim#Find('gF')<CR>
|
||||
nnoremap <silent><buffer> <C-W>f :<C-U>call vim#Find("\<lt>C-W>F")<CR>
|
||||
nnoremap <silent><buffer> <C-W>gf :<C-U>call vim#Find("\<lt>C-W>gF")<CR>
|
||||
endif
|
||||
|
||||
" Let the matchit plugin know what items can be matched.
|
||||
|
Reference in New Issue
Block a user