2
votes

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?

3
What you did is right: write your own command, by adding an interactive spec. What kind of interactive spec you use depends on the interactive behavior you want. (@Stefan's answer mentions using Shift selection, for example.) It it's for more than your own individual use, or if for some other reason you need to be able to use the original function interactively, then consider advising the function (as Stefan also indicated). - Drew

3 Answers

2
votes

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))))
2
votes

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.

0
votes

Following @Stefan's suggestion, I filed a Github issue and submitted a patch, which adds the line (interactive "P") in the source code:

(defun markdown-back-to-heading (&optional invisible-ok)
  "Move to previous heading line, or beg of this line if it's a heading.
Only visible heading lines are considered, unless INVISIBLE-OK is non-nil."
  (interactive "P")
  (markdown-move-heading-common #'outline-back-to-heading invisible-ok))

and now I can keybind it with

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

I had installed markdown-mode from MELPA, so this change required uninstalling the package, then these steps from the repo README. I forked the repo and cloned the repo locally:

git clone [email protected]:miguelmorin/markdown-mode

and added these lines to Emacs initialization:

(add-to-list 'load-path (expand-file-name "~/code/markdown-mode"))

(autoload 'markdown-mode "markdown-mode"
   "Major mode for editing Markdown files" t)
(add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))

(autoload 'gfm-mode "markdown-mode"
   "Major mode for editing GitHub Flavored Markdown files" t)
(add-to-list 'auto-mode-alist '("README\\.md\\'" . gfm-mode))

(require 'markdown-mode)