I have the following vimscript .vim/ftplugin dir:
" change to header file from c file or vice versa
function! CppAlter()
python << endpy
import vim
import os
bufferNames = [os.path.basename(b.name) for b in vim.buffers]
currentBufName = vim.eval("expand('%:p:t')")
currentBufStem, currentBufExt = os.path.splitext(currentBufName)
if currentBufExt == ".cpp" or currentBufExt == ".c" or currentBufExt == ".cc":
altBufName1 = currentBufStem + ".h"
altBufName2 = currentBufStem + ".hpp"
if altBufName1 in bufferNames:
vim.command("b " + altBufName1)
elif altBufName2 in bufferNames:
vim.command("b " + altBufName2)
else:
raise ValueError("No header file corresponding to this c file")
elif currentBufExt == ".h" or currentBufExt == ".hpp":
altBufName1 = currentBufStem + ".cpp"
altBufName2 = currentBufStem + ".c"
altBufName3 = currentBufStem + ".cc"
if altBufName1 in bufferNames:
vim.command("b " + altBufName1)
elif altBufName2 in bufferNames:
vim.command("b " + altBufName2)
elif altBufName3 in bufferNames:
vim.command("b " + altBufName3)
else:
raise ValueError("No c file corresponding to this header file")
else:
raise ValueError("This is not a c type file")
endpy
endfunction
nnoremap <leader>vc :call CppAlter()<cr>
inoremap <leader>vc <esc>:call CppAlter()<cr>
When I open vim I get an error:
" vim.error: Vim(function):E127: Cannot redefine function CppAlter: It is in use
But if I save it in /tmp and explicitly :so /tmp/x.vim, there is no error msg. Wondering what is wrong here.
Inside your function, you're loading another buffer (e.g. vim.command("b " + altBufName1)
). When that buffer has the same filetype, the current ftplugin script is sourced again as part of the filetype plugin handling, but the original function hasn't returned yet, so you get the E127
.
I recommend putting the function itself into an autoload script, e.g. in ~/.vim/autoload/ft/cppalter.vim
:
function! ft#cppalter#CppAlter()
...
Your ftplugin script becomes much smaller and efficient, as the function is only sourced once:
nnoremap <leader>vc :call ft#cppalter#CppAlter()<cr>
...
(You should probably use :nnoremap <buffer>
here to limit the mapping's scope.)
If you don't want to break this up, move the function definition(s) to the bottom and add a guard, like:
nnoremap <leader>vc :...
if exists('*CppAlter')
finish
endif
function! CppAlter()
...
I encountered an interesting case of E127
, which pretty much sums up why it would occur in almost any situation. Let me explain.
First, let's look at what the docs say.
E127 E122
When a function by this name already exists and [!] is
not used an error message is given. There is one
exception: When sourcing a script again, a function
that was previously defined in that script will be
silently replaced.
When [!] is used, an existing function is silently
replaced. **Unless it is currently being executed, that
is an error.**
For the next part notice what the last line has to say.
Let's understand this by an example. Below is a function that guesses and sources the current script based on what filetype it has. Notice how the exec
command will initiate an endless recursive sourcing of the current file on calling this function.
function! s:SourceScriptImplicit()
if !&readonly
w
endif
let l:bin=system("which " . &filetype)[:-2]
let l:sourcecommand=
\ #{
\ vim: "source %",
\ sh: "!source %",
\ javascript: "!node %",
\ python: "!python3 %"
\ }
exec l:sourcecommand[split(l:bin, "/")[-1]]
endfunction
To fix this, simply remove the recursive part out of the function.
function! s:SourceScriptImplicit()
if !&readonly
w
endif
let l:bin=system("which " . &filetype)[:-2]
let l:sourcecommand=
\ #{
\ vim: "source %",
\ sh: "!source %",
\ javascript: "!node %",
\ python: "!python3 %"
\ }
return l:sourcecommand[split(l:bin, "/")[-1]]
endfunction
nn <leader>so :exec <SID>SourceScriptImplicit()<cr>
Now it works perfectly!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With