由于最近有很多麻烦的事困扰着我,一直没有把一些心得体会或者是学到的技巧写出来,这是一个很大的遗憾。今天心情尚好,索性就写一下了。因为前面学习了一点HTML(如果你非常理解成那个邪恶的全称我也没有办法)的基本知识,顺便也用这篇文章练手了。哈哈!
是的,你没有看错,这篇文章的题目有一点点小的幽默在里面,如果你知道Yasnippet全称的话。哈哈。geek就应该有geek的幽默风格。:-)
之前有一些时间让我去研究一些有意思的东西,这当然是最好的事情了。所以就把研究的一个小的成果和心得写在这些,供大家学习借鉴,恰笑于大方之家了。
当然,如果你还不知道Yasnippet是什么的话,那你可能要先去做一些功课了。不过这里到是有一篇不错的文章介绍Yasnippet,你可以先去看看。其实本文可以看作是对这这篇文章的一个补充。所以你还是先去看看吧。当然如果你还不知道什么是Emacs的话,那我建议你还是去GNU官方看看消息,当然Google也行,那里有你所需要的东西。其实上面那个链接里面讲得非常不错,只是对于我等新手还是不够细致。所以我就来补充一下。重点放在编写简单的模板,并提供一些技巧心得。
上面的链接讲了如何创建一个模板,但是没有具体讲一些语法细节。好吧,先让我们慢慢来。Yasnippet会根据Emacs当前处在何种模式来确定把当前的模板放在哪里。以笔者常用到的c-mode为例。如果你执行过M-x yas/new-snippet之后在你的插件加载目录(你可以粗糙的认为就是你放yasnippet-bundle.el那个目录)下面没有对应的c-mode目录,它就 会自动创建,并提示你是否在创建该目录。其它的目录也应该可以,反正我没试过,你试完可以告诉我。对应的在其它模式下也会有相应的目录比如text-mode,或者cperl-mode吧。
讲讲具体的语法了。其实Yasnippet的语法比较简单,而我也没有专门去看相关的内容。我只是找了几段代码看了看,试了试就明白了。由此可知,你也应该可以用同样的时间掌握,不过我写了这个之后,你就可以以更快的时间写出一些简单的模板了。有关Yasnippet的讲法最好的讲解就是直接去看yasnippet-bundle.el文件了,不过那个太复杂了,我们放到后面讲。我们先从最直观的讲。利用gedit的插件来看看最基本的模板应该怎么写。不过你首先应该在Edit-Prenference-plugins里面选中Snippets插件。然后在Tools-Manage Snippets中你可以看到
for (${1:i} = ${2:0}; ${1:i} < ${3:count}; ${1:i} += ${4:1}) { $0 }
如果这个时候你能先在gedit里面用一下这个for的模板你会发现其实这个语句比较简单。${}和脚本语言里面的引用变量方式类似,所以${1:i}的意思就是定义光标第一次出现的位置,并指定该位置的默认值为i.后面都类似。如果要在其它位置引用它的值,直接$1即可。那我们就发现了一个重要的原则$后面跟着数字代表光标第几次出现的位置。要特别强调一点的就是$0是光标最后出现的位置。也就是说你用Tab键(也可能是你自己定义的其它按键反正能用Yasnippet就是了)跳转光标的最后一个位置是$0出现的位置。当然你可不要小看它,因为这种光标的控 制还要具有一定的逻辑性。
好的在我们直观的了解了snippet如何运作的时候我们就可以写出Yasnippet的模板了(这两种模板的写法类似,但是有些时候的解释并不相同)。下面是一个Yasnippet的for模板写法,至少是符合笔者风格的写法。
for (${1:i} = ${2:0}; $1 < ${3:count}; $1++) { $0 }
其实在Yasnippet原生的模板中是有for模板的在yasnippet-bundle.el中可以找到相关定义,本来的定义被我改了。下面是我改过的
("for" "for (${1:i} = ${2:0}; $1 < ${3:count}; $1++) {\n $0\n}\n" "for (...; ...; ...) { ... }" nil nil nil nil nil)
可以发现的是这种写法里面必须使用\n这类符号实现控制。
因此到这里我们介绍了两种添加模板的方式。一种是通过yas/new-snippet命令添加当前模式下的模板,不足之处就是只能在当前模式下使用。比如你要想在text-mode下面使用c-mode下面定义的for模板是不行的(不太明白的话可以去看一下上面那个链接的内容)。另一种是通过直接在yasnippet-bundle.el添加我们需要的模板语句。不过这种方式有些麻烦,而且不太直观。不这看你个人喜好了。如果你愿意以这两种方式添加同一个模板的不同形式也是可以的,就看你使用的yasnippet先解释哪个模板。反正只会有一种结果,不存在二义性问题。
下面展示笔者自己常用的几个模板(自带的模板请直接看插件源文件相关部分).
# -*- mode: snippet -*- # name: union # key: union # -- union ${1:name} { $0 }; # -*- mode: snippet -*- # name: typedef # key: typedef # -- typedef ${1:newtype} ${2:type} $0 # -*- mode: snippet -*- # name: else_if # key: else if # -- else if (${1:condition}) { $2 } $0
自己去试试吧,希望能够给大家以启迪。哈哈。