Vim Tips

Vim是个很神奇的东西。从很早以前就开始使用它作为我的默认文本编辑器。

Vim是Bram Moolenaar的作品,同时也是几乎在所有Unix平台上都带有的VI的功能增强版本。Vim其实就是个文本编辑器,与常用的UltraEdit、EditPlus一样,都是程序员们常用的代码编辑工具。

Vim能做什么?目前流行的文本编辑器所有的功能,Vim几乎都能做到。不仅如此,Vim是个可扩展的编辑器,想实现什么功能,都可以通过script完成。

Vim对于新手而言,是个超级难用的编辑器。完全和以往人们的想法不同。(虽然现在Vim也提供Easy Vim,但那毕竟不是Vim的灵魂。用Easy Vim也没办法完全体会Vim的神奇。)

Vim可以从它的主页上下载,并且是完全免费的。同时,Vim支持常见的操作系统,这当然包括Windows、Mac、Linux/Unix。对于Windows用户来说,我推荐在安装过程中选择Full。这样会在%SYSTEMROOT%中创建几个BAT文件,能够方便快速的启动Vim。

Vim的配置依赖于.vimrc文件,该文件存在于$HOME目录中(Windows系统中为%USERPROFILE%)。很奇怪的是,Windows不允许将文件重命名为以“.”开头,却允许以“.”开头的文件存在。

要创建以“.”开头的文件,只要随便创建一个文件,然后进入命令提示符中,输入“ren 文件名 .vimrc”就可以了。或者更简单,在命令提示符中输入“echo a > .a”,就可以得到一个以“.”开头的文件。

看到这里,其实你不用创建.vimrc。Vim也支持在Windows环境下使用_vimrc作为配置文件。另外,配置文件并不是必须,没有这个文件,仍然可以运行Vim,只是默认设置而已。

这里我不打算讨论Easy Vim,因为和普通的编辑器没有什么区别,而且反而不如其他编辑器好用。如果你愿意以Easy Vim入手,okay,go ahead,但下面的内容貌似没有什么太大的用处了。

Normal Mode

Vim是模式(Model)的,默认的启动状态为Normal Mode,除此之外,还有Insert Mode、Command Mode和Vistual Mode。在Normal Mode中,键盘的输入都会被作为操作命令,而不是输入的内容。试试看,在一个刚刚启动的Vim中,按键是不会得到想要的输入的。

Normal Mode是最基础的模式。任何情况下,如果想进入Normal Mode,只要按ESC键就可以。同样,如果不确定当前在什么模式下,可以通过通过按ESC键的方式(或反复按ESC键),返回最基础的Normal Mode。如果此时已经处于Normal Mode,再按下ESC,Vim会给出声音警告。这也就是判断当前处于Normal Mode的一个方法。

Tip:如果你遗失在某个模式中,反复按ESC键盘,最终是会回到Normal Mode中的。嘀嘀的声音也会提示你已经进入Normal Mode。

模式之间的切换

模式之间的切换,是相对容易的。前面已经提到,要回到Normal Mode,只要按ESC键。

要想能够写文字,则首先应该切换到Insert Mode中。在Normal Mode中,按下i,就可以进入Insert Mode,此时会在窗口的最下方显示“– INSERT –”。

Tip:Vim中的各个命令都是区分大小写的。i和I将是两个不同的功能。

编辑文本

在初始的Normal Mode中,按下进入插入模式的命令即可。这些命令包括:
a在当前字符右侧插入
i在当前字符位置插入
A在当前行尾插入
O在当前行上方插入空行
o在当前行下方插入空行

同样,使用替换命令也可以对文本进行修改:
r替换当前位置字符
R进入替换状态

对于修改大小写这样的工作,则更是可以使用简单的命令完成:
guu本行小写
gUU本行大写

移动光标

在Vim的Normal Mode中移动光标,除了可以使用上、下、左、右的方向键外,更为正宗和传统的是使用hjkl,其中h表示左移,l表示右移,j表示向下,k表示向上。这种设计可以让使用者不移动手指的位置,就可以操作光标。

Tip:同样的光标移动快捷键,也出现在Google各产品(如:Gmail、Reader等)。

需要提醒的是,hjkl只能在Normal Mode中移动光标。而在Insert Mode中,则会作为文本插入到光标的位置。

Vim的命令

Vim的命令是区分大小的,而且是可以组合的。不仅如此,还可以通过数字,指定命令的执行次数。例如:d是删除的主命令,dd表示删除本行,dw删除当前词(w表示操作对象为词,其他命令中也可能用到),d^删除到行首(^表示行首),d$删除到行尾($表示行尾),d4d或者4dd表示执行4次dd命令,d3w表示删除3个词,等等……

打开和关闭文件

写好了文本,需要保存。只要输入:w即可;如果文件未命名,则可以使用:w 文件名。默认的当前路径是$HOME(Windows环境下为%USERPROFILE%)。

打开已经存在的文件,可以使用如下命令:

  1. :e 文件名

打开和保存文件,都支持Tab补全功能。只要输入文件或路径的开头几个字母,然后按下Tab键,就可以自动补全以此开头的文件或路径名,反复按Tab键可以在多个以此开头的名称中切换。

编辑完后,要退出Vim,只要使用

  1. :q

命令也是可以组合的,比如要保存当前文件,并退出,可以使用

  1. :wq

该命令也可以简化为ZZ。

命令也是可以强制执行的,如果当前文件没有保存,而使用:q退出,Vim会提示当前文件未保存。这时可以在命令后面加上“!”表示强制执行该命令(比如:q!表示不保存文本,强制退出)。同样的,如果:w也可以强制执行,表示文件即使是只读的,也强制保存。

搜索与替换

Vim的搜索可以说是强大。不仅支持正则表达式(RegEx),操作还非常方便。

搜索是以在Normal Mode中“/”开头的命令/{pattern}<CR>,例如搜索RegEx,只要在Normal Mode中输入:

  1. /RegEx

需要注意的是,Vim默认情况下,搜索、替换都是区分大小写的,但也可以修改这项设置(:set ignorecase)。

而smartcase功能,则聪明的实现了根据你的输入来确定是否匹配大小写。例如:输入全小写单词会忽略大小写匹配功能,而任意字母大写,则会区分大小写匹配。

但是,如果只打算在一个字符上忽略大小写怎么办呢?只要在需要忽略大小写的字符前面加上\C即可,例如“/\CReg\cEx”,就会匹配RegEx、regex、Regex和regEx,但不会匹配REGEX。该选项会忽略smartcase和ignorecase的设定。

搜索还可以偏移,b表示开头,e表示结尾,正数表示右移,负数表示左移。例如:“/test/e-1”就会搜索test并把光标置为s字母上;同理,“/test/b+2”会移动到同样的位置上。

如果打开incsearch功能(set incsearch),则在输入要搜索文字的同时,就可以同步显示出找到的内容。

搜索完成后,n可以搜索下一次出现的{pattern},p可以搜索上一个。重复上次搜索,还可以直接输入“/<CR>”。

替换操作同样是这样完成,输入:{range}s[ubstitute]/{exp1}/{exp2}/{flags}。{range}可以是行号(1,2,3或者1-10),也可以是%表示所有行,如果没有写,则表示只替换当前行。{flag}是可选的,g表示替换每一行中所有的匹配项,c表示每次替换都需要confirm。

代码折叠

代码折叠功能是我印象中Vim7中增加的。挺早以前,Visual Studio、UltraEdit、Source Insight等软件中的代码折叠功能,都是非常好用,直到Vim也增加同样的功能。

Vim的代码折叠,除了可以根据语法外,还可以根据自定义的正则表达式来完成。

对于一般的程序代码而言,最简单的创建折叠的方法,就是按照代码语法创建折叠(set fdm=syntax)。之后可以zc折叠代码,zo打开代码。

剪贴板和寄存器

Vim中的每个字母都是一个寄存器,相当于有26个寄存器。寄存器既可以作为存储文本使用,也可以作为记录一组命令(宏)使用。

要复制一段选中的文本到寄存器,只要按下”{reg}y即可,其中{reg}可以是a~z的任何一个字母。不仅如此,我们还可以添加文本到寄存器中,方法是”{REG}y,区别就是把寄存器的名字变为大写。

要把寄存器的内容插入到文本中,需要按下”{reg}p。

这里有个特别的寄存器,就是+,它可以实现Vim和其他应用程序(Windows剪贴板或X11的剪贴板)的连接。所以,如果在Vim外用C+Insert(或CTRL+C)复制了文本,要粘贴到Vim中,只要按下”+p即可;反之,要把Vim的文本复制到其他应用程序中,则可以使用”+y。

如果要将Vim中的全文都复制到别的程序中,可以使用ggVG “+y。

寄存器还可以用来存储一组命令(宏),方法是q{reg},之后操作的命令都会被记录到这个寄存器中,@{reg}可以回放这组命令。同样的q{REG}可以向寄存器中添加命令。

如果对于整行的操作,复制文本也可以使用yy和p。

编写代码

当你用编辑器编写OO语言的程序(其实在普通的C语言中也可能),经常遇到每行的部分内容都一样的情况。例如,我们经常碰到这种情况:

  1. Obj.Instance[0].Data.Set.test1 = 1;
  2. Obj.Instance[0].Data.Set.test2 = 2;
  3. Obj.Instance[0].Data.Set.test3 = 3;
  4. Obj.Instance[0].Data.Set.test5 = 4;

这种情况,Vim可以借助I命令很好的快速完成这些工作(UltraEdit也有类似的功能,叫做Column Mode)。

先写这样的代码,把每行不同的部分打出来就可以了:

  1. 1 = 1;
  2. 2 = 2;
  3. 3 = 3;
  4. 4 = 4;

然后把光标移动到左上角的1的位置,并在Normal Mode中按下CTRL+V进入VISUAL BLOCK Mode;按3次j移动到4上面,这是第一列的1~4都被选中了。接着按I,输入前面的那部分“Obj.Instance[0].Data.Set.test”,然后按下ESC键。是不是所有选中行都出现了呢?

当然,如果你只是重复上一行的输入的话,在Insert Mode下,直接按下CTRL+Y,就可以复制上一行上同位置的字符。

而代码中的缩进,可以使用下面的命令实现:
SHIFT+>>:缩进Tab
SHIFT+<<:左移一个Tab

生成目录

对于本文这样的文本,每个标题都是使用<H3>标记的,所以Vim同样支持针对这样的文本,生成目录。

:vimgrep/{pattern}/%:根据{pattern}取得目录,对于这个文档,可以是^<\Ch3>。
:cw:显示目录
:CTRL+W H:将目录显示在左侧

标签(Tags)

Tag需要另一个工具叫ctags,可以从SourceForge上下载(Unix下比较省心,不需要安装)。所谓Tag,实际上实现的功能就是代码跳转。

在实现代码跳转前,首先要调用ctags生成标签文件。命令很简单,下面的命令就是对当前目录下所有的C文件生成标签:

  1. ctags *.c

具有标签文件后,只要在文件中按下CTRL+]就可以实现跳转。例如,代码中有个函数叫foo,如果看到别的地方调用这段代码,只要在调用的foo函数上按下ctrl+]就可以跳转到对应的定义位置。

.vimrc

.vimrc是Vim的配置文件,默认存放在$HOME中(Windows环境为%USERPROFILE%)。当然Vim并不一定要求配置文件一定存在上面的路径中,放在$VIMRUNTIME中也可以。

.vimrc可以提供对Vim的全部的配置,或者是对功能的扩充(可以写自己的script)。

这里提供一些配置:

对于GUI模式,自动展开语法菜单

  1. " Make Syntax menu expended to show each language syntax in the menu
  2. if has('gui_running')
  3. let do_syntax_sel_menu=1
  4. endif

设置UTF-8为默认编码方式

  1. " Make UTF-8 as default encoding
  2. if $LANG !~ '\.'
  3. set encoding=utf-8
  4. endif
  5. set fileencodings=ucs-bom,utf-8,gbk

对于未指定宽度的UTF-8编码文字,指定为双字节宽
设置本项,即可解决在UTF-8编码下,某些符号只显示半个

  1. " Set Unknown char as double byte
  2. " Refer to http://www-128.ibm.com/developerworks/cn/linux/l-tip-vim1/
  3. if has('multi_byte') &amp;&amp; v:version &gt; 601
  4. set ambiwidth=double
  5. endif

设置不兼容VI
Vim提供更多的功能,设置为不兼容模式后,则可以使用这些功能

  1. set nocompatible

设置自动缩进

  1. set autoindent

设置CTRL+S为保存的快捷键

  1. noremap  :update
  2. vnoremap  :update
  3. inoremap  :update

打开当前文件目录中的文件

  1. "   Edit another file in the same directory as the current file
  2. "   uses expression to extract path from current file's path
  3. if has("unix")
  4. map ,e :e =expand("%:p:h") . "/"
  5. else
  6. map ,e :e =expand("%:p:h") . "\\"
  7. endif

设置增量搜索,显示所有匹配项,并将F2作为取消高亮显示的快捷键

  1. set incsearch
  2. set showmatch
  3. " Key mapping to stop the search highlight
  4. nmap        :nohlsearch
  5. imap   :nohlsearch

提供与其他应用程序复制粘贴的快捷键

  1. " Key mapping to Cut/Copy/Paste from public register
  2. vnoremap  "+y
  3. vnoremap  "+x
  4. map  "+p
  5. cmap  "+p
  6. imap  "+p
  7. vmap  "+p

备份当前文件,并继续编辑

  1. " backup current file with a new name then start edit
  2. map  s   :up \| saveas! %:p:r-=strftime("%y%m%d")-bak \| 3sleep \| e #

重新对代码调整缩进

  1. gg=G
Tags: ,
Posted by Wei@15:39 11/11/2008 in Computer Science | Permalink | Trackback | No comments.

7 Habits For Effective Text Editing 2.0

Bram Moolenaar是Vim的作者。这里是他在February 13, 2007的Google Tech Talks上的Presentation。

Loading...

http://www.youtube.com/watch?v=eX9m3g5J-XA

Tags:
Posted by Wei@17:06 12/12/2007 in Computer Science | Permalink | Trackback | No comments.

Vim中编辑不同编码的文件的方法

先来说一下Vim中编码的基础内容:

Vim中存在3个与编码相关的变量:

  • encoding - 用于buffer、script、register的编码设置,与system locale相同
  • fileencoding - 写入文件的编码类型。如果为空,就使用encoding的设置,所以默认情况就是system locale
  • termencoding -输出到terminal的编码类型。默认为空值,也就是输出到terminal的时候不做转换

文件的编码类型和自动识别:文件编码类型并非保存在文件内的,也就是说没有任何描述性的字段来记录文档是何种编码类型的。因此我们在编辑文档的时候,要么必须知道这文档保存时是以什么编码保存的,要么通过另外的一些手段来断定编码类型。这另外的手段,就是通过某些编码的码表特征来断定,例如每个字符占用的字节数,每个字符的ascii值是否都大于某个字段来断定这个文件属于何种编码。这就是vim的自动编码识别机制。但这种机制由于编码各式各样,不可能每种编码都有显著的特征来辨别,所以是不可能100%准确的。对于GB2312编码,由于其中文是使用了2个acsii值高于127的字符组成汉字字符的,因此不可能把gb2312编码的文件与latin1编码区分开来,因此自动识别编码的机制对于gb2312是不成功的,它只会将文件辨识为latin1编码。此问题同样出现在gbk,big5上等。因此在编辑此类文档时,需要手工设定encoding和fileencoding。如果文档编码为utf-8时,一般vim都能自动识别正确的编码。

客户运行vim的终端所使用的编码类型:这将决定vim输出内容到终端时使用的编码,如果此编码类型和终端认为它收到的数据的编码类型不同,则又会产生乱码问题。在linux本地X环境下,一般终端都认为其接收的数据的编码类型和系统locale类型相符,因此不需关心此方面是否存在问题。但如果牵涉到远程终端,例如ssh登录服务器,则问题就有可能出现了。例如从1台locale为GB2310的系统(称作客户机)ssh 到locale为utf-8的系统(称作服务器)并开启vim编辑文档。在不加任何改动的情况下,服务器返回的数据为utf-8的,但客户机认为服务器返回的数据是gb2312的,按照gb2312来解释数据,则肯定就是乱码了。这时就需要设置termencoding为gb2312来解决这个问题。此问题更多出现在windows desktop机远程ssh登录服务器的情况下,这里牵扯到不同系统的编码转换问题。所以又与windows本身以及ssh客户端有很大相关性。在 windows下存在两种编码类型的软件,一种是本身就为unicode编码方式编写的软件,一种是ansi软件,也就是程序处理数据直接采用字节流,不关心编码。前一种程序可以在任何语言的windows上正确显示多国语言,而后一种则编写在何种语言的系统上则只能在何种语言的系统上显示正确的文字。对于这两种类型的程序,需要区别对待。以ssh客户端为例,如果使用的putty是unicode软件,而secure CRT则是ansi 软件。对于前者,要正确处理中文,只要保证vim输出到终端的编码为utf-8即可,就是termencoding=utf-8。但对于后者,一方面要确认windows系统默认代码页为cp936(中文windows默认值),另一方面要确认vim设置的termencoding=cp936。

常见问题1:Terminal和system locale都被设置为utf-8,但编辑的文件是GB2312或者GBK 编码的。这时在Vim通常会显示为乱码。(前面说过,这将导致Vim的自动编码识别把文件错误地识别为latin1。这时的encoding=utf-8,fileencoding=latin1,termencoding=<empty>。)

解决方法:修正fileencoding为对应的文件编码方式为cp936或者euc-cn(这两个是一个东西,只是名字不同):

  1. :edit ++enc=cp936

或者简写为

  1. :e ++enc=cp936

(注意不能用set fileencoding=utf-8这种方式,因为这种方式实际上是修改了文件保存的编码,而非load的编码)。

另一种方法是临时改变Vim启动环境的locale,设置LANG=zh_CN。此时的encoding=euc-cn

常见问题2:一台Windows主机上ANSI的程序SSH到system locale为utf-8的主机上,并编辑文件。(此时:encoding=utf-8,fileencoding=latin1,termencoding=<empty>)

解决方法:设置termencoding=cp936。或者用同样修改system locale(如上)。

Tags:
Posted by Wei@0:13 26/26/2007 in Computer Science | Permalink | Trackback | 1 Comment.