diff options
author | Teddy Wing | 2020-10-03 14:31:37 +0200 |
---|---|---|
committer | Teddy Wing | 2020-10-04 00:22:41 +0200 |
commit | 810068af5e6a50e87ce3f692b66f5d4a4e051f38 (patch) | |
tree | 067bc74bcc759c5089c0c1d860c2c63cc2b689f1 /ftplugin | |
parent | 44b3924298992c374b4ed4b11d900c072ae8264b (diff) | |
download | dotvim-810068af5e6a50e87ce3f692b66f5d4a4e051f38.tar.bz2 |
ftplugin/typescript.vim: Make `gf` open `index.ts` if path is directory
In TypeScript and Node.js, you can import a file `./directory/index.ts`
by importing `./directory`.
I wanted `gf` and friends to open the `index` file if the import refers
to a directory. By default, `gf` opens the directory using Netrw.
At first tried to do this by setting 'includeexpr' as follows:
setlocal includeexpr=<SID>FindFile(v:fname)
function! s:FindFile(fname)
echom 'FindFile: ' . a:fname
if filereadable(a:fname)
return a:fname
endif
return a:fname . '/index'
endfunction
This gave me the following error:
E120: Using <SID> not in a script context: <SID>FindFile
so I tried removing `<SID>`:
setlocal includeexpr=FindFile(v:fname)
function! FindFile(fname)
echom 'FindFile: ' . a:fname
if filereadable(a:fname)
return a:fname
endif
return a:fname . '/index.ts'
endfunction
The problem was, my 'includeexpr' function wasn't getting executed every
time I used `gf`, only some times. And it never ran when I used `gf` on
a directory.
After asking on Freenode#vim, 'crose' made the following suggestion:
augroup typescript_maybe_append_filename
au!
au BufEnter * if expand('<amatch>')->isdirectory()
\ | call s:maybe_append_filename()
\ | endif
augroup END
fu s:maybe_append_filename() abort
if getbufvar('#', '&ft', '') == 'typescript'
exe 'e ' .. expand('%:p') .. 'index.ts'
endif
endfu
This works, but it adds the Netrw directory buffer to the jumplist, and
feels more like a mitigation than a solution.
I looked at the following language ftplugins for inspiration:
* .../vim/8.2.1650/share/vim/vim82/ftplugin/ruby.vim
* https://github.com/moll/vim-node/blob/master/autoload/node.vim
These prompted me to override `gf` with a custom mapping since it looked
like 'includeexpr' wasn't going to be the right tool for this. The
`s:FindFile()` function has similar logic, but is now written as a map
rhs function, taking into account the different ways of invoking `gf`.
When defined as a script-local function, I at first kept getting this
error using `gf` on a directory:
E127: Cannot redefine function <SNR>111_FindFile: It is in use
Thanks to Ingo Karkat
(https://stackoverflow.com/users/813602/ingo-karkat) and this Stack
Overflow answer which describes how to keep the function in the same
file (so I didn't have to move it to an autoload function) and still
prevent it from being redefined:
https://stackoverflow.com/questions/22633115/why-do-i-get-e127-from-this-vimscript/22633702#22633702
I needed to prepend `<C-v>` to the `<C-w>` characters in the map
function calls because these would actually run in the command line,
deleting the preceding word, and messing up the mapping. In order to
pass those `<C-w>` characters in the string arguments, I needed to
escape them with `<C-v>`, even though it resulted in non-obvious looking
code.
Diffstat (limited to 'ftplugin')
-rw-r--r-- | ftplugin/typescript.vim | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/ftplugin/typescript.vim b/ftplugin/typescript.vim index c68494a..94b9c9e 100644 --- a/ftplugin/typescript.vim +++ b/ftplugin/typescript.vim @@ -1,3 +1,41 @@ " TypeScript vim settings setlocal commentstring=//\ %s + +setlocal suffixesadd+=.ts + +let b:undo_ftplugin = '' + + +nnoremap <silent> <buffer> gf + \ :<C-u>call <SID>FindFile(v:count1, expand('<cfile>'), 'find', 'gf')<CR> +nnoremap <buffer> <C-w>f + \ :<C-u>call <SID>FindFile(v:count1, expand('<cfile>'), 'sfind', '<C-v><C-w>f')<CR> +nnoremap <silent> <buffer> <C-w><C-f> + \ :<C-u>call <SID>FindFile(v:count1, expand('<cfile>'), 'sfind', '<C-v><C-w><C-v><C-f>')<CR> +nnoremap <silent> <buffer> <C-w>gf + \ :<C-u>call <SID>FindFile(v:count1, expand('<cfile>'), 'tabfind', '<C-v><C-w>gf')<CR> + +let b:undo_ftplugin .= 'nunmap <buffer> gf' +let b:undo_ftplugin .= '| nunmap <buffer> <C-w>f' +let b:undo_ftplugin .= '| nunmap <buffer> <C-w><C-f>' +let b:undo_ftplugin .= '| nunmap <buffer> <C-w>gf' + + +if exists('*s:FindFile') + finish +endif + +" If `fname` is a directory, open fname/index.ts using `command`. Otherwise, +" run `map` with `count`. +function! s:FindFile(count, fname, command, map) + let relative_file = expand('%:h') . '/' . a:fname + + if isdirectory(relative_file) + execute a:command . ' ' . relative_file . '/index.ts' + + return + endif + + execute 'normal! ' . a:count . a:map +endfunction |