为什么我从这个vimscript获得E127?

时间:2014-03-25 11:24:54

标签: python vim

我有以下vimscript .vim / ftplugin目录:

" 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>

当我打开vim时出现错误:

" vim.error: Vim(function):E127: Cannot redefine function CppAlter: It is in use

但是如果我将它保存在/ tmp中并明确地保存:so /tmp/x.vim,则没有错误消息。 想知道这里有什么问题。

3 个答案:

答案 0 :(得分:8)

在您的函数内部,您正在加载另一个缓冲区(例如vim.command("b " + altBufName1))。当该缓冲区具有相同的文件类型时,当前的ftplugin脚本将作为 filetype plugin 处理的一部分再次获取,但原始函数尚未返回,因此您获得E127

解决方案

我建议将功能本身放入自动加载脚本,例如在~/.vim/autoload/ft/cppalter.vim

function! ft#cppalter#CppAlter()
    ...

您的ftplugin脚本变得更小更高效,因为该功能仅来源一次:

nnoremap <leader>vc :call ft#cppalter#CppAlter()<cr>
...

(你应该在这里使用:nnoremap <buffer>来限制映射的范围。)

替代

如果您不想解决此问题,请将功能定义移至底部并添加一个警卫,例如:

nnoremap <leader>vc :...

if exists('*CppAlter')
    finish
endif
function! CppAlter()
    ...

答案 1 :(得分:1)

我遇到了一个有趣的 E127 案例,它几乎总结了为什么它几乎在任何情况下都会发生。让我解释一下。

首先,让我们看看文档是怎么说的。

                                                                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.**

对于下一部分,请注意最后一行要说的内容。

让我们通过一个例子来理解这一点。下面是一个函数,它根据当前脚本的文件类型猜测和获取当前脚本的来源。请注意 exec 命令如何在调用此函数时启动当前文件的无限递归源。

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

要解决这个问题,只需从函数中删除递归部分即可。

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>

现在完美运行!

答案 2 :(得分:0)

我想你应该注意到 | 对于在底部命令行中执行命令很有用,例如 :source expand("%") | source ./awesome.vim
这是我的 .init.vim(或 .vimrc)代码段,其 func 正在获取 .vim 目录中的所有 /home/zarkli/.config/nvim/myInitCustom/ 文件:

function SourceVimScripts() 
    let l:command = ""
    let l:files = split(globpath('/home/zarkli/.config/nvim/myInitCustom/','*.vim'),'\n') " use absolute path to avoid problems when opening an non-nvim_init file
    for l:file in l:files
        let l:command .= "source ".l:file." |"
    endfor
    " the end of the l:command should be '|',but that doesn't matter
    return l:command
endfunction
exec SourceVimScripts()

它可以完美地解决您的问题。