1

When using ivy, say I want the current match to be red when calling counsel-M-x, but blue when calling counsel-find-file.

Is there a simple way of changing ivy-current-match depending on the function calling it?

1

AFAIK, there is no built-in support for this, but Ivy provides various hooks that you can plug your own logic into. Here is one way to achieve what you want, using the ivy-hooks-alist user option:

(defvar my-ivy-match-faces
  '((counsel-M-x (:background "red")))
  "Alist mapping Ivy callers to a list of face specs.
Used by `my-ivy-remap-match-face', which see.")

(defun my-ivy-remap-match-face ()
  "Locally remap `ivy-current-match' to caller-specific face specs.
Which face specs to apply for each caller is determined by
`my-ivy-match-faces'.  If the current caller is unknown, or if
there is no entry for it, no remapping is applied."
  (when-let* ((caller (ivy-state-caller ivy-last))
              (specs  (alist-get caller my-ivy-match-faces)))
    (apply #'face-remap-add-relative 'ivy-current-match specs)))

(with-eval-after-load 'ivy
  ;; Remap the current match face as the default Ivy hook.  Note that specifying
  ;; a different hook for a particular caller will override this setting.
  (setf (alist-get t ivy-hooks-alist) #'my-ivy-remap-match-face))

The idea here is to look up the current Ivy caller (e.g. counsel-M-x) right after Ivy has set up the minibuffer, and then locally remap[1] the ivy-current-match face to a list of face specs of your choosing. In the sample code above, I have remapped the background to be red for counsel-M-x (see the variable my-ivy-match-faces).

Note that the way I modify ivy-hooks-alist, namely by setting my-ivy-remap-match-face as the default fallback hook, is kind of brittle. This is because any subsequent addition to this alist may override my-ivy-remap-match-face. Vanilla Ivy does not modify ivy-hooks-alist, so this is not an issue at the moment, but it may become one in the future or if you use other packages which modify this user option.

A more robust solution would then be to submit a feature request or PR[2] to make ivy-hooks-alist more flexible, e.g. by supporting multiple hooks per caller, and always running the default fallback hooks.

If that is not an option, you can advise[3] specific entries in ivy-hooks-alist to do your bidding. I will be happy to provide a sample implementation of this if asked.

| improve this answer | |
  • this is almost perfect. Your solution changes the color of the current line. The only issue is that when I start typing, the matched characters show up in the default color of ivy-current-match. I tried to fix this by also remapping ivy-prompt-match, but this doesn't seem to control the color of the matched characters. – scaramouche Feb 10 at 18:56
  • @scaramouche I cannot reproduce what you describe. Please update your question with a step-by-step reproduction recipe, describing what you expect and what you actually see, ideally with screenshots, at every step. – Basil Feb 17 at 9:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.