Emacs Dired和Openwith

7
我希望配置emacs,以便在dired模式下打开图像文件时使用外部应用程序。另一方面,我也想在emacs缓冲区中使用内联图像。为了在外部应用程序中打开文件,我使用openwith.elhttp://www.emacswiki.org/emacs/OpenWith。 openwith小模式的问题在于它是全局的,并且当通过dired-mode-hook启用时。
(add-hook 'dired-mode-hook
          (lambda ()
            (setq truncate-lines t)
            (openwith-mode t)
            ))

它可以在任何地方起作用,在Emacs缓冲区中的所有内联图像都会在外部应用程序中打开。
我试图进行更改。
:global t 

:global nil 

openwith.el中,但它会完全禁用openwith模式。
所以,我的问题是:如何告诉emacs仅在dired缓冲区中使用openwith小模式,而不是在任何其他地方使用?
谢谢。
3个回答

4
开启openwith-mode的工作方式有些特殊:它假设你要么全局使用,要么不使用。但是你想在这里仅在dired缓冲区中使用。

这很难实现,但以下是一种方法。

打开openwith-mode的源文件 openwith.el。然后向下滚动到实际次要模式的定义处。然后通过在每行开头添加分号来注释掉该定义:

;;;###autoload
; (define-minor-mode openwith-mode
;   "Automatically open files with external programs."
;   :lighter ""
;   :global t
;   (if openwith-mode
;       (progn
;         ;; register `openwith-file-handler' for all files
;         (put 'openwith-file-handler 'safe-magic t)
;         (put 'openwith-file-handler 'operations '(insert-file-contents))
;         (add-to-list 'file-name-handler-alist '("" . openwith-file-handler)))
;     (setq file-name-handler-alist
;           (delete '("" . openwith-file-handler) file-name-handler-alist))))

在这段代码下方(但在(provide 'openwith)之前),插入以下代码:

(defvar openwith-mode nil)

(mapc (lambda (function) 
        (ad-add-advice function 
                       '(dired-openwith nil t (advice . (lambda () (let ((openwith-mode t)) ad-do-it))))
                       'around 0))
      '(dired-find-alternate-file 
        dired-find-file 
        dired-find-file-other-window
        dired-mouse-find-file-other-window
        dired-view-file))

(put 'openwith-file-handler 'safe-magic t)
(put 'openwith-file-handler 'operations '(insert-file-contents))
(add-to-list 'file-name-handler-alist '("" . openwith-file-handler))

这段代码做了几件事情。

首先,它定义了一个名为openwith-mode的变量。这个变量在openwith-mode的某个函数中被使用,该函数决定是否使用外部应用程序。通常,在定义小模式时,像这样的变量会由Emacs自动提供 -- 但是由于我们刚刚注释掉了实际的minor mode的定义,因此我们在这里明确地重新引入了这个变量。

该变量的目的是作为一种开关,通过它可以控制图像文件是内联还是传递给外部查看器。

接下来是(mapc ...)表达式。我们在这里遍历五个函数的列表:

  • dired-find-alternate-file
  • dired-find-file
  • dired-find-file-other-window
  • dired-mouse-find-file-other-window
  • dired-view-file

这些函数是dired提供的用于打开文件的函数。对于每个这样的函数,我们都添加了一小段代码,采用了advising技术:当调用这五个函数之一时,(ad-add-advice...)将变量openwith-mode设置为t。在函数调用之外,该变量保持为nil。

这样做的效果是,每当使用dired的函数打开一个文件时,负责调用外部应用程序的openwith-mode函数看到变量设置为t,并立即尝试打开已知的外部应用程序。我们必须通过这种方式跳过障碍,是因为同样的openwith-mode函数也会在使用C-x C-f打开图像文件时被调用 -- 这就是openwith-mode的实现方式。

(注意:不幸的是,我们不能只使用当前主模式作为开关,因为这将是已经为要打开的文件创建的新缓冲区的主模式。它总是fundamental-mode。)

最后,最后三行只是从我们之前注释掉的小模式定义中复制粘贴的。他们说我们已经经常提到并且负责调用外部应用程序 -- 叫做open-with-filehandler -- 是所谓的文件处理程序。对于实际访问文件,它不会真正特别的事情,因此我们为该函数设置了safe-magic。此外,我们声明操作insert-file-contents由我们的函数以非平凡的方式处理。(有关这些属性的更多信息,请参见此处。)

最后,我们实际安装了文件处理程序。


重要提示: openwith-mode 文档建议您将以下两行代码放入您的 .emacs 文件中:

(require 'openwith)
(openwith-mode t)

现在没有小模式openwith-mode了(我们已经注释掉了它的定义),请确保您也注释掉第二行:

;; (openwith-mode t)

在重新启动Emacs之后,如果你使用dired打开图像文件,它应该会在外部应用程序中打开;如果你通过C-x C-f打开它,它将嵌入到一个缓冲区中。

已点赞,但您没有解释为什么需要注释掉模式定义(或直接修改库 - eval-after-load 是添加额外代码的更常规方法)。 - phils
@phils 说得好 - 我只是简单地评论了一下,但并不是很清楚: openwith-mode 的设计方式是全局的,它既可以打开也可以关闭:它添加了一个全局文件处理器,并且当该模式打开时,该文件处理器会检查外部应用程序,如果关闭,则不会执行任何操作。 - Thomas
但是,如果您使用 eval-after-load 包装 (fmakunbound 'openwith-mode) 和您的代码的其余部分,而不实际触及原始库,您不会获得相同的结果吗? - phils
@phils 哦,我知道你的意思了。是的,你说得对,那应该可以运行。 (不过针对任何一种方法,我都能看出有利有弊。) - Thomas

4

0

一个方法可能是在 openwith.el 中的 openwith-associations 中设置 emacsclient 作为您喜欢的文件类型的首选程序,然后开始使用 emacsclient。

您可以每次启动新的 Emacs 会话,但听起来比以前的建议更糟。


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