Vim 经验与技巧

教程

  1. 用Vimwiki建一个维基世界
  2. 自动同步你的 vimwiki 到线上网站

准备工作

请先在你的 vimrc 里定义变量 $VIMFILES 。比如说 Windows 下,我把 vimfiles 放在了 Vim 安装目录的 vimfiles 目录下:

if has("win32")
    let $VIMFILES = $VIM.'/vimfiles'
    let $V = $VIM.'/_vimrc'
else
    let $VIMFILES = $HOME.'/.vim'
    let $V = $HOME.'/.vimrc'
endif

你知道吗?

Vim7.3 的持久撤销

Vim 7.3 提供 持久撤销 (Persistent Undo) 功能,即使文件关闭后,再次打开时仍然可以撤销文件关闭之前的编辑历史。要使用这一功能,在 vimrc 中添加

" 重启后撤销历史可用 persistent undo 
set undofile
set undodir=$VIMFILES/\_undodir
set undolevels=1000 "maximum number of changes that can be undone

set undofile - 开启本功能。开启之后会默认在文件当前目录下建立一个 filename.ext.un~ 的文件,自然是会给我们带来麻烦的。所以配置一个 undodir 集中放置所有undofile。

$VIMFILES/\_undodir - $VIMFILES 是我们之前在 vimrc 中定义的环境变量, windows 下是 $VIM/vimfiles/ 。请注意,为了和其他目录区分,undodir前面有下划线 _undodir 。因为有下划线,前面的反斜杠又不可少了。而且这个目录必须自己手动建立。如果不存在,Vim 是不会帮你自动建立的。

颤抖吧!IDE!

编辑状态的保存

大部分IDE都提供记录文件关闭前的状态的功能,个别考虑比较全面的还可以记住软件关闭前都打开了哪些文件。这些功能Vim都能做到。

记录文件状态(包括独立于该文件的键盘映射、代码折叠状态等):

autocmd BufWinLeave * if expand('%') != '' && &buftype == '' | mkview | endif
autocmd BufRead     * if expand('%') != '' && &buftype == '' | silent loadview | syntax on | endif

那些 if 判断是为了避免进入新建文件的缓冲区时,出现文件名不存在的错误。

如果参数为空,记录/载入 Vim 关闭时的状态。

一般来说,上面的代码就够用了。最大的缺陷可能就是时间长了 $VIMFILES/views 目录下就会有很多垃圾文件,有些文件你可能一辈子也不会打开了,但它们的状态文件仍然存在。你可以写一段删除过老文件的脚本,在 Linux 下就像这样:

function! RemoveOldViewFiles
    exe 'find '.$VIMFILES.'/view* -mtime +90 -exec rm {} \;'
endfunction
nmap <leader>.cl :call RemoveOldViewFiles<cr>

删除 90 天以前的文件。

至于类似于“恢复工作区”这样的功能,则可以通过session文件来实现:

编辑你的 vimrc :

" Session files Vim关闭时保存会话状态
set sessionoptions+=unix
set sessionoptions-=blank
"set sessionoptions-=options
autocmd VimEnter * call LoadSession()
autocmd VimLeave * call MakeSession() 

function! MakeSession()
    if !has('gui_running')
        hi clear
    endif
    if bufname('')  == ''
        exe 'bdelete '.bufnr('')
    endif
    let l:count = 0
    let l:i = 0
    while l:i <= bufnr('$')
        if buflisted(count)
            let l:count += 1
        endif
        let l:i+=1
    endwhile
    if l:count >= 4
        mksession! ~/.last_session.vim
    endif
endfunction

function! LoadSession()
    "if exists('g:SessionLoaded')
    "return
    "endif
    if expand('%') == '' && filereadable($HOME.'/.last_session.vim') && !&diff
        silent so ~/.last_session.vim
    endif

    let l:buftotal = bufnr('$')
    let l:i = 0
    let l:crtpath = getcwd() 
    while l:i <= l:buftotal
        " 列表中还未载入的buffer,如果不在当前工作目录,会被删除
        if !bufloaded(l:i) && buflisted(l:i) && expand('%:p') !~ l:crtpath
            exe 'bdelete '.l:i
            echo expand('%:p') .' !~ '. l:crtpath
        endif
        let l:i += 1
    endwhile
endfunction

这段代码应该很好读懂,我就不解释了~ 有什么问题,请留言

介绍 Vim 中的批量查找替换

1. vimgrep 命令 试用 :vimgrep word * 可以在当前目录的任意文件下查找“word”,并生成 quickfix 列表。试用 :cl 可以查看所有匹配结果。使用 :cn 到下一个, :cp 到上一个。

使用 :vimgrep /pattern/gj *.php 可以在当前目录的php文件中按搜索模式 pattern 查找。标志位 g 代表每次匹配都加入匹配结果列表,否则每行只匹配一次。标志位 j 表示只更新 quickfix 列表,否则 vim 会跳到第一个匹配上。

更多说明,请 :h vimgrep 或者 点这里

2. arguments 参数列表 参数列表就是一系列文件列表。在上面链接的文章已有介绍,不细讲。

在 Vim 中启用 JSLint

明爷(gracecode.com)曾介绍过如何在Vim中使用JSLint,他写这篇文章时还没有诞生我今天要介绍的插件:jslint.vim

事实证明,这个插件是很好用的。不过最初安装时要花点功夫。Linux下按照README的说明来,应该不会遇到什么问题,我这里讲一下在Windows下的注意事项。

1. 这个插件只能装在系统用户目录下($HOME),即你在Vim里执行 :cd ~ 所到的目录。(Win7下是 C:\Users\Username )

要突破上面的限制,修改 ftplugin/javascript/jslint.vim 第16行定义 install_dir 的部分:

if has("win32")
	let s:install_dir = '"' . expand($VIMFILES."/ftplugin/javascript") . '"'
else

2. 对于带中文的JS文件,容易出现行定位错误的问题。原因和小明那篇文章里说的一样。我们同样在关键地方添加 iconv 转一下字符即可。

修改定义 b:jslint_output 的地方:

let b:jslint_output = system(s:cmd, iconv(join(s:jslintrc + getline(b:firstline, b:lastline), "\n") . "\n", &enc, "gbk"))

这么简单的问题,我折腾了两个小时。之前以为是换行符的问题。唉...

试试 Google Closure Linter

JSLint 默认的规则在有些情况下不太实用,比如说jQuery就会无视一些JSLint的错误。基于 Google 的编码风格,有一个 *Closure Linter*,我们可以试着把它集成到 Vim 中。

我修改了上面的 Vim 插件,有需要的可以点击这里下载。

gjslint 唯一的遗憾就是“字数过多”这个限制太严格了,对于我们宽屏用户来说,80个字符远远不够啊。暂时没有找到解决办法。

Vim Tips

插件与配置

  1. 在Vimwiki中,可以用 %title 自定义输出的 HTML 的 title ,但是最好写在文件最末尾,不然如果同时使用了 %toc (自动目录), 就会产生嵌套错误。这个bug将来可能会修正,但保持习惯是没错的。
  2. 把 _vimrc 和 vimfiles 拷到 msysgit 的安装目录下( C:\Program Files\Git\share\vim ),可以让 Git Bash 里的 vim 也符合你平时的操作习惯。
  3. NERDTree Explorer 里带星号的文件代表这个文件是可执行文件

编辑

  1. 除了普通模式,可视模式,插入模式,你是否还知道有一个替换模式?正如在普通编辑器里按 Insert 键所切换入的那样,输入的文本会逐字替换光标下的字符。
  2. 要在 Vim 里跨行匹配,可以用 \_. 匹配包括换行符在内的任意字符。
  3. 使用 \{-} 实现类似常见 perl 正则里的 ? 之作用的懒惰匹配,尽量少的匹配前面的匹配元。
  4. 使用 :s (替换)命令时,添加标志位 e 可以忽略找不到 pattern 的错误,这在函数或键盘映射命令中非常有用。如,下面的代码可以格式化CSS(虽然并不完美): map <leader>css :%s/;\s*\([a-z*_-}]\)/;\r\1/ge<cr>:%s/\(\w\)\s*{\([^\r]\)/\1\ {\r\2/ge<cr>:%s/:\(\w\)/:\ \1/ge<cr>:%s/}\(\w\\|#\\|\.\)/}\r\1/ge<cr>,=

你可能不知道的快速编辑快捷键: gv 选中之前选中过的内容 g~{motion} 切换{motion}跨越的文本的大小写 g~~ 切换当前行的大小写 gU{motion} 切换为大写 gu{motion} 切换为小写

不小心打开了一个需要 sudo 权限才能保存的文件,但是编辑了一大半才发现?下面的命令可以救急:

:w !sudo tee %

也可以做一个命令映射,安静地保存:

command W w !sudo tee % > /dev/null

使用 Vim Script

  1. 获取当前buffer的总行数的函数: line("$")
  2. 静默执行shell: :silent !cmd