Xaldew
Xaldew

Reputation: 658

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!

Upvotes: 5

Views: 829

Answers (2)

whatacold
whatacold

Reputation: 680

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.

Upvotes: 1

itsjeyd
itsjeyd

Reputation: 5280

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.

Upvotes: 3

Related Questions