缘起
听从《Web开发敏捷之道》的建议,将几个IDE和编辑器尝试了一番,没一个满意的,要太大或要不太吃内存。最后,我还是回到VIM上,老实的学习如何使用VIM扩展的插件。
正文
关于VIM插件,目前,在开发Rails中需要使用插件如下:NERD_tree,CommandT,snipMate,vim-ruby,vim-rails。备注:这里只是个人的看法。
VIM不是一个简单的易学的编辑器,但也不是那么难学,花点时间熟悉命令总是好好。对于VIM的学习,伯乐在线提供很多不错的学习文章,网上有人汇总了一些资料,这里推荐池建强的《谁说Vim不是IDE?》和《手把手教你把vim改造成IDE》,当然,可以通过VIM的帮助文档来学习,VIM的中文帮助文档地址:http://vimcdoc.sourceforge.net。中文版的VIM pdf文档2601页,当然这不是我见过页数最多的文档,Mysql的英文文档3344页,长文档有个好处-详细,闲着没事是看看,打发打发时间。
以下安装的插件都是通过pathogen来管理的,关于Pathogne的安装参考https://github.com/tpope/vim-pathogen的主页。
1. NERDTree
NERDTree提供了丰富的键盘操作方式来浏览和打开文件。在打开vi之后,输入:NERDTree打开NERDTree,其界面如下:
图 1.1 NERDTree打开的界面
备注:简单的使用后发现,NERDTree打开的水平窗口的大小是固定的,要学习如何调整大小
NERDTree的一些常用的快捷键介绍如下:
- l 和编辑文件一样,通过h j k l移动光标定位
- l o 打开关闭文件或者目录,如果是文件的话,就会在图1.1的右侧打开该文件,启动鼠标后,鼠标点击效果相同
- l go 效果同上,不过光标保持在文件目录里,类似预览文件内容的功能
- l i和s可以水平分割或纵向分割窗口打开文件,前面加g类似go的功能
- l t 在标签页中打开,并跳转到打开的标签页
- l T 在标签页中打开,光标依然停留在当前页面中
- l K 到同目录第一个节点
- l J 到同目录最后一个节点
- l C 切换目录,进入当前所在的目录,不会改变bash所在的目录
- l m 显示文件系统菜单(添加、删除、移动操作)
- l ? 帮助,有一点不好的就是,帮助显示的位置
- l q 关闭
2. CommandT
Command-T的功能挺强大,可以在不显式目录树时(即不使用NERDTree时),检索并定位当前目录树下的文件。
安装参考《谁说Vim不是IDE?》,打开命令为:CommandT,使用界面为:
Command-T常用操作:
- l ctrl+j/k(或↑↓)上下选择文件,选中后回车(Enter)打开文件
- l ctrl+t 以tab方式打开文件
- l ctrl+s/v 可以水平或垂直分割窗口打开文件
- l ctrl+c 退出该模式
该插件还有个常用命令,:CommandTBuffer,可以浏览缓冲区的文件,并重新打开。操作方式同上。
备注:该插件的唯一一个缺点就是命令太长了,参考了VIM中文手册(2601页)后,想了个办法,在.vimrc中设置插件的缩写,设置内容如下:
command CT CommandT
command CB CommandTBuffer
输入时,可以输入小写字母ct或cb,然后按Tab键自动补全。
3. snipMate
SnipMate是为了提供类似TextMate的的文本片段。备注,看了好久,就是没能有一个可感的演示,有点不知所云。
3.1. 安装
安装SnipMate(使用pathogen管理)
$cd ~/.vim/bundle
#tlib_vim有何作用
$git clone https://github.com/tomtom/tlib_vim.git
#vim-addon-mw-utils有何作用
$git clone https://github.com/MarcWeber/vim-addon-mw-utils.git
$git clone https://github.com/garbas/vim-snipmate.git
# 可选的:
$git clone https://github.com/honza/vim-snippets.git
3.2. 具体使用
SnipMate仅工作在VI不兼容模式下。SnipMate在VIM中实现了片段特性,片段类似模板,可以减少重复性插入的文件片段。每个片段包含一个扩展和一个触发器,在buffer中输入触发器,然后按下触发按钮。SnipMate允许多个片段使用相同的触发器,触发时会弹出可选的列表。SnipMate搜索包含在'runtimepath'中的每个实体。文件加载依赖filetype和syntax。片段可以被自动加载和刷新。
注意:SnipMate本身不携带任何片段,用户可以自己编写或者使用vim-snippets库。
3.2.1. 命令
:SnipMateOpenSnippetFiles 打开基于当前SnipMate-scopes中所有有效的位置。已存在的片段先显示。
:SnipMateLoadScope[!] scope [scope ...] 加载附加的片段域。没有[!]时,附加的域仅被加载到当前缓冲区中。例如,:SnipMateLoadScopes rails就会将rails的片段加载到当前缓冲区。
3.2.2. 选项
g:snipMate 该字典包含其他SnipMate的选项,简而言之,在设置其他的SnipMate之前,添加let g:snipMate = {}到你的.vimrc文件中。
g:snipMate.scope_aliases 关联到带有其他域的特定文件类型的字典值。其中的实体由文件类型(filetype)的键值和以逗号分隔的别名值组成。例如:
let g:snipMate.scope_aliases = {}
let g:snipMate.scope_aliases['ruby'] = 'ruby,ruby-rails'
告诉SnipMate,当编辑ruby或者包含ruby的文件类型时,ruby-rails片段附加到ruby片段中。局部缓冲区变量b:snipMate_scope_aliases被合并到全局变量中。
g:snipMate_no_default_aliases 注意:该选项将会被重命名
g:snipMate.no_default_aliases 设置为1时,确保SnipMate加载默认的域别名,默认值为(Filetype:Alias):cpp:c,cu:c,eruby:eruby-rails,html,html:javascript,mxml:actionscript,Objc:c,php:php,html,javascript,ur:html,javascript,xhtml:html
个别默认值可以通过设置为空来禁止,比如:let g:snipMate.scope_aliases.php = ''将会禁止PHP的别名。
g:snipMate['no_match_completion_feedkeys_chars'] 在某一触发器没有任何匹配时插入的字符串,默认情况下,根据'expandtab','tabstop','softtabstop'插入tab健。设置为空可以避免插入任何东西。
3.2.3. 映射
SnipMate使用的映射可以通过:map命令定制。例如,改变触发片段的健和移动到下一个tabstop的健。
:imap <C-J> <Plug>snipMateNextOrTrigger
:smap <C-J> <Plug>snipMateNextOrTrigger
下面列出可能的<Plug>映射:
<Plug>snipMateNextOrTrigger: 默认为<Tab>,跳到下一个tab stop,或者尝试扩展一个片段。可工作在插入和选择模式。
<Plug>snipMateTrigger Default: unmapped Mode: Insert
Try to expand a snippet regardless of any
existing snippet expansion. If done within an
expanded snippet, the outer snippet's tab
stops are lost, unless expansion failed.
没有默认映射,
<Plug>snipMateBack Default: <S-Tab> Mode: Insert, Select
Jump to the previous tab stop, if it exists.
Use in both insert and select modes.
<Plug>snipMateShow Default: <C-R><Tab> Mode: Insert
Show all available snippets (that start with
the previous text, if it exists). Use in
insert mode.
<Plug>snipMateVisual Default: <Tab> Mode: Visual
See |SnipMate-visual|.
Additionally, <CR> is mapped in visual mode in .snippets files for retabbing
snippets.
3.3. 实现相关
SnipMate是可配置的.plugin/SnipMate.vim分配了三个重要的健:
" default implementation collecting snippets by handlers
let g:SnipMate['get_snippets'] = SnipMate#GetSnippets
" default handler:
let g:SnipMateSources['default'] = SnipMate#DefaultPool
" default directories containing snippets:
let g:SnipMate['snippet_dirs']
\ = funcref#Function('return split(&runtimepath,",")')
这些设置是可以覆盖的。默认的snippets集是由vim的rtp决定的。
Example 1:~
autoload/SnipMate_python_demo.vim 演示了如何通过Python函数即刻注册附加的创建片段源。
Example 2:~
Add to your ~/.vimrc: For each know snippet add a second version ending in _
adding folding markers >
添加到你的配置文件(~/.vimrc)中,
let g:commentChar = {
\ 'vim': '"',
\ 'c': '//',
\ 'cpp': '//',
\ 'sh': '#',
\ 'python': '#'
\ }
" url https://github.com/garbas/vim-snipmate/issues/49
fun! AddFolding(text)
return substitute(a:text,'\n'," ".g:commentChar[&ft]." {{{\n",1)."\n".g:commentChar[&ft]." }}}"
endf
fun! SnippetsWithFolding(scopes, trigger, result)
" hacky: temporarely remove this function to prevent infinite recursion:
call remove(g:SnipMateSources, 'with_folding')
" get list of snippets:
let result = SnipMate#GetSnippets(a:scopes, substitute(a:trigger,'_\(\*\)\?$','\1',''))
let g:SnipMateSources['with_folding'] = funcref#Function('SnippetsWithFolding')
" add folding:
for k in keys(result)
let a:result[k.'_'] = map(result[k],'AddFolding(v:val)')
endfor
endf
" force setting default:
runtime plugin/SnipMate.vim
" add our own source
let g:SnipMateSources['with_folding'] = funcref#Function('SnippetsWithFolding')
参考SnipMate-syntax寻找更多关于rtp所有可能的相关定位的信息。
4. vim-ruby
Vim-ruby提供了对vim的在ruby中移动动作和文本对象功能的增强。扩展不多,看起来应该很实用,具体的实现,我猜是通过正则匹配。
4.1. Vim-ruby中动作
Vim提供了诸如[m和]m这样的跳转到方法定义的开始和结束的动作,但这仅对花括号的语言,而不是Ruby。Vim-ruby插件增强了这些动作,使其能够在ruby文件中工作。
]m 跳转到下一个方法定义开始的地方
]M 跳转到下一个方法定义结束的地方
[m 跳转到上一个方法定义开始的地方
[M 跳转到上一个方法定义结束的地方
]] 跳转到下一个模块或类定义开始的地方
][ 跳转到下一个模块或类定义结束的地方
[[ 跳转到前一个模块或类定义开始的地方
[] 跳转到前一个模块或类定义结束的地方
备注:这里的动作看起来不似那么难记,估计多用用就熟了。
4.2. Vim-ruby中文本对象
VIM的文本对象可以用来对文本域进行选择和操作。vim-ruby插件增加操作方法和类的文本对象。
am:"a method",选择从def到end文本快,包括def和end
im:"inner method",选择def和end之间的块,不包括def和end本身。
aM:"a class",选择从class到end之间的文本,包括class和end
iM:"inner class",选择从class到end之间的文本,不包括class和end.
5. vim-rails
Vim-rails提供了可以在VIM编辑界面下处理一切开发事宜的强大命令,前提是vim必须在Rails项目根目录打开。Rails.vim提供在VIM下开发RoR应用的一些特性如下:
- l 方便的Rails目录结构导航:gf考虑上下文,:A和:R方便的在文件之间跳转,:Emodel,:Eview,:Econtroller提供文件类型编辑(:edit)文件.SVT对应:split,:vsplit,:tabedit.导航帮助命令::help rails-navigation
- l 增强的语法高亮:比如ActiveRecord中的DSL has_and_belongs_to_many
- l rake命令的接口:使用:Rake运行当前测试,说明,夹具,迁移等,帮助命令:help rails-rake
- l rails命令的接口,例如,:Rails console 调用rails控制台。很多命令包装了附加的特性,例如:Rgenerate controller Blog 生成blog控制器并将生成的文件添加到quickfix(??)列表中。:Rrunner包装了rails runner和直接测试运行。详细查看:help rails-scripts
- l Partial以及concern提取。在视图中,:Rextract {file}将选择的特定文本块替代为render {file}。在模型或控制器中,concern将会被创建。更多参考:help rails-:Rextract
- l 完全定制。在全局,app,gem包层次定义导航命令并复写可选的文件,默认的rake任务,语法高亮,缩写。更多参考:help rails-projections
- l 与其他的插件的集成,[dbext.vim]安装之后,将能透明的配置和反射database.yml,[abolish.vim]的用户 get pluralize and tableize coercions,[bundler.vim]的用户get a smattering of features.更多信息参考:help rails-integration
5.1. 安装
如果没有喜好的安装方法,推荐使用pathogen.vim 安装VIM插件。然后,简单的复制粘贴命令就行了:
cd ~/.vim/bundle
git clone git://github.com/tpope/vim-rails.git
git clone git://github.com/tpope/vim-bundler.git
不一定要求安装bundler.vim,但它会有一定的作用。一旦生成了help标签,就可以通过:help rails来查看手册。
5.2. 使用
Vim-rails提供了可以在VIM编辑界面下处理一切开发事宜的强大命令,前提是vim必须在Rails项目根目录打开。下面是该插件的一部分命令,详情请看帮助(备注:有些命令好像不太管用,难道是我自己没有学习到家):
- l :Rake,例如:Rake db:migrate, :Rake db:create, ......
- l :Rmodel,例如:Rmodel info (查找model名称为info的文件)
- l :Rview,例如:Rview infos/new (查找infos控制器下的new视图文件)
- l :Rcontroller,例如:Rcontroller infos(查找控制器名称为infos的文件)
- l :Rfind,例如:Rfind infos_controller(查找infos_controller.rb文件)
- l :Rails,例如:Rails console 或 :Rails generate model info age:integer
- l :Rscript,例如:Rscript console 或 :Rscript generate model info age:integer(注意Rscript相当于script/rails命令)
- l :Redit,例如:Redit 相对路径
- l :Rlog,例如:Rlog development 打开development.log日志文件
- l :Rpreview 打开一个浏览器,http://localhost:3000
- l :Rrefresh 刷新
- l R,在目录下直接shift+r,可以刷新目录
- l gf 根据当前光标处内容跳转到文件
- l :Rmigration 查找migration文件
- l :Rlayout 查找layout文件
- l :Rhelper 查找helper文件
- l :Rstylesheet
- l :Rjavascript
- l :Rplugin
- l :Rlib
- l :Rtask
- l :Rserver
5.3. 常见问题
> I installed the plugin and started Vim. Why does only the `:Rails`
> command exist?
This plugin cares about the current file, not the current working
directory. Edit a file from a Rails application.
该插件只关心当前文件,不是当前工作目录,使用请从Rails应用程序中编辑文件。
> I opened a new tab. Why does only the `:Rails` command exist?
This plugin cares about the current file, not the current working
directory. Edit a file from a Rails application. You can use the `:RT`
family of commands to open a new tab and edit a file at the same time.
> Can I use rails.vim to edit Rails engines?
It's not supported, but if you `touch config/environment.rb` in the root
of the engine, things should mostly work.
> Can I use rails.vim to edit other Ruby projects?
I wrote [rake.vim](https://github.com/tpope/vim-rake) for exactly that
purpose. It activates for any project with a `Rakefile` that's not a
Rails application.
> What Rails versions are supported?
All of them. A few features like syntax highlighting tend to reflect the
latest version only.
> Didn't rails.vim used to handle indent settings?
It got yanked after increasing contention over JavaScript. Check out
[sleuth.vim](https://github.com/tpope/vim-sleuth).
6.TIPS
使用gt或gT切换标签页(go tab)。
X windows中存在剪切板(vim中”+)和类似剪切板的当前选择区(VIM中的“*),ctrl+v是对剪切板中内容进行复制,鼠标中健的点击对当前选择区中内容进行复制。这一点和Windows不同,windows只有剪切板,不了解的话,会对系统的行为感到困惑。不过当前选择区确实很有意思,只要被选择就被复制,很强大。
后记
上面这些,就是为了在VIM中开发Rails程序准备的一些插件。没有大量使用过,以后再修改和添加。
上面的这些程序,除了snipMate比较难以理解,其他的一些插件都很好理解和使用。
Ubuntu/Linux很有意思,就像一个神秘的盒子,有时想窥探一下其中包含的秘密,然后确实可以发现其中的秘密。对于Windows,盒子外面贴着”禁止进入“的封条。
参考文献
1.VIM教程与学习资料汇总:http://bbs.51osos.com/thread-8017-1-1.html