Post-Candide
After the garden...
Preventing spurious yas-snippet expanding
Taming yasnippet-snippets with yas-buffer-local-condition
#
If you use yasnippet-snippets alongside corfu, you may have run into this: you type a prefix like hi-l (heading for hi-lock-mode), press TAB expecting a completion popup, and instead get a let snippet expanded in your buffer.
Why it happens #
yasnippet-snippets ships hundreds of snippets with short, common keys. The problem is that word-separator characters like - break Emacs’s word boundaries, so the l after hi- is seen as a fresh word. Yasnippet happily matches it against its l or let key and expands before corfu gets a chance.
The naive fix is to add a # condition: guard directly in the offending snippet file — something like:
# condition: (not (member (char-before (- (point) 1)) '(?- ?_ ?/)))
This works for one snippet, but yasnippet-snippets has many short keys and you don’t want to patch them individually (nor maintain that across updates).
A better solution: yas-buffer-local-condition
#
Yasnippet provides yas-buffer-local-condition, a Lisp form evaluated before every expansion. If it returns nil, the snippet is suppressed. Setting its default value globally is the clean solution:
(setq-default yas-buffer-local-condition
'(let* ((key (and yas--current-template
(yas--template-key yas--current-template)))
(char-before-key (and key (char-before (- (point) (length key))))))
(or (null char-before-key)
(not (memq (char-syntax char-before-key) '(?w ?_))))))
Basically, look at the character immediately before the matched snippet key. If it has word (?w) or symbol (?_) syntax, suppress the expansion. This covers -, _, /, :, & and anything else the current mode’s syntax table treats as a word or symbol constituent.
Because it uses the syntax table rather than a fixed set of characters, it adapts to whatever mode you’re in without extra configuration.
I wonder why it’s not a default, I can’t think of a good reason to not prevent this behaviour.
What it doesn’t break #
- Deliberate snippet expansion still works: typing
defunat the start of a line and pressingTABexpands normally, because there’s no word character beforedefun. - Org-mode’s
<src TABstructure templates are unaffected — that’s org-tempo, a completely separate mechanism. consult-yasnippetfor explicit snippet selection is of course unaffected.
Comments