关于unix:你母亲从未告诉过你的Vim的黑暗角落是什么?

What are the dark corners of Vim your mom never told you about?

在人们谈论常用技巧时,有很多问题,特别是"vim+ctags技巧和技巧"。

然而,我并没有提到一些刚接触Vim的人会觉得很酷的常用快捷方式。我说的是一个经验丰富的Unix用户(无论他们是开发人员、管理员,还是两者都是),他们认为我们99%的人从未听说过或梦想过什么。这些东西不仅使他们的工作更容易,而且很酷也很刻薄。毕竟,Vim居住在世界上最黑暗的角落里,拥有丰富的操作系统,因此它应该有一些只有少数特权知道的错综复杂的东西,并且希望与我们分享。


可能不是99%的vim用户不知道的,但这是我每天使用的东西,任何Linux+vim poweruser都必须知道。

基本命令,但非常有用。

1
:w !sudo tee %

我经常在编辑一个我没有写权限的文件之前忘记使用sudo。当我开始保存那个文件并得到一个权限错误时,我只是发出vim命令来保存这个文件,而不需要将它保存到一个临时文件中,然后再次复制它。

显然,您必须在安装了sudo的系统上,并且拥有sudo权限。


最近我发现了一件我认为很酷的事情:

1
:earlier 15m

将文档还原为15分钟前的状态。可以在您想要回滚的时间内使用各种参数,这取决于撤消级别。可以用相反的命令:later来反转


当您在VIM中时,:! [command]执行一个外部命令。

但是在冒号后面加一个点,:.! [command],它将把命令的输出转储到当前窗口中。那是: . !

例如:

1
:.! ls

我经常使用这个方法,例如将当前日期添加到我正在键入的文档中:

1
:.! date


不完全是模糊的,但是有几个"delete-in"命令非常有用,比如……

  • diw删除当前字
  • di(在当前parens中删除
  • 删除报价之间的文本。

其他可以在:help text-objects上找到。


按可删除所有内容,直至单词结束。在你心中的渴望。

ci(xyz[esc]——这是一个奇怪的。这里,"i"不是指插入模式。相反,它的意思是在括号内。所以这个序列会将您所站在括号内的文本剪切,并将其替换为"xyz"。它也在方括号和数字括号内工作——相应地做ci[或ci即可。当然,您可以执行DI(如果您只想删除所有文本而不键入任何内容)。如果要删除括号,而不仅仅是括号内的文本,也可以使用a而不是i

ci"-在当前引号中剪切文本

ciw-剪切当前单词。这和前一个一样,只是(w取代了。

C-切断线路的其余部分并切换到插入模式。

zz—保存并关闭当前文件(比ctrl-f4关闭当前选项卡快得多!)

DDP-将当前行下移一行

xp—将当前字符向右移动一个位置

u-大写,所以viwUupercases这个词

~-切换大小写,所以viw~将反转整个单词的大小写。

ctrl+u/ctrl+d向上或向下滚动半屏页面。这似乎比通常的全屏分页更有用,因为这样更容易看到两个屏幕之间的关系。对于那些仍然想一次滚动整个屏幕的人,有ctrl+f表示前进,ctrl+b表示后退。ctrl+y和ctrl+e一次向下或向上滚动一行。

疯狂但非常有用的命令是ZZ——它滚动屏幕使这条线出现在中间。这对于将您正在处理的代码放在您注意力的中心非常好。兄弟命令——zt和zb——使这行成为sreen上的顶部或底部行,这并没有那么有用。

%查找并跳到匹配的括号。

de——从光标到词尾的删除(也可以通过dE删除,直到下一个空格)

bde—删除当前单词,从左到右分隔符

df[空格]——删除直到并包括下一个空格

D.--删除到下一个点

dd—删除整行

Ye(或Ye)--将文本从这里拉到单词的结尾

ce-将单词的结尾切掉

再见--复制当前单词(让我想知道"嗨"是什么意思!)

YY—复制当前行

cc——切断当前的线路,你也可以用S代替。还有下盖的S,它可以切断当前字符并切换到插入模式。

VIWY或VIWC。扬起或更改当前单词。多次点击w以继续选择后面的每个单词,使用b向后移动

vi-选择图括号中的所有文本。va-选择所有文本,包括s

vi(p-突出显示()s中的所有内容,并替换为粘贴的文本

b和e逐字移动光标,类似于ctrl+箭头通常的方式。不过,单词的定义有点不同,因为几个连续的斜线被视为一个单词。如果从一个词的中间开始,按B键将始终使您到达当前词的开头,并且每个连续的B将跳到下一个词的开头。同样,也很容易记住,e将光标移到当前单词的末尾,以及后面的每个单词。

b/e类似,大写be逐字移动光标,只使用空格作为分隔符。

大写D(深呼吸)删除光标右侧的行的其余部分,与正常编辑器中的shift+end/del相同(注意2个按键--shift+d--而不是3)


我很少在大多数VIM教程中找到,但是它非常有用(至少对我来说),是

g; and g,

在变更列表中移动(向前、向后)。

我来演示一下我是如何使用它的。有时我需要复制和粘贴一段代码或字符串,比如说CSS文件中的十六进制颜色代码,所以我搜索、跳转(不关心匹配的地方),复制它,然后跳转回(g;)我编辑代码的地方,最终粘贴它。不需要创建标记。更简单。

就我两分钱。


1
:%!xxd

使vim成为十六进制编辑器。

1
:%!xxd -r

回复。

警告:如果不使用二进制文件(-b)进行编辑,可能会损坏文件。—乔希·李在评论中。


1
gv

重新选择最后一个视觉选择。


有时.vimrc中的设置会被插件或自动命令覆盖。要调试它,一个有用的技巧是将:verbose命令与:set结合使用。例如,要确定Cindent的设置/取消设置位置:

1
:verbose set cindent?

这将输出如下内容:

1
2
cindent
    Last set from /usr/share/vim/vim71/indent/c.vim

这也适用于地图和高光。(感谢JoeyWiddle指出这一点。)例如:

1
2
3
4
5
6
7
:verbose nmap U
n  U             <C-R>
        Last set from ~/.vimrc

:verbose highlight Normal
Normal         xxx guifg=#dddddd guibg=#111111 font=Inconsolata Medium 14
        Last set from ~/src/vim-holodark/colors/holodark.vim


不确定这是否算是黑暗角落,但我只是刚刚学会了…

1
:g/match/y A

将所有包含"匹配"的行拉入(复制)到"a/@a寄存器。(大小写为EDOCX1[6]使vim追加扬克而不是替换以前的寄存器内容。)我最近在制作Internet Explorer样式表时经常使用它。


:%TOhtml

创建当前文件的HTML呈现。


要查看您的:命令历史记录吗?

1
q:

然后浏览、编辑并最终执行命令。

有没有对两个文件做过类似的更改并在它们之间来回切换?(比如,源文件和头文件?)

1
2
:set hidden
:map <TAB> :e#<CR>

然后在这些文件之间来回切换。


例如,Vim将打开一个URL

1
vim http://stackoverflow.com/

当你需要调出一个页面的源代码以供参考时很好。


宏可以调用其他宏,也可以调用自身。

如:

1
qq0dwj@qq@q

…将从每行删除第一个单词,直到文件结束。

这是一个很简单的例子,但它展示了VIM的一个非常强大的特性。


假设您在中编译了Perl和/或Ruby支持,:rubydo:perldo将在一个范围内的每一行(默认为整个缓冲区)上运行ruby或perl-one行,并且$_绑定到当前行的文本(减去新行)。操作$_将更改该行的文本。

您可以使用它来做一些在脚本语言中很容易做的事情,但是使用VIM内置函数并不是很明显。例如,要颠倒一行中单词的顺序:

1
:perldo $_ = join ' ', reverse split

在每行末尾插入8个字符(a-z)的随机字符串:

1
:rubydo $_ += ' ' + (1..8).collect{('A'..'Z').to_a[rand 26]}.join

一次只能在一行上操作,不能添加换行符。


^和^ i

转到旧/新位置。当您在文件中移动(通过搜索、移动命令等)时,Vim会记住这些"跳跃",这样您就可以重复这些向后跳跃(^o-o表示旧的)和向前跳跃(^i-刚好在键盘上的i旁边)。我发现它在编写代码和执行大量搜索时非常有用。

胃肠道

转到上次停止插入模式的位置。我发现自己经常编辑然后寻找一些东西。要返回编辑位置,请按gi。

GF

将光标放在文件名上(如包含头文件),按gf,文件打开。

GF

类似于gf,但识别格式为"[文件名]:[行号]"。按gf将打开[文件名]并将光标设置为[行号]。

p和^ n

编辑时自动完成文本(^p-上一个匹配项和^n下一个匹配项)

^ xl

当编辑完成到同一行时(对编程有用)。您编写代码,然后回忆起在文件中的某个地方有相同的代码。只需按^x^l,整行就完成了

^ ^ ^ f

完整的文件名。你写了"/etc/pass"嗯。你忘了文件名。只需按^x^f,文件名就完成了。

z或:嘘

临时移动到外壳。如果你需要一个快速的打击:

  • 按^Z(将vi置于背景)返回原始shell,按fg返回vim back
  • 按:sh转到子shell,按^d/退出返回vi


这是一个用不同编码重新打开当前文件的好技巧:

1
:e ++enc=cp1250 %:p

当您必须使用旧编码时很有用。支持的编码列在encoding-values下的表格中(见helpencoding-values)。类似的事情也适用于++ff,这样,如果第一次出现错误,您可以使用Windows/Unix行尾重新打开文件(参见helpff)。


1
2
3
4
5
6
" insert range ip's
"

"          ( O O )

" =======oOO=(_)==OOo======


:for i in range(1,255) | .put='10.0.0.'.i | endfor


键入==将根据上面的行更正当前行的缩进。

实际上,您可以在任何移动命令后执行一个=符号。= {运动}

例如,可以使用在匹配大括号之间移动的%移动。将光标放在上,代码如下:

1
2
3
4
5
6
if (thisA == that) {
//not indented
if (some == other) {
x = y;
}
}

按.%立即得到:

1
2
3
4
5
6
if (thisA == that) {
    //not indented
    if (some == other) {
        x = y;
    }
}

或者,您可以在代码块中执行=a,而不是将自己定位在字符上。


1
imap jj <esc>


让我们来看一些非常小的IDE编辑器进行列转换。

1
:%s/\(.*\)^I\(.*\)/\2^I\1/

解释

\(\)是如何记住regex-land中的内容。而\1\2等是如何找回记忆中的东西。

1
>>> \(.*\)^I\(.*\)

记住所有的事情,然后是^I(tab),然后是所有的事情。

1
>>> \2^I\1

用"你记得的第二件事"和"你记得的第一件事"来替换上面的东西——本质上是做一个换位。


不完全是一个黑暗的秘密,但我喜欢把下面的映射放到我的.vimrc文件中,这样我可以随时点击"-"(减号)打开文件资源管理器,显示与我刚编辑的文件相邻的文件。在文件资源管理器中,我可以点击另一个"-"向上移动一个目录,从而无缝浏览复杂的目录结构(就像现在的MVC框架所使用的那样):

1
map - :Explore<cr>

这些可能对某些人也有用。我喜欢滚动屏幕,同时向前移动光标:

1
2
map <c-j> j<c-e>
map <c-k> k<c-y>

标签导航-我喜欢标签,我需要在它们之间轻松移动:

1
2
map <c-l> :tabnext<enter>
map <c-h> :tabprevious<enter>

仅在Mac OS X上:类似于Safari的选项卡导航:

1
2
map <S-D-Right> :tabnext<cr>
map <S-D-Left> :tabprevious<cr>


我喜欢用"sudo bash",我的系统管理员讨厌这个。他锁定了"sudo",这样它只能与少数命令(ls、chmod、chown、vi等)一起使用,但我仍然可以使用vim获取根shell:

1
2
3
bash$ sudo vi +'silent !bash' +q
Password: ******
root#


通常,我喜欢在编辑时更改当前目录-所以我必须少指定路径。

1
cd %:h


我经常在项目中使用许多窗口,有时我需要调整它们的大小。我用的是:

1
2
map + <C-W>+
map - <C-W>-

这些映射允许增加和减小当前窗口的大小。很简单,但很快。


不是一个模糊的功能,但非常有用和节省时间。

如果要保存打开的缓冲区、选项卡、标记和其他设置的会话,可以发出以下命令:

1
mksession session.vim

您可以使用以下方式打开会话:

1
vim -S session.vim


将f5映射为快速rot13您的缓冲区:

1
map <F5> ggg?G``

你可以把它当作老板的钥匙。


1
:r! <command>

将外部命令的输出粘贴到缓冲区中。

做一些数学运算,直接在文本中得到结果:

1
:r! echo $((3 + 5 + 8))

获取写入makefile时要编译的文件列表:

1
:r! ls *.c

不要查阅你在维基百科上读到的事实,直接把它粘贴到你正在写的文档中:

1
:r! lynx -dump http://en.wikipedia.org/wiki/Whatever


今天我通过国家自然科学基金会发现了这个:

注释代码块。

按ctrl-v进入分块视觉模式。

标记要注释的块。

点击i(大写i)并在行首输入注释字符串。(/对于C++)

按Esc键,所选的所有行都将//置于行的前面。


我使用vim进行几乎所有的文本编辑,所以我经常使用复制和粘贴。问题是,vim在默认情况下经常会通过粘贴来扭曲导入的文本。阻止这种情况的方法是

1
:set paste

在粘贴数据之前。这样就不会把事情搞得一团糟。

请注意,您必须发出:set nopaste以恢复自动缩进。粘贴预先格式化的文本的另一种方法是剪贴板寄存器(*+:r!cat(必须用^d结束粘贴的片段)。

有时打开高对比度配色方案也很有帮助。这可以用

1
:color blue

我注意到它不适用于我使用的所有版本的VIM,但是它适用于大多数版本。


这是一些不明显的东西。如果您的$home中有很多自定义插件/扩展,并且您需要从su/sudo/工作。有时,这可能是有用的。

在您的~/.bashrc中:

export VIMINIT=":so $HOME/.vimrc"

在你的~/.vimrc中:

ZZU1〔10〕

它将允许您的本地插件加载-无论您使用什么方式来更改用户。

您可能还希望将*.swp文件从当前路径中取出并放入~/vimtmp(这将进入.vimrc):

ZZU1〔11〕

另外,我使用一些映射使编辑更容易-使ctrl+s像escape一样工作,ctrl+h/l切换选项卡:

ZZU1〔12〕


当处于插入模式时,ctrl-n将根据打开缓冲区中的所有单词自动完成您键入的任何单词。如果有多个匹配项,它将为您提供一个可以使用ctrl-n和ctrl-p循环使用的单词列表。


1
gg=G

更正整个文件的缩进。我在Eclipse中丢失了我的可靠的,但刚发现vim处理得很好。


sudo-write的变化:

VIMRC

1
cmap w!! w !sudo tee % >/dev/null

重新加载VIM后,可以将"sudo save"作为

1
:w!!


能够在基于客户机/服务器的模式上运行VIM。

例如,假设您正在处理一个项目,其中有许多缓冲区、选项卡和其他信息保存在名为session.vim的会话文件中。

您可以通过发出以下命令打开会话并创建服务器:

1
vim --servername SAMPLESERVER -S session.vim

注意,如果您想创建一个服务器,并且它不一定是一个会话,那么您可以打开常规文本文件。

现在,假设您在另一个终端中,需要打开另一个文件。如果您通过发布以下内容定期打开:

1
vim new_file.txt

您的文件将在单独的VIM缓冲区中打开,这很难与会话中的文件进行交互。要在服务器上的新选项卡中打开new_file.txt,请使用以下命令:

1
vim --servername SAMPLESERVER --remote-tab-silent new_file.txt

如果没有运行服务器,则会像打开常规文件一样打开此文件。

因为每次想要运行这些标志时都提供这些标志非常繁琐,所以可以为创建客户机和服务器创建单独的别名。

我在我的bashrc文件中放置了以下内容:

1
2
alias vims='vim --servername SAMPLESERVER'
alias vimc='vim --servername SAMPLESERVER --remote-tab-silent'

您可以在以下网址找到有关此的更多信息:http://vimdoc.sourceforge.net/htmldoc/remote.html


想要一个IDE吗?

:make将运行当前目录中的makefile,解析编译器输出,然后可以使用:cn:cp逐步排除打开每个文件并查找相关行号的编译器错误。

:syntax on打开vim的语法突出显示。


如何:在bash中使用vim时自动完成ctags。对于其他使用vim和ctags的人,我为bash编写了一个小型的自动完成函数。将以下内容添加到~/.bash_完成文件中(如果不存在,则创建它):

感谢Styleshpants对他的许多修复和改进。

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
_vim_ctags() {
    local cur prev

    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    case"${prev}" in
        -t)
            # Avoid the complaint message when no tags file exists
            if [ ! -r ./tags ]
            then
                return
            fi

            # Escape slashes to avoid confusing awk
            cur=${cur////\\/}

            COMPREPLY=( $(compgen -W"`awk -vORS="" "/^${cur}/ { print \\$1 }" tags`" ) )
            ;;
        *)
            _filedir_xspec
            ;;
    esac
}

# Files matching this pattern are excluded
excludelist='*.@(o|O|so|SO|so.!(conf)|SO.!(CONF)|a|A|rpm|RPM|deb|DEB|gif|GIF|jp?(e)g|JP?(E)G|mp3|MP3|mp?(e)g|MP?(E)G|avi|AVI|asf|ASF|ogg|OGG|class|CLASS)'

complete -F _vim_ctags -f -X"${excludelist}" vi vim gvim rvim view rview rgvim rgview gview

重新启动bash会话(或创建新会话)后,可以键入:

代码:

1
~$ vim -t MyC<tab key>

它会像对文件和目录那样自动完成标记:

代码:

1
2
MyClass MyClassFactory
~$ vim -t MyC

当我跳进一个快速的错误修复程序时,我发现它真的很有用。


我经常想突出显示一个特定的单词/函数名,但还不想搜索它的下一个实例:

1
map m* *#


我什么都用VIM。当我编辑电子邮件时,我使用:

gqap(或gwap)

广泛地以一段一段的方式轻松、正确地重新格式化,即使使用引号前导字符也是如此。为了实现此功能,我还添加了:

-c 'set fo=tcrq' -c 'set tw=76'

调用外部编辑器的命令。一个值得注意的添加是向fo(formatOptions)参数添加"a"。这将在键入和导航内容时自动重新格式化段落,但可能会干扰或导致邮件中包含的格式错误或奇怪的问题。


%当你想在一个项目的两个不同的副本之间区分文件,而不磨损小指(从项目1的根目录)时,这也是很好的方法:

1
:vert diffs /project2/root/%

:setlocal autoread

自动重新加载当前缓冲区..在查看日志文件时特别有用,它几乎可以从VIM中为UNIX中的"tail"程序提供功能。

检查VIM中的编译错误。根据语言设置makeprg变量,比如Perl

:setlocal makeprg = perl\ -c \ %

对于PHP

set makeprg=php\ -l\ %
set errorformat=%m\ in\ %f\ on\ line\ %l

发出":make"运行相关的makeprg并在QuickFix窗口中显示编译错误/警告,可以轻松导航到相应的行号。


由于延迟和缺少颜色(我喜欢颜色方案:)我不喜欢在远程机器上用油灰编程。所以我开发了这个技巧来解决这个问题。我在窗户上用。

你需要

  • 1X GVIM
  • 远程和本地计算机上的1X rsync
  • 远程计算机的1X ssh私钥身份验证,因此不需要键入密码
  • 1X选美
  • 1X腻子

设置远程机器

配置rsync以使您的工作目录可访问。我使用ssh隧道,并且只允许来自隧道的连接:

1
2
3
4
5
6
7
address = 127.0.0.1
hosts allow = 127.0.0.1
port = 40000
use chroot = false
[bledge_ce]
    path = /home/xplasil/divine/bledge_ce
    read only = false

然后启动rsyncd:rsync--daemon--config=rsyncd.conf

设置本地计算机

从cygwin安装rsync。启动页导航并加载远程计算机的私钥。如果您正在使用ssh调音,请启动putty来创建通道。在工作目录中创建一个批处理文件push.bat,它将使用rsync将更改的文件上载到远程计算机:

1
rsync --blocking-io *.cc *.h SConstruct rsync://localhost:40001/bledge_ce

sconstruct是scons的生成文件。根据需要修改文件列表。如果不使用ssh调优,则将localhost替换为远程计算机的名称。

配置VIM现在很容易。我们将使用QuickFix功能(:make和错误列表),但编译将在远程计算机上运行。所以我们需要设置makeprg:

1
set makeprg=push\ &&\ plink\ -batch\ xplasil@anna.fi.muni.cz\ "cd\ /home/xplasil/divine/bledge_ce\ &&\ scons\ -j\ 2"

这将首先启动push.bat任务来上载文件,然后使用ssh(putty套件中的plink)在远程计算机上执行命令。命令首先将目录更改为working dir,然后启动build(我使用scons)。

构建结果将很容易显示在您的本地GVIM错误列表中。


从十六进制值输入字符(插入模式):

1
<C-Q>x[type the hexadecimal byte]


把它放到.vimrc中,让它有一个命令来漂亮地打印XML:

1
2
3
4
5
6
7
8
function FormatXml()
    %s:\(\S\)\(<[^/]\)\|\(>\)\(</\):\1\3
\2\4:g
    set filetype=xml
    normal gg=G
endfunction

command FormatXml :call FormatXml()


1
2
3
4
5
6
7
8
9
==========================================================
In normal mode
==========================================================
gf ................ open file under cursor in same window --> see :h path
Ctrl-w f .......... open file under cursor in new window
Ctrl-w q .......... close current window
Ctrl-w 6 .......... open alternate file --> see :h #
gi ................ init insert mode in last insertion position
'0 ................ place the cursor where it was when the file was last edited


我肯定有人已经把这个贴出来了,但是这里有。

请使用任何构建系统;make,mvn,ant,随便什么。在项目目录的根目录中,创建您一直使用的命令的文件,如下所示:

MVN安装
MVN清洁安装
…诸如此类

要进行构建,请将光标放在行上并键入!!sh,即筛选该行;将其写入shell并替换为结果。

生成日志将替换行,随时可以滚动、搜索或执行任何操作。

查看完日志后,键入u以撤消,然后返回命令文件。


或是我set colorcolumn=+1set cc=+17.3


一些有用的:

1
2
3
:set nu # displays lines
:44     # go to line 44
'.      # go to last modification line

我最喜欢的:ctrl+n单词完成!


在处理构建过程缓慢的项目时,我总是在后台构建,并将输出通过管道传输到名为errors.err的文件(类似于make debug 2>&1 | tee errors.err)。这使我可以在构建过程中继续编辑或查看源代码。当它准备好(使用gtk上的pynotify通知我它已经完成)时,我可以使用quickfix查看vim中的结果。首先发出:cf[ile],它读取错误文件并跳转到第一个错误。我个人喜欢使用cWindow在单独的窗口中获取构建结果。


:sp %:h—使用当前文件目录的目录列表/文件选择器

(属于Rampion'scd提示下的评论,但我还没有评论权)


在复制和粘贴到stackoverflow之前:

1
2
3
:retab 1
:% s/^I/ /g
:% s/^/    /

现在复制并粘贴代码。

根据评论要求:

RATAB 1。这会将选项卡大小设置为1。但它也会通过代码添加额外的制表符和空格,这样格式就不会移动任何实际的文本(即文本在Ratab之后看起来是一样的)。

%注意,^i是点击标签的结果。这将搜索所有选项卡并用一个空格替换它们。因为我们刚刚做了一个重新标记,这不应该导致格式改变,但因为把标签放进一个网站被点击和错过,删除它们是很好的。

%S/^/:将行首替换为四个空格。因为您不能用它在行首插入的四个空格来替换行首(这是SO格式需要的,以便使代码突出)。


让vim更像一个IDE编辑器:

  • 为左边距中的行号设置nu。
  • set cul-突出显示包含光标的行。


在插入模式下,ctrl+xbakbd、ctrl+p将完成(如果您喜欢的话,还有可能完成的菜单)您正在键入的当前长标识符。

1
2
3
4
5
6
if (SomeCall(LONG_ID_ <-- type c-x c-p here
            [LONG_ID_I_CANT_POSSIBLY_REMEMBER]
             LONG_ID_BUT_I_NEW_IT_WASNT_THIS_ONE
             LONG_ID_GOSH_FORGOT_THIS
             LONG_ID_ETC
             ∶


重新使用

与其他命令混合的动作,这里更多。

1
2
3
tx
fx
Fx

在Vim中使用您最喜欢的工具。

1
:r !python anything you want or awk or Y something

在视觉模式下重复,与上面的提示结合使用时很强大。

1
;


1
2
3
In Insert mode
<C-A>   - Increments the number under cursor
<C-X>   - Decrements the number under cursor

如果我们想在vim中生成序列号,这将非常有用假设我们要插入第1-10行,数字从1到10[如第1行的"1",第2行的"2…"。
在第一行插入"0",并复制该行和过去9次以便所有行都显示"0"。

运行以下ex命令

1
:g/^/exe"norm" . line(".") ."\<C-A>"


我喜欢:指挥。


创建一个函数,使用它的shebang(假设设置了一个)来执行当前缓冲区,并使用crtl-x调用它。

1
2
3
4
5
6
7
8
9
10
11
12
map <C-X> :call CallInterpreter()<CR>

au BufEnter *
\ if match (getline(1) , '^\#!') == 0 |
\   execute("let b:interpreter = getline(1)[2:]") |
\ endif

fun! CallInterpreter()
    if exists("b:interpreter")
        exec("!".b:interpreter." %")
    endif
endfun

尝试使用perltidy通过=正常模式命令格式化。

1
:set equalprg=perltidy

要将文本从VIM复制到剪贴板以供其他应用程序使用,请在视觉模式下选择要复制的文本,然后按"+Y"。这样,您可以轻松地将文本粘贴到其他应用程序。

如果您已经垂直拆分了窗口,并且希望从右窗口复制某些内容,那么这尤其有用。使用set mouse=r,对这种情况没有帮助,因为它也会选择左侧窗口中的所有内容。

请注意,必须使用xterm支持编译VIM。


使用鼠标右键在gvim中切换插入模式,设置如下在~/GVIMRC中:

1
2
3
4
5
6
7
"
"------------------------------------------------------------------

" toggle insert mode <--> 'normal mode with the <RightMouse>-key

"------------------------------------------------------------------

nnoremap  <RightMouse> <Insert>
inoremap  <RightMouse> <ESC>
"


下面这两个都不是很死板,但我发现它非常有用。

微不足道的捆绑,但我不能没有。它可以在插入模式下(使用ctrl键)启用hjkl样式的移动。在正常模式下:ctrl-k/j向上/向下滚动半个屏幕,ctrl-l/h转到下一个/上一个缓冲区。μ和_映射尤其适用于Azerty键盘,并转到下一个/上一个make error。

1
2
3
4
5
6
7
8
9
10
11
imap <c-j> <Down>
imap <c-k> <Up>
imap <c-h> <Left>
imap <c-l> <Right>
nmap <c-j> <c-d>
nmap <c-k> <c-u>
nmap <c-h> <c-left>
nmap <c-l> <c-right>

nmap ù :cp<RETURN>
nmap μ :cn<RETURN>

我写的一个小函数用来突出显示函数、全局、宏、结构和typedef。(对于非常大的文件可能比较慢)。每种类型都有不同的突出显示(请参见":帮助组名称"了解当前颜色主题的设置)用法:使用ww保存文件(默认值为"ww")。你需要CTAG。

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
nmap <Leader>ww :call SaveCtagsHighlight()<CR>

"Based on: http://stackoverflow.com/questions/736701/class-function-names-highlighting-in-vim

function SaveCtagsHighlight()
    write

    let extension = expand("%:e")
    if extension!="c" && extension!="cpp" && extension!="h" && extension!="hpp"
        return
    endif

    silent !ctags --fields=+KS *
    redraw!

    let list = taglist('.*')
    for item in list
        let kind = item.kind

        if     kind == 'member'
            let kw = 'Identifier'
        elseif kind == 'function'
            let kw = 'Function'
        elseif kind == 'macro'
            let kw = 'Macro'
        elseif kind == 'struct'
            let kw = 'Structure'
        elseif kind == 'typedef'
            let kw = 'Typedef'
        else
            continue
        endif

        let name = item.name
        if name != 'operator=' && name != 'operator ='
            exec 'syntax keyword '.kw.' '.name
        endif
    endfor
    echo expand("%")." written, tags updated"
endfunction

我有编写大量代码和函数的习惯,我不喜欢为它们编写原型。所以我做了一些函数来生成C样式源文件中的原型列表。它有两种风格:一种删除形式参数的名称,另一种保留形式参数的名称。每次需要更新原型时,我都会刷新整个列表。它避免了不同步的原型和函数定义。也需要CTAG。

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
46
47
48
49
50
51
52
53
54
"Usage: in normal mode, where you want the prototypes to be pasted:
":call GenerateProptotypes()

function GeneratePrototypes()
    execute"silent !ctags --fields=+KS".expand("%")
    redraw!
    let list = taglist('.*')
    let line = line(".")
    for item in list
        if item.kind =="function"  &&  item.name !="main"
            let name = item.name
            let retType = item.cmd
            let retType = substitute( retType, '^/\^\s*','','' )
            let retType = substitute( retType, '\s*'.name.'.*', '', '' )

            if has_key( item, 'signature' )
                let sig = item.signature
                let sig = substitute( sig, '\s*\w\+\s*,',        ',',   'g')
                let sig = substitute( sig, '\s*\w\+\(\s)\)', '\1', '' )
            else
                let sig = '()'
            endif
            let proto = retType ."\t" . name . sig . ';'
            call append( line, proto )
            let line = line + 1
        endif
    endfor
endfunction


function GeneratePrototypesFullSignature()
   "execute"silent !ctags --fields=+KS".expand("%")
    let dir = expand("%:p:h");
    execute"silent !ctags --fields=+KSi --extra=+q".dir."/*"
    redraw!
    let list = taglist('.*')
    let line = line(".")
    for item in list
        if item.kind =="function"  &&  item.name !="main"
            let name = item.name
            let retType = item.cmd
            let retType = substitute( retType, '^/\^\s*','','' )
            let retType = substitute( retType, '\s*'.name.'.*', '', '' )

            if has_key( item, 'signature' )
                let sig = item.signature
            else
                let sig = '(void)'
            endif
            let proto = retType ."\t" . name . sig . ';'
            call append( line, proto )
            let line = line + 1
        endif
    endfor
endfunction

映射宏

我经常发现,像定义宏一样,动态定义一些键映射非常有用。这里的转折点是,映射是递归的,执行到失败为止。

例子:

1
2
3
4
5
6
7
8
enum ProcStats
{
        ps_pid,
        ps_comm,
        ps_state,
        ps_ppid,
        ps_pgrp,
:map X /ps_<CR>3xixy<Esc>X

给予:

1
2
3
4
5
6
7
enum ProcStats
{
        xypid,
        xycomm,
        xystate,
        xyppid,
        xypgrp,

只是一个愚蠢的例子:)。

我完全意识到了所有的缺点——只是碰巧我发现它在某些场合非常有用。此外,在工作中观看也很有趣;)。


全部替换

1
  :%s/oldtext/newtext/igc

给a替换全部:)


这些年来我收集了这些。

1
2
3
4
5
6
7
8
9
10
11
12
" Pasting in normal mode should append to the right of cursor
nmap <C-V>      a<C-V><ESC>
" Saving

imap <C-S>      <C-o>:up<CR>
nmap <C-S>      :up<CR>
" Insert mode control delete

imap <C-Backspace> <C-W>
imap <C-Delete> <C-O>dw
nmap    <Leader>o       o<ESC>k
nmap    <Leader>O       O<ESC>j
" tired of my typo

nmap :W     :w


我想在after-directory中安排一些我自己的配置文件。它对ftplugin特别有用。

您可以避免在.vimrc文件中编写一个很长的augroup列表,而不是为每种类型编写单独的文件。

但是,显然,.vim/ftplugin目录与.vim/after/ftplugin目录做的是相同的事情,但是我更愿意将.vim目录留给vim插件。


使移动以环绕模式在当前屏幕行上操作的映射。我在一篇VIM提示的评论中发现了这一点,它被证明非常方便。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function! ScreenMovement(movement)
  if &wrap
    return"g" . a:movement
  else
    return a:movement
  endif
endfunction
onoremap <silent> <expr> j ScreenMovement("j")
onoremap <silent> <expr> k ScreenMovement("k")
onoremap <silent> <expr> 0 ScreenMovement("0")
onoremap <silent> <expr> ^ ScreenMovement("^")
onoremap <silent> <expr> $ ScreenMovement("$")
nnoremap <silent> <expr> j ScreenMovement("j")
nnoremap <silent> <expr> k ScreenMovement("k")
nnoremap <silent> <expr> 0 ScreenMovement("0")
nnoremap <silent> <expr> ^ ScreenMovement("^")
nnoremap <silent> <expr> $ ScreenMovement("$")

我最喜欢在窗口之间来回切换的方法:

1
2
3
4
5
6
7
8
9
10
function! SwitchPrevWin()
    let l:winnr_index = winnr()
    if l:winnr_index > 1
       let l:winnr_index -= 1
    else
      "set winnr_index to max window open

        let l:winnr_index = winnr('$')
    endif
    exe l:winnr_index ."wincmd w"
endfunction
1
2
nmap <M-z> :call SwitchPrevWin()
imap <M-z> <ESC>:call SwitchPrevWin()
1
2
nmap <C-z> :wincmd w
imap <C-z> <ESC>:wincmd w


我的是使用宏而不是搜索-将宏与可视模式结合有时效率更高。


我的一些必备品是:

cscope+ctags+vim,可以在网上找到。

一些用于快速启动新代码文件的缩写,例如:

1
2
3
4
5
6
7
8
ab cpph #include <iostream><CR>#include <string><CR>#include <cstdlib><CR>#include <cassert><CR>#include <vector><CR>#include <
stdexcept><CR>using namespace std;<CR>int main(int argc, char *argv[]) {
ab perlh #!/usr/bin/perl<CR>use strict;<CR>use warnings;<CR>
ab chdr #include <stdio.h><CR>#include <sys/types.h><CR>#include <unistd.h><CR>#include <stdlib.h><CR>#include <sys/stat.h><CR>
#include <sys/wait.h><CR>#include <string.h><CR>int main(int argc, char *argv[]) {
ab xhtmlhdr <?xml version="1.0" encoding="UTF-8"?><CR><!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.o
rg/TR/xhtml1/DTD/xhtml1-strict.dtd"><CR><html xmlns="http://www.w3.org/1999/xhtml"><CR>  <head><CR>  <CR><link h
ref="style.css" rel="STYLESHEET" type="text/css"><CR></head>

例如,cpph将插入main.cc文件的基本框架

还有我对功能键的映射:

1
2
3
4
5
6
7
8
9
10
11
12
map <F1> <Esc>:w<CR>:perl $e = `./error.pl`; my ($f,$l,@w) = split(":",$e); my $w=join(":",@w); $curwin->Cursor($l,0); VIM::Msg($w);<CR>
map <F2> :wincmd w<CR>
map <F3> :wincmd s<CR>
map <F4> :wincmd v<CR>
map <F5> :wincmd o<CR>
map <F6> :sball<CR>
map <F7> :wq<CR>
map <F8> :wincmd q<CR>
map <F9> :wincmd -<CR>
map <F10> :wincmd +<CR>
map <F11> :wincmd <<CR>
map <F12> :wincmd ><CR>

在这种情况下,我的f1被映射为将光标放在下一个需要为源代码迁移更正的错误上。

1
map _ ebi"^[ea"^[

这张地图会使一个字符串


按此线程

为了给一组行加前缀,我使用两种不同的方法之一:

一种方法是块选择(由某物提到)。通常,您可以选择一个矩形区域,并使用ctrl-v,然后移动光标。突出显示一个矩形后,按SHIFT-I将在矩形的左侧插入字符,或按SHIFT-A将在矩形的右侧附加字符。因此,可以使用此技术生成一个矩形,其中包含要作为前缀的行的最左边的列,单击shift-i,键入前缀,然后单击escape。

另一种方法是使用替换(如BrianAgnew所提到的)。Brian的替换将影响整个文件(命令中的%表示"所有行")。要只影响几行,最简单的方法是在第一行/最后一行上单击shift-v(启用可视行模式),然后移动到最后一行/第一行。然后键入:

:s/^/您的前缀/

^是一个regex(在本例中是行首)。通过在可视行模式下键入,您将看到在s前面自动插入"<",">"。这意味着替换的范围将是可视选择。

额外提示:如果前缀包含斜杠,可以用反斜杠转义它们,也可以在命令中使用不同的标点符号作为分隔符。例如,为了添加C++行注释,我通常写:

s:^:/ /

对于添加后缀,替换方法通常更容易,除非所有行的长度完全相同。只需将$用于模式而不是^并且您的字符串将被追加而不是预挂起。

如果要同时添加前缀和后缀,可以执行以下操作:

:s/*/前缀和后缀/

*与整行匹配。替换中的&;会将匹配的文本(整行)放回原处,但现在将添加前缀和后缀。

顺便说一句:在注释代码时,您可能希望稍后取消对它的注释。您可以使用可视块(ctrl-v)选择斜线,然后单击d删除斜线,或者使用替换(可能是使用可视线选择,使用shift-v创建)删除前导斜线,如下所示:

S://: