Emacs 22中(interactive "^")的向后兼容性问题

3
在 Emacs 23 和 24 中,以下内容可以正常工作:
(defun foo (&optional arg)
  (interactive "^p")
  (message "arg is %i" arg))

在Emacs 22中,我遇到了以下错误:

交互调用字符串中的无效控制字母“^”(136)

我尝试了下面这个方法:
(defun foo (&optional arg)
  (interactive (concat (if (> emacs-major-version 22) "^" "") "p"))
  (message "arg is %i" arg))

但我得到了以下错误信息:

Wrong type argument: listp, "^p"

在Emacs 23或24中使用^的最佳方法是什么,但在Emacs 22中不能使用?

2个回答

3

我认为你需要做类似于以下的操作:

(interactive
  (progn
    (when (fboundp 'handle-shift-selection)
      (handle-shift-selection))
    (list (prefix-numeric-value current-prefix-arg))))

如果传递给interactive的参数不是字符串类型,则它应该被解析为一个列表(记住,interactive不是一个函数,它是一个特殊形式)。

2
实际上,最好使用(fboundp 'handle-shift-selection)而不是(> emacs-major-version 22) - Stefan
2
有没有办法避免重新实现(interactive)的功能?我不想去弄清楚如何重新实现(interactive "^NEnter a number: ")。看一下调用交互式函数的Emacs源码,我猜它没有提供这样的功能。 - Richard Hansen
@Stefan:如果Emacs有读取时条件语句,那就更容易了:#+handle-shift-selection "^p" #-handle-shift-selection "p" - sds

2

您可以定义一个宏,此宏会扩展为一个defun函数,其中interactive表单如果支持Shift选择,则以^开头。例如:

(defmacro my-defun (name args doc inter &rest body)
  "Like `defun' but enables shift selection, if supported.

Note that the documentation string and the `interactive' form
must be present. Requires a string literal as argument to
`interactive'.

See `this-command-keys-shift-translated' for the meaning of shift
translation.

This is implemented by adding the `^' token to the `interactive'
string, when shift selection is supported."
  `(defun ,name ,args
     ,doc
     ,(progn
        (assert (stringp doc))
        (assert (listp inter))
        (assert (eq (length inter) 2))
        (assert (eq (car inter) 'interactive))
        (let ((s (nth 1 inter)))
          (assert (stringp s))
          (if (fboundp 'handle-shift-selection)
              (setq s (concat "^" s)))
          (list 'interactive s)))
     ,@body))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接