Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to turn a (non-interactive) function into a command (interactive function) in Emacs-LISP?

I want to call the function markdown-back-to-heading, which is native in Markdown mode in Emacs. I understand that interactive turns non-interactive functions interactive, or formally functions into commands:

Special Form: interactive arg-descriptor

This special form declares that a function is a command, and that it may therefore be called interactively (via M-x or by entering a key sequence bound to it).

I tried:

(define-key markdown-mode-map (kbd "C-c C-h") 'markdown-back-to-heading)

This throws an error: Wrong type argument: commandp, markdown-back-to-heading.

So I wrapped it with an interactive function, and it works:

(defun my-markdown-back-to-heading ()
  "Wrap function to be called interactively."
  (interactive)
  (markdown-back-to-heading))

(define-key markdown-mode-map (kbd "C-c C-h") 'my-markdown-back-to-heading)

Is there a better way to turn the native function into an interactive command?

like image 406
miguelmorin Avatar asked Sep 07 '25 10:09

miguelmorin


2 Answers

You can alternatively use the interactive-form symbol property.

For details see C-hig (elisp)Using Interactive

Here's a simple example:

;; Enable M-x kill-process (to kill the current buffer's process).
;; (This is not normally a command, but it is useful as one.)
(put 'kill-process 'interactive-form '(interactive))

The more complex version that I actually use is:

(put 'kill-process 'interactive-form
     '(interactive
       (let ((proc (get-buffer-process (current-buffer))))
         (if (process-live-p proc)
             (unless (yes-or-no-p (format "Kill %S? " proc))
               (error "Process not killed"))
           (error (format "Buffer %s has no process" (buffer-name))))
         (list proc))))
like image 77
phils Avatar answered Sep 10 '25 08:09

phils


If want to make markdown-back-to-heading interactive, you have a few different good options:

  • file a bug report to get upstream to make it so. Including a patch along with the bug-report can help speed up the process.
  • use an advice such as:

    (advice-add 'markdown-back-to-heading :before
                (lambda () (interactive "^") nil))
    

If instead you want to improve the interactivity of a function, e.g. if you want to support shift-selection, you can add the interactive code ^ with (interactive "^") instead of (interactive) so that Emacs knows this is a navigation command (and hence if you use it with a shifted-binding it will select the corresponding text). Here is a manual page with the list of interactive codes, and other options for interactivity at the manual page you mentioned.

like image 43
Stefan Avatar answered Sep 10 '25 06:09

Stefan