[Vim]用行号参与替换

一个小技巧。Vim有好处千种,”替换”只是其中一个。

除了强大的正则表达式,\=也是一个好用的工具。
比如要生成这么一个文件

This is number 1
This is number 2
This is number 3
This is number 4
This is number 5
This is number 6
This is number 7
This is number 8
This is number 9
This is number 10

方法当然有很多。用\=可以这么做:
先输入一行

This is number X

复制出另外9行

yy9p

得到

This is number X
This is number X
This is number X
This is number X
This is number X
This is number X
This is number X
This is number X
This is number X

然后冒号进入Command-line模式 (关于Vim的几种模式)

:%s@X@\=line('.')

就得到了

This is number 1
This is number 2
This is number 3
This is number 4
This is number 5
This is number 6
This is number 7
This is number 8
This is number 9
This is number 10

\=其实就是对\=之后的表达式求值用来做替换。line(‘.’)是一个返回数值的函数,返回当前行的行号,所以每一行的行号被作为\=的返回值,用来替换X,就得到了需要的结果。

其他方法比如做一个宏(Macro)来逐行递增也可以达到效果,但是不如用这个\=方便。
因为\=后面的部分是作为表达式来处理的,所以更复杂一些的替换都可以很简单的得到实现,比如 (先撤销掉之前的改动,下同):

:%s@X@\=line('.')*line('.')

就可以得到

This is number 1
This is number 4
This is number 9
This is number 16
This is number 25
This is number 36
This is number 49
This is number 64
This is number 81
This is number 100

我个人觉得最好用的是这个功能

:%s@X@\=printf("%03d", line('.'))

可以得到

This is number 001
This is number 002
This is number 003
This is number 004
This is number 005
This is number 006
This is number 007
This is number 008
This is number 009
This is number 010

printf的加入又带来了太多种可能的玩法,非常称手。

Linux Tips (1)

这里记录一些小技巧,比较杂。

1. bash下,x{a,b}会被展开为xa xb,很适合文件备份。
如果你要复制一份a.txt作为备份,到a.txt的路径又太长了,这么写比较方便。

cp /a/long/long/long/path/to/file/a.txt{,bak}

2. vim下,要把某些内容替换成为行号,可以用\=line(“.”)来处理。“.”用来连接行号和其它内容。

:%s/xxxx/\=line(".") . " "/g

3. bash脚本下,如果要写多行到文件里,可以用

cat > file << EOF
file content line 1
file content line 2
file content line 3
file content line 4
EOF

这是一种固定写法,从第二行起,遇到EOF就停止,把之前的内容写到file里。EOF也可以换成别的。

4. Trap SIGINT的时候记得要处理SIGINT信号。

#! /bin/bash

trap "echo 'hello'; exit 1" SIGINT SIGTERM

while [ 1=1 ];
do
    sleep 1
done

exit 1这部分是必须的,否则虽然按下Ctrl + C的时候会显示hello,但是脚本不会被终止。

Project-Specific Vim Configuration

Usually, we have our own vim configuration in the file ~/.vimrc
What if we want one for our project?
For example, we are working on certain project which needs to read in a tags file.
Well, here is a possible solution.

You put a line at then end of your ~/.vimrc file

source ./.project.vim

Then for each project, put your project-specific stuff in a the file “.project.vim”.

If you don’t want the error message says vim cannot find the file “.project.vim”,
wrap the line above with an if statement:

if filereadable("./.project.vim")
    source ./.project.vim
endif

:]

vimGdb

又回到了用VIM的状态。刚装起来了vimGdb,vim的各种gdb插件还是这个比较顺手。唯一的不足之处是vimGdb需要给源码打一个Patch。

vim最新的稳定版本是7.3,对应的vimGdb在这里 larrupingpig/vimgdb-for-vim7.3

下面的说明比较清楚了,需要注意的是vim的源码必须是 vim-7.3.tar.bz2 这个包,如果是从最新的库里checkout的代码会和patch不匹配。

比如在~/Temp下有

vim-7.3.tar.bz2 vimgdb-for-vim7.3.tar.gz

解压

$tar xvf ./vim-7.3.tar.bz2
$tar xvf ./vimgdb-for-vim7.3.tar.gz

打patch

$patch -p0 < ./vimgdb-for-vim7.3/vim73.patch

编译

$cd ./vim73
$./configure --enable-gdb
$make
$sudo make install

把./vimgdb-for-vim7.3/vimgdb_runtime/里面的文件拷贝到~/.vim/下
推荐使用Pathogen管理plugin,会比较方便一点

在~/.vimrc里增加一句

source ~/.vim/macros/gdb_mappings.vim

然后就OK了。编译代码的时候用-gstabs+让gcc把调试的信息加上去。
具体请参看vimGBD的文档。这里也行:gdb.txt

P.S.
大神们真无聊啊,居然把vim移植到iOS上去了...Vim iOS

[Tips]2011-10-30

vim的paste mode

我们会遇到这样的情况:
需要从Vim之外的其它程序里拷贝一大段文字,然后在Vim里粘贴。

一般的,启动vim之后,按i进入插入模式 (Insert Mode),然后粘贴就行了。
但是当Vim的配置越来越多,插入模式下粘贴大段文字时可能会遇到各种诡异的情况。
因为这个时候的粘贴就相当于手动输入这些内容,于是各种映射 (Mapping) 就被触发了….

:set paste

可以启动一种paste模式,这个时候各种Mapping会被无视,各种自动缩进也无效。和在记事本里粘贴效果一致。

paste命令也符合Vim的通常规范

:set nopaste

可以关掉它。

[Tips]2011-10-19

两个Vim的小技巧 :]

其实就是两个正则表达式,刚好今天用到了,就记下来。

1. 有多行文本,其中有几行是URL,要保留这几行URL,其它的行删掉。

:g!/:\/\//d

g本来是用来做grep类似的事情的,:g/pattern 会显示出符合pattern的所有行
惊叹号!表示相反,就是指选中的行是不符合pattern的。后面的/d是表示删掉选中的行。

2. 有多行文本,每行都是类似这样的

keyA=valA&keyB=valB&keyC=valC

现在要交换key和val的位置,变成

valA=keyA&valB=keyB&valC=keyC

:%s/\<\(\w*\)\>=\<\(\w*\)\>/\2=\1/gi

%s是全局替换,这个比较常用了。\<和\>是不太常用的anchor字符(锚字符),分别表示word的开始和结束。
\(..\)也比较常用了,可以保存匹配结果。\w*表示一个或多个word字符。
word字符包括a-zA-Z _ 和 0-9

:]

[Vim]vim的几种模式和按键映射

Map是Vim强大的一个重要原因,可以自定义各种快捷键,用起来自然得心应手。
vim里最基本的map用法也就是

:map c a

这里把c映射成了a,在map生效的情况下,按下c就等同于按下了a
当然,常用的Ctrl,Shift,Alt自然也是支持的。

  • 令Ctrl+a对应到a
  • :map  a
    
  • 令Alt+a对应到a
  • :map  a
    
  • 令Ctrl+Alt+a对应到a
  • :map  a
    

到此,我们已经可以做很多事情了。
但是map命令远不只这一种,在不同的模式下,同一组按键可以被映射到不同的组合上。
Vim的模式众多,但是一般被提及的也就是这么几种:

  1. Normal Mode
  2. 也就是最一般的普通模式,默认进入vim之后,处于这种模式。

  3. Visual Mode
  4. 一般译作可视模式,在这种模式下选定一些字符、行、多列。
    在普通模式下,可以按v进入。

  5. Insert Mode
  6. 插入模式,其实就是指处在编辑输入的状态。普通模式下,可以按i进入。

  7. Select Mode
  8. 在gvim下常用的模式,可以叫作选择模式吧。用鼠标拖选区域的时候,就进入了选择模式。
    和可视模式不同的是,在这个模式下,选择完了高亮区域后,敲任何按键就直接输入并替换选择的文本了。
    和windows下的编辑器选定编辑的效果一致。普通模式下,可以按gh进入。

  9. Command-Line/Ex Mode
  10. 就叫命令行模式和Ex模式吧。两者略有不同,普通模式下按冒号(:)进入Command-Line模式,可以输入各种命令,
    使用vim的各种强大功能。普通模式下按Q进入Ex模式,其实就是多行的Command-Line模式。

对于Map,有几个基本的概念

  • 命令的组合
  • 同Vim下的其他命令一样,命令的名字往往由好几段组成。前缀作为命令本身的修饰符,微调命令的效果。
    对于map而言,可能有这么几种前缀

    1. nore
    2. 表示非递归,见下面的介绍

    3. n
    4. 表示在普通模式下生效

    5. v
    6. 表示在可视模式下生效

    7. i
    8. 表示在插入模式下生效

    9. c
    10. 表示在命令行模式下生效

  • Recursive Mapping
  • 递归的映射。其实很好理解,也就是如果键a被映射成了b,c又被映射成了a,如果映射是递归的,那么c就被映射成了b。

    :map a b
    :map c a
    

    对于c效果等同于

    :map c b
    

    默认的map就是递归的。如果遇到[nore]这种前缀,比如:noremap,就表示这种map是非递归的。

  • unmap
  • unmap后面跟着一个按键组合,表示删除这个映射。

    :unmap c
    

    那么在map生效模式下,c不再被映射到a上。

    同样,unmap可以加各种前缀,表示影响到的模式。

  • mapclear
  • mapclear直接清除相关模式下的所有映射。
    同样,mapclear可以加各种前缀,表示影响到的模式。

这里列出常用的一些map命令,默认map命令影响到普通模式和可视模式。

:map :noremap :unmap :mapclear
:nmap :nnoremap :nunmap :nmapclear
:vmap :vnoremap :vunmap :vmapclear
:imap :inoremap :iunmap :imapclear
:cmap :cnoremap :cunmap :cmapclear

可以试试这些命令

  1. 命令行模式下建一个mapping
     nmap b a 
  2. 现在普通模式下,按b,可以进入插入模式,随便输入一些字符
  3. 命令行模式下建一个mapping
     vmap b d 
  4. 现在普通模式下,按V,进入了可视模式,并且选定了一整行,按下b,可以删除整行
  5. 命令行模式下建一个mapping
     imap b a 
  6. 现在试着给正在编辑的这个文件输入一个字符”b”吧 :p
  7. 命令行模式下建一个mapping
     cmap b c 
  8. 命令行模式下, 按下b,会出来一个a

好了,到此vim的按键已经被你弄得乱七八糟了,试着用unmap和mapclear清除这些mapping吧。:]

Vim Encoding

每次新装VIM都得设置编码相关的选项,记在这里备忘吧。

encoding: VIM内部编码,也就是内容在VIM内部的表现形式。

fileencoding: 文件读写编码,在打开文件时VIM认为此文件是采用fileencoding所指的编码,于是会进行编码转换,转换为encoding所指编码。

fileencodings: 一个编码序列,VIM依次尝试其中的编码,看看是否能成功转换为encoding所指编码。
termencoding:terminal采用的编码,vim如果要输出到terminal,会将文件转码为termencoding所指编码。

在Linux下,八子一般采用

let &termencoding=&encoding
set fileencodings=utf-8,gbk,ucs-bom,cp936

感谢:
http://edyfox.codecarver.org/html/vim_fileencodings_detection.html