The difference between fiction and reality? Fiction has to make sense.

- Tom Clancy

继续补充vim配置技巧——上次的vimrc还不够强力

June 7, 2009

picture-4.png首先要补充一些MacVim的配置,其实写上篇文章的时候我还在用已经过时的基于Carbon界面的vim for osx,更接近传统的unix版本,但是好久没更新,只支持vim6.0,soureforge上有一个7.2的版本,bug诸多,其中的乱码和字体抗锯齿的问题让我完全无法忍。而MacVim是基于Cocoa开发,支持到7.2,还含有很多讨好mac用户的设计,比如对标签的良好支持,华丽的界面(背景颜色支持透明度,字体抗锯齿更漂亮,几乎跟TextMate的效果没区别)……非常后悔以前没仔细试用这个版本!目前为止只发现行高linespace的设置会无法生效,不过这个bug在最新的快照版里已经修正了。

插播一个道歉:由于spam太多,我前段时间在wordpress黑名单里加了一个很苛刻的条件,把所有评论都挡到待审核列表里去了,好像还直接删了一部分……咳……

我在.vimrc里增加了一些专门针对MacVim的设置:

  1. if has("gui_macvim")
  2.   "取消默认的快捷键
  3.   let macvim_skip_cmd_opt_movement = 1
  4.   let macvim_hig_shift_movement = 1
  5.  
  6.   "设置背景透明度
  7.   set transparency=2
  8.   "隐藏工具条
  9.   set guioptions-=T "egmrt
  10.  
  11.   "绑定自己需要的cmd快捷键
  12.   macm File.Save                              key=<D-s>
  13.   macm File.Save\ As\.\.\.                    key=<D-S>
  14.   macm Edit.Undo                              key=<D-z> action=undo:
  15.   macm Edit.Redo                              key=<D-Z> action=redo:
  16.   macm Edit.Cut                               key=<D-x> action=cut:
  17.   macm Edit.Copy                              key=<D-c> action=copy:
  18.   macm Edit.Paste                             key=<D-v> action=paste:
  19.   macm Edit.Select\ All                       key=<D-A> action=selectAll:
  20. endif

之所以要取消MacVim默认的一些快捷键是因为它们都占用了cmd苹果键,而我习惯用这个键来替代ctrl在vim里的作用(在mbp的键盘上就算我想用ctrl也不方便……),不过其中有几个快捷键是非常非常有价值的,比如保存(省去了输入:w的麻烦),全选(否则要摁六下:ggVG),复制粘贴剪切(否则为了使用剪贴板,比如猛摁这种玩意:”+y,还不能在插入模式下使用 ),幸好它们的快捷键都不跟vim其他操作冲突,所以自己设置。为了完全删除MacVim默认的cmd快捷键,还需要打开app中自带的vimrc文件(可以这样编辑::tabe $VIM/vimrc ),删除末尾那些macm开头的代码。


MacVim的安装包里包含一个mvim,是像gvim一样的脚本,用来在命令行中调用GUI版的vim,但是mvim默认会在新窗口打开文件,我相信多数人都喜欢在当前窗口的新标签页里打开罢,需要在命令后加–remote-tab参数,不过这篇文章里给出了直接修改脚本的方法,把mvim底部从# Last step: fire up vim开始的部分删掉,改成:

  1. tabs=true
  2.  
  3. # Last step:  fire up vim.
  4. if [ "$gui" ]; then
  5. if $tabs && [[ `$binary --serverlist` = "VIM" ]]; then
  6.     exec "$binary" -g $opts --remote-tab-silent ${1:+"$@"}
  7. else
  8. exec "$binary" -g $opts ${1:+"$@"}
  9. fi
  10. else
  11. exec "$binary" $opts ${1:+"$@"}
  12. fi

P.S. 上面给出的那个blog不能直接打开,也许是需要翻墙,不过我顺便介绍一个很方便的利用google网页快照的方法~ 用谷歌翻译打开这个网址 XD


刚安装好的MacVim打开gb编码的文件仍然把中文显示成乱码(好无奈,GBK编码是土豆网的历史遗留问题,页面里的script标签也几乎都没加charset=”utf-8″,所以大部分js文件都只好用gb18030的编码,textmate正是因为不支持gb编码才被我降为二等公民的,其实我有正版cdkey……),我在.vimrc里加上了encoding似乎能解决这个问题:

  1. set encoding=utf-8
  2. set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936

解释一下:对于编码,vim里有三个设置选项,encoding是设置vim以何种编码显示文件(缩写enc),fileencoding是当前文件实际的编码(缩写fenc), 而fileencodings指示vim如何解码(缩写fencs),因此vim在打开一个文件时实际上会先根据fileencodings里的列表反复测试,直到成功解码,转换成encoding指定的编码,然后正常显示,转码的过程是用iconv实现的(所以windows上用vim还要配置iconv的dll路径和参数……麻烦),保存的时候会根据fileencoding来保存,跟是否显示为乱码没有关系。

所以如果想转换一个文件的编码,比如从utf-8转换到gb18030,可以在编辑器中直接输入两个命令:

  1. :set enc=gb18030
  2. :set fenc=gb18030

然后保存就ok了~其实如果不用继续编辑的话,第一行都可以省去,因为它的目的只是让编辑器用gb18030来显示当前文件,避免乱码,但是并不影响文件保存时的编码和正确性。

以前我都是依赖mac上的Coda来转换编码(确实最方便)……vim又成功了抢了它的饭碗……


MacVim还有一个问题是会显示一个很宅很不人性的标签栏名称,比如我编辑/usr/local/bin/mvim这个文件,标签栏上写的是“/u/l/b/mvim”,如果目录结构再深一点就看不到真正的文件名了,在.vimrc里加入下面这行可以让标签栏只显示文件名:

  1. set guitablabel=%t



上次的.vimrc里还增加了两处很重要的设置,主要是受这位老爷写的《vim使用进阶》的启发,首先是让.vimrc每次编辑保存后自动生效,避免重启:

  1. autocmd! bufwritepost .vimrc source ~/.vimrc

autocmd实际上是vim脚本的事件机制,表示在某个事件触发后自动执行的命令


接下来要实现的是保存和恢复编辑器的当前状态,类似Eclipse的Workspace,不过vim的session更强大,几乎可以还原一切状态……Easwy老爷介绍的命令比较繁琐,缺乏“一键恢复”的快感……身为一个习惯使用“高级语言”的程序员,在这种时候就抑制不住继续封装和提高抽象层的欲望……所以自定义了以下两个命令:

  1. function! GetMySession(spath, ssname)
  2. if a:ssname == 0
  3. let a:sname = ""
  4. else
  5. let a:sname = "-".a:ssname
  6. endif
  7. execute "source $".a:spath."/session".a:sname.".vim"
  8. execute "rviminfo $".a:spath."/session".a:sname.".viminfo"
  9. execute "echo \"Load Success\: $".a:spath."/session".a:sname.".vim\""
  10. endfunction
  11.  
  12. function! SetMySession(spath, ssname)
  13. if a:ssname == 0
  14. let a:sname = ""
  15. else
  16. let a:sname = "-".a:ssname
  17. endif
  18. execute "cd $".a:spath
  19. execute "mksession! $".a:spath."/session".a:sname.".vim"
  20. execute "wviminfo! $".a:spath."/session".a:sname.".viminfo"
  21. execute "echo \"Save Success\: $".a:spath."/session".a:sname.".vim\""
  22. endfunction
  23.  
  24. " load session from certain path
  25. command! -nargs=+ LOAD call GetMySession(<f-args>)
  26.  
  27. " load session from certain path
  28. command! -nargs=+ SAVE call SetMySession(<f-args>)

为了用最简单的方法选择路径,使用时需要先在终端的初始化脚本(比如~/.bashrc,在我的OSX系统里通常用~/.profile)里添加相应的环境变量,比如我常用的三个路径:

  1. export TUISVN="/Users/dexteryy/Sites/Tudou/ui/ui/"
  2. export TUIDEV="/Volumes/ui.tudou.com/"
  3. export MYWEB="/Users/dexteryy/Sites/www/"

当我在MYWEB的路径下做项目的时候,如果需要保存当前状态,只要输入:SAVE MYWEB 0就行了,这里的0是因为考虑到在同一个工作目录里可能需要使用到不同文件组合的工作区,提供的一个简单的版本号,这段命令执行后会在/Users/dexteryy/Sites/www/目录里生成两个文件: session.viminfo和session.vim,如果版本号是大于0的整数,比如2,文件名会是session2.viminfo和session2.viminfo

需要恢复的时候只要输入命令::LOAD MYWEB 0 就行叻~

喔对了,为了能在VIM命令里使用bash中定义的变量,你需要在MacVim的preferences里把“Launch Vim processes in a login shell”勾选,熟悉Mac应用的同学应该都能想到这个设置会记录在/Library/Preferences/或~/Library/Preferences/里的某个配置文件里,MacVim对应的是~/Library/Preferences/org.vim.MacVim.plist,所以你也可以直接用这个命令在终端里修改:

  1. defaults write org.vim.MacVim MMLoginShell 1

如果使用的是Gvim或windows版本的vim,也可以直接把路径变量写在.vimrc里,比如:

  1. let g:TUISVN="/Users/dexteryy/Sites/Tudou/ui/ui/"

然后修改上面的两个函数GetMySession和SetMySession,把a:spath前面的$都删掉…………因为VIM里的变量只能由大写字母开头……

完整的.vimrc在这里…………呃好罢我发现google code真是备份和维护配置脚本的好地方XD


最后继续讨论一下插件~

首先是Taglist,这是一个能让vim具备类似Aptana的Outline View的功能,还能像JAVA的IDE那样通过类名和方法名直接跳转到相应的源码,它借助了一个叫ctags的工具,可以解析源码生成标签文件(在同一个名录下,叫tags),详细的介绍请参考Easwy老爷的文章,记得务必安装最新版的Exuberant Ctags……我是用MacPorts装的:sudo port install ctags

Exuberant Ctags号称支持34种语言,包括javascript,但是它对javascript的理解非常OUT……比如现在定义JS方法几乎主要依靠匿名函数了,ctags却无法识别这种形式……

已经有人在尝试自己添加匹配规则,我自己也写了一大坨:

  1. --langdef=js
  2. --langmap=js:.js
  3. --regex-js=/[ \t.]([A-Z][A-Z0-9._$]+)[ \t]*=[ \t]*[0-9"'\[\{]/\1/n,constant/
  4. --regex-js=/([A-Za-z0-9._$]+)[ \t]*=[ \t]*\{/\1/o,object/
  5. --regex-js=/['"]*([A-Za-z0-9_$]+)['"]*[ \t]*:[ \t]*\{/\1/o,object/
  6. --regex-js=/([A-Za-z0-9._$]+)\[["']([A-Za-z0-9_$]+)["']\][ \t]*=[ \t]*\{/\1\.\2/o,object/
  7. --regex-js=/([A-Za-z0-9._$]+)\.prototype[ \t.=]/\1/c,class/
  8. --regex-js=/([A-Za-z0-9._$]+)[ \t]*=[ \t]*\(function\(\)/\1/c,class/
  9. --regex-js=/['"]*([A-Za-z0-9_$]+)['"]*:[ \t]*\(function\(\)/\1/c,class/
  10. --regex-js=/var[ \t]*([A-Za-z$][A-Za-z0-9_$()]+)[ \t]*=[ \t]*function[ \t]*\(/\1/f,function/
  11. --regex-js=/function[ \t]+([A-Za-z$][A-Za-z0-9_$]+)[ \t]*\(([^)])\)/\1/f,function/
  12. --regex-js=/['"]*([A-Za-z$][A-Za-z0-9_$]+)['"]*:[ \t]*function[ \t]*\(/\1/m,method/
  13. --regex-js=/([A-Za-z$][A-Za-z0-9_$]+)[ \t]*=[ \t]*function[ \t]*\(/\1/m,method/
  14. --regex-js=/([A-Za-z0-9_$]+)\[["']([A-Za-z0-9_$]+)["']\][ \t]*=[ \t]*function[ \t]*\(/\2/m,method/
  15. --regex-js=/([A-Za-z0-9._$]+)[ \t]*=[ \t]*\[/\1/a,array/
  16. --regex-js=/['"]*([A-Za-z$][A-Za-z0-9_$]+)['"]*:[ \t]*\[/\1/a,array/
  17. --regex-js=/([A-Za-z0-9._$]+)\[["']([A-Za-z0-9_$]+)["']\][ \t]*=[ \t]*\[/\1\.\2/a,array/

匹配以下语法形式,其中粗体部分是标签名称:

  1. var MY_CONSTANT = 250; //constant
  2. ns.myobject = {}; //object
  3. myobject: {}, //object
  4. ns["myobject"] = {}; //object, 生成的tag是”ns.myobject
  5. ns.myclass.prototype.myfunc = function(){}; //class
  6. ns.myclass = (function(){return {};}); //class
  7. ns["myclass"] = (function(){return {};}); //class, 生成的tag是”ns.myclass
  8. var myfunc = function(){}; //function, 必须有var, _开头的忽略
  9. function myfunc(){}; //function
  10. myfunc: function(){} //method
  11. ns.myfunc = function(){}; //method
  12. ns["myfunc"] = function(){}; //method, 生成的tag是”ns.myfunc
  13. ns.myarray = []; //array
  14. myarray: [], //array
  15. ns["myarray"] = []; //array, 生成的tag是”ns.myarray

使用方法是建一个~/.ctags文件,把上面那段代码放进去就行。为了在taglist窗口里显示类别(比如class和method),还需要在.vimrc里设置一个变量:

  1. let g:tlist_javascript_settings = 'javascript;f:function;c:class;o:object;m:method;s:string;a:array;n:constant'



另一个要强烈推荐的插件是NERD Commenter,从名字能看出跟上次推荐的NERD Tree是同一个强者写的,功能是针对各种文件类型快速的添加和删除注释,除了单行,多行,还提供“sexily”的注释……比如js里添加文档内容时常用的那种(如果首行写成/**,在aptana里会认作script doc格式)

不过这个插件默认使用了大量,c开头的快捷键……而,在vim里一般都用作自定义的键(的默认值是\,很显然小拇指没食指方便……),我没有找到相关的设置选项……所以直接修改了插件脚本……


唔唔就先写到这里罢,虽然vim无论日常使用还是hack都很爽,但是写起来还是挺枯燥的,头有点晕555……

posted in JavaScript, OpenSource, 代码, 工具 by Dexter.Yy

Follow comments via the RSS Feed | Leave a comment | Trackback URL

4 Comments to "继续补充vim配置技巧——上次的vimrc还不够强力"

  1. broom wrote:

    写得好长,赞。是水木的Limbo么……
    推荐一下FuzzyFinder插件,可能是我现在使用频率最高的插件了。

  2. dexter_yy wrote:

    FuzzyFinder我也装了,一堆f开头的快捷键好麻烦……而且我感觉在普通的命令窗口里用ctrl/cmd d 列出当前目录的内容更顺手哑~ 用FuzzyFinder经常点错-___-b

    PS: limbo不是我的id,不过水木VIM班确实很赞~要找时间去仔细刨一遍XD

  3. pt wrote:

    # “取消默认的快捷键
    # let macvim_skip_cmd_opt_movement = 1
    # let macvim_hig_shift_movement = 1
    这两段好像不是取消所有默认的快捷键,而是取消跟方位键有关的快捷键,详见$VIM/gvimrc

  4. PHP Blog | Mac OS X 上的PHP开发环境 wrote:

    [...] 对于Linux用户来说,Vim再也熟悉不过了,因为这个开源软件本身的魅力,更有很多人在Windows下使用Gvim,在Mac下使用Macvim。这里有两位国内的Vim爱好者做了不少的研究,非常感谢他们的blog提供的技术分享: Dexter.Yy: 面向前端开发者和TextMate粉丝的vim配置 继续补充vim配置技巧——上次的vimrc还不够强力 [...]

Leave Your Comment

YY in Limbo (混沌海狂想) © Dexter.Yy

Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution - NonCommercial - ShareAlike 3.0(署名-非商业性使用-相同方式共享).
Creative Commons License