How can I trigger an event when a Yasnippet macro can fire?
Asked Answered
S

1

12

I love yasnippet, but it requires time to memorize. What I'd like to do is change the cursor color when I am at a point that can expand a macro (and back again when there is no macro). However, from what I remember about how yasnippet works, that might not exactly be performant.

A friend suggested that what I want here is a yasnippet-can-fire-p, but I'm still not sure as to the best way to go about doing this. What's the cleanest path towards implementing this that won't drive my sistem to a grinding halt?

Sailing answered 10/1, 2013 at 17:56 Comment(2)
The solution below looks good enough, but I think the best course of action would be to use yasnippet integrated with one of the completion packages, like auto-complete or company-mode. They show completions when Emacs is idle, and in addition to indication that expansion is possible, they will also show what it will expand to. In fact, auto-complete already has a source for yasnippet. I haven't tried it, though.Marxmarxian
It is possible to use Yasnippet and never have to memorize anything. Clear name: attributes are very helpful for yasnippet search autocompletion.Sugar
L
14

Took some time to find the function that did the checking whether or not it can expand, but was 'lucky' enough to find it eventually.

The key is that this function would normally expand, or otherwise, perform the fallback behavior. I cloned this function and set the cursor colors in those places instead.

And, surprisingly, it actually does not slow down at all.

;; It will test whether it can expand, if yes, cursor color -> green.
(defun yasnippet-can-fire-p (&optional field)
  (interactive)
  (setq yas--condition-cache-timestamp (current-time))
  (let (templates-and-pos)
    (unless (and yas-expand-only-for-last-commands
                 (not (member last-command yas-expand-only-for-last-commands)))
      (setq templates-and-pos (if field
                                  (save-restriction
                                    (narrow-to-region (yas--field-start field)
                                                      (yas--field-end field))
                                    (yas--current-key))
                                (yas--current-key))))

  (set-cursor-color (if (and templates-and-pos (first templates-and-pos)) 
                        "green" "red"))))

; As pointed out by Dmitri, this will make sure it will update color when needed.
(add-hook 'post-command-hook 'yasnippet-can-fire-p)

Added this to my lisp collection (I was actually thinking that this would be useful as well).


Update: In latest version of yasnippet [from august 2014, from 0.8.1], yas--current-key function has been renamed into yas--templates-for-key-at-point. cf Issue

Lackey answered 10/1, 2013 at 18:56 Comment(9)
Using post-self-insert-hook or even post-command-hook instead of advice would be nicer here. You can make them local to certain buffers and, if you use the latter, trigger the cursor change after commands other than self-insert-command.Marxmarxian
You can simplify the last 4 lines as follows (set-cursor-color (if (and templates-and-pos (first templates-and-pos)) "green" "red"))))Cantatrice
@Cantatrice Thanks, incorporated your advice!Lackey
@Dualinity: you can also move the unless into the let-binding, dropping the setq: (let ((templates-and-pos (unless (foo) (if field ...)))) (set-cursor-color ...)).Cantatrice
Wow, thanks for doing all the hard work! With what you have, I refactored it a bit to be more customizable for people who may want to do something slightly different. I can't include the reply here, but here is a gist: gist.github.com/4506396Sailing
gist.github.com/4506396 Here's my slight refactor. The main thing it to make yasnippet-can-fire-p is its own boolean function, so you can use it to trigger other events if you'd like.Sailing
I actually am considering to "if possible expand, then expand". It is quite interesting but it doesn't work when you have shorthand writing like r for require (imagine that on any written r it will expand). I am considering to rewrite snippets to a bit longer version (so when you write them, they are unique and you're sure it will trigger correctly!)Lackey
It seems that yas--current-key no longer exist in latest yasnippet: Error in post-command-hook (yasnippet-can-fire-p): (void-function yas--current-key)Tunicate
@PascalvKooten you're welcome. :) (It might be a good idea to push this to yasnippets itself, but that wasn't my call)Tunicate

© 2022 - 2024 — McMap. All rights reserved.