Come visualizzare il contenuto del minibuffer al centro della cornice di emacs?


20

Quando si lavora su un frame Emacs ingrandito, avere il contenuto del minibuffer / area di eco visualizzata nella parte inferiore dello schermo può essere difficile da vedere, ma fa anche perdere attenzione al testo che si sta modificando quando si digita un comando - che è piuttosto un problema in termini di usabilità.

C'è un modo per spostare l'area del minibuffer / echo al centro dell'attuale buffer emacs, sul testo in fase di modifica quando il minibuffer è attivo o, meglio, per acquisire il contenuto del minibuffer e visualizzarlo anche al centro del buffer corrente mentre si digita il comando?


Per completezza, dovrei aggiungere che la mia attuale soluzione a questo problema di usabilità è aumentare la dimensione del carattere del minibuffer, ma sembra sciocca su frame non massimizzati.
Sébastien Le Callonnec,

Risposte:


10

Popup Minibuffer al centro

Ecco un modo per fare esattamente quello che hai chiesto: visualizzare il minibuffer al centro dello schermo .

  1. Avere un telaio separato per il minibuffer
  2. Posizionalo al centro
  3. Solleva questo riquadro ogni volta che il minibuffer prende fuoco.

È relativamente facile da ottenere ed è quello che otterrai con il oneonone.elpacchetto (come sottolinea @Drew). Il problema con questo approccio è che il minibuffer viene utilizzato anche per i messaggi, quindi tenerlo nascosto non è molto conveniente. Da non preoccuparsi! Ho trovato un'altra soluzione.

  1. Fai visualizzare un secondo minibuffer su un telaio separato.
  2. Posizionalo al centro.
  3. Utilizzare il secondo frame per i comandi interattivi, mentre il minibuffer originale (primo) viene utilizzato per l'eco dei messaggi.

Implementazione

Per implementarlo, dobbiamo creare il frame del minibuffer all'avvio di emacs.

(defvar endless/popup-frame-parameters
  '((name . "MINIBUFFER")
    (minibuffer . only)
    (height . 1)
    ;; Ajust this one to your preference.
    (top . 200))
  "Parameters for the minibuffer popup frame.")

(defvar endless/minibuffer-frame
  (let ((mf (make-frame endless/popup-frame-parameters)))
    (iconify-frame mf) mf)
  "Frame holding the extra minibuffer.")

(defvar endless/minibuffer-window
  (car (window-list endless/minibuffer-frame t))
  "")

Quindi patch read-from-minibufferper usare questo secondo minibuffer, invece del minibuffer del telaio originale.

(defmacro with-popup-minibuffer (&rest body)
  "Execute BODY using a popup minibuffer."
  (let ((frame-symbol (make-symbol "selected-frame")))
    `(let* ((,frame-symbol (selected-frame)))
       (unwind-protect 
           (progn 
             (make-frame-visible endless/minibuffer-frame)
             (when (fboundp 'point-screen-height)
               (set-frame-parameter
                endless/minibuffer-frame 
                'top (point-screen-height)))
             (select-frame-set-input-focus endless/minibuffer-frame 'norecord)
             ,@body)
         (select-frame-set-input-focus ,frame-symbol)))))

(defun use-popup-minibuffer (function)
  "Rebind FUNCTION so that it uses a popup minibuffer."
  (let* ((back-symb (intern (format "endless/backup-%s" function)))
         (func-symb (intern (format "endless/%s-with-popup-minibuffer"
                                    function)))
         (defs `(progn
                  (defvar ,back-symb (symbol-function ',function))
                  (defun ,func-symb (&rest rest)
                    ,(format "Call `%s' with a poupup minibuffer." function)
                    ,@(list (interactive-form function))
                    (with-popup-minibuffer 
                     (apply ,back-symb rest))))))
    (message "%s" defs)
    (when (and (boundp back-symb) (eval back-symb))
      (error "`%s' already defined! Can't override twice" back-symb))
    (eval defs)
    (setf (symbol-function function) func-symb)))

;;; Try at own risk.
(use-popup-minibuffer 'read-from-minibuffer)
;;; This will revert the effect.
;; (setf (symbol-function #'read-from-minibuffer) endless/backup-read-from-minibuffer)
;; (setq endless/backup-read-from-minibuffer nil)

Questo potrebbe non funzionare con assolutamente tutto, ma ha funzionato su tutto quello che ho provato finora --- find-file, ido-switch-buffer, eval-expression. Se fai trovare eventuali eccezioni, è possibile correggere queste funzioni su una base caso per caso, chiamando use-popup-minibuffersu di loro.

Posizione vicino al punto

Per posizionare questo telaio del minibuffer vicino all'altezza del punto, è sufficiente definire qualcosa come la seguente funzione. Non è perfetto (in effetti, è terribile in molti casi), ma fa un buon lavoro nel valutare l'altezza del punto.

(defun point-screen-height ()
  (* (/ (face-attribute 'default :height) 10) 2
     (- (line-number-at-pos (point))
        (line-number-at-pos (window-start)))))

Invece di scherzare con (setf (symbol-function function) ...)te sarebbe meglio usare advice-add(o il più vecchio ad-add-advice).
Stefan,

6

Minibuffer in alto

La visualizzazione del minibuffer al centro dello schermo è complicata. Un'alternativa ragionevole (che potresti trovare o meno più leggibile) è spostarla in alto.

È possibile configurare la posizione (o l'esistenza) del minibuffer di un frame con il minibufferparametro frame nella initial-frame-alist variabile.

Cornice separata

L'impostazione del parametro su nilconfigurerà il frame in modo che non abbia un minibuffer ed Emacs creerà automaticamente un frame di minibuffer separato per te. Puoi posizionare questi due frame usando il window manager del tuo sistema operativo, oppure puoi farlo da Emacs.

Il frammento seguente mostra come posizionare il telaio del minibuffer in alto, con il telaio normale proprio sotto di esso, ma dovrai sicuramente cambiare i numeri per tener conto delle dimensioni del tuo monitor.

(setq initial-frame-alist
      '((left . 1) (minibuffer . nil)
        ;; You'll need to adjust the following 3 numbers.
        (top . 75) ; In pixels
        (width . 127) ; In chars
        (height . 31)))

(setq minibuffer-frame-alist
      '((top . 1) (left . 1) (height . 2)
        ;; You'll need to adjust the following number.
        (width . 127)))

Il modo più rapido per regolarlo è ridimensionare i frame nel gestore delle finestre e quindi valutare (frame-parameters)per vedere i valori dei parametri che hai.

Stesso telaio

Un'altra possibilità è impostare il minibufferparametro su una finestra. Sfortunatamente, non sono riuscito a farlo funzionare per una finestra nella stessa cornice.


5

Library oneonone.elti dà questo fuori dalla scatola.

Basta personalizzare l'opzione 1on1-minibuffer-frame-top/bottomnella posizione desiderata per il telaio del minibuffer autonomo. Il valore è il numero di pixel dall'alto (se non negativo) o dal basso (se negativo) del display. Ad esempio, imposta il valore per l'altezza di visualizzazione diviso per 2, per centrarlo verticalmente.

Se invece vuoi che sia posizionato dinamicamente, diciamo nel centro verticale del fotogramma corrente, allora puoi farlo (a) lasciando 1on1-minibuffer-frame-top/bottom= nile (b) consigliando 1on1-set-minibuffer-frame-top/bottom alla funzione di legare dinamicamente quella variabile nella posizione appropriata. Per esempio:

(defadvice 1on1-set-minibuffer-frame-top/bottom (around center activate)
  (let ((1on1-minibuffer-frame-top/bottom  (my-dynamic-position ...)))
    ad-do-it))

(Definire la funzione my-dynamic-positionper calcolare la posizione desiderata, in base ai criteri desiderati (dimensione e posizione della finestra / cornice attuali, fase della luna, ...).

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.