指向“快速查看”键的点预览文件


19

我想创建一个函数,对指向下方向的文件进行“快速查看”。

我想要的工作方式是按住一个功能键,然后使该文件在缓冲区中可见,但是当我松开该键时,缓冲区将关闭并且干缓冲区将返回。 我不想用关闭临时缓冲区 C-x k

有没有办法在Emacs中实现此功能?如果可以将功能绑定到按键/按下,这似乎是可能的。


1
您无法绑定到按下事件,但是可以使用自定义映射和计时器来侵入此功能。
Jordon Biondo 2014年

您是在谈论带有预览弹出的新窗口吗?还是在按下键时在缓冲区窗口中显示缓冲区的内容?
nispio 2014年

1
是否有努力让我们绑定事件?我想要这个功能。
wdkrnls

Answers:


9

这是我利用计时器来模拟按键按下/按下事件绑定的超级技巧。

总的来说,我建议您按照Sigma的回答进行操作,但是您要求通过放手来关闭预览,因此我不得不尝试。

基本上,您可以做的是将某个将成为“ keydown”功能的功能绑定到一个键绑定,然后在该动作内,启动一个空闲计时器,该计时器执行一个作为“ keyup”功能的功能,只要您按住给定键,“ keydown”功能将反复触发,这将阻止空闲计时器运行。当然,您需要补偿该命令会反复触发的事实,可能是通过将键重新绑定到“ keydown”函数中的某种noop函数,然后重新绑定“ keyup”函数中的“ keydown”函数来弥补的。

因此,对于您的用例,您的“ keydown”函数将打开一个预览缓冲区,其中的文件内容位于该点,并且在该预览缓冲区中将相同的键组合绑定到某些noop like命令。您的“ keydown”功能还将启动一个空闲计时器,该计时器将删除您的预览缓冲区并将您恢复到原来的位置。

长话短说,这里是代码:

将此功能绑定到一个组合键(我用过C-M-v),当您在文件名上按下它时,它将打开一个新的缓冲区,显示该点的文件内容;放开时,您将切换回原始文件缓冲。

(setq lexical-binding t)

(defun quick-view-file-at-point ()
  "Preview the file at point then jump back after some idle time.

In order for this to work you need to bind this function to a key combo, 
you cannot call it from the minibuffer and let it work.

The reason it works is that by holding the key combo down, you inhibit
idle timers from running so as long as you hold the key combo, the 
buffer preview will still display."
  (interactive)
  (let* ((buffer (current-buffer))
         (file (thing-at-point 'filename t))
         (file-buffer-name (format "*preview of %s*" file)))
    (if (and file (file-exists-p file))
        (let ((contents))
          (if (get-buffer file)
              (setq contents (save-excursion
                               (with-current-buffer (get-buffer file)
                                 (font-lock-fontify-buffer)
                                 (buffer-substring (point-min) (point-max)))))
            (let ((new-buffer (find-file-noselect file)))
              (with-current-buffer new-buffer
                (font-lock-mode t)
                (font-lock-fontify-buffer)
                (setq contents (buffer-substring (point-min) (point-max))))
              (kill-buffer new-buffer)))
          (switch-to-buffer (get-buffer-create file-buffer-name))
          (setq-local header-line-format "%60b")
          (delete-region (point-min) (point-max))
          (save-excursion (insert contents))
          (local-set-key (kbd "C-M-v") (lambda () (interactive) (sit-for .2)))
          (run-with-idle-timer
           .7 
           nil
           (lambda ()
             (switch-to-buffer buffer)
             (kill-buffer file-buffer-name))))
      (message "no file to preview at point!"))))

这也是它的效果,我要做的就是:

  • 将光标放在文件上
  • 按住我的绑定
  • 显示预览
  • 当我放手时,预览被终止,您又回到了原来的位置。

在此处输入图片说明

需要注意的重要一件事是空闲计时器的秒数,在我使用的代码中.7,它有点神奇,您想保持它很小,但是如果您看到预览闪烁两次,请尝试将其每次每秒提高1/10。直到找到适合您机器的位置。

*还请注意,在该函数中,我尝试对预览缓冲区进行一些字体化,但无法使其正常工作,这将是使其更有用的下一步。**


真好!这是我们需要在这里看到的东西。
马拉巴巴2014年

我得到了一个Error running timer: (void-variable buffer),看起来buffervar里面没有var run-with-idle-timer
李H

确保词法绑定为t
Jordon Biondo 2014年

您可能要在那儿重复这个答案。
马拉巴巴

8

如注释中指出的那样,函数绑定到键,而不是事件。但是要退后一步,我不确定我是否理解为什么在(大概)读取文件内容时按住键很重要。它也将与基本(合理的)动作(例如滚动获取更多内容)不兼容。更不用说这样的事实,如果花费一些时间,它可能会变得不舒服:)

怎么样重复的关键呢?类似以下内容可能是等效功能的基本框架:

(defun my-dired-view-file ()
  (interactive)
  (dired-view-file)
  (local-set-key (kbd "<f5>") 'View-quit))

(define-key dired-mode-map (kbd "<f5>") 'my-dired-view-file)

无论如何,我现在比回答您的问题更具挑战性,因为这与按键/按下绑定无关:)


我正在想象一堆冗长的文件。我不确定每个文件的内容。如果我可以让F5查看,请让F5停止查看并变深,然后继续寻找下一个候选对象,依此类推。再次按F5停止观看。
埃里克·布朗

您建议的功能与Midnight Commander(F3)中的功能相当
埃里克·布朗

1
@Sigma提交的答案很有趣。但是,当使用Dired浏览目录时,您已经可以按v来查看文件,而当查看该文件时,请按q退出并返回目录。我想,按相同的键进行查看和退出比较容易。
Nsukami _

@LeMeteore感谢您提醒我dired-view-file!我已经编辑了代码以利用它。是的,我想在这种情况下,不必使用其他密钥很重要。
Sigma

4

我建议不要在按下某个键时显示文件(这很难实现),而是建议显示该文件,直到按下下一个键为止。

(defun dired-find-file-until-key ()
  (interactive)
  (let ((filename (dired-file-name-at-point))
    (buffer-count (length (buffer-list))))
    (dired-find-file)
    (message "Showing %s temporarily..." filename)
    (isearch-unread-key-sequence (list (read-event)))
    (if (= (length (buffer-list)) buffer-count)
    (bury-buffer)
      (kill-buffer))))

这是在另一个窗口中显示文件的变体,我认为这是更方便的用户界面。

(defun dired-find-file-other-window-until-key ()
  (interactive)
  (let ((buffer-count (length (buffer-list))))
    (dired-find-file-other-window)
    (isearch-unread-key-sequence (list (read-event)))
    (if (= (length (buffer-list)) buffer-count)
    (delete-window)
      (kill-buffer-and-window))))

您将无法做的只是滚动缓冲区。在接受滚动命令的情况下,实施“快速查看”模式可能更有意义,但是其他输入事件会导致快速查看模式退出并根据先前的模式(例如Isearch)进行解释。

使用vdired-view-file),您会得到一些中间结果:缓冲区是在“ 视图”模式下编辑的,您可以在其中滚动,搜索等。但是关闭缓冲区是简单的按键操作q


2

如果使用鼠标,另一种可能性是将所需的预览放在工具提示中。然后,将鼠标移到文件名(带有属性help-echo)上时,将弹出预览。

我在Dired +中使用了此技术,例如,当您将鼠标悬停在文件名上时,(可选)显示与图像文件关联的图像的预览。

您可以通过在加载后执行以下操作来查看此操作的效果dired+.el

  • 确保tooltip-mode已打开:(tooltip-mode 1)

  • 确保该选项diredp-image-preview-in-tooltip具有非nil值(缩略图尺寸或full全尺寸图像)。

  • 将鼠标指针放在Dired中的图像文件名上。

您可以使用功能中的代码diredp-mouseover-help作为完成所需操作的灵感(鼠标悬停时显示“快速查看”)。有关该函数的用法,请参见该函数的调用。这是一个这样的电话:

 (add-text-properties (line-beginning-position) (line-end-position)
                      '(mouse-face highlight help-echo diredp-mouseover-help))

您因为“如果使用鼠标”而迷失了我。;-)这对我不起作用。image-dired正常,但是当我将鼠标悬停在上面时,我看到的只是mouse-1: visit this file/dir in another window
nispio 2014年

如果不加载dired+.el并按照我给的其他指示,您将看不到我说的话。这不是普通的Emacs功能。我试图描述如何才能滚动自己的代码来执行所需的操作。该dired+.el代码是非常接近,我认为,你说你想要的。但是可以,鼠标悬停工具提示要求您使用鼠标。如果您不这样做,那么使用工具提示的建议将无济于事。;-)
Drew

我了解如何加载软件包并按照说明进行操作,但是它对我不起作用。我不确定如何恢复聊天中的对话,但是也许我们应该这样做。
nispio 2014年


1

从干燥的缓冲区中 v将以仅q查看模式访问文件,然后退出查看模式,并带您返回干缓冲区。这是预览文件的快速方法,它提供了滚动甚至搜索缓冲区的可能性。

我认为emacs不能传递从操作系统接收到的任何低级按键消息。这可能部分是出于历史原因。在1970年代至1980年代开发emacs时,可供黑客(阅读“程序员”)使用的终端不适用于实时按键向上/向下事件,而只能用于字符和转义序列的简单输入。迄今为止,emacs在仅使用简单ASCII字符和转义序列的简单终端或SSH会话范围内仍然可以出色地运行。

但这并不是说这些年来功能并未显着增长,以包括菜单,多帧管理和鼠标交互等功能。没有理由(据我所知)无法更改emacs(在其核心)以使扩展可以使用低级关键消息,但我不会屏住呼吸。

免责声明:此职位应被视为观点和猜测,而不是硬道理。)


1

我在这个问题中给出了解决方案 /programming/26409768/how-to-show-buffer-content-in-real-time-in-other-window-when-focus-is-in-缓冲

我的答案是更改导航键的行为,np在另一个窗口中的某个位置显示文件。焦点停留在干燥的缓冲区中,继续进行浏览时,我们会杀死访问的缓冲区。

我创建了一个次要模式来轻松启用/禁用此功能。请注意,我们仍然具有用于“普通”导航的箭头键。致电M-x dired-show-mode(或ranger-mode由于这是我在护林员文件管理器中发现的功能)。

代码:(感谢任何评论和错误报告!) https://gitlab.com/emacs-stuff/my-elisp/blob/master/dired-show.el

(defgroup dired-show nil
  "See the file at point when browsing in a Dired buffer."
  :group 'dired
  )

(setq show-next-current-buffer nil)

(defun show-next ()
     (interactive)
     (next-line 1)
     (dired-find-file-other-window)
     (if show-next-current-buffer (kill-buffer show-next-current-buffer))
     (setq show-next-current-buffer (current-buffer))
     (other-window 1)
     )

(defun show-previous ()
     (interactive)
     (previous-line 1)
     (dired-find-file-other-window)
     (if show-next-current-buffer (kill-buffer show-next-current-buffer))
     (setq show-next-current-buffer (current-buffer))
     (other-window 1)
     )


(define-minor-mode dired-show-mode
  "Toggle preview of files when browsing in a Dired buffer."
  :global t
  :group 'dired-show
  (if dired-show-mode
      (progn
        (define-key dired-mode-map "n" 'show-next)
        (define-key dired-mode-map "p" 'show-previous)
        )
  (define-key dired-mode-map "n" 'diredp-next-line)
  (define-key dired-mode-map "p" 'diredp-previous-line)
  ))

(defalias 'ranger-mode 'dired-show-mode)

(provide 'dired-show)
;;; dired-show ends here

0

您需要轮询事件队列,直到读取到另一个事件为止,或者没有事件被读取。CPU负载虽然很低,但值得注意。

(defun dired-preview-command ()
  (interactive)
  (let* ((file (or (dired-get-filename nil t)
                   (error "No file here")))
         (visited-p (get-file-buffer file))
         (buffer (or visited-p (find-file-noselect file)))
         (window
          (display-buffer buffer '(nil . ((inhibit-same-window . t)))))
         (event (read-event)))
    (while (and event (eq last-command-event event))
      (setq event (read-event nil nil 0.1)))
    (when event
      (setq unread-command-events
            (list event)))
    (quit-window (not visited-p) window)))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.