Comment afficher le contenu du mini-tampon au milieu du cadre emacs?

20

Lorsque vous travaillez sur un cadre Emacs maximisé, il peut être difficile de voir le contenu de la zone du mini-tampon / écho en bas de l'écran, mais aussi de perdre le focus sur le texte en cours de modification lors de la frappe d'une commande - ce qui est assez problème en termes de convivialité.

Existe-t-il un moyen de déplacer la zone du mini-tampon / écho au centre du tampon emacs actuel, sur le texte en cours de modification lorsque le mini-tampon est actif, ou, mieux, de capturer le contenu du mini-tampon et de l'afficher également au centre du tampon en cours en tapant la commande?

Sébastien Le Callonnec
la source
Pour être complet, je dois ajouter que ma solution actuelle à ce problème d'utilisation est d'augmenter la taille de la police du mini-tampon, mais cela semble idiot sur les cadres non maximisés.
Sébastien Le Callonnec

Réponses:

10

Minibuffer Popup au Centre

Voici une façon de faire exactement ce que vous avez demandé: afficher le mini-tampon au centre de l'écran .

  1. Avoir un cadre séparé pour le mini-tampon
  2. Positionnez-le au centre
  3. Relevez ce cadre chaque fois que le mini-tampon gagne en concentration.

C'est relativement facile à réaliser et c'est ce que vous obtiendrez avec le oneonone.elpackage (comme le souligne @Drew). Le problème avec cette approche, c'est que le mini-tampon est également utilisé pour les messages, donc le garder caché n'est pas quelque chose de très pratique. Ne pas s'inquiéter! J'ai trouvé une autre solution.

  1. Ayez un deuxième mini-tampon affiché sur un cadre séparé.
  2. Positionnez-le au centre.
  3. Utilisez le deuxième cadre pour les commandes interactives, tandis que le (premier) mini-tampon d'origine est utilisé pour faire écho aux messages.

la mise en oeuvre

Pour l'implémenter, nous devons créer le cadre du mini-tampon au démarrage d'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))
  "")

Ensuite, nous corrigeons read-from-minibufferpour utiliser ce deuxième mini-tampon, au lieu du mini-tampon du cadre d'origine.

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

Cela pourrait ne pas fonctionner avec absolument tout, mais il a travaillé sur tout ce que j'ai essayé jusqu'à présent --- find-file, ido-switch-buffer, eval-expression. Si vous ne trouvez aucune exception, vous pouvez patcher ces fonctions sur une base au cas par cas en appelant use-popup-minibuffersur eux.

Position près du point

Pour positionner ce cadre de mini-tampon près de la hauteur du point, définissez simplement quelque chose comme la fonction suivante. Ce n'est pas parfait (en fait, c'est horrible dans beaucoup de cas), mais il fait un travail décent d'estimation de la hauteur du point.

(defun point-screen-height ()
  (* (/ (face-attribute 'default :height) 10) 2
     (- (line-number-at-pos (point))
        (line-number-at-pos (window-start)))))
Malabarba
la source
Au lieu de jouer avec (setf (symbol-function function) ...)vous, vous feriez mieux d'utiliser advice-add(ou l'ancienne ad-add-advice).
Stefan
6

Minibuffer en haut

L'affichage du mini-tampon au milieu de l'écran est compliqué. Une alternative raisonnable (que vous trouverez ou non plus lisible) consiste à la déplacer vers le haut.

Vous pouvez configurer l'emplacement (ou l'existence) du mini-tampon d'un cadre avec le minibufferparamètre de cadre dans la initial-frame-alist variable.

Cadre séparé

La définition du paramètre sur nilconfigurera le cadre pour qu'il n'y ait pas de mini-tampon, et Emacs créera automatiquement un cadre de mini-tampon séparé pour vous. Vous pouvez positionner ces deux cadres à l'aide du gestionnaire de fenêtres de votre système d'exploitation, ou vous pouvez le faire à partir d'Emacs.

L'extrait suivant explique comment placer le cadre du mini-tampon en haut, avec le cadre normal juste en dessous, mais vous devrez certainement modifier les nombres pour tenir compte de la taille de votre moniteur.

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

Le moyen le plus rapide de régler cela est de redimensionner les cadres dans votre gestionnaire de fenêtres, puis d'évaluer (frame-parameters)pour voir les valeurs des paramètres que vous avez.

Même cadre

Une autre possibilité consiste à définir le minibufferparamètre sur une fenêtre. Malheureusement, je n'ai pas pu faire fonctionner cela pour une fenêtre dans le même cadre.

Malabarba
la source
5

La bibliothèque oneonone.elvous donne ceci hors de la boîte.

Personnalisez simplement l'option 1on1-minibuffer-frame-top/bottomà la position souhaitée pour le cadre du mini-tampon autonome. La valeur est le nombre de pixels du haut (si non négatif) ou du bas (si négatif) de votre affichage. Par exemple, définissez la valeur sur votre hauteur d'affichage divisée par 2, pour la centrer verticalement.

Si vous souhaitez plutôt qu'il soit positionné dynamiquement, par exemple au centre vertical du cadre actuel, vous pouvez le faire en (a) laissant 1on1-minibuffer-frame-top/bottom= nilet (b) en conseillant à la fonction 1on1-set-minibuffer-frame-top/bottom de lier dynamiquement cette variable à la position appropriée. Par exemple:

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

(Définissez la fonction my-dynamic-positionpour calculer la position que vous voulez, en fonction de tous les critères que vous souhaitez (taille et position actuelle de la fenêtre / du cadre, phase de la lune, ...).

A dessiné
la source