Minibúfer emergente en el centro
Aquí hay una manera de hacer exactamente lo que pidió: mostrar el minibúfer en el centro de la pantalla .
- Tener un marco separado para el minibúfer
- Posicionarlo en el centro
- Eleve este marco cada vez que el minibúfer se enfoque.
Eso es relativamente fácil de lograr y es lo que obtendrá con el
oneonone.el
paquete (como señala @Drew). El problema con este enfoque es que el minibúfer también se usa para mensajes, por lo que mantenerlo oculto no es algo muy conveniente. ¡No es para preocuparse! Se me ocurrió otra solución.
- Haga que se muestre un segundo minibúfer en un marco separado.
- Colóquelo en el centro.
- Use el segundo marco para comandos interactivos, mientras que el minibúfer original (primero) se usa para hacer eco de mensajes.
Implementación
Para implementar esto, necesitamos crear el marco de minibúfer al inicio de 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))
"")
Luego aplicamos parches read-from-minibuffer
para usar este segundo minibúfer, en lugar del minibúfer del marco original.
(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)
Esto podría no funcionar con absolutamente todo, pero trabajado en todo lo que probé hasta ahora --- find-file
, ido-switch-buffer
,
eval-expression
. Si haces encontrar alguna excepción, se puede parchear estas funciones sobre una base de caso por caso llamando
use-popup-minibuffer
en ellos.
Posición cerca del punto
Para colocar este marco de minibúfer cerca de la altura del punto, simplemente defina algo como la siguiente función. No es perfecto (de hecho, es horrible en muchos casos), pero hace un trabajo decente al estimar la altura del punto.
(defun point-screen-height ()
(* (/ (face-attribute 'default :height) 10) 2
(- (line-number-at-pos (point))
(line-number-at-pos (window-start)))))