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!
Here is a suggestion:
Define a variable to hold the current coding style:
(setq current-coding-style 'default)
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
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{"))
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With