Tecla directa de "vista rápida" para previsualizar el archivo en el punto

19

Me gustaría crear una función que haga una "vista rápida" de un archivo que está bajo punto en dired.

La forma en que me gustaría que esto funcione es que mantengo presionada una tecla de función, que luego hace que el archivo sea visible en un búfer, pero cuando suelto la tecla, el búfer se cierra y el búfer directo regresa. No quiero tener que cerrar el búfer temporal con C-x k .

¿Hay alguna manera de hacer esta funcionalidad en Emacs? Parece posible si puedo vincular funciones para presionar / presionar teclas.

Eric Brown
fuente
1
No puede vincularse para presionar eventos de depresión, pero esta funcionalidad definitivamente se puede piratear con el uso de un mapa personalizado y un temporizador.
Jordon Biondo
¿Estás hablando de una nueva ventana emergente con una vista previa? ¿O se mostrará el contenido del búfer en la ventana dired mientras se presiona la tecla?
nispio
1
¿Hay esfuerzos para permitirnos unirnos a los eventos? Quiero esta característica
wdkrnls

Respuestas:

9

Aquí está mi manera súper hacky de simular la vinculación de eventos arriba / abajo de la tecla aprovechando los temporizadores.

En general, sugeriría seguir la respuesta de Sigma, pero usted solicitó una forma de cerrar la vista previa al dejar ir, así que estoy obligado a intentarlo.

Básicamente, lo que puede hacer es vincular alguna función que será su función "keydown" a una combinación de teclas y dentro de esa acción, inicie un temporizador inactivo que ejecute una función que es su función "keyup", siempre que mantenga presionada la tecla teclas dadas, la función "keydown" se activará una y otra vez y esto inhibirá la ejecución de los temporizadores inactivos. Por supuesto, debe compensar el hecho de que el comando se disparará una y otra vez, probablemente volviendo a vincular la tecla a algún tipo de función noop en su función "keydown", y luego volviendo a vincular la función "keydown" en la función "keyup".

Entonces, para su caso de uso, su función "keydown" abrirá un búfer de vista previa con el contenido del archivo en el punto y en ese búfer de vista previa, vinculará la misma combinación de teclas a algún comando similar a un noop. Su función "keydown" también iniciará un temporizador inactivo que eliminará su búfer de vista previa y lo restaurará a donde estaba.

Larga historia corta aquí está el código:

Vincula esta función a un combo de teclas (que usé C-M-v), cuando lo presionas sobre el nombre de un archivo, se abrirá un nuevo búfer que muestra el contenido del archivo en ese momento, cuando lo sueltes, volverás al original buffer.

(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!"))))

También aquí hay un gif en acción, todo lo que hago es:

  • coloco mi cursor sobre el archivo
  • mantén presionado el teclado
  • se muestra la vista previa
  • cuando lo dejo ir, la vista previa se mata y vuelves a donde estabas.

ingrese la descripción de la imagen aquí

Una cosa importante a tener en cuenta son los segundos del temporizador inactivo, en mi código que utilicé .7pero es una especie de número mágico, desea mantenerlo realmente pequeño, pero si ve que la vista previa parpadea dos veces, intente aumentarlo 1/10 por segundo cada vez hasta que encuentre el lugar adecuado para su máquina.

* También tenga en cuenta que en la función trato de hacer una fuente del búfer de vista previa pero no pude hacerlo funcionar, ese será el siguiente paso para hacerlo más útil. **

Jordon Biondo
fuente
¡Agradable! Esto es algo que necesitamos ver aquí.
Malabarba
Me sale un Error running timer: (void-variable buffer)con esto, parece que la buffervar no está disponible dentro de run-with-idle-timer?
Lee H
Asegúrese de que el enlace léxico sea t
Jordon Biondo
Es posible que desee repetir esta respuesta allí .
Malabarba
8

Como se señaló en los comentarios, las funciones están vinculadas a teclas, no a eventos. Pero para dar un paso atrás, no estoy seguro de entender por qué es importante que mantenga presionada la tecla mientras está (presumiblemente) leyendo el contenido del archivo. También sería incompatible con acciones básicas (y razonables) como desplazarse para obtener más. Sin mencionar el hecho de que si lleva un tiempo, puede ser incómodo :)

¿Qué hay de repetir una clave en su lugar? Algo como lo siguiente podría ser el esqueleto básico de un equivalente funcional:

(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)

De todos modos, estoy más desafiando su caso de uso que respondiendo a su pregunta en este momento, ya que esto no tiene nada que ver con las pulsaciones de teclas / enlaces de pulsación :)

Sigma
fuente
Me estoy imaginando una larga lista de archivos en dired. No estoy seguro de cuáles son los contenidos de cada uno de los archivos. si pudiera F5 para ver, dejar F5 para dejar de ver y volver a dirigir, luego continuar con el próximo candidato, etc. No creo que haya refutado mi caso de uso, pero puede haber sugerido una buena alternativa basada al presionar F5 nuevamente para dejar de ver.
Eric Brown
lo que sugieres es comparable con la funcionalidad en Midnight Commander (F3)
Eric Brown
1
La respuesta presentada por @Sigma es interesante. Pero cuando explore un directorio usando dired, ya puede presionar v para ver el archivo, y cuando vea ese archivo, presione q para salir y regresar al directorio. Supongo que presionar la misma tecla para ver y salir es más fácil.
Nsukami _
@LeMeteore gracias por recordarme dired-view-file! He editado mi código para aprovecharlo. Sí, supongo que en este tipo de escenario, no es necesario moverse a una clave diferente.
Sigma
4

En lugar de mostrar el archivo mientras se presiona una tecla, lo que sería muy difícil de implementar, sugiero mostrar el archivo hasta que se presione la siguiente tecla.

(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))))

Aquí hay una variante que muestra el archivo en otra ventana, que creo que es una interfaz de usuario más conveniente.

(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))))

No podrá hacer tanto como desplazarse en el búfer. Podría tener más sentido implementar un modo de "vista rápida" donde se acepten comandos de desplazamiento, pero otros eventos de entrada hacen que el modo de vista rápida salga y se interpreten de acuerdo con el modo anterior, como Isearch.

Con v( dired-view-file), obtienes algo intermedio: el búfer se edita en el modo Vista , donde puedes desplazarte, buscar, etc., pero cerrar el búfer es la simple pulsación de tecla q.

Gilles 'SO- deja de ser malvado'
fuente
2

Otra posibilidad, si usa un mouse, es colocar la vista previa que desea en la información sobre herramientas . Luego, cuando mueva el mouse sobre un nombre de archivo (con propiedad help-echo), aparecerá la vista previa.

Utilizo esta técnica en Dired + , por ejemplo, para (opcionalmente) mostrar vistas previas de las imágenes asociadas con los archivos de imagen, al pasar el mouse sobre los nombres de los archivos.

Puede ver el efecto de esto haciendo esto después de cargar dired+.el:

  • Asegúrese de que tooltip-modeestá activada: (tooltip-mode 1).

  • Asegúrese de que la opción no diredp-image-preview-in-tooltiptenga nilvalor (ya sea el tamaño de la miniatura o fullpara una imagen de tamaño completo).

  • Coloque el puntero del mouse sobre el nombre de un archivo de imagen en Dired.

Puede usar el código de función diredp-mouseover-helpcomo inspiración para hacer lo que quiera (muestre su "vista rápida" al pasar el mouse). Vea las llamadas de esa función para saber cómo usarla. Aquí hay una de esas llamadas:

 (add-text-properties (line-beginning-position) (line-end-position)
                      '(mouse-face highlight help-echo diredp-mouseover-help))
Dibujó
fuente
Me perdiste en "si usas un mouse". ;-) Esto no está funcionando para mí. image-diredfunciona bien, pero todo lo que veo cuando paso el mouse esmouse-1: visit this file/dir in another window
nispio
No verá lo que dije si no carga dired+.ely sigue las otras instrucciones que le di. No es una característica vainilla de Emacs. Estaba tratando de describir cómo puedes hacer rodar tu propio código para hacer lo que quieras. El dired+.elcódigo está muy cerca, creo, de lo que dices que quieres. Pero sí, la información sobre herramientas de mouseover requiere que use un mouse. Si no lo hace, la sugerencia de usar una información sobre herramientas no ayudará mucho. ;-)
Drew
Entiendo cómo cargar paquetes y seguir instrucciones, pero no funciona para mí. No estoy seguro de cómo reanudar esta conversación en el chat, pero quizás deberíamos hacerlo.
nispio
1

Desde un búfer dired, vvisitará un archivo en modo de solo lectura, saldrá del qmodo de vista y lo llevará de regreso al búfer dired. Esta es una forma rápida de obtener una vista previa de un archivo, y ofrece la posibilidad de desplazarse e incluso buscar en el búfer.

No creo que emacs tenga la capacidad de transmitir mensajes de pulsación de teclas de bajo nivel que recibe del sistema operativo. Esto puede ser en parte por razones históricas. Los terminales disponibles para los piratas informáticos (léase "programadores") en el momento en que se desarrollaba emacs en los años 70 y 80 no funcionaban con eventos clave arriba / abajo en tiempo real, sino más bien una simple entrada de caracteres y secuencias de escape. Hasta el día de hoy, emacs todavía puede funcionar de manera impresionante en los límites de una sesión simple de terminal o SSH utilizando solo caracteres ASCII simples y secuencias de escape.

Esto no quiere decir que la funcionalidad no haya crecido significativamente a lo largo de los años para incluir características como menús, administración de múltiples cuadros e interacción con el mouse. No hay ninguna razón (que yo sepa) de que no se pueda alterar emacs (en esencia) para que los mensajes clave de bajo nivel estén disponibles para las extensiones, pero no aguanto la respiración.

( Descargo de responsabilidad: esta publicación debe tomarse como una opinión y una especulación, en lugar de un hecho difícil).

nispio
fuente
1

Di mi solución en esta pregunta SO /programming/26409768/how-to-show-buffer-content-in-real-time-in-other-window-when-focus-is-in- buffer

y mi respuesta es cambiar el comportamiento de las teclas de navegación ny pmostrar el archivo en el punto en otra ventana. El foco permanece en el búfer dired y matamos el búfer visitado cuando continuamos navegando.

Creé un modo menor para habilitar / deshabilitar esta función fácilmente. Tenga en cuenta que todavía tenemos las teclas de flechas para la navegación «normal». Llamar M-x dired-show-mode(o ranger-modedado que esta es una característica que descubrí en el administrador de archivos del guardabosques ).

El código: (¡se aprecia cualquier revisión e informe de error!) 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
Ehvince
fuente
0

Tendrá que sondear la cola del evento hasta que se lea un evento diferente, o ninguno. La carga de la CPU es notable, aunque razonablemente baja.

(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)))
politza
fuente