Tasto “visualizzazione rapida” diretto per visualizzare l'anteprima del file nel punto


19

Vorrei creare una funzione che esegua una "visualizzazione rapida" di un file su cui è diretto dired.

Il modo in cui vorrei che funzionasse è che tengo premuto un tasto funzione, che quindi rende il file visibile in un buffer, ma quando lascio perdere la chiave, il buffer si chiude e ritorna il buffer diretto. Non voglio chiudere il buffer temporaneo con C-x k .

C'è un modo per rendere questa funzionalità in Emacs? Sembra possibile se posso associare le funzioni a premere / premere il tasto.


1
Non puoi impegnarti a premere eventi depressi, ma questa funzionalità può sicuramente essere compromessa con l'uso di una mappa personalizzata e un timer.
Jordon Biondo,

Stai parlando di una nuova finestra che si apre con un'anteprima? O il contenuto del buffer verrebbe visualizzato nella finestra indirizzata mentre il tasto è premuto?
nispio,

1
Ci sono sforzi per permetterci di legarci agli eventi? Voglio questa funzione.
wdkrnls,

Risposte:


9

Ecco il mio modo super hacky per simulare l'associazione di eventi down / up chiave sfruttando i timer.

Nel complesso, suggerirei di seguire la risposta di Sigma, ma hai chiesto un modo per chiudere l'anteprima lasciando andare, quindi sono obbligato a provare.

Fondamentalmente quello che puoi fare è associare una funzione che sarà la tua funzione "keydown" a un keybinding e all'interno di quell'azione, avviare un timer inattivo che esegue una funzione che è la tua funzione "keyup", finché si tiene premuto il dati i tasti, la funzione "keydown" si attiverà ripetutamente e ciò inibirà il funzionamento dei timer inattivi. Ovviamente è necessario compensare il fatto che il comando si attiverà ripetutamente, probabilmente riconducendo la chiave a una sorta di funzione noop nella funzione "keydown", quindi rilegando la funzione "keydown" nella funzione "keyup".

Quindi per il tuo caso d'uso la tua funzione "keydown" aprirà un buffer di anteprima con i contenuti del file in quel punto e in quel buffer di anteprima associerà la stessa combinazione di tasti a un comando noop like. La tua funzione "keydown" avvierà anche un timer di inattività che eliminerà il buffer di anteprima e ripristinerà la tua posizione.

Per farla breve ecco il codice:

Associa questa funzione a una combinazione di tasti (che ho usato C-M-v), quando lo premi in cima al nome di un file si aprirà un nuovo buffer che mostra il contenuto del file in quel punto, quando lo lasci andare tornerai all'originale 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!"))))

Anche qui è una gif in azione, tutto ciò che faccio è:

  • posiziona il cursore sul file
  • tenere premuto il mio tasto
  • viene visualizzata l'anteprima
  • quando lascio andare, l'anteprima viene uccisa e sei tornato dove eri.

inserisci qui la descrizione dell'immagine

Una cosa importante da notare sono i secondi del timer inattivo, nel mio codice l'ho usato .7ma è un po 'un numero magico, vuoi mantenerlo davvero piccolo, ma se vedi l'anteprima lampeggiare due volte prova ad alzarlo di 1/10 di secondo ogni volta finché non trovi il posto giusto per la tua macchina.

* Nota anche che nella funzione cerco di fare una fontificazione del buffer di anteprima ma non sono riuscito a farlo funzionare, quello sarà il prossimo passo per renderlo più utile. **


Bello! Questo è qualcosa che dobbiamo vedere qui.
Malabarba,

Ottengo un Error running timer: (void-variable buffer)con questo, sembra che il buffervar non sia disponibile all'interno del run-with-idle-timer?
Lee H,

Assicurati che il legame lessicale sia t
Jordon Biondo,

Potresti voler ripetere questa risposta laggiù .
Malabarba,

8

Come indicato nei commenti, le funzioni sono associate ai tasti, non agli eventi. Ma per fare un passo indietro, non sono sicuro di capire perché è importante tenere premuta la chiave mentre (presumibilmente) stai leggendo il contenuto del file. Sarebbe anche incompatibile con azioni di base (e ragionevoli) come lo scorrimento per ottenerne di più. Per non parlare del fatto che se ci vuole un po ', potrebbe essere scomodo :)

Che ne dici di ripetere una chiave invece? Qualcosa di simile al seguente potrebbe essere lo scheletro di base di un equivalente funzionale:

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

Ad ogni modo, sto sfidando il tuo caso d'uso piuttosto che rispondere alla tua domanda a questo punto, poiché questo non ha nulla a che fare con i tasti premete / premete i tasti :)


Sto immaginando un lungo elenco di file in dired. Non sono sicuro di quali siano i contenuti di ciascuno dei file. se potessi visualizzare F5, lasciare F5 per interrompere la visualizzazione ed essere di nuovo diretto, quindi passare al candidato successivo, ecc. Non credo che tu abbia smentito il mio caso d'uso, ma potresti aver suggerito una buona alternativa basata premendo di nuovo F5 per interrompere la visualizzazione.
Eric Brown,

quello che suggerisci è paragonabile alla funzionalità di Midnight Commander (F3)
Eric Brown,

1
La risposta inviata da @Sigma è interessante. Ma quando si sfoglia una directory usando dired, è già possibile premere v per visualizzare il file e, durante la visualizzazione di quel file, premere q per uscire e tornare alla directory. Immagino che sia più facile premere lo stesso tasto per visualizzare e uscire.
Nsukami _

@LeMeteore grazie per avermelo ricordato dired-view-file! Ho modificato il mio codice per sfruttarlo. Sì, credo in questo tipo di scenario, non è necessario passare a una chiave diversa è importante.
Sigma,

4

Invece di mostrare il file mentre è premuto un tasto, il che sarebbe molto difficile da implementare, suggerisco di mostrare il file fino a quando non viene premuto il tasto successivo.

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

Ecco una variante che mostra il file in un'altra finestra, che penso sia un'interfaccia utente più comoda.

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

Non sarai in grado di fare tanto quanto scorrere nel buffer. Potrebbe essere più sensato implementare una modalità di "visualizzazione rapida" in cui i comandi di scorrimento sono accettati, ma altri eventi di input fanno uscire la modalità di visualizzazione rapida e sono interpretati secondo la modalità precedente, come Isearch.

Con v( dired-view-file), ottieni qualcosa di intermedio: il buffer viene modificato in modalità Visualizza , dove puoi scorrere, cercare, ecc. Ma chiudere il buffer è la semplice sequenza di tasti q.


2

Un'altra possibilità, se si utilizza un mouse, è di inserire l'anteprima desiderata in una descrizione comandi . Quindi, quando si sposta il mouse su un nome file (con proprietà help-echo), verrà visualizzata l'anteprima.

Uso questa tecnica in Dired + , ad esempio, per (facoltativamente) mostrare anteprime delle immagini associate ai file di immagine, quando passi il mouse sui nomi dei file.

Puoi vedere l'effetto di questo facendo questo dopo aver caricato dired+.el:

  • Verificare che tooltip-modeè acceso: (tooltip-mode 1).

  • Assicurati che l'opzione non diredp-image-preview-in-tooltipabbia un nilvalore (o la dimensione della miniatura o fullper un'immagine a dimensione intera).

  • Posiziona il puntatore del mouse sul nome di un file immagine in Dired.

È possibile utilizzare il codice in funzione diredp-mouseover-helpcome ispirazione per fare ciò che si desidera (visualizzare la "visualizzazione rapida" al passaggio del mouse). Vedi le chiamate di quella funzione per come usarla. Ecco una di queste chiamate:

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

Mi hai perso a "se usi un mouse". ;-) Questo non funziona per me. image-diredfunziona benissimo, ma tutto quello che vedo quando mouse-1: visit this file/dir in another window
passo con il

Non vedrai ciò che ho detto se non carichi dired+.ele segui le altre indicazioni che ho dato. Non è una funzionalità Emacs alla vaniglia. Stavo cercando di descrivere come si può fare per far rotolare il proprio codice per fare ciò che si desidera. Il dired+.elcodice è molto vicino, credo, a quello che dici di volere. Ma sì, le descrizioni dei comandi del mouseover richiedono l'uso di un mouse. In caso contrario, il suggerimento di utilizzare una descrizione comandi non sarà di grande aiuto. ;-)
Ha

Capisco come caricare i pacchetti e seguire le indicazioni, ma non funziona per me. Non sono sicuro di come riprendere questa conversazione in chat, ma forse dovremmo farlo.
nispio,


1

Da un buffer diretto, vvisiterà un file in modalità di sola visualizzazione e quscirà dalla modalità di visualizzazione per tornare al buffer diretto. Questo è un modo rapido per visualizzare l'anteprima di un file e offre la possibilità di scorrere e persino cercare il buffer.

Non penso che emacs abbia la capacità di trasmettere tutti i messaggi di pressione di basso livello che riceve dal sistema operativo. Questo può essere in parte per motivi storici. I terminali disponibili per gli hacker (leggi "programmatori") ai tempi dello sviluppo di emacs negli anni '70 -'80 non funzionavano con eventi chiave su / giù in tempo reale, ma piuttosto un semplice input di caratteri e sequenze di escape. Fino ad oggi emacs può ancora funzionare in modo impressionante bene nei confini di un semplice terminale o sessione SSH usando solo semplici caratteri ASCII e sequenze di escape.

Ciò non significa che la funzionalità non sia aumentata in modo significativo nel corso degli anni per includere funzionalità come menu, gestione di più frame e interazione con il mouse. Non c'è motivo (che io sappia) che emacs non possa essere modificato (al suo interno) per rendere disponibili i messaggi chiave di basso livello alle estensioni, ma non trattengo il respiro.

( Disclaimer: questo post dovrebbe essere preso come opinione e speculazione, piuttosto che come un fatto reale.)


1

Ho dato la mia soluzione in questa domanda SO /programming/26409768/how-to-show-buffer-content-in-real-time-in-other-window-when-focus-is-in- buffer

e la mia risposta è cambiare il comportamento dei tasti di navigazione ne pmostrare il file nel punto in un'altra finestra. Il focus rimane nel buffer diretto e noi uccidiamo il buffer visitato quando continuiamo a navigare.

Ho creato una modalità secondaria per abilitare / disabilitare questa funzione facilmente. Nota che abbiamo ancora i tasti freccia per la navigazione «normale». Chiama M-x dired-show-mode(o ranger-modepoiché questa è una funzione che ho scoperto nel file manager ranger ).

Il codice: (apprezzata qualsiasi recensione e segnalazione di bug!) 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

Dovresti eseguire il polling della coda degli eventi fino a quando non viene letto un evento diverso o nessuno. Il carico della CPU è evidente, sebbene ragionevolmente basso.

(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)))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.