【问题标题】:in Emacs, what's the best way for keyboard-escape-quit not destroy other windows?在 Emacs 中,keyboard-escape-quit 不破坏其他窗口的最佳方法是什么?
【发布时间】:2009-02-17 15:15:03
【问题描述】:

编辑: 我知道有键盘退出(通常绑定到 C-g);但我更想知道如何处理 Emacs 附带的编辑功能(如本例中)。当我想改变一些内置函数时,我有时会遇到这种情况。

在 emacs 中,当你按 M-ESC ESC(或 ESC 三次)时,你可以摆脱很多情况,如瞬态标记等。但我习惯性地按了转义键(我实际上将它重新映射为一次按一下转义键)超出了我的预期,这最终会杀死我的 Windows 配置,这很烦人。函数keyboard-escape-quit在simple.el中定义:

(defun keyboard-escape-quit ()
  "Exit the current \"mode\" (in a generalized sense of the word).
This command can exit an interactive command such as `query-replace',
can clear out a prefix argument or a region,
can get out of the minibuffer or other recursive edit,
cancel the use of the current buffer (for special-purpose buffers),
or go back to just one window (by deleting all but the selected window)."
  (interactive)
  (cond ((eq last-command 'mode-exited) nil)
    ((> (minibuffer-depth) 0)
     (abort-recursive-edit))
    (current-prefix-arg
     nil)
    ((and transient-mark-mode mark-active)
     (deactivate-mark))
    ((> (recursion-depth) 0)
     (exit-recursive-edit))
    (buffer-quit-function
     (funcall buffer-quit-function))
    ((not (one-window-p t))
     (delete-other-windows))
    ((string-match "^ \\*" (buffer-name (current-buffer)))
     (bury-buffer))))

我可以看到我不想要这些线条:

    ((not (one-window-p t))
     (delete-other-windows))

但是修改此功能的最佳方法是什么?我只能看到两种方法:1)修改 simple.el 2)将此函数复制到我的 .emacs 文件并在那里进行修改。这两种方式都不是真的;理想情况下,我希望在 defadvice 上看到一些东西,但在这种情况下我不知道该怎么做。

【问题讨论】:

    标签: emacs elisp dot-emacs


    【解决方案1】:

    你可以使用 around 建议并重新定义违规函数来做你想做的事情(即 one-window-p 应该总是返回 t):

    (defadvice keyboard-escape-quit (around my-keyboard-escape-quit activate)
      (let (orig-one-window-p)
        (fset 'orig-one-window-p (symbol-function 'one-window-p))
        (fset 'one-window-p (lambda (&optional nomini all-frames) t))
        (unwind-protect
            ad-do-it
          (fset 'one-window-p (symbol-function 'orig-one-window-p)))))
    

    这种行为类似于 (let ...),但必须更复杂,因为您需要覆盖有限范围的函数而不是变量。

    【讨论】:

    • 使用 flet 的更好的单行版本(即 let 的函数版本): (defadvice keyboard-escape-quit (around my-keyboard-escape-quit activate) (flet ((one-window -p (&optional nomini all-frames) t)) ad-do-it))
    • 您可能还需要将flet 更改为cl-flet
    • @polyglot 我知道现在是 2021 年,但您可能知道为什么 Emacs 27.1 在我尝试您的代码时会显示 Warning (bytecomp): ‘(one-window-p (&optional nomini all-frames) t)’ is a malformed function 吗?
    【解决方案2】:

    我通常发现 'keyboard-quit (C-g) 可以摆脱所有这些情况。

    但是,如果您真的想拥有此功能的变体,我认为复制到您的 .emacs 文件(并重命名,我通常使用 bp 的前缀)并在那里进行编辑可能是最好的选择。

    编辑,响应编辑:一般来说,每当我想要一个 emacs 函数的编辑版本时,我要么自己编写,要么将其复制到我的 .emacs 中,将其重命名为 bp-whotever,然后进行适当的编辑。

    这样做的缺点是我的 .emacs 是巨大的,并且可能对不再使用的古老函数非常笨拙......优点是每当我需要编写新的东西时,我都有大量的示例代码看看……

    【讨论】:

      【解决方案3】:

      这是另一个更简单的建议,它利用keyboard-escape-quit 在关闭窗口之前调用buffer-quit-function 的事实:

      (defadvice keyboard-escape-quit
        (around keyboard-escape-quit-dont-close-windows activate)
        (let ((buffer-quit-function (lambda () ())))
          ad-do-it))
      

      适用于 Emacs 25.1。 (我最初使用了@scottfrazer 的建议,但在 25.1 中它不满意。还没有打扰调试。)

      【讨论】:

      • 完美。谢谢
      【解决方案4】:

      默认情况下,按 Escape 键作为 Meta 前缀键;即涉及到 Meta 键的键绑定。

      三次按 Escape 键将运行 keyboard-escape-quit,这与键盘退出类似,但更多的是“按我的意思做”的行为。

      此代码可能对您的用例有所帮助。你可以在你的 Emacs 初始化文件中使用它:

      ;;; esc always quits
      (define-key minibuffer-local-map [escape] 'minibuffer-keyboard-quit)
      (define-key minibuffer-local-ns-map [escape] 'minibuffer-keyboard-quit)
      (define-key minibuffer-local-completion-map [escape] 'minibuffer-keyboard-quit)
      (define-key minibuffer-local-must-match-map [escape] 'minibuffer-keyboard-quit)
      (define-key minibuffer-local-isearch-map [escape] 'minibuffer-keyboard-quit)
      (global-set-key [escape] 'keyboard-quit)
      

      【讨论】:

        【解决方案5】:

        我更想知道如何处理 Emacs 附带的编辑功能(如本例所示)。当我想改变一些内置函数时,我有时会遇到这种情况。

        这正是我创建库el-patch 的目的。你可以把它放在你的初始化文件中:

        (el-patch-defun keyboard-escape-quit ()
          "Exit the current \"mode\" (in a generalized sense of the word).
        This command can exit an interactive command such as `query-replace',
        can clear out a prefix argument or a region,
        can get out of the minibuffer or other recursive edit,
        cancel the use of the current buffer (for special-purpose buffers),
        or go back to just one window (by deleting all but the selected window)."
          (interactive)
          (cond ((eq last-command 'mode-exited) nil)
            ((> (minibuffer-depth) 0)
             (abort-recursive-edit))
            (current-prefix-arg
             nil)
            ((and transient-mark-mode mark-active)
             (deactivate-mark))
            ((> (recursion-depth) 0)
             (exit-recursive-edit))
            (buffer-quit-function
             (funcall buffer-quit-function))
            (el-patch-remove
              ((not (one-window-p t))
               (delete-other-windows)))
            ((string-match "^ \\*" (buffer-name (current-buffer)))
             (bury-buffer))))
        

        【讨论】:

          【解决方案6】:

          这是一种使用 cl-lib 代替现在已弃用的 cl 的新方法:

          ;; Make it so keyboard-escape-quit doesn't delete-other-windows
            (defadvice keyboard-escape-quit
                (around keyboard-escape-quit-dont-delete-other-windows activate)
              (cl-letf (((symbol-function 'delete-other-windows)
                         (lambda () nil)))
                ad-do-it))
          

          您需要确保在此之前您已致电:

          (require 'cl-lib)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-12-20
            • 1970-01-01
            • 2010-09-14
            • 1970-01-01
            • 2021-08-30
            • 2019-02-14
            • 1970-01-01
            相关资源
            最近更新 更多