不同编码风格的Emacs Yasnippet

不同编码风格的Emacs Yasnippet,emacs,elisp,yasnippet,Emacs,Elisp,Yasnippet,最近刚开始在emacs上使用yasnippet,并且非常喜欢它的工作方式,但是我遇到了一个小麻烦,如果可能的话,我希望得到一些帮助来解决 我特别喜欢的一个片段是“for”-片段,即: # -*- mode: snippet -*- # name: for # key: for # -- for (${1:i = 0}; ${2:i < N}; ${3:i++}) { $0 } #-*-模式:代码段-*- #姓名:for #关键字:用于 # -- 对于(${1:i=0};${2:i

最近刚开始在emacs上使用yasnippet,并且非常喜欢它的工作方式,但是我遇到了一个小麻烦,如果可能的话,我希望得到一些帮助来解决

我特别喜欢的一个片段是“for”-片段,即:

# -*- mode: snippet -*-
# name: for
# key: for
# --
for (${1:i = 0}; ${2:i < N}; ${3:i++}) {
    $0
}
#-*-模式:代码段-*-
#姓名:for
#关键字:用于
# --
对于(${1:i=0};${2:i
然而,我最近开始从事一个项目,我们有一个不同的编码风格。简单地说,上面的代码段将被更改为将起始大括号位置放置为:

# -*- mode: snippet -*-
# name: for
# key: for
# --
for (${1:i = 0}; ${2:i < N}; ${3:i++})
{
    $0
}
#-*-模式:代码段-*-
#姓名:for
#关键字:用于
# --
对于(${1:i=0};${2:i
然而,我希望能够轻松地在不同的项目之间切换,从而在不同的编码风格之间切换,而无需手动更改代码片段或创建许多重复项。因此,我认为应该可以在代码段中编写一些elisp代码,以自动适应当前活动的编码样式

查看一些Emacs/elisp文档,我发现了所谓的c-hangg-brace-alist(),我觉得我应该能够以某种方式使用它。然而,我从来没有在elisp中真正完成过任何编程,我也不确定如何实现这一点。任何帮助或建议都将不胜感激

这里有一个建议:

  • 定义用于保存当前编码样式的变量:

    (setq current-coding-style 'default)
    
  • 定义一个命令以在默认样式和新项目中使用的样式之间切换,并将其绑定到您选择的键序列:

    (defun toggle-coding-style ()
      (interactive)
      (if (eq current-coding-style 'default)
          (setq current-coding-style 'special)
        (setq current-coding-style 'default)))
    
    (global-set-key (kbd "C-c t") 'toggle-coding-style) ;; Replace C-c t 
                                                        ;; with another binding
                                                        ;; if you like
    
  • 定义根据当前“活动”的编码样式放置开口支撑的函数:

  • 用对该函数的调用替换代码段的
    中的大括号(如前所述,任意Elisp代码可以通过将其括在反引号中嵌入到代码段中):

    #-*-模式:代码段-*-
    #姓名:for
    #关键字:用于
    # --
    对于(${1:i=0};${2:i

  • 有了这个功能,在编码样式(以及相应的代码段扩展)之间切换所需做的就是按C-C t键。

    最近我还想知道如何以一种不那么麻烦、更通用的方式来实现这一点, 幸运的是,我在yasnippet项目中发现了与此相关的问题:

    简言之,维护人员建议在退出代码段挂钩后使用
    yas来实现它,
    下面是我接下来想到的:

    ;; https://en.wikipedia.org/wiki/Indentation_style
    ;; auto/allman/k&r
    (setq my-yasnippet-brace-style 'auto)
    
    ;; see https://github.com/joaotavora/yasnippet/issues/728
    (setq yas-after-exit-snippet-hook
          #'(lambda ()
              (let* ((begin yas-snippet-beg)
                     (end yas-snippet-end)
                     (snippet (buffer-substring-no-properties begin end))
                     (point (point))
                     rep
                     new-snippet)
                (unless (eq 'auto my-yasnippet-brace-style)
                  (setq rep (case my-yasnippet-brace-style
                              ('allman ")\n{")
                              (('k&r t) ") {")))
                  (setq new-snippet (replace-regexp-in-string ")[ \t\r\n]*{" rep snippet))
                  (delete-region begin end)
                  (insert new-snippet)
                  ;; XXX what's the proper way to retain point? save-excursion doesn't work.
                  (goto-char (+ point (- (length new-snippet) (length snippet))))
                  (indent-region begin end)))))
    

    希望这能有所帮助。

    这是一个很好的解决方案,但也有一些可能的改进:使用elisp cond而不是if来支持更多样式。不过,在接受答案之前,我会再等一段时间,看看是否还有其他建议。@xaldow只是想让你知道,你总是可以。。。
    # -*- mode: snippet -*-
    # name: for
    # key: for
    # --
    for (${1:i = 0}; ${2:i < N}; ${3:i++})`(place-brace)`
        $0
    }
    
    ;; https://en.wikipedia.org/wiki/Indentation_style
    ;; auto/allman/k&r
    (setq my-yasnippet-brace-style 'auto)
    
    ;; see https://github.com/joaotavora/yasnippet/issues/728
    (setq yas-after-exit-snippet-hook
          #'(lambda ()
              (let* ((begin yas-snippet-beg)
                     (end yas-snippet-end)
                     (snippet (buffer-substring-no-properties begin end))
                     (point (point))
                     rep
                     new-snippet)
                (unless (eq 'auto my-yasnippet-brace-style)
                  (setq rep (case my-yasnippet-brace-style
                              ('allman ")\n{")
                              (('k&r t) ") {")))
                  (setq new-snippet (replace-regexp-in-string ")[ \t\r\n]*{" rep snippet))
                  (delete-region begin end)
                  (insert new-snippet)
                  ;; XXX what's the proper way to retain point? save-excursion doesn't work.
                  (goto-char (+ point (- (length new-snippet) (length snippet))))
                  (indent-region begin end)))))