ivy-posframe-avy 一闪而过,ivy-posframe-swiper-avy 显示位置不对

M-x, C-h-f, C-h-v 中使用 ivy-posframe-avy, avy-keys 会显示在每行候选项的左端,但是一闪而过。但是继续按相应的 avy-keys,仍然是有效果的。

另外在 swiper 中使用 ivy-posframe-swiper-avy, avy-keys 显示在被搜索的 buffer 中,而不是在 ivy-posframe frame 中。

我在以下的配置中测试会出现上述问题

(use-package counsel 
  :ensure t
  :diminish counsel-mode
  :after ivy
  :bind (("M-r" . counsel-register)
	 ("M-y" . counsel-yank-pop)
	 ("C-x d" . counsel-dired)
	 :map ivy-minibuffer-map ("M-y" . ivy-next-line))
  :init
  (counsel-mode)
  :config
  (setq counsel-dired-listing-switches "-alhtgG"))

(use-package ivy 
  :ensure t 
  :diminish (ivy-mode) 
  :bind (("C-x b" . ivy-switch-buffer))
  :init
  (ivy-mode)
  :config
  (setq ivy-use-virtual-buffers t) 
  (setq ivy-count-format "%d/%d ") 
  (setq ivy-display-style 'fancy)
  (setq ivy-initial-inputs-alist '((counsel-minor . "^+")
				   (counsel-package . "^+")
				   (counsel-org-capture . "^")
				   (counsel-M-x . "^")
				   (counsel-describe-symbol . "^")
				   (org-refile . "^")
				   (org-agenda-refile . "^")
				   (org-capture-refile . "^")
				   (Man-completion-table . "^")
				   (woman . "^")
				   (ryb-register . "^")
				   (counsel-register . "^"))))

(use-package ivy-avy
  :ensure t)

(use-package swiper 
  :ensure t 
  :bind (("C-s" . swiper) 
	 ("M-x" . counsel-M-x)
	 ("C-t" . isearch-forward)
	 ("C-x C-f" . counsel-find-file)) 
  :config
  (progn 
    (setq ivy-use-virtual-buffers t) 
    ;; (setq ivy-display-style 'fancy) 
    (define-key read-expression-map (kbd "C-r") 'counsel-expression-history)))

(use-package avy 
  :ensure t 
  :bind (("M-s" . avy-goto-word-1)
	 ("M-S" . avy-goto-char))
  :config
  (setq avy-all-windows nil)
  (setq avy-line-insert-style 'below)
  (setq avy-orders-alist '((avy-goto-char . avy-order-closest)
			   (avy-goto-word-1 . avy-order-closest))))


(use-package ivy-posframe
  :ensure t
  :diminish ivy-posframe-mode
  :config
  (setq ivy-posframe-display-functions-alist
	'((t . ivy-posframe-display-at-frame-bottom-left)))
  (setq ivy-posframe-parameters
	'((left-fringe . 8)
          (right-fringe . 8)))
  (setq ivy-posframe-border-width 2)
  :init (ivy-posframe-mode 1))

请教大家如何解决这两个问题?

不会啊,显示正常。你要的是这效果吧

是的,我这边这个效果就是一闪而过。我在 archlinux 和 windows 上都试过,结果都是一闪而过 :sob:

你有没有用emacs -Q 试试?

非常感谢开发者的回复 :grinning:

我用如下方式做了测试,结果仍是一闪而过 (限于我有限的 emacs 知识,如有不合适的,请指正):

  1. 在终端中用 emacs -q 启动
  2. 对如下的文件用了 eval-buffer
(tool-bar-mode 0)
(scroll-bar-mode 0)

(require 'package)
(setq package-enable-at-startup nil)

(package-initialize)

;; Bootstrap `use-package'
(unless (package-installed-p 'use-package) 
  (package-refresh-contents) 
  (package-install 'use-package))

;; ------------------------

(require 'ivy-avy)

(require 'swiper)

(global-set-key "\C-s" 'swiper)
(global-set-key (kbd "M-x") 'counsel-M-x)
(global-set-key (kbd "C-x C-f") 'counsel-find-file)

(require 'ivy-posframe)

(ivy-posframe-mode 1)

这个问题可能和 ivy-posframe randomly blink #21 有关。

加载 kongds 的如下代码后,ivy-posframe-avy 一闪而过的问题就解决了。

(defvar ivy-posframe--first-show t)
(defun ivy-posframe-cleanup ()
  "Cleanup ivy's posframe."
  (setq ivy-posframe--first-show t)
  (when (posframe-workable-p)
    (posframe-hide ivy-posframe-buffer)))
(defun ivy-posframe--display (str &optional poshandler)
  "Show STR in ivy's posframe with POSHANDLER."
  (if (not (posframe-workable-p))
      (ivy-display-function-fallback str)
    (with-ivy-window
      (if (not ivy-posframe--first-show)
          (with-current-buffer ivy-posframe-buffer
            (erase-buffer)
            (insert str))
          (setq ivy-posframe--first-show nil)
          (apply #'posframe-show
                 ivy-posframe-buffer
                 :font ivy-posframe-font
                 :string str
                 :position (point)
                 :poshandler poshandler
                 :background-color (face-attribute 'ivy-posframe :background nil t)
                 :foreground-color (face-attribute 'ivy-posframe :foreground nil t)
                 :internal-border-width ivy-posframe-border-width
                 :internal-border-color (face-attribute 'ivy-posframe-border :background nil t)
                 :override-parameters ivy-posframe-parameters
                 (funcall ivy-posframe-size-function)))
      (ivy-posframe--add-prompt 'ignore)))
  (with-current-buffer ivy-posframe-buffer
    (setq-local truncate-lines ivy-truncate-lines)))

关键问题是,为什么会出现闪烁?

我比对了上述 kongds 的代码和原始的 ivy-posframe--display 代码,主要起作用的是下面这行:

:hidehandler #'ivy-posframe-hidehandler

进一步,修改 ivy-posframe-avy 如下

(defun ivy-posframe-avy ()
  "Ivy-posframe's `ivy-avy'."
  (interactive)
  (let ((avy-pre-action #'ignore))
    (message "buffer-name-outside is %s" (buffer-name))    ;; Line 1
    (with-selected-window (ivy-posframe--window)
      (message "buffer-name-inside is %s" (buffer-name)) ;; Line 2
      (ivy-avy))))

并在 M-x 中用 ivy-posframe-avy (按 C-'),返回如下

buffer-name-outside is  *Minibuf-1*                        ;; Line 1
buffer-name-inside is  *ivy-posframe-buffer*               ;; Line 2

在测试过程中,ivy-posframe-hidehandler 一直在执行,从而在 ivy-posframe-avywith-selected-window (ivy-posframe--window) 后,似乎有个窗口短暂的变换过程导致 ivy-posframe-hidehandler 返回 t

今天看了 @tumashu 提交的commit:Fix: ivy-posframe disappear in a flash after ivy-posframe-avy #114 · tumashu/ivy-posframe@61ff941 · GitHub ,才发现为啥我的Centaur没有闪烁,是因为我自己重写了 ivy-posframe-hidehandler :joy:

看来我的patch也可以去掉了。。。 :smile: 不过,@tumashu 你的修改这个效率咋样?

应该不对效率有多大影响,毕竟是 timer 运行的函数。

1 个赞