1

I have a workflow that goes like, 1) use a snippet then 2) call a function.

What a glorious opportunity to automate! But how?


The snippet ipdb inserts import ipdb; ipdb.set_trace(). It has definition:

# -*- mode: snippet -*-
# name: ipdb
# key: ipdb
# --
import ipdb; ipdb.set_trace()

The function bm-toggle, from the lovely bm package, sets a visual bookmark on the current line.

The result of using each in sequence is a highlighted line indicating where my debug statement is:

enter image description here

I immediately think of hooks and see that there are indeed a variety of yas hooks. However, these hooks appear to be general; I only want to call a hook on a specific snippet.

  • yas-after-exit-snippet-hook should be sufficient if you can recognize the snippet from its expansion. – Tobias Feb 22 at 16:39
2

You can make snippet-specific bindings with # expand-env:

# -*- mode: snippet -*-
# name: ipdb
# key: ipdb
# expand-env: ((yas-after-exit-snippet-hook #'bm-toggle))
# --
import ipdb; ipdb.set_trace()

See also yasnippet#702.

1

How do I do it? By not being lazy and reading the fine manual!

Solution 1

(add-hook 'yas-after-exit-snippet-hook
          (lambda () (if (buffer-substring yas-snippet-beg yas-snippet-end)
                         (bm-toggle))))

The yas-after-exit-snippet-hook runs in an environment where yas-snippet-beg and yas-snippet-end are defined. These give the beginning and end points (i.e. region) of the inserted snippet.

The function buffer-substring returns the contents of a given region within the current buffer. We can use this with yas-snippet-beg and yas-snippet-end. If the snippet worked, then there will be text in the region. We expect the snippet to either work or fail gracefully, not defining the snippet region or running the hook. Anything non-nil evaluates to t. So, when we insert a snippet, the conditional will trigger and run the toggle.

Since it's unlikely we'd use this functionality anywhere else, there's no point defining an explicit function. The use of lambda creates an anonymous function. This function is added to the hook. When the hook is called, our function is created, called, and destroyed.

Solution 2

Another possibility is to search for the string explicitly.

(add-hook 'yas-after-exit-snippet-hook
          (lambda () (if (string-match-p (regexp-quote "import ipdb; ipdb.set_trace()") (thing-at-point 'line t))
                         (bm-toggle))))

This code checks for the thing-at-point on the current line. A quirk is that (thing-at-point 'line) returns a string with a newline at the end. So, instead of matching against the snippet "character-for-character", we can match it with a regex and accept any line containing the snippet.

  • 1
    You could use (buffer-substring yas-snippet-beg yas-snippet-end) instead of the thing-at-point-thing. (See the doc of yas-after-exit-snippet-hook.) – Tobias Feb 22 at 17:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.