Copilot 打开时会弹出一个 warning,如果你使用了 popper 管理这个 warning 窗口而且设置 popper-display-function
为 popper-select-popup-at-bottom
,那么在弹出 warning 时会导致 current-buffer
转移到 warning 窗口,进而导致后续操作和 hooks 中各种函数发生错误(因为他们仍然以为自己在原来的 buffer 中)。
鉴于这个问题可能会带来意想不到的错误,因此仅修改 copilot 的代码是不够的,最好从根源上解决这个问题。解决的办法是允许 popper 根据定义的规则自行选中弹出的窗口是否应该被选中。在研究了 popper 的代码后我发现实现这一点并不容易,并且作者也不希望在这个包中实现这个功能(为了正交性)。因此我用一个 hack 一些的手段实现了这个操作。
:init
(setq +popper-reference-buffers-select ;; ...
+popper-reference-buffer-no-select ;; ...
popper-reference-buffers (append +popper-reference-buffers-select
+popper-reference-buffer-no-select))
;; ...
:config
;; HACK: do not select window in `+popper-reference-buffer-no-select'
(defvar +popper-unpacked-vars '(popper--reference-names
popper--reference-modes
popper--reference-predicates
popper--suppressed-names
popper--suppressed-modes
popper--suppressed-predicates))
(defvar +popper-unpacked-vars-no-select '())
(dolist (var +popper-unpacked-vars)
(let ((var-name (intern (concat "+" (symbol-name var) "-no-select"))))
(eval
`(progn
(defvar ,var-name nil)
(push ',var-name +popper-unpacked-vars-no-select)))))
(setq +popper-unpacked-vars-no-select (reverse +popper-unpacked-vars-no-select))
(cl-progv `(popper-reference-buffers ,@+popper-unpacked-vars)
(list +popper-reference-buffer-no-select)
(popper--set-reference-vars)
(dolist (var +popper-unpacked-vars)
(eval `(setq ,(intern (concat "+" (symbol-name var) "-no-select")) ',(symbol-value var)))))
(defun +popper-smart-popup-at-bottom (buffer &optional alist)
(let ((window (popper-display-popup-at-bottom buffer alist)))
(unless (cl-progv +popper-unpacked-vars
(mapcar #'symbol-value +popper-unpacked-vars-no-select)
(popper-popup-p buffer))
(select-window window))))
(setq popper-display-function #'+popper-smart-popup-at-bottom)