vim -b test.bin
vim 的 -b 选项是告诉 vim 打开的是一个二进制文件,不指定的话,会在后面加上 0x0a ,即一个换行符,这样若是二进制文件,则文件被改变了,后面多了一个0x0a。
命令行模式下:
:%!xxd
可以看二进制文件时候被插入了换行符。
再 :%!xxd -r
变换回来
列模式编辑
把C语言输出为html:
命令模式下的TOhtml
命令可把C语言输出为html文件,结合syntax on
,可产生比较好的web page把代码发布出去。
vi/vim 中可以使用 :s 命令来替换字符串。该命令有很多种不同细节使用方法,可以实现复杂的功能,记录几种在此,方便以后查询。
:s/vivian/sky/ 替换当前行第一个 vivian 为 sky
:s/vivian/sky/g 替换当前行所有 vivian 为 sky
:n,$s/vivian/sky/ 替换第 n 行开始到最后一行中每一行的第一个 vivian 为 sky
:n,$s/vivian/sky/g 替换第 n 行开始到最后一行中每一行所有 vivian 为 sky
:v/word1/d 仅保留包含word1的行,将其余的行全部删除
:v/word1\|word2/d 仅保留包含word1或者包含word2的行,将其余的行全部删除
n 为数字,若 n 为 .,表示从当前行开始到最后一行
:%s/vivian/sky/ (等同于 :g/vivian/s//sky/) 替换每一行的第一个 vivian 为 sky
:%s/vivian/sky/g (等同于 :g/vivian/s//sky/g) 替换每一行中所有 vivian 为 sky
可以使用 # 作为分隔符,此时中间出现的 / 不会作为分隔符
:s#vivian/#sky/# 替换当前行第一个 vivian/ 为 sky/
:%s+/oradata/apras/+/user01/apras1+ (使用+ 来 替换 / ): /oradata/apras/替换成/user01/apras1/
1.:s/vivian/sky/ 替换当前行第一个 vivian 为 sky
:s/vivian/sky/g 替换当前行所有 vivian 为 sky
2. :n,$s/vivian/sky/ 替换第 n 行开始到最后一行中每一行的第一个 vivian 为 sky
:n,$s/vivian/sky/g 替换第 n 行开始到最后一行中每一行所有 vivian 为 sky
(n 为数字,若 n 为 .,表示从当前行开始到最后一行)
3. :%s/vivian/sky/ (等同于 :g/vivian/s//sky/) 替换每一行的第一个 vivian 为 sky
:%s/vivian/sky/g (等同于 :g/vivian/s//sky/g) 替换每一行中所有 vivian 为 sky
4. 可以使用 # 作为分隔符,此时中间出现的 / 不会作为分隔符
:s#vivian/#sky/# 替换当前行第一个 vivian/ 为 sky/
链接:http://blog.jobbole.com/103343/
从 2009 年开始,我就一直把 Vim 当做我的主要(唯一)文本编辑器。在过去的这些年,我学到了很多好用的 Vim 技巧,它们令我感觉相见恨晚,因为它们极大地提高了我的文本编辑效率。在这篇博文中,我想与你们分享其中的最精华部分。
HJKL
Vim 新手通常会收到的第一条建议是“使用 h/j/k/l 键代替方向键!”在很长一段时间,我都忽略了这一条建议因为我觉得那很荒谬:我究竟为何非得那么做?然而,有天我还是决定试一试,并且一试便一发不可收拾了。虽然我花了很多天时间才适应了这条建议,可是一旦上手,我才恍然大悟。h/j/k/l 几个键直接处于本位列上,所以你的手不用(像在使用方向键时那样)移动太远的距离。这不仅节省了键盘操作时间,提高了效率,而且让我的双手得以更加放松。我相信这是治好我手腕疼的因素之一。另一个因素是,我在手下面垫了一块腕垫。
如果你想学会使用 h/j/k/l 键代替方向键,那我建议你要么关闭方向键要么把它们重映射为其他更有用的指令。另一个不使用方向键的好处是,你将会适应更好的移动指令,如 f/F/t/T,w/W/b/B,0/^/$,或者搜索指令。使用这些指令,比起简单地按下方向键或者 h/j/k/l键,你的输入效率会更高。在 Vim 中,单键指令是一种反面模式。
相对行号
像很多用户一样,我也使用绝对行号,好吧,所有用户都使用它。然而,有天我偶然发现了这篇文章,令我陷入思考:万一相对行号更好用呢?我决定用用看。然后,就像 Ben 在这个视频中所言,绝对行号在我的生活中就是一个谎言。Vim的正宗用法是启用相对行号。
启用相对行号之前,我建议把下列命令行添加到 .vimrc 文件中:
set number
set relativenumber
这两个命令行一起,使 Vim 对当前行显示绝对行号,而对其它行显示相对行号。
接下来,我要说明相对行号的用处。很多 Vim 命令都有一个数字作为前缀。例如,要移动当前行以下的 10 行,可以用 10j。要移动当前行以上的 4 行,使用 4k。要对当前行及以下 2 行缩进,使用 >2j。明白了吧?有了相对行号,其它行(距离当前行)有多远就一目了然了。如果你使用的是绝对行号,你要知道两行之间相距多少行就必须做口算,把两个行号(可能很大)相减。使用相对行号就可以减少这种数学运算。
同时,你仍然可以使用绝对行号。例如,你编译了一个源文件,然后编译器告知第 943 行有一个语法错误,这时你可以用 943G 或 :943<CR> 定位到这一行。
Vim 的一个非常好的特性是,你可以设置折行功能。很多用户包括我会把 j/k 键重映射为 gj/gk,使得按下它们时,光标按虚拟行而不是按物理行移动。然而,这种重映射影响了前文提到的计数功能。为了弥补这一不足,基于这篇stackoverflow.com的博文,我们重新进行如下映射:
noremap <silent> <expr> j (v:count == 0 ? 'gj' : 'j')
noremap <silent> <expr> k (v:count == 0 ? 'gk' : 'k')
这样之后,当遇到没有行号的行时,gj/gk 命令会使光标按虚拟行移动,而当遇到有行号的行时,光标则按物理行移动。这与相对行号一起,堪称绝配。
Vim and Tmux
在很长一段时间里,我都是使用 GVim,不涉及 Vim 终端。因为它更炫,与窗口环境及集成度更高,等等。后来,我还是发现了 Tmux,它极大地改善了我的工作流程。简言之,通过它,你可以在一个终端中打开多个独立的会话(session),在每个会话中又可以打开多个窗口(window),而每个窗口又可以分为多个窗格(pane)。看看这个截屏感受一下吧。
Tmux 也让我进退两难:怎么把它跟 GVim 配合使用呢?Tmux 是一款终端应用,而 GVim 则是一款独立的 GUI 应用。幸运的是,通过设置,Vim 几乎可以具备与 GVim 一样的功能。最好用的插件是 CSApprox。它可以令 GVim 专属的配色方案轻松地应用于 Vim 终端上。还有其他很多设置帮助我转移到 Vim 终端上工作,参考我的 .vimrc 文件。
Tmux+Vim 组合的最大优势是,它可以令你在一个终端就可以完成几乎所有的开发工作。例如,你可以通过 ssh 远程登录到一个服务器并在那里做开发,这样你也可以在不同地方甚至不同电脑上无缝对接之前的工作。另一个好处是,服务器的运行速度通常要比笔记本或台式电脑快。你甚至可能在一台拥有海量核芯与内存的服务器上做开发,这取决于你公司的预算。这样的体验简直会让人流连忘返。
如果你从未用过 Tmux,那我建议你至少试它一试。它真是一个很棒的工具。万事开头难,我在这里详述了 Tmux 的配置过程,给你做个指南。仔细看看,或许你能从中学到一些技巧帮你调整并改善工作流程。例如,在该文中我介绍了一种在 Vim 与 Tmux 之间实现无缝导航的方法。
操作与行动
Vim 的一个独特之处是它能让你可以通过一门语言与之对话。例如,Vim 命令中有类似动词的 d(删除)或 y(复制),类似名词的 b(括号)或 s(句子),以及类似形容词的 i(内部的)或 a(全部的)。你可以把它们自由组合,因此,dib 代表删除括号内的所有文本,yap 代表复制当前的段落。在你学会这门简单语言之后,你不用再思考删除一个段落需要做什么,只需简单地输入 dap。很多人觉得 Vim 很难掌握,就是因为他们不习惯用这种方式来看待 Vim。
更难能可贵之处是 Vim 语言是可扩展的。事实上,用户可以在 Vim 语法的基础上创建自己的“动词”和“名词”(Vim 语法中的操作和行动/文本对象)。下面介绍一些我日常必备的好用插件。
操作
-
tcomment-vim——执行代码注释操作:gc。例如,为一个段落注释,可以用 gcap(go comment a paragraph);为当前行及以下 5 行注释,可以用 gc5j(感谢有相对行号!)。
-
vim-sort-motion——执行排序操作:gs。例如,在 Python 中,对光标所在处的 imports 进行排序,可以用 gsip(go sort inside paragraph)。
-
ReplaceWithRegister——执行替换操作:gr。执行替换文本操作不会覆盖寄存器的内容。例如,要用默认的寄存器替换当前单词,可以用 griw(go replace inner word )。gr 操作还可以与点号命令配合(.,重复上一次动作),这使它更加高效。它是我最喜欢的操作之一。
行动/文本对象
-
targets.vim——添加许多有用的文本对象。例如,daa 用于删除一个函数调用的一个参数(deletes an argument of a function call),ci$ 用于改变美元符号之间的文本(在 LaTeX 中非常有用)。该插件的另一个特点是,即使光标未落在所欲编辑的文本对象之处,用户也可以通过该插件使用该文本对象。例如,用 di”(delete inside quotes)可以删除距离光标最近的双引号内的内容。
-
vim-indent-object——对当前的缩进执行操作。例如,将当前代码块向左移动,可以用 <ii(left-shift inside indent)。这对 Python 来说很有用,因为它用空格标识代码块,而不是大括号。
-
vim-surround——对周围环境操作。例如,cs”‘ 表示用单引号替换周围的双引号,而 dsb 则表示删除周围的括号。
当然,你也可以把在以上插件中提及的操作与行动结合起来使用。例如,在一个 Python 列表中每一项都在单独成行,为了对列表排序,可以使用 gsii(go sort inside indent)。
有些简单的文本对象甚至可以不借助插件来定义。例如,对一整个文件进行操作,可以把下列这行代码加入 .vimrc:
onoremap af :<C-u>normal! ggVG<CR>
于是,要复制整个文件的内容(更准确地讲,整个缓冲器),可以使用 yaf(yank a file)。
模糊查找
在 Vim 中打开一个文件,可以用 edit 或者 tabnew 命令,分别在当前缓冲器或新标签页中打开该文件。这种方式的一个缺点是,当你打开的是一个内嵌有很多目录及文件的大工程时,就会非常慢。例如,要编辑文件 frontend/scripts/js/view/viewer.js,你就得敲入整个路径。嗯,必须要有更好的方法……
幸运的是,确实有!通过使用模糊查找器,如 Command-T。现在只需要简单地启用查找器(输入 ,t),敲入 fsviewer(f 与 s 是文件路径的一部分),就可以在当前窗口或者新标签页中瞬间打开上述文件。一旦你知道自己工程的路径结构或文件名,使用模糊查找器可以极大地提高文件的打开速度。
检索
我们经常要列出所有包含给定短语或单词(如一个函数的名称)的文件。在我刚开始使用 Vim 时,我会转到终端然后输入 gvim grep –r FUNC | cut –d: -f1 从而在 GVim 中打开找到的文件。然而,为何不把这个简单的任务交给 Vim 来做呢?
你既可以用 Vim 内置的 grep 命令,也可以用一款更高级的插件,如 vim-grepper,它能让用户选择一种检索工具(grep,git grep 或 ag)并选择怎样显示结果。例如,用户可以映射 ,/ 来在一个工程中检索所有包含某个单词的文件,或者用 ,∗ 在整个项目范围内检索包含光标所在单词的文件。在检索过程结束后,会弹出一个包含目标文件的窗口,Vim 用户可以直接打开这些文件。
作为外部编辑器的 Vim
如果你在使用一款文本编辑器,最重要的是尽可能经常使用它。毕竟,当你已经了解 Vim 了,为何还要去学另一款编辑器呢?例如网页上的 textarea forms?如果你在工作中处处使用 Vim,甚至还可以把它的优点发挥在之前想像不到的地方。
例如,在火狐浏览器中,有一个插件叫 It’s All Text!,该插件能让用户在 Vim 中编辑 textarea 元素。这为用户使用自己最爱的的编辑器编辑维基网页,写博文,提交 bug 报告等活动提供了便利。对 Vim 用户来说,这意味着他们可以尽情享受其语法高亮、拼写检查、字典补全、代码片段以及其他功能。
又如,在雷鸟邮件客户端中也有一个 It’s All Text! 插件。比起内置的编辑器,使用该插件可以让你写邮件写得更快、更舒适。
很多终端应用也支持把 Vim 作为外部编辑器使用。例如,你可以把 Midnight Commander设置为从 Vim 打开文件。Vim 的另一个可贵之处表现在用版本控制系统,如 Git,写提交说明的时候。你厌倦了排印错误吗?那就在 Vim 中设定拼写检查。你想通过使用 Ctrl+n 让出现在 diff 文件中的单词能自动补全吗?那就与 -verbose 参数一起提交吧。它可以把整个 diff 文件复制到 Vim 中,因此你就可以使用字典补全功能,就像函数名那样。老板再也不用担心你写提交说明了。
最后,我要提的是另一款火狐浏览器插件,Vimperator。它能让用户在浏览网页的时候也可以运用 Vim 的原则,使浏览器用起来像 Vim 。例如,不需要动鼠标,你就可以快速地在网页上打开连接、复制文本或者制作书签稍后再返回。Vimperator 甚至能让你在一个类似 .vimrc 的文件中配置火狐浏览器。这个是我的版本。
运行外部命令
假设你正在写 Pyhton 代码,并且你要在当前文件中执行单元测试。或者,假设你正在写 Latex 文档,为了查看结果你得进行编译。其中一个办法是打开一个终端,然后执行测试或进行编译。然而,这并不是一种高效的办法,因为它造成你工作流程的中断。
一种较好的方式是利用 Vim 能执行外部命令的特性。例如,利用下列的自动命令,你只需要简单的按下 F9 就可以为你的 Python 代码保存并执行当前编辑好的单元测试:
au FileType python nnoremap <buffer> <F9> :wa<CR>:!clear; nosetests %<CR>
在 Tmux 中运行 Vim 的另一个好处就是,使在 Tmux 窗格或窗口执行外部命令成为可能。例如,你可以将当前的 Tmux 窗口分为两个窗格,其中一个用于编辑文件,另一个用于执行测试,而不需要在它们之间切换。为了让你体验一下我的工作流程,下面我做个示范。我工作中使用了双显示器,并做了相应设置。对于一个工程,我打开两个终端,分别在其中打开一个 Tmux 控制台,然后令每个显示器中分别显示一个终端。这时,我可以在第一个 Tmux 控制台上写代码,如果我想执行测试,生成文档,或用 lint 类似的工具检查代码,我只需通过 Vim 发送一条命令到第二个 Tmux 控制台,测试就会在第二个显示器中进行。这样,我就可以在第一个显示器的分割窗口中写代码和测试文档,在第二个显示器中运行 git 命令、执行测试等。我还对 Fluxbox进行设置,从而可以用 Ctrl+Alt+h/l 在两个显示器之间切换。这是我的配置文件。此外,还有更精彩的部分哦!那就是以上介绍的工作流程甚至适用于通过 SSH 登录到远程服务器运行 Tmux 的情况。
配置选项与映射
Vim 是高度可扩展的。你可以根据个人喜好对它进行配置,可以为你经常使用的动作添加映射和命令。在过去的时光中,我逐渐完善了我自己的 .vimrc 文件,其中包含了很多有用的设置、映射。以下是其中的一部分,不过,我建议你们看完我的整个 .vimrc 文件。
" Quickly select the text that was just pasted. This allows you to, e.g.,
" indent it after pasting.
noremap gV `[v`]
" Stay in visual mode when indenting. You will never have to run gv after
" performing an indentation.
vnoremap < <gv
vnoremap > >gv
" Make Y yank everything from the cursor to the end of the line. This makes Y
" act more like C or D because by default, Y yanks the current line (i.e. the
" same as yy).
noremap Y y$
" Make Ctrl-e jump to the end of the current line in the insert mode. This is
" handy when you are in the middle of a line and would like to go to its end
" without switching to the normal mode.
inoremap <C-e> <C-o>$
" Allows you to easily replace the current word and all its occurrences.
nnoremap <Leader>rc :%s/<<C-r><C-w>>/
vnoremap <Leader>rc y:%s/<C-r>"/
" Allows you to easily change the current word and all occurrences to something
" else. The difference between this and the previous mapping is that the mapping
" below pre-fills the current word for you to change.
nnoremap <Leader>cc :%s/<<C-r><C-w>>/<C-r><C-w>
vnoremap <Leader>cc y:%s/<C-r>"/<C-r>"
" Replace tabs with four spaces. Make sure that there is a tab character between
" the first pair of slashes when you copy this mapping into your .vimrc!
nnoremap <Leader>rts :%s/ / /g<CR>
" Remove ANSI color escape codes for the edited file. This is handy when
" piping colored text into Vim.
nnoremap <Leader>rac :%s/<C-v><Esc>[(d{1,2}(;d{1,2}){0,2})?[m|K]//g<CR>
参数折叠
最后这点也很重要,我要提一下 vim-argwrap 插件。它可以让你快速折叠或展开函数参数(表)、列表或字典。例如,你可以用它把下列代码
decompiler = Decompiler(api_url=args.api_url, api_key=args.api_key)
转换为
decompiler = Decompiler(
api_url=args.api_url,
api_key=args.api_key
)
反之亦然,仅需要作一个简单映射。
使用Marks:
Command | Description |
---|---|
ma | 在当前行新建mark |
'a | 跳转到mark a,光标定位到该行的第一个非空字符 |
`a | 跳转到mark a,光标定位到 建立 a 时的准确 列 位置。 |
d'a | 从当前行一直删到mark a所在的行,包含当前行及mark a的行 |
d`a | 删除从当前光标位置到mark a建立时的光标位置,包含开始字符,但不含结尾的字符 |
c'a | change text from current line to line of mark a |
y`a | yank text to unnamed buffer from cursor to position of mark a |
:marks | list all the current marks |
:marks aB | list marks a, B |
Commands like d'a
operate "linewise" and include the start and end lines.
Commands like d`a
operate "characterwise" and include the start but not the end character.
It is possible to navigate between lowercase marks:
Command | Description |
---|---|
]' | jump to next line with a lowercase mark |
[' | jump to previous line with a lowercase mark |
]` | jump to next lowercase mark position |
[` | jump to previous lowercase mark position |
The above commands take a count. For example, 5]`
jumps to the fifth mark after the cursor.
Special marksEdit
Vim has some special marks which it sets automatically. Here are some of the most useful:
Command | Description |
---|---|
`. | jump to position where last change occurred in current buffer |
`" | jump to position where last exited current buffer |
`0 | jump to position in last file edited (when exited Vim) |
`1 | like `0 but the previous file (also `2 etc) |
'' | jump back (to line in current buffer where jumped from) |
`` | jump back (to position in current buffer where jumped from) |
`[ or `] | jump to beginning/end of previously changed or yanked text |
`< or `> | jump to beginning/end of last visual selection |
See the full list at :help '[ and following.
Deleting marksEdit
If you delete a line containing a mark, the mark is also deleted.
If you wipeout a buffer (command :bw
), all marks for the buffer are deleted.
The :delmarks
command (abbreviated as :delm
) may be used to delete specified marks.
Command | Description |
---|---|
:delmarks a | delete mark a |
:delmarks a-d | delete marks a, b, c, d |
:delmarks abxy | delete marks a, b, x, y |
:delmarks aA | delete marks a, A |
:delmarks! | delete all lowercase marks for the current buffer (a-z) |
我自己使用的是 showmarks.vim 插件,不过这个插件有些问题,启动的时候提示: ShowMarks.0 错误,所以我自己找了一个经过自定义的 showmarks.vim (直接放在 ~/.vim/plugin 目录里),文件在百度云盘里(云盘的 work/shell 目录下),这里代码也粘贴下:
" ============================================================================== " Name: ShowMarks " Description: Visually displays the location of marks. " Authors: Anthony Kruize <trandor@labyrinth.net.au> " Michael Geddes <michaelrgeddes@optushome.com.au> " Version: 2.2 " Modified: 17 August 2004 " License: Released into the public domain. " ChangeLog: See :help showmarks-changelog " " Usage: Copy this file into the plugins directory so it will be " automatically sourced. " " Default keymappings are: " <Leader>mt - Toggles ShowMarks on and off. " <Leader>mo - Turns ShowMarks on, and displays marks. " <Leader>mh - Clears a mark. " <Leader>ma - Clears all marks. " <Leader>mm - Places the next available mark. " " Hiding a mark doesn't actually remove it, it simply moves it " to line 1 and hides it visually. " " Configuration: *********************************************************** " * PLEASE read the included help file(showmarks.txt) for a * " * more thorough explanation of how to use ShowMarks. * " *********************************************************** " The following options can be used to customize the behavior " of ShowMarks. Simply include them in your vimrc file with " the desired settings. " " showmarks_enable (Default: 1) " Defines whether ShowMarks is enabled by default. " Example: let g:showmarks_enable=0 " showmarks_include (Default: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'`^<>[]{}()\"") " Defines all marks, in precedence order (only the highest " precence will show on lines having more than one mark). " Can be buffer-specific (set b:showmarks_include) " showmarks_ignore_type (Default: "hq") " Defines the buffer types to be ignored. " Valid types are: " h - Help p - preview " q - quickfix r - readonly " m - non-modifiable " showmarks_textlower (Default: ">") " Defines how the mark is to be displayed. " A maximum of two characters can be displayed. To include " the mark in the text use a tab(\t) character. A single " character will display as the mark with the character " suffixed (same as "\t<character>") " Examples: " To display the mark with a > suffixed: " let g:showmarks_textlower="\t>" " or " let g:showmarks_textlower=">" " To display the mark with a ( prefixed: " let g:showmarks_textlower="(\t" " To display two > characters: " let g:showmarks_textlower=">>" " showmarks_textupper (Default: ">") " Same as above but for the marks A-Z. " Example: let g:showmarks_textupper="**" " showmarks_textother (Default: ">") " Same as above but for all other marks. " Example: let g:showmarks_textother="--" " showmarks_hlline_lower (Default: 0) " showmarks_hlline_upper (Default: 0) " showmarks_hlline_other (Default: 0) " Defines whether the entire line for a particular mark " should be highlighted. " Example: let g:showmarks_hlline_lower=1 " " Setting Highlighting Colours " ShowMarks uses the following highlighting groups: " ShowMarksHLl - For marks a-z " ShowMarksHLu - For marks A-Z " ShowMarksHLo - For all other marks " ShowMarksHLm - For multiple marks on the same line. " (Highest precendece mark is shown) " " By default they are set to a bold blue on light blue. " Defining a highlight for each of these groups will " override the default highlighting. " See the VIM help for more information about highlighting. " ==============================================================================" Check if we should continue loading if exists( "loaded_showmarks" )finish endif let loaded_showmarks = 1" Bail if Vim isn't compiled with signs support. if has( "signs" ) == 0echohl ErrorMsgecho "ShowMarks requires Vim to have +signs support."echohl Nonefinish endif" Options: Set up some nice defaults if !exists('g:showmarks_enable' ) | let g:showmarks_enable = 1 | endif if !exists('g:showmarks_textlower' ) | let g:showmarks_textlower = ">" | endif if !exists('g:showmarks_textupper' ) | let g:showmarks_textupper = ">" | endif if !exists('g:showmarks_textother' ) | let g:showmarks_textother = ">" | endif if !exists('g:showmarks_ignore_type' ) | let g:showmarks_ignore_type = "hq" | endif if !exists('g:showmarks_ignore_name' ) | let g:showmarks_ignore_name = "" | endif if !exists('g:showmarks_hlline_lower') | let g:showmarks_hlline_lower = "0" | endif if !exists('g:showmarks_hlline_upper') | let g:showmarks_hlline_upper = "0" | endif if !exists('g:showmarks_hlline_other') | let g:showmarks_hlline_other = "0" | endif" This is the default, and used in ShowMarksSetup to set up info for any " possible mark (not just those specified in the possibly user-supplied list " of marks to show -- it can be changed on-the-fly). let s:all_marks = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'`^<>[]{}()\""" Commands com! -nargs=0 ShowMarksToggle :call <sid>ShowMarksToggle() com! -nargs=0 ShowMarksOn :call <sid>ShowMarksOn() com! -nargs=0 ShowMarksClearMark :call <sid>ShowMarksClearMark() com! -nargs=0 ShowMarksClearAll :call <sid>ShowMarksClearAll() com! -nargs=0 ShowMarksPlaceMark :call <sid>ShowMarksPlaceMark()" Mappings (NOTE: Leave the '|'s immediately following the '<cr>' so the mapping does not contain any trailing spaces!) if !hasmapto( '<Plug>ShowmarksShowMarksToggle' ) | map <silent> <unique> <leader>mt :ShowMarksToggle<cr>| endif if !hasmapto( '<Plug>ShowmarksShowMarksOn' ) | map <silent> <unique> <leader>mo :ShowMarksOn<cr>| endif if !hasmapto( '<Plug>ShowmarksClearMark' ) | map <silent> <unique> <leader>mh :ShowMarksClearMark<cr>| endif if !hasmapto( '<Plug>ShowmarksClearAll' ) | map <silent> <unique> <leader>ma :ShowMarksClearAll<cr>| endif if !hasmapto( '<Plug>ShowmarksPlaceMark' ) | map <silent> <unique> <leader>mm :ShowMarksPlaceMark<cr>| endif noremap <unique> <script> \sm m noremap <silent> m :exe 'norm \sm'.nr2char(getchar())<bar>call <sid>ShowMarks()<CR>" AutoCommands: Only if ShowMarks is enabled if g:showmarks_enable == 1aug ShowMarksau!autocmd CursorHold * call s:ShowMarks()aug END endif" Highlighting: Setup some nice colours to show the mark positions. hi default ShowMarksHLl ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold hi default ShowMarksHLu ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold hi default ShowMarksHLo ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold hi default ShowMarksHLm ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold" Function: GetMarkLine() " Authors: Easwy Yang " Description: This function will return the line number where the mark " placed. In VIM 7.0 and later, function line() always returns line number but " not 0 in case an uppercase mark or number mark is placed. However, in VIM 6, " it only returns 0 when the uppercase mark isn't placed in current file. fun! s:GetMarkLine(mark)if v:version < 700let lnum = line(a:mark)elselet pos = getpos(a:mark)let lnum = pos[1]if pos[0] && bufnr("%") != pos[0]let lnum = 0endifendifreturn lnum endf" Function: IncludeMarks() " Description: This function returns the list of marks (in priority order) to " show in this buffer. Each buffer, if not already set, inherits the global " setting; if the global include marks have not been set; that is set to the " default value. fun! s:IncludeMarks()if exists('b:showmarks_include') && exists('b:showmarks_previous_include') && b:showmarks_include != b:showmarks_previous_include" The user changed the marks to include; hide all marks; change the" included mark list, then show all marks. Prevent infinite" recursion during this switch.if exists('s:use_previous_include')" Recursive call from ShowMarksHideAll() return b:showmarks_previous_includeelseif exists('s:use_new_include')" Recursive call from ShowMarks() return b:showmarks_includeelselet s:use_previous_include = 1call <sid>ShowMarksHideAll()unlet s:use_previous_includelet s:use_new_include = 1call <sid>ShowMarks()unlet s:use_new_includeendifendifif !exists('g:showmarks_include')let g:showmarks_include = s:all_marksendifif !exists('b:showmarks_include')let b:showmarks_include = g:showmarks_includeendif" Save this include setting so we can detect if it was changed.let b:showmarks_previous_include = b:showmarks_includereturn b:showmarks_include endf" Function: NameOfMark() " Paramaters: mark - Specifies the mark to find the name of. " Description: Convert marks that cannot be used as part of a variable name to " something that can be. i.e. We cannot use [ as a variable-name suffix (as " in 'placed_['; this function will return something like 63, so the variable " will be something like 'placed_63'). " 10 is added to the mark's index to avoid colliding with the numeric marks " 0-9 (since a non-word mark could be listed in showmarks_include in the " first 10 characters if the user overrides the default). " Returns: The name of the requested mark. fun! s:NameOfMark(mark)let name = a:markif a:mark =~# '\W'let name = stridx(s:all_marks, a:mark) + 10endifreturn name endf" Function: VerifyText() " Paramaters: which - Specifies the variable to verify. " Description: Verify the validity of a showmarks_text{upper,lower,other} setup variable. " Default to ">" if it is found to be invalid. fun! s:VerifyText(which)if strlen(g:showmarks_text{a:which}) == 0 || strlen(g:showmarks_text{a:which}) > 2echohl ErrorMsgecho "ShowMarks: text".a:which." must contain only 1 or 2 characters."echohl Nonelet g:showmarks_text{a:which}=">"endif endf" Function: ShowMarksSetup() " Description: This function sets up the sign definitions for each mark. " It uses the showmarks_textlower, showmarks_textupper and showmarks_textother " variables to determine how to draw the mark. fun! s:ShowMarksSetup()" Make sure the textlower, textupper, and textother options are valid.call s:VerifyText('lower')call s:VerifyText('upper')call s:VerifyText('other')let n = 0let s:maxmarks = strlen(s:all_marks)while n < s:maxmarkslet c = strpart(s:all_marks, n, 1)let nm = s:NameOfMark(c)let text = '>'.clet lhltext = ''if c =~# '[a-z]'if strlen(g:showmarks_textlower) == 1let text=c.g:showmarks_textlowerelseif strlen(g:showmarks_textlower) == 2let t1 = strpart(g:showmarks_textlower,0,1)let t2 = strpart(g:showmarks_textlower,1,1)if t1 == "\t"let text=c.t2elseif t2 == "\t"let text=t1.celselet text=g:showmarks_textlowerendifendiflet s:ShowMarksDLink{nm} = 'ShowMarksHLl'if g:showmarks_hlline_lower == 1let lhltext = 'linehl='.s:ShowMarksDLink{nm}.nmendifelseif c =~# '[A-Z]'if strlen(g:showmarks_textupper) == 1let text=c.g:showmarks_textupperelseif strlen(g:showmarks_textupper) == 2let t1 = strpart(g:showmarks_textupper,0,1)let t2 = strpart(g:showmarks_textupper,1,1)if t1 == "\t"let text=c.t2elseif t2 == "\t"let text=t1.celselet text=g:showmarks_textupperendifendiflet s:ShowMarksDLink{nm} = 'ShowMarksHLu'if g:showmarks_hlline_upper == 1let lhltext = 'linehl='.s:ShowMarksDLink{nm}.nmendifelse " Other signs, like ', ., etc.if strlen(g:showmarks_textother) == 1let text=c.g:showmarks_textotherelseif strlen(g:showmarks_textother) == 2let t1 = strpart(g:showmarks_textother,0,1)let t2 = strpart(g:showmarks_textother,1,1)if t1 == "\t"let text=c.t2elseif t2 == "\t"let text=t1.celselet text=g:showmarks_textotherendifendiflet s:ShowMarksDLink{nm} = 'ShowMarksHLo'if g:showmarks_hlline_other == 1let lhltext = 'linehl='.s:ShowMarksDLink{nm}.nmendifendif" Define the sign with a unique highlight which will be linked when placed.exe 'sign define ShowMark'.nm.' '.lhltext.' text='.text.' texthl='.s:ShowMarksDLink{nm}.nmlet b:ShowMarksLink{nm} = ''let n = n + 1endw endf" Set things up call s:ShowMarksSetup()" Function: ShowMarksOn " Description: Enable showmarks, and show them now. fun! s:ShowMarksOn()if g:showmarks_enable == 0call <sid>ShowMarksToggle()elsecall <sid>ShowMarks()endif endf" Function: ShowMarksToggle() " Description: This function toggles whether marks are displayed or not. fun! s:ShowMarksToggle()if g:showmarks_enable == 0let g:showmarks_enable = 1call <sid>ShowMarks()aug ShowMarksau!autocmd CursorHold * call s:ShowMarks()aug ENDelselet g:showmarks_enable = 0call <sid>ShowMarksHideAll()aug ShowMarksau!autocmd BufEnter * call s:ShowMarksHideAll()aug ENDendif endf" Function: ShowMarks() " Description: This function runs through all the marks and displays or " removes signs as appropriate. It is called on the CursorHold autocommand. " We use the marked_{ln} variables (containing a timestamp) to track what marks " we've shown (placed) in this call to ShowMarks; to only actually place the " first mark on any particular line -- this forces only the first mark " (according to the order of showmarks_include) to be shown (i.e., letters " take precedence over marks like paragraph and sentence.) fun! s:ShowMarks()if g:showmarks_enable == 0returnendifif ((match(g:showmarks_ignore_type, "[Hh]") > -1) && (&buftype == "help" ))\ || ((match(g:showmarks_ignore_type, "[Qq]") > -1) && (&buftype == "quickfix"))\ || ((match(g:showmarks_ignore_type, "[Pp]") > -1) && (&pvw == 1 ))\ || ((match(g:showmarks_ignore_type, "[Rr]") > -1) && (&readonly == 1 ))\ || ((match(g:showmarks_ignore_type, "[Mm]") > -1) && (&modifiable == 0 ))returnendiflet n = 0let s:maxmarks = strlen(s:IncludeMarks())while n < s:maxmarkslet c = strpart(s:IncludeMarks(), n, 1)let nm = s:NameOfMark(c)let id = n + (s:maxmarks * winbufnr(0))"let ln = line("'".c)let ln = s:GetMarkLine("'".c)if ln == 0 && (exists('b:placed_'.nm) && b:placed_{nm} != ln)exe 'sign unplace '.id.' buffer='.winbufnr(0)elseif ln > 1 || c !~ '[a-zA-Z]'" Have we already placed a mark here in this call to ShowMarks?if exists('mark_at'.ln)" Already placed a mark, set the highlight to multipleif c =~# '[a-zA-Z]' && b:ShowMarksLink{mark_at{ln}} != 'ShowMarksHLm'let b:ShowMarksLink{mark_at{ln}} = 'ShowMarksHLm'exe 'hi link '.s:ShowMarksDLink{mark_at{ln}}.mark_at{ln}.' '.b:ShowMarksLink{mark_at{ln}}endifelseif !exists('b:ShowMarksLink'.nm) || b:ShowMarksLink{nm} != s:ShowMarksDLink{nm}let b:ShowMarksLink{nm} = s:ShowMarksDLink{nm}exe 'hi link '.s:ShowMarksDLink{nm}.nm.' '.b:ShowMarksLink{nm}endiflet mark_at{ln} = nmif !exists('b:placed_'.nm) || b:placed_{nm} != lnexe 'sign unplace '.id.' buffer='.winbufnr(0)" exe 'sign place '.id.' name=ShowMark'.nm.' line='.ln.' buffer='.winbufnr(0)if ln > 0 " conditional which tests for the line number as greater than 0exe 'sign place '.id.' name=ShowMark'.nm.' line='.ln.' buffer='.winbufnr(0)endif " end conditionallet b:placed_{nm} = lnendifendifendiflet n = n + 1endw endf" Function: ShowMarksClearMark() " Description: This function hides the mark at the current line. " It simply moves the mark to line 1 and removes the sign. " Only marks a-z and A-Z are supported. fun! s:ShowMarksClearMark()let ln = line(".")let n = 0let s:maxmarks = strlen(s:IncludeMarks())while n < s:maxmarkslet c = strpart(s:IncludeMarks(), n, 1)"if c =~# '[a-zA-Z]' && ln == line("'".c)if c =~# '[a-zA-Z]' && ln == s:GetMarkLine("'".c)let nm = s:NameOfMark(c)let id = n + (s:maxmarks * winbufnr(0))exe 'sign unplace '.id.' buffer='.winbufnr(0)" Easwy, we can really remove marks in VIM 7.0 and laterif v:version >= 700exe 'delm '.celseexe '1 mark '.cendif" Easwy, endlet b:placed_{nm} = 1endiflet n = n + 1endw endf" Function: ShowMarksClearAll() " Description: This function clears all marks in the buffer. " It simply moves the marks to line 1 and removes the signs. " Only marks a-z and A-Z are supported. fun! s:ShowMarksClearAll()let n = 0let s:maxmarks = strlen(s:IncludeMarks())while n < s:maxmarkslet c = strpart(s:IncludeMarks(), n, 1)if c =~# '[a-zA-Z]'let nm = s:NameOfMark(c)let id = n + (s:maxmarks * winbufnr(0))exe 'sign unplace '.id.' buffer='.winbufnr(0)" Easwy, we can really remove marks in VIM 7.0 and laterif v:version >= 700exe 'delm '.celseexe '1 mark '.cendif" Easwy, endlet b:placed_{nm} = 1endiflet n = n + 1endw endf" Function: ShowMarksHideAll() " Description: This function hides all marks in the buffer. " It simply removes the signs. fun! s:ShowMarksHideAll()let n = 0let s:maxmarks = strlen(s:IncludeMarks())while n < s:maxmarkslet c = strpart(s:IncludeMarks(), n, 1)let nm = s:NameOfMark(c)if exists('b:placed_'.nm)let id = n + (s:maxmarks * winbufnr(0))exe 'sign unplace '.id.' buffer='.winbufnr(0)unlet b:placed_{nm}endiflet n = n + 1endw endf" Function: ShowMarksPlaceMark() " Description: This function will place the next unplaced mark (in priority " order) to the current location. The idea here is to automate the placement " of marks so the user doesn't have to remember which marks are placed or not. " Hidden marks are considered to be unplaced. " Only marks a-z are supported. fun! s:ShowMarksPlaceMark()" Find the first, next, and last [a-z] mark in showmarks_include (i.e." priority order), so we know where to "wrap".let first_alpha_mark = -1let last_alpha_mark = -1let next_mark = -1if !exists('b:previous_auto_mark')let b:previous_auto_mark = -1endif" Find the next unused [a-z] mark (in priority order); if they're all" used, find the next one after the previously auto-assigned mark.let n = 0let s:maxmarks = strlen(s:IncludeMarks())while n < s:maxmarkslet c = strpart(s:IncludeMarks(), n, 1)if c =~# '[a-z]'"if line("'".c) <= 1if s:GetMarkLine("'".c) <= 1" Found an unused [a-z] mark; we're done.let next_mark = nbreakendifif first_alpha_mark < 0let first_alpha_mark = nendiflet last_alpha_mark = nif n > b:previous_auto_mark && next_mark == -1let next_mark = nendifendiflet n = n + 1endwif next_mark == -1 && (b:previous_auto_mark == -1 || b:previous_auto_mark == last_alpha_mark)" Didn't find an unused mark, and haven't placed any auto-chosen marks yet," or the previously placed auto-chosen mark was the last alpha mark --" use the first alpha mark this time.let next_mark = first_alpha_markendifif (next_mark == -1)echohl WarningMsgecho 'No marks in [a-z] included! (No "next mark" to choose from)'echohl Nonereturnendiflet c = strpart(s:IncludeMarks(), next_mark, 1)let b:previous_auto_mark = next_markexe 'mark '.ccall <sid>ShowMarks() endf" ----------------------------------------------------------------------------- " vim:ts=4:sw=4:noet
同时,为了更好的使用该 showmarks plugin 的功能,.vimrc 需要在末尾增加点东西:
" ------------------------------------------------------------------ " Desc: ShowMarks " ------------------------------------------------------------------ let g:showmarks_enable = 1 let showmarks_include = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" " Ignore help, quickfix, non-modifiable buffers let showmarks_ignore_type = "hqm" " Hilight lower & upper marks let showmarks_hlline_lower = 1 let showmarks_hlline_upper = 0" update custom highlights " ======================================================== " ShowMarks " ========================================================" For marks a-z hi clear ShowMarksHLl hi ShowMarksHLl term=bold cterm=none ctermbg=DarkBlue gui=none guibg=DarkBlue " For marks A-Z hi clear ShowMarksHLu hi ShowMarksHLu term=bold cterm=bold ctermbg=LightRed ctermfg=DarkRed gui=bold guibg=LightRed guifg=DarkRed " For all other marks hi clear ShowMarksHLo hi ShowMarksHLo term=bold cterm=bold ctermbg=LightYellow ctermfg=DarkYellow gui=bold guibg=LightYellow guifg=DarkYellow " For multiple marks on the same line. hi clear ShowMarksHLm hi ShowMarksHLm term=bold cterm=none ctermbg=LightBlue gui=none guibg=SlateBlue
" highlight current line
" highlight current line set cursorline " set cursorcolumn highlight CursorLine cterm=NONE ctermfg=DarkGreen ctermbg=black guibg=NONE guifg=NONE term=boldhighlight LineNr ctermfg=darkgray ctermbg=black