📄 usr_41.cnx
字号:
Note(注意) 为了避免其它映射引起麻烦,在第 28 行使用了 ":noremap"。比如有人可能重新映射了 ":call"。在第 24 也用到了 ":noremap",但我们又希望重新映射"<SID>Add"。这就是为什么在这儿要用 "<script>"。这只允许定义脚本本地的映射。|:map-<script>| 同样的道理在第 25 行也用了 ":noremenu"。|:menu-<script>|<SID> 和 <Plug> *using-<Plug>*<SID> 和 <Plug> 都是用来避免映射的键序列和那些仅仅用于其它映射的映射起冲突。Note(注意) <SID> 和 <Plug> 的区别:<Plug> 在脚本外部是可见的。它被用来定义那些用户可能定义映射的映射。<Plug> 是一个 键盘输入之外的特殊代码。 使用结构:<Plug> 脚本名 映射名,可以使得其它插件使用同样次序的字符来定义映 射的几率变得非常小。在我们上面的例子中,脚本名是 "Typecorr",映射名是 "Add"。 结果是 "<Plug>TypecorrAdd"。 只有脚本名和映射名的第一个字符是大写的,所以我 们可以清楚地看到映射名从什么地方开始。<SID> 是脚本的标示,用来唯一的代表一个脚本。Vim 在内部将 <SID> 翻译为 "<SNR>123_",其中 "123" 可以是任何数字。这样一个函数 "<SID>Add()" 可能 在一个脚本中被命名为 "<SNR>11_Add()",而在另一个脚本中被命名为 "<SNR>22_Add()"。如果你用 ":function" 命令来获得系统中的函数列表你就可 以看到了。映射中对 <SID> 的翻译是完全一样的。这样你才有可能通过一个映射 来调用某个脚本中的本地函数。用 户 命 令现在让我们来定义一个用来添加更正的用户命令: > 38 if !exists(":Correct") 39 command -nargs=1 Correct :call s:Add(<q-args>, 0) 40 endif这个用户命令只在系统中没有同样名称的命令时才被定义。否则我们会得到一个错误。用":command!" 来覆盖现存的用户命令是个坏主意。这很可能使用户不明白自己定义的命令为什么不起作用。|:command|脚 本 变 量当一个变量前面带有 "s:" 时,我们将它称为脚本变量。该变量只能在脚本内部被使用。在脚本以外该变量是不可见的。这样就避免了在不同的脚本中使用同一个变量名的麻烦。该变量在 Vim 的运行期间都是可用的。当再次调用 (source) 该脚本时使用的是同一个变量。|s:var|有趣的是这些变量也可以在脚本定义的函数、自动命令和用户命令中使用。在我们的例子中我们可以加入几行用来统计更正的个数: > 19 let s:count = 4 .. 30 function s:Add(from, correct) .. 34 let s:count = s:count + 1 35 echo s:count . " corrections now" 36 endfunction起初 s:count 被脚本初始化为 4。当后来 s:Add() 函数被调用时,其值被增加了。在哪里调用函数无关紧要。只要它是定义在该脚本以内的,就可以使用脚本中的本地变量。结 果下面就是完整的例子: > 1 " Vim global plugin for correcting typing mistakes 2 " Last Change: 2000 Oct 15 3 " Maintainer: Bram Moolenaar <Bram@vim.org> 4 " License: This file is placed in the public domain. 5 6 if exists("loaded_typecorr") 7 finish 8 endif 9 let loaded_typecorr = 1 10 11 let s:save_cpo = &cpo 12 set cpo&vim 13 14 iabbrev teh the 15 iabbrev otehr other 16 iabbrev wnat want 17 iabbrev synchronisation 18 \ synchronization 19 let s:count = 4 20 21 if !hasmapto('<Plug>TypecorrAdd') 22 map <unique> <Leader>a <Plug>TypecorrAdd 23 endif 24 noremap <unique> <script> <Plug>TypecorrAdd <SID>Add 25 26 noremenu <script> Plugin.Add\ Correction <SID>Add 27 28 noremap <SID>Add :call <SID>Add(expand("<cword>"), 1)<CR> 29 30 function s:Add(from, correct) 31 let to = input("type the correction for " . a:from . ": ") 32 exe ":iabbrev " . a:from . " " . to 33 if a:correct | exe "normal viws\<C-R>\" \b\e" | endif 34 let s:count = s:count + 1 35 echo s:count . " corrections now" 36 endfunction 37 38 if !exists(":Correct") 39 command -nargs=1 Correct :call s:Add(<q-args>, 0) 40 endif 41 42 let &cpo = s:save_cpo第 32 还没有解释过。它将新定义的更正用在当前光标下的单词上。|:normal| 被用来使用新的缩写。 Note(注意) 虽然这个函数是被一个以 ":noremap" 定义的映射调用的,这里的映射和缩写还是被展开使用了。推荐对 'fileformat' 选项使用 "unix" 值。这样的 Vim 脚本就可以在所有系统内使用。对 'fileformat' 选项使用 "dos" 的脚本无法正常的在 Unix 上使用。参见|:source_crnl| 。为确保该值被城正确设置,在写入文件前执行下面的命令: > :set fileformat=unix文 档 *write-local-help*给你的插件写一些文档是个好主意。特别是当用户可以自己定义其中的某些功能时。关于如何安装文档,请查阅 |add-local-help|。下面是一个插件帮助文档的简单例子,名叫 "typecorr.txt": > 1 *typecorr.txt* Plugin for correcting typing mistakes 2 3 If you make typing mistakes, this plugin will have them corrected 4 automatically. 5 6 There are currently only a few corrections. Add your own if you like. 7 8 Mappings: 9 <Leader>a or <Plug>TypecorrAdd 10 Add a correction for the word under the cursor. 11 12 Commands: 13 :Correct {word} 14 Add a correction for {word}. 15 16 *typecorr-settings* 17 This plugin doesn't have any settings.其实只有第一行是文档的格式所必需的。Vim 将从该帮助文件中提取该行并加入到help.txt 的 "LOCAL ADDITIONS:" |local-additions| (本地附加文档) 一节中。第一个 "*" 一定要在第一行的第一列。加入你的帮助文件之后用 ":help" 来检查一下各项是否很好的对齐了。你可以为你的帮助文档在 ** 之间加入更多的标签。但注意不要使用现存的帮助标签。你最好能在标签内使用插件名用以区别,比如上例中的 "typecorr-settings"。建议使用 || 来引用帮助系统中的其它部分。这可以使用户很容易得找到相关联的帮助。小 结 *plugin-special*关于插件的小结:s:name 脚本的本地变量。<SID> 脚本标示,用于脚本本地的映射和函数。hasmapto() 用来检测插件定义的映射是否已经存在的函数。<Leader> "mapleader"的值。用户可以通过该变量定义插件所定义 映射的起始字符。:map <unique> 如果一个映射已经存在的话,给出警告信息。:noremap <script> 仅使用脚本的本地映射,而不使用全局的。exists(":Cmd") 检查一个用户命令是否存在。==============================================================================*41.11* 编写文件类型插件 *write-filetype-plugin* *ftplugin*文件类型插件和全局插件其实很相似。但是它的选项设置和映射等仅对当前缓冲有效。这类插件的用法请参阅 |add-filetype-plugin|。请先阅读上面 |41.10| 关于全局插件的叙述。其中所讲得对文件类型插件也都适用。这里只讲述一些额外的东西。最更本的不同是文件类型插件只应该对当前缓冲生效。禁 用如果你在编写一个提供很多人使用的文件类型插件,这些用户应该有机会选择不加载该插件。你应该在插件的顶端加上: > " Only do this when not done yet for this buffer if exists("b:did_ftplugin") finish endif let b:did_ftplugin = 1这同时也避免了同一插件在同一缓冲内被多次执行的错误 (当使用不带参数的 ":edit"命令时就会发生)。现在用户只要编写一个如下的一行的文件类型插件就可以完全避免加载缺省的文件类型插件了: > let b:did_ftplugin = 1当然这要求该文件类型插件所处的文件类型插件目录在 'runtimepath' 所处的位置在$VIMRUNTIME 之前!如果你的确希望使用缺省的插件,但是又想自行支配其中的某一选项,你可以用一个类似下例的插件: > set textwidth=70现在将这个文件存入那个 "after" 目录中。这样它就会在调用 Vim 本身的 "vim.vim"文件类型插件之后被调用 |after-directory|。对于 Unix 系统而言,该目录会是"~/.vim/after/ftplugin/vim.vim"。 Note 缺省的文件类型插件已经设置了"b:did_ftplugin", 但在这里被忽略了。选 项为了确保文件类型插件仅仅影响当前缓冲,应该使用 > :setlocal命令来设置选项。还要注意只设定缓冲的本地选项 (查查有关选项的帮助)。当|:setlocal| 被用于设置全局选项或者某窗口的本地选项时,会影响到多个缓冲,这是文件类型插件应该避免的。当一个选项的值是多个项目的 "合" 时,考虑使用 "+=" 和 "-=",这样可以保留现有的值。注意用户可能已经改变了该选项的值了。通常先将选项的值复位成缺省值再做改动是个好主意。例: > :setlocal formatoptions& formatoptions+=ro映 射为了确保键盘映射只对当前缓冲生效,应该使用 > :map <buffer>命令。这还应该和上面讲述的两步映射法连起来使用。下面是一个例子: > if !hasmapto('<Plug>JavaImport') map <buffer> <unique> <LocalLeader>i <Plug>JavaImport endif noremap <buffer> <unique> <Plug>JavaImport oimport ""<Left><Esc>|hasmapto()| 被用来检查用户是否已经定义了一个对 <Plug>JavaImport 的映射。如果没有,该文件类型插件就定义缺省的映射。因为缺省映射是以 |<LocalLeader>| 开始,就使得用户可以自己定义映射的起始字符。缺省的是反斜杠。 "<unique>" 的用途是当已经存在的了这样的映射或者和已经存在的映射有重叠的时候给出错误信息。|:noremap| 被用来防止其他用户定义的映射干扰。你可能会希望使用":noremap <script>" 来允许以 <SID> 开头的脚本重新定义映射。一定要给用户保留禁止一个文件类型插件内的映射而不影响其它功能的能力。下面通过一个邮件文件类型插件来演示如何做到这一点: > " Add mappings, unless the user didn't want this. if !exists("no_plugin_maps") && !exists("no_mail_maps") " Quote text by inserting "> " if !hasmapto('<Plug>MailQuote') vmap <buffer> <LocalLeader>q <Plug>MailQuote nmap <buffer> <LocalLeader>q <Plug>MailQuote endif vnoremap <buffer> <Plug>MailQuote :s/^/> /<CR> nnoremap <buffer> <Plug>MailQuote :.,$s/^/> /<CR> endif其中用到了两个全局变量:no_plugin_maps 禁止所有文件类型插件中的映射no_mail_maps 禁止某一特定的文件类型插件的映射用 户 名 令在使用 |:command| 命令时,如果加上 "-buffer" 开关,就可以为某一类型的文件加入一个用户命令,而该命令又只能用于一个缓冲。例: > :command -buffer Make make %:r.s变 量文件类型插件对每一个该类型的文件都会被调用。脚本本地变量 |s:var| 会被所有的调用共享。如果你想定义一个仅对某个缓冲生效的变量,使用缓冲本地变量 |b:var|。函 数一个函数只需要定义一次就行了。可是文件类型插件会在每次打开相应类型的文件时都被调用。下面的结构可以确保函数只被定义一次: > :if !exists("*s:Func") : function s:Func(arg) : ... : endfunction :endif<撤 消当用户执行 ":setfiletype xyz" 时,之前的文件类型命令应该被撤消。在你的文件类型插件中设定 b:undo_ftplugin 变量为撤消各种设置的命令。例如: > let b:undo_ftplugin = "setlocal fo< com< tw< commentstring<" \ . "| unlet b:match_ignorecase b:match_words b:match_skip"在 ":setlocal" 命令的选项后使用 "<" 会将其值复位为全局值。这可能是最好的复位选项值的方法。但这也需要把 "C" 标志从 'cpoptions' 选项中去除,就像上面 |use-cpo-save| 提到的那样。文 件 名文件类型必须被包括在插件文件名中 |ftplugin-name|。可以使用一下三种形式之一: .../ftplugin/stuff.vim .../ftplugin/stuff_foo.vim .../ftplugin/stuff/bar.vim"stuff" 是文件类型,"foo" 和 "bar" 是任意名字。小 结 *ftplugin-special*以下是有关文件类型插件一些特殊环节:<LocalLeader> "maplocalleader" 的值,用户可以通过它来自定 义文件类型插件中映射的起始字符:map <buffer> 定义一个仅对缓冲有效的本地映射。:noremap <script> 仅重定义脚本中以 <SID> 开始的映射。:setlocal 仅对当前缓冲设定选项。:command -buffer 定义一个仅对缓冲有效的本地命令。exists("*s:Func") 查看是否已经定义了某个函数。参阅所有插件的特殊环节 |plugin-special|。==============================================================================*41.12* 编写编译器插件 *write-compiler-plugin*编译器插件可以用来设定于某一特定编译器相关的选项。用户可以使用 |:compiler|命令来加载之。主要是用以设定 'errorformat' 及 'makeprg' 选项。最简单的方法就是参考一下例子。下面的命令将编辑所有缺省的编译器插件: > :next $VIMRUNTIME/compiler/*.vim用 |:next| 可以查阅下一个插件文件。这类插件唯一特别的是一个允许用户否决或者增强缺省的文件的机制。缺省的文件以下面的代码开始: > :if exists("current_compiler") : finish :endif :let current_compiler = "mine"当你编写一个编译器文件并将其放置在个人运行期目录 (例如, Unix 下的~/.vim/compiler),你可以给 "current_compiler" 赋值,使得缺省文件不执行其设定。当你为 Vim 发行或者整个系统编写编译器插件时,应该使用上面提到的机制。这样当用户插件已经定义了 "current_compiler" 的时候什么也不做。当你为了自行定义缺省插件的一些设定而编写编译器插件时,不要检查 "current_compiler"。这个插件应该在最后加载,因此其所在目录应该在 'runtimepath'的最后。对于 Unix 来说可能是 ~/.vim/after/compiler。==============================================================================下一章: |usr_42.txt| 添加新的菜单版权:参见 |manual-copyright| vim:tw=78:ts=8:ft=help:norl:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -