complete-computing-environment/ivy_posframe.org

61 lines
3.5 KiB
Org Mode

:PROPERTIES:
:ID: cce/ivy_posframe
:ROAM_ALIASES: "Ivy Posframe"
:END:
#+TITLE: Floating Minibuffer via Ivy/PosFrame
#+filetags: :Emacs:CCE:Tool:
#+PROPERTY: header-args :mkdirp yes :results none
#+PROPERTY: header-args:emacs-lisp :tangle ivy-posframe.el
#+ARCOLOGY_KEY: cce/ivy-posframe
#+ARCOLOGY_ALLOW_CRAWL: t
,#+ARROYO_EMACS_MODULE: ivy-posframe
#+CCE_PREDICATE: (not t)
#+CCE_PRIORITY: 10
#+begin_src emacs-lisp
(provide 'cce/ivy-posframe)
#+end_src
[[https://github.com/tumashu/ivy-posframe][Ivy/PosFrame]] is an [[id:cce/emacs][Emacs]] [[id:9cbcc3b3-321b-4830-96a5-58000d595c4b][Glue Library]] which allows me to take the [[id:cce/ivy_and_counsel][Ivy]] minibuffer and display it in a temporary Emacs frame, which in [[id:modern_interface_terms][Modern Interface Terms]] means that it appears in a dedicated window above my Emacs window, rather than taking a section of it. In EXWM this has the added benefit of not forcing windows to constantly re-size themselves whenever I hit =M-x= or go to swap buffers.
Configuration is more or less taken from the repository's =README.md= file, except that I tell it to display most things at frame center, where my eyes are likely going to find it most easily. Swiper, however, gets to stay pinned to its parent frame, since it needs to stay out of the way when I am looking at text. Of note here as well, I set =parent-frame= to nil in the temporary frame created by =posframe=, which allows them to float above EXWM-managed windows, based on advice provided in [[https://github.com/ch11ng/exwm/issues/550][this GitHub issue]].
#+begin_src emacs-lisp
(use-package ivy-posframe
:diminish
:config
(setq ivy-posframe-parameters '((left-fringe 10)
(right-fringe 10)
(z-group . above)
(parent-frame nil))
ivy-posframe-display-functions-alist '((swiper . ivy-display-function-fallback)
(complete-symbol . ivy-posframe-display-at-point)
(t . ivy-posframe-display-exwm)))
(ivy-posframe-mode))
#+end_src
EXWM and Ivy/PosFrame don't interact well, as hinted above, and in the case of having multiple monitors, Ivy/PosFrame simply doesn't know where to put the window, causing it to appear off-screen at a logical 0,0 coordinate. Ivy/PosFrame lets users define our own display-function, and someone in the thread above implemented one which uses EXWM's workspace metadata to construction a frame location. I haven't tried it, and need to integrate it properly the next time I am on my desktop. I implemented something similar but this is more clear.
#+begin_src emacs-lisp
(defun ivy-posframe-display-exwm (str)
(if (memq #'exwm-init after-make-frame-functions)
(ivy-posframe--display str
(lambda (info)
(let* ((workarea (elt exwm-workspace--workareas exwm-workspace-current-index))
(x (aref workarea 0))
(y (aref workarea 1))
(fw (aref workarea 2))
(fh (aref workarea 3))
(pw (plist-get info :posframe-width))
(ph (plist-get info :posframe-height)))
(cons (+ x (/ (- fw pw) 2)) (+ y (/ (- fh ph) 2))))))
(ivy-posframe-display-at-frame-center str)))
#+end_src