半模式编辑/自动前缀键

时间:2009-02-17 03:46:48

标签: emacs

大多数emacs模式都包含某种激活其功能的前缀。例如,当使用 GUD 时,“next”是“C-c C-n”。在这些模式中,许多模式提供了特殊的缓冲区,其中一个可以使用单个键来激活某些功能(例如,只需“n”或“p”来读取 GNUS 中的下一个/上一个邮件)。

然而,并非所有模式都提供这样的缓冲区,并且重复输入前缀可能很烦人。是否有一个众所周知的elisp位允许在一段时间内对所有输入进行特殊的前缀键规范? (例如,在点击ESC或其他一些受制裁的密钥之前)

4 个答案:

答案 0 :(得分:15)

我同意Joe Casadonte的回答,即走法是定义自己的次要(或主要)模式。

话虽如此,你的问题很有意思。

这是一个解决方案,提示您输入一个键序列,并采用前缀击键并将该键盘映射提升到顶层。

e.g。假设以下键映射:

M-g ESC         Prefix Command
M-g g           goto-line
M-g n           next-error
M-g p           previous-error

当您运行M-x semi-modal-minor-mode时,它会提示您进行一些击键。如果输入M-g n,则会设置以下键绑定:

ESC         Prefix Command   (same as M-g ESC)
g           goto-line
n           next-error
p           previous-error

所以现在n不会自动插入,而是跳转到下一个错误。请参阅下面的代码。

注意:启用此次要模式时,<f12>绑定到禁用次要模式的命令。这是因为键绑定可能会很好地禁用您的Emacs(例如,如果M-x有新的键绑定,该怎么办)。

编辑添加这些想法:小模式变量最初是缓冲本地的,但除非你制作次模式 - alist变量,否则这不起作用缓冲本地(duh)。但是,你也(可能)不想在迷你缓冲区中使用这些绑定...所以,我不打算测试它b / c它真的取决于你想要什么,但我已经添加了对代码的评论反映这种想法。

没有进一步的麻烦:

(defvar semi-modal-minor-mode-keymap (make-sparse-keymap)
  "keymap holding the prefix key's keymapping, not really used")
(defvar semi-modal-minor-mode-disable-key (kbd "<f12>")
  "key to disable the minor mode")
(defun semi-modal-minor-mode-disable ()
  "disable the minor mode"
  (interactive)
  (semi-modal-minor-mode 0))

(define-minor-mode semi-modal-minor-mode
  "local minor mode that prompts for a prefix key and promotes that keymap to the toplevel
e.g. If there are bindings like the following:

M-g ESC         Prefix Command
M-g g           goto-line
M-g n           next-error
M-g p           previous-error

And you enter 'M-g n' when prompted,
then the minor mode keymap has the bindings
  g   ->   goto-line
  n   ->   next-error
  p   ->   previous-error
  ESC ->   Prefix Command (same as M-g ESC)

The variable semi-modal-minor-mode-disable-key is bound to disable the minor mode map.
This is provided because often the mappings make the keyboard unusable.
Use at your own risk."
  nil " Semi" semi-modal-minor-mode-keymap
  (make-local-variable 'semi-modal-minor-mode)
  (make-local-variable 'minor-mode-map-alist)
  (let ((pair-holding-keymap-to-modify (assq 'semi-modal-minor-mode minor-mode-map-alist)))
    (setcdr pair-holding-keymap-to-modify (make-sparse-keymap))
    (if semi-modal-minor-mode
        (let (key
              keymap)
          ;; all but last (b/c we want a prefix
          (setq key (substring (read-key-sequence "Enter a full key combination, the prefix will be used: ") 0 -1))
          (if (and (not (equal "" key))
                   (not (equal (kbd "C-g") key))
                   (let ((semi-modal-minor-mode nil))
                     (keymapp (setq keymap (key-binding key)))))
              (progn
                (setcdr pair-holding-keymap-to-modify (copy-keymap keymap))
                (when semi-modal-minor-mode-disable-key
                  (define-key (cdr pair-holding-keymap-to-modify)
                    semi-modal-minor-mode-disable-key 'semi-modal-minor-mode-disable)))
            (semi-modal-minor-mode 0))))))

答案 1 :(得分:1)

Emacs中键绑定的模式特定(模态?)部分是通过覆盖通用全局映射的各种本地映射来实现的。大多数主要和次要模式都定义了自己的本地地图;例如,有一个gud-mode-map。仅当当前缓冲区处于相应模式时,才会激活本地键映射中的键绑定。您可以通过模式的挂钩自定义特定于模式的键映射。例如,您可以将此代码段放入〜/ .emacs

    (add-hook 'gud-mode-hook
      (lambda () 
        (local-set-key (kbd "C-n") 
                       (lookup-key (current-local-map) (kbd "C-c C-n")))))

有关键盘图的更多详细信息,请参阅Elisp reference manual

答案 2 :(得分:1)

这里的基本问题是本身没有当前的键盘映射。有一个全局键映射被主模式的键映射覆盖,而键映射又被一个或多个次模式键映射覆盖(并且它们可以以某种定义的方式相互踩,我敢肯定)。定义新的主模式仍然会使次模式键起作用,定义新的次模式只会影响您在次模式键映射中定义的任何键。

例如,只要次要模式处于活动状态,您就可以定义一个可以执行所需操作的次要模式。您定义了一个新的次要模式my-gud-mode,它将拥有自己的键盘映射。然后你必须为它定义所有的键映射(例如n,p等),你还必须定义你不想工作以绑定到函数{{1}的所有键。 }。这是真正的痛苦,重新映射所有其他键。不过,次要模式很容易打开和关闭;这是优势。

乍一看定义一个新的主要模式会更容易,因为它可以让你在一次拍摄中覆盖更多的“当前键盘图”。它应该注意缓冲区局部变量中的当前主要模式,以便稍后在临时主模式关闭时可以恢复它。但是你仍然会有其他次要模式侵入你的键盘映射,所以它不会是“纯粹的”。

在这种情况下我做的是定义一个更简单的前缀!对于我每天都在使用的东西,我每天都给他们一个功能键(例如我将F1作为我的jabber-mode键)。对于不那么直接有用的东西,我还有另外两个功能键,F3和F12(我确定我很久以前就选择了它们,但我不再记得原因)。 F3定义了始终可用的键,无论主要模式如何。 F12定义了与主模式相关的键。一些例子:

我已将F3-m-设置为切换主要模式的前缀(例如F3-mp切换到cperl模式)和F3-M-作为次模式的前缀(例如F3-Mv切换视图模式) 。这些都是可用的,因此您可以执行类似绑定F3-g-的操作作为您的gud前缀,并为之前的类型输入F3-g-p等等。

我的F12键与模式有关。因此,在直接模式下,F12-e将在当前文件上调用ignore,在emacs-lisp模式下,F12-e将调用dired-nt-open-in-excel。不知怎的,我从来没有让他们感到困惑。

如果您需要帮助来定义这样的键盘映射,请告诉我。

答案 3 :(得分:0)

Viper模式允许您在可视模式下使用“esc”键输入命令到键或键序列。返回插入模式“i”。
请查看viper-in-more-modes.el其使用viper-modify-major-mode 我还想使用viper-vi-global-user-map:来自我的.emacs文件的snippet