让 minibuffer 显示在屏幕中间

非常有趣的一个效果

实现代码:

(defvar endless/popup-frame-parameters
    '((name . "MINIBUFFER")
      (minibuffer . only)
      (height . 10)
      (left . 400)
      ;; Ajust this one to your preference.
      (top . 300))
    "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))
    "")
  (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)

来自于 How to display the content of minibuffer in the middle of the emacs frame? - Emacs Stack Exchange

目前实用价值还有限,因为没办法让 helm 从中间弹出来。不知道有没有 helm-ag 的替代品

4 个赞

我对你的 gif 的开头的 “amazing graphics goes on…” 比较感兴趣,怎么弄的?

M-x butterfly emacs 自带的

这样,C-x o还能切换buffer吗?

C-x o 不是切换 Window 么,,工作正常

好像是比较经典的一个梗。Bing/Googleemacs butterfly第一条就是出处。(当然你多半已经搜过了。。)

GVim 上的 fzf 也是弹出第二个frame不过是借用 XTerm 之类的终端

如果把这个butterfly函数改一下,然后在一条单独的线程中运行,或许可以作为不错的开机动画

可以直接用ivy-posframe或helm-posframe,很方便调整minibuffer显示位置

1 个赞

做了下修改,能做到:

  • 手动关闭弹窗后不出现“Debugger entered–Lisp error: (wrong-type-argument frame-live-p #<dead frame MINIBUFFER 1c80e7e8>)”问题
  • 支持“recursive-edit”
  • 根据当前窗口来适当居中所弹出的窗口

(when (display-graphic-p)
  (eval
   `(defun earned::read-from-minibuffer (oldfun &rest rest)
      "让 minibuffer 显示在屏幕中间 - Emacs-general - Emacs China: https://emacs-china.org/t/topic/890"
      (let ((select (selected-frame))
            (frame
             (make-frame
              `((name . "*Minibuffer*")
                (minibuffer . only)
                ,(when (boundp (quote ivy-height))
                   (cons (quote height) ivy-height))
                (width . ,(max (/ (- (frame-inner-width)
                                     (* 20 (frame-char-width)))
                                  (frame-char-width))
                               40))
                (left . ,(+ (eval (alist-get (quote left)
                                             (frame-parameters)))
                            (* (frame-char-width)
                               10)))
                (top . ,(+ (eval
                            (alist-get (quote top)
                                       (frame-parameters)))
                           (/ (frame-inner-height)
                              3)))))))
        (make-frame-visible frame)
        (select-frame-set-input-focus frame (quote norecord))
        (unwind-protect
            (apply oldfun rest)
          (select-frame-set-input-focus select)
          (delete-frame frame))))))

(dolist (symbol
         (quote
          (read-from-minibuffer
           read-string)))
  (when (functionp (function earned::read-from-minibuffer))
    (advice-add symbol :around (function earned::read-from-minibuffer))))

ivy-posframe,感觉效果还是不错的。

ivy-posframe

2 个赞

现在也在用 ivy-posframe,效果完全满足期望

ivy-posframe肯定满足需求了,而且比单独的 frame 要快速和好看些。不过用起来都有所卡顿,不如原生 minibuffer 流畅,用了一段时间还是放弃了。懒猫最新的 snails 也是放在中间,只是功能比较单一,只能搜索,很多功能是没有的。

我之前重新整理了一下,写了一个类似的完整的package

https://github.com/honmaple/dotfiles/blob/master/emacs.d/site-lisp/maple/maple-minibuffer.el

让minibuffer显示位置可选屏幕或window中间,上下左右角,有兴趣的同道可以试试

有点意思,有效果图之类的参考下吗?感觉实现跟 snails 一样,都是用 frame 的?老兄考虑过上 mepla 吗?

有使用说明吗?可以单独一个完整的package发出来呀

Peek%202019-08-06%2015-10

确实是用frame实现的,之前写这个的目的好像是因为ivy-posframe无法隐藏当前minibuffer和光标无法跟随,不过不会上mepla,我用过几次,感觉还是有些不太习惯,又换回去了

我创建了一个单独的仓库,使用上很简单,load-file然后激活maple-minibuffer-mode即可

用起来确实还不如原生的 minibuffer,感觉卡卡的、怪怪的。

感谢大神!赞叹大神!试了下感觉比ivy-posframe可靠。速度也很快。不过我遇到了个小问题是遇到recursive edit的时候frame的位置会跑掉。不知道有没有办法修复?GIF 如下:

Peek 2020-02-28 22-04

具体重现步骤:

  1. C-x C-f (counsel-find-file)
  2. 直接在minibuffer存在的时候按下M-x (counsel-M-x)

结果原本被我设置在中间的minibuffer就突然跑到左上角了,不知道有没有办法修复?感谢。