linux · vim · 2015-02-01 · yuex

上篇讲到 SmartQuit(),通过处理 Vim 中的 E37 异常,让我们可以更畅快地退出 Vim。但这个解法并不完美,例如我们通过 vim 命令编辑无名文件时,SmartQuit() 在退出时会尝试用 w 进行保存,但由于当前文件没有文件名,所以会遭遇 Vim 中的 E32 异常

E32: No file name

在这篇文章里,我提供一个我在用的 SmartWrite() 函数,来解决 E32。闲言少叙,我们还是直接上代码

首先,我们先将 SmartWrite() 的调用绑定到一个键位,这里暂时用 wq 替代好了。

1
nnoremap <unique> wq :call SmartWrite()<CR>

一个更好的方法是将 ; 映射为 <Leader> 键,然后用 <Leader>w 来调用 SmartWrite(),这个键位按起来很方便而且很好记。当然,如果插件较多,按键不够用,我们还可以开启 <Alt> 键来使用更多的组合键。不过这些都不打紧,因为在文章的最后,我们会把 SmartWrite() 的调用整合进 SmartQuit() 中,这样就只要记忆一个 <C-c> 就可以了。

接下来,是 SmartWrite() 的代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
function SmartWrite(...)
    let cmd = 'w'
    if a:0 > 0
        let cmd = a:1
    endif
    if empty(bufname('%'))
        call WriteWithName(cmd)
    else
        exec cmd
    endif
endfunction

function WriteWithName(cmd)
    call inputsave()

    let filename = input(':'.a:cmd.' ', '', 'file')
    let cmds = [a:cmd, filename]
    if !empty(glob(filename))
        redraw
        echohl WarningMsg
        echo '"'.filename.'" existed. Force '.a:cmd.' [!] ? [Y/n] '
        echohl None

        let choice = nr2char(getchar())
        if choice == "\<CR>" || choice ==? 'y'
            call CmdExecute(cmds, 1)
        endif
    else
        call CmdExecute(cmds, 0)
    endif

    call inputrestore()
endfunction

function CmdExecute(cmds, force)
    if a:force
        let cmd = a:cmds[0].'! '.join(a:cmds[1:])
    else
        let cmd = join(a:cmds)
    endif

    if exists('cmd')
        exec cmd
    endif
endfunction

好在 Vimscript 并不严格要求函数定义与使用的先后顺序,因为是脚本语言嘛,所以这里就按照逻辑上最自然的先后顺序给出代码了。在 SmartWrite() 中,我们进行一个判断,看当前文件是否有名字。如果有名字,就直接执行默认为写的命令;如果没有名字,就调用 WriteWithName()。这个函数会要求输入一个文件名字,然后会检查是否存在同名的文件。如果存在,会提示是否强制写,默认是只有 <Enter>y 或者 Y 起头的输入,才会进行强制写入。决定之后,会调用 CmdExecute() 来真正执行写入的命令。

最后,只要在 SmartQuit() 里进行一下小的调整,就可以将 SmartWrite() 整合进去了。我们赘述如下,注意其中的 <C-w><C-s> 键的设置,其实是配置了 保存 保存退出 两个键位。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function SmartQuit()
    if !&modified
        exec "quit"
    else
        redraw
        echohl WarningMsg
        echo "Buffer changed! [^W]w [^S]x [^B^N]q!: "
        echohl None

        let cmd = ""
        let ret = nr2char(getchar())

        if ret == "\<C-b>" || ret == "\<C-n>"
            let cmd = "q!"
        elseif ret == "\<C-w>"
            let cmd = "call SmartWrite('w')"
        elseif ret == "\<C-s>"
            let cmd = "call SmartWrite('x')"
        endif

        redraw
        if !empty(cmd)
            exec cmd
        endif
    endif
endfunction

最后的最后,别忘了我们的 <C-c> 键映射

1
nnoremap <unique> <C-c> :call SmartQuit()<CR>

以上。