Buttons in emacs are a little bit of a black box.

This makes it difficult wish to extend or modify a mode that uses buttons: yasnippet, for example.

Here is how to find out what the button does before you click on it.

Get the function

This is all you need for most cases.

(defun get-button-action ()
  "Get the action of the button at point"
  (interactive)
  (let ((b (button-at (point))))
    (if b (button-get b 'action))))

Special case: help-mode and yasnippet

Applying (get-button-action) in yasnippet very unhelpfully provides this help-button-action.

help-button-action, as it turns out, is from help-mode.

help-mode has uses one level of indirection when creating buttons and makes use of an additional property (help-function) to store the actual behaviour of the button.

Other modes that create buttons may act like this too and you’d then need to create more cases.

(defun copy-button-action ()
  (interactive)
  ;; sym2str wont work here because it might be a closure/sexp instead of a function/symbol
  ;; therefore, I must use str
  (let ((f (get-button-action)))
    (if (eq f 'help-button-action)
        (setq f `(progn (apply ,(button-get (button-at (point)) 'help-function)
                               (button-get (button-at (point)) 'help-args))
                        nil)))
    (my/copy (str f))))

Frustratingly, the value of help-args (above) in yasnippet is a very large sexp indeed and therefore it’s not practical to evaluate it before copying.

But now, running copy-button-action above a button when browsing snippets will result in the following command being copied to the clipboard.

(progn
  (apply
   (lambda (template) (yas--visit-snippet-file-1 template))
   (button-get (button-at (point)) (quote help-args)))
  nil)

Useful!