Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emacs Yasnippet for Different Coding Styles

Just recently started using yasnippet for emacs and really like the way it works, however I've run into a minor nuisance I'd like some help to solve if possible.

One snippet I like in particular is the "for"-snippet, i.e.:

# -*- mode: snippet -*-
# name: for
# key: for
# --
for (${1:i = 0}; ${2:i < N}; ${3:i++}) {
    $0
}

However I recently started working on a project where we have a different coding style. Simply put the snippet above would be changed to place the starting brace position to:

# -*- mode: snippet -*-
# name: for
# key: for
# --
for (${1:i = 0}; ${2:i < N}; ${3:i++})
{
    $0
}

I would however like to easily switch between different projects and consequently between different coding styles without having to manually change the snippets or create many duplicates. So I figured it should be possible to write some elisp code in the snippet to automatically adapt to the currently active coding style.

Looking around at some of the Emacs/elisp documentation, I found the so called c-hanging-brace-alist (GNU doc) which I feel I should be able to use somehow. However I have never really done any programming in elisp, and I'm not really sure how to accomplish this. Any help or advice would be appreciated!

like image 891
Xaldew Avatar asked Oct 31 '22 16:10

Xaldew


2 Answers

Here is a suggestion:

  1. Define a variable to hold the current coding style:

    (setq current-coding-style 'default)
    
  2. Define a command to toggle between the default style and the style used in your new project, and bind it to a key sequence of your choosing:

    (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
    
  3. Define a function that places the opening brace according to the coding style that is currently "active":

    (defun place-brace ()
      (if (eq current-coding-style 'default) " {" "\n{"))
    
  4. Replace the opening brace in the for snippet with a call to this function (as explained here, arbitrary Elisp code can be embedded into snippets by enclosing it in backquotes):

    # -*- mode: snippet -*-
    # name: for
    # key: for
    # --
    for (${1:i = 0}; ${2:i < N}; ${3:i++})`(place-brace)`
        $0
    }
    

With this in place all you need to do to switch between coding styles (and corresponding snippet expansions) is press C-c t.

like image 152
itsjeyd Avatar answered Nov 09 '22 02:11

itsjeyd


I also wonder how to do this in a less intrusive and more general way recently, luckily I find an issue on yasnippet project regarding this: Convert snippets to your brace style · Issue #728 · joaotavora/yasnippet - github.com

In brief the maintainer recommended using yas-after-exit-snippet-hook to achieve it, here is what I come up following it:

;; 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)))))

Hope this may help.

like image 41
whatacold Avatar answered Nov 09 '22 03:11

whatacold