Нажатие клавиши быстрого просмотра для предварительного просмотра файла в точке


19

Я хотел бы создать функцию, которая делает "быстрый просмотр" файла, который находится под указанием в dired.

Я хотел бы, чтобы это работало, так как я удерживаю функциональную клавишу, которая затем делает файл видимым в буфере, но когда я отпускаю эту клавишу, буфер закрывается, и восстановленный буфер возвращается. Я не хочу закрывать временный буфер с помощью C-x k .

Есть ли способ сделать эту функциональность в Emacs? Кажется возможным, если я смогу связать функции с нажатием / нажатием клавиши.


1
Вы не можете связать нажатия событиями нажатия, но эта функциональность может быть определенно взломана с использованием пользовательской карты и таймера.
Джордон Биондо

Вы говорите о появлении нового окна с предварительным просмотром? Или содержимое буфера будет отображаться в всплывающем окне, пока нажата клавиша?
Ниспио

1
Существуют ли усилия, чтобы позволить нам привязаться к событиям? Я хочу эту функцию.
wdkrnls

Ответы:


9

Вот мой супер хакерский способ имитировать привязку событий нажатия клавиш вниз / вверх, используя таймеры.

В целом, я хотел бы предложить ответ Сигмы, но вы попросили способ закрыть предварительный просмотр, отпустив, поэтому я обязан попробовать.

По сути, вы можете привязать некоторую функцию, которая будет вашей функцией «keydown», к привязке клавиш, и внутри этого действия запустить таймер простоя, который выполняет функцию, которая является вашей функцией «keyup», до тех пор, пока вы удерживаете по заданным клавишам функция «keydown» будет срабатывать снова и снова, и это будет препятствовать работе таймеров простоя. Конечно, вам нужно компенсировать тот факт, что команда будет запускаться снова и снова, вероятно, связав ключ с какой-то noop-функцией в вашей функции «keydown», а затем повторно связав функцию «keydown» в функции «keyup».

Таким образом, для вашего варианта использования ваша функция «keydown» откроет буфер предварительного просмотра с содержимым файла в точке и в этом буфере предварительного просмотра свяжет тот же комбо-ключ с какой-то noop-подобной командой. Ваша функция «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 в секунду каждый раз пока вы не найдете подходящее место для вашей машины.

* Также обратите внимание, что в функции я пытаюсь сделать некоторую фонификацию буфера предварительного просмотра, но я не смог заставить его работать, это будет следующим шагом в том, чтобы сделать его более полезным. **


Ницца! Это то, что нам нужно увидеть здесь.
Малабарба

Я получаю Error running timer: (void-variable buffer)с этим, похоже, что bufferвар не доступен внутри run-with-idle-timer?
Ли Х

Убедитесь, что лексическое связывание
Jordon Biondo

Вы можете повторить этот ответ там .
Малабарба

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)

В любом случае, я более сложен для вашего случая использования, чем отвечаю на ваш вопрос на данный момент, так как это не имеет ничего общего с привязками нажатия / нажатия :)


Я представляю длинный список файлов в Dired. Я не уверен, что содержимое каждого из файлов. если бы я мог просмотреть F5, отпустите F5, чтобы прекратить просмотр и вернуться в режим ожидания, затем перейти к следующему кандидату и т. д. Я не думаю, что вы опровергли мой вариант использования, но вы, возможно, предложили хорошую альтернативу на основе при нажатии F5 снова, чтобы остановить просмотр.
Эрик Браун

то, что вы предлагаете, сравнимо с функциональностью Midnight Commander (F3)
Эрик Браун

1
Ответ, представленный @Sigma, интересен. Но при просмотре каталога с использованием dired вы уже можете нажать v, чтобы просмотреть файл, а при просмотре этого файла нажмите q, чтобы выйти и вернуться в каталог. Полагаю, проще нажать одну и ту же клавишу для просмотра и выхода.
Нсуками _

@LeMeteore спасибо, что напомнили мне о dired-view-file! Я отредактировал свой код, чтобы использовать его. Да, я полагаю, что в этом сценарии важно не переходить к другому ключу.
Сигма

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.

С помощью v( dired-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
нахожу

Вы не увидите, что я сказал, если вы не загрузите dired+.elи будете следовать другим указаниям, которые я дал. Это не ванильная особенность Emacs. Я пытался описать, как вы можете развернуть свой собственный код, чтобы делать то, что вы хотите. dired+.elКод очень близко, я думаю, что вы говорите , что вы хотите. Но да, подсказки при наведении курсора мыши требуют использования мыши. Если вы этого не сделаете, то предложение использовать всплывающую подсказку не очень поможет. ;-)
Дрю

Я понимаю, как загружать пакеты и следовать указаниям, но это не работает для меня. Я не уверен, как возобновить этот разговор в чате, но, возможно, мы должны это сделать.
Ниспио


1

Из буфера Dired, vперейдите к файлу в режиме только для просмотра, иq выйдет из режима просмотра и вернет вас в буфер с задержкой. Это быстрый способ предварительного просмотра файла, и он дает возможность прокрутки и даже поиска в буфере.

Я не думаю, что в emacs есть возможность передавать любые низкоуровневые сообщения нажатия клавиш, которые он получает от операционной системы. Это может быть частично по историческим причинам. Терминалы, доступные хакерам (читай «программистам») в то время, когда emacs разрабатывался в 1970–1980-х годах, работали не с событиями клавиш вверх / вниз в реальном времени, а с простым вводом символов и escape-последовательностей. По сей день emacs все еще может работать впечатляюще хорошо в рамках простого терминала или сеанса SSH, используя только простые символы ASCII и escape-последовательности.

Это не означает, что функциональность за последние годы значительно не расширилась и включает такие функции, как меню, управление несколькими кадрами и взаимодействие с мышью. Нет никакой причины (которую я знаю), что emacs нельзя было бы изменить (по своей сути), чтобы сделать низкоуровневые ключевые сообщения доступными для расширений, но я бы не стал задерживать дыхание.

( Отказ от ответственности: этот пост следует воспринимать как мнение и предположение, а не как факт.)


1

Я дал свое решение в этом вопросе /programming/26409768/how-to-show-buffer-content-in-real-time-in-other-window-when-focus-is-in- буфер

и мой ответ - изменить поведение клавиш навигации nи pпоказать файл в другом окне. Фокус остается в буфере, и мы убиваем посещенный буфер, когда продолжаем просмотр.

Я создал вспомогательный режим, чтобы легко включить / отключить эту функцию. Обратите внимание, что у нас все еще есть клавиши со стрелками для «нормальной» навигации. Позвоните 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

Вам нужно будет опрашивать очередь событий до тех пор, пока не будет прочитано другое событие или его нет. Нагрузка на процессор заметна, хотя и достаточно низкая.

(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)))
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.