如何在 Emacs-LISP 中将一个(非交互)函数变成一个命令(交互函数)?
How to turn a (non-interactive) function into a command (interactive function) in Emacs-LISP?
我想调用函数 markdown-back-to-heading
,它在 Emacs 的 Markdown 模式下是原生的。我知道 interactive
将非交互函数变成交互函数,或者正式地 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).
我试过了:
(define-key markdown-mode-map (kbd "C-c C-h") 'markdown-back-to-heading)
这会引发错误:Wrong type argument: commandp, markdown-back-to-heading
。
所以我用交互功能包装了它,它起作用了:
(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)
有没有更好的方法将原生函数变成交互式命令?
如果想markdown-back-to-heading
互动,你有几个不同的好选择:
- 提交一个错误报告,让上游做到这一点。在错误报告中包含一个补丁可以帮助加快这个过程。
使用如下建议:
(advice-add 'markdown-back-to-heading :before
(lambda () (interactive "^") nil))
如果您想提高功能的交互性,例如如果你想支持 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.
按照@Stefan 的建议,我filed a Github issue and submitted a patch,在源代码中添加行(interactive "P")
:
(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))
现在我可以用
键绑定它
(define-key markdown-mode-map (kbd "C-c C-h") 'markdown-back-to-heading)
我已经从 MELPA 安装了 markdown-mode
,因此需要进行此更改 uninstalling the package, then these steps from the repo README. I forked the repo 并在本地克隆存储库:
git clone git@github.com:miguelmorin/markdown-mode
并将这些行添加到 Emacs 初始化中:
(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)
您也可以使用 interactive-form
符号 属性。
详情见C-hig (elisp)Using Interactive
这是一个简单的例子:
;; 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))
我实际使用的比较复杂的版本是:
(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))))
我想调用函数 markdown-back-to-heading
,它在 Emacs 的 Markdown 模式下是原生的。我知道 interactive
将非交互函数变成交互函数,或者正式地 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).
我试过了:
(define-key markdown-mode-map (kbd "C-c C-h") 'markdown-back-to-heading)
这会引发错误:Wrong type argument: commandp, markdown-back-to-heading
。
所以我用交互功能包装了它,它起作用了:
(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)
有没有更好的方法将原生函数变成交互式命令?
如果想markdown-back-to-heading
互动,你有几个不同的好选择:
- 提交一个错误报告,让上游做到这一点。在错误报告中包含一个补丁可以帮助加快这个过程。
使用如下建议:
(advice-add 'markdown-back-to-heading :before (lambda () (interactive "^") nil))
如果您想提高功能的交互性,例如如果你想支持 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.
按照@Stefan 的建议,我filed a Github issue and submitted a patch,在源代码中添加行(interactive "P")
:
(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))
现在我可以用
键绑定它(define-key markdown-mode-map (kbd "C-c C-h") 'markdown-back-to-heading)
我已经从 MELPA 安装了 markdown-mode
,因此需要进行此更改 uninstalling the package, then these steps from the repo README. I forked the repo 并在本地克隆存储库:
git clone git@github.com:miguelmorin/markdown-mode
并将这些行添加到 Emacs 初始化中:
(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)
您也可以使用 interactive-form
符号 属性。
详情见C-hig (elisp)Using Interactive
这是一个简单的例子:
;; 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))
我实际使用的比较复杂的版本是:
(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))))