EMACS-DOCUMENT

=============>集思广益

在Spacemacs中为Yasnippet添加自定义snippet

Yasnippet能够将少量的输入内容扩展为一个代码模板从而节省时间. YASnippet包含了大量特定mode下的snippets,它能将这些snippet扩展为任何东西,从简单的替换为另一段文本到一段允许你在各参数间遍历的代码块. 在这个视频中可以看到Yasnippet的演示.

要使用某个snippet很简单,只需要输入缩写然后按下 M-/ 就行了. 比如,在html-mode下输入 div 然后按下 M-/ 就会扩展为 <div id="▮" class="▯">▯</div>. 并且光标放在让你输入id值的位置上,你再按一下 TAB 键就又会跳转到输入class值的位置,最后再按一下 TAB 会跳转到输入 div 内容的位置.

你也可以将yasnippet与自动补全功能整合起来,从自动补全菜单中选择想要的snippet.

Spacemacs对于它支持的语言大多内置了大量的snippets. 而且,YASnippets的模板系统也很容易学习. 下面就让我们看看在Spacemacs中如何自定义snippet吧.

一般来说,yasnippets扩展函数的快捷键是TAB,但是该快捷键在Spacemacs被其他功能占用了,因此使用M-/代替该快捷键. 如果你想要的仅仅是纯粹的替换一段文本,你可以试试 Emacs Abbrev mode.

1 Adding your private snippets to Spacemacs

你可以将你自己的snippet定义文件放到 ~/.emacs.d/private/snippets 目录下. 具体来说,你需要在该目录下创建一个与相关mode同名的文件夹(比如markdown-mode). 在这个文件夹中再以缩写为名创建snippet定义文件.

例如,若我要为markdown-mode定义一个缩写为wip的snippet,则我要创建的文件为 ~/.emacs.d/private/snippets/markdown-mode/wip.

要使新snippet生效,你可以重启Spacemacs或者在snippet文件的buffer中运行 M-x yas-load-snippet-buffer. 随后该snippet就会在所有的markdown-mode buffer中生效了.

1.1 Managing your snippets

虽然可以把自定义的snippet放在private snippets目录中,但该目录并没有纳入版本控制. 因此你不用担心自定义的snippet会被Spacemacs所覆盖,但也意味着这些snippets也不会被备份起来.

若你将自定义snippet放在 ~/.spacemacs.d/snippets/modename-mode/ 这样的目录下,则你就可以使用Git或类似的版本控制工具将之管理起来了.

2 How to write a snippet

一般来说,每个snippet模板都存放在各自的文件中,且文件名与缩写一致. 因此一个缩写为 wip 的snippet定义在名为 wip 的文件中, 且该文件存放在以相关Emacs mode为名的目录中.

一个snippet模板的基本架构如下:

#key : the name of the snippet you type                                     
#name : A description of the snippet (this shows in autocompletion menu too)
#contributor: John Stevenson <john@jr0cket.co.uk>                           
# --                                                                        
Add the content you want to replace the snippet name with when it expands   

其中的内容可以是简单的一段文本,也可以是一段包含占位符的代码结构,扩展后每次按下tab就会把光标跳转到下一个占位符的位置. 你甚至还可以在模板中使用Elisp代码.

2.1 Example: Simple text replacement

我经常要用markdown mode来写东西. 当我写markdown时经常要凸出显示还有哪些章节是尚未完成的. 因此我创建了一个名为 wip 的snippet来帮我输入这段常用的信息.

#key : wip                                        
#name : WorkInProgress                            
#contributor: John Stevenson <john@jr0cket.co.uk> 
# --                                              
> **Fixme** work in progress                      

当你用 M-/ 扩展这段snippet时,snippet的名字就会替代为它的内容了.

2.2 Example: Using tab stops

html-mode下有一个名为form的snippet,让我们来看一下这个snippet. 该snippet会扩展为一个html form,同时允许你在method,id,action和content属性之间跳转.

#contributor : Jimmy Wu <frozenthrone88@gmail.com>      
#name :<form method="..." id="..." action="..."></form> 
# --                                                    
<form method="$1" id="$2" action="$3">                  
  $0                                                    
</form>                                                 

这个snippet与上面那个简单的例子类似,不同之处在于它用$符和数字设置了占位符. 当扩展上面那个snippet时,snippet的名字也会被它的内容所替代,但不仅如此,光标也会放置在第一个定位符$1处. 每次你按下TAB键就会把光标移动到下一个定位符处.

$0表示snippet的退出点,在这个地方按下TAB键的作用与在YASnippet外的作用一致.

3 Creating a snippet from existing text

创建新snippet的最快的方法莫过于直接利用snippet扩展后的内容了.

若只是为了简单的文本替换,则你只需要选中扩展后的文本,然后调用 helm-yas-create-snippet-on-region, 保存自动生成的snippet为缩写名称就行了.

若需要创建带定位符的代码结构,则需要选中扩展后的代码结构,调用 helm-yas-create-snippet-on-region, 然后编辑snippet,用$1,$2,$3,$4之类的定位符替代里面的内容就好.

3.1 Example: Create a simple text replacement

当我写博客时,我会用一个图片缩略图来指示文章的顶部. 我不想每次都手工录入这一段,因此我创建了一个snippet.

首先我选中新snippet要扩展成的内容,在本例中就是 {% img img-thumbnail /images/spacemacs.png %} .

然后我调用函数 helm-yas-create-snippet-on-region. 它会提示我输入该snippet所属的mode是那个,这里我输入 markdown-mode, 然后会提示输入该snippet文件存放的位置,输入 ~/.emacs/private/snippets/markdown-mode/imgtmb-spacemacs. 然后就会有一个新的buffer创建出来了,且snippet的内容已经填好了.

# -*- mode: snippet -*-                       
#name : imgtmb-spacemacs                      
#key : imgtmb-spacemacs                       
#contributor : jr0cket                        
# --                                          
{% img img-thumbnail /images/spacemacs.png %} 

这个新产生的snippet buffer中的name和key的值自动被设置为该snippet的文件名: imgtmb-spacemacs. snippet的主体内容也自动填充为我选择的文本了. 因此只需要保存这个snippet就行了.

4 Testing your snippets

写好snippet后,可以通过运行 M-x yas-tryout-snippet 来测试一下. 该命令会在合适的major mode下新开一个空白的buffer,你可以在这个buffer中输入缩写,然后按下 M-/ 测试该snippet.

若你想在已有的buffer中试用一下该snippet,需要先用 M-x yas-load-snippet-buffer 加载该snippet并关闭关闭该snippet buffer(必要时会提示保存该buffer).

这些命令在Spacemacs中没有预设快捷键,不过你可以手工为它们设置快捷键. 这种快捷键一般以 C-o 为前缀,例如设置 C-o C-s 来测试snippet, C-o C-s 来加载snippet.

5 Adding yas-snippets to autocompletion in Spacemacs

在Spacemacs中启用autocompletion layer后,就能在自动补全菜单中显示YASnippets的内容了.

不过默认情况下,auto-completion是不会将snippet作为补全项的,你需要设置 auto-completion-enable-snippets-in-popupt.

(setq-default dotspacemacs-configuration-layers
              '((auto-completion :variables
                                 auto-completion-enable-snippets-in-popup t)))

6 Summary

想了解更多YASnippets与autocompletion的话,请查看Github repository for Spacemacs autocompletion layer.

想了解更多如何编写自定义的snipplet,参见下面这些链接: