21

I have been using flx-ido-mode for a while and I like it. Ivy can behave the same way by using ivy--regex-fuzzy.

The problem is that swiper will also use fuzzy matching now and in this case I don't really like it (at least not as a default, all the time).

So I'd like to continue using fuzzy matching with Ivy except in swiper. Is there a way to configure this? Or can I somehow tell swiper that I'm really looking for "this" substring right now by prefixing something?

Basil
  • 12,019
  • 43
  • 69
B_old
  • 717
  • 5
  • 14

2 Answers2

25

I'd like to continue using fuzzy matching with Ivy except in swiper.

The variable that determines which "regexp builder", as Ivy refers to these functions, is used for which collection function is ivy-re-builders-alist:

ivy-re-builders-alist is a variable defined in ‘ivy.el’.
Its value is ((t . ivy--regex-plus))

Documentation:
An alist of regex building functions for each collection function.

Each key is (in order of priority):
1. The actual collection function, e.g. ‘read-file-name-internal’.
2. The symbol passed by :caller into ‘ivy-read’.
3. ‘this-command’.
4. t.

Each value is a function that should take a string and return a
valid regex or a regex sequence (see below).

Possible choices: ‘ivy--regex’, ‘regexp-quote’,
‘ivy--regex-plus’, ‘ivy--regex-fuzzy’.

If a function returns a list, it should format like this:
’(("matching-regexp" . t) ("non-matching-regexp") ...).

The matches will be filtered in a sequence, you can mix the
regexps that should match and that should not match as you
like.

So, in order to change the default regexp builder from ivy--regex-plus to ivy--regex-fuzzy, but keep the former for swiper, you could

(setq ivy-re-builders-alist
      '((swiper . ivy--regex-plus)
        (t      . ivy--regex-fuzzy)))

or, more programmatically,

(with-eval-after-load 'ivy
  (push (cons #'swiper (cdr (assq t ivy-re-builders-alist)))
        ivy-re-builders-alist)
  (push (cons t #'ivy--regex-fuzzy) ivy-re-builders-alist))

This is described in more detail in (ivy) Completion Styles.

I don't really like [fuzzy matching] (at least not as a default, all the time)

Ivy allows you to rotate the regexp builder on the fly via its hydra interface. The fairly hidden last sentence of (ivy) ivy--regex-fuzzy alludes to this, and a more complete description can be found under (ivy) Hydra in the minibuffer, but it looks like the manual is a bit outdated given it's been a little while since the last release.

The upshot is that, since 2017-07-04, Ivy allows you to cycle through regexp builders during completion via C-om (ivy-rotate-preferred-builders). Edit: as pointed out by Asme Just in a comment, the default key binding was changed to C-oM on 2019-02-06.

Basil
  • 12,019
  • 43
  • 69
  • Could you please elaborate on the completion cycling a bit? For example if I have started a swiper search, C-o will immediately give me a "command-execute: Cannot open load file: No such file or directory, ivy-hydra" message. – B_old Nov 10 '17 at 08:11
  • @B_old Try installing the optional `ivy-hydra` package first. The moral question of whether a default keybinding should exist for an optional (i.e. not always installed) feature [has already been raised](https://github.com/abo-abo/swiper/issues/1127) and the status quo seems unlikely to change soon. If you have other questions about `ivy-hydra` which the manual does not address, please consider creating new Emacs SE questions for them. – Basil Nov 11 '17 at 15:21
  • (`ivy-rotate-preferred-builders`) is `C-o M` for me currently by default. – Asme Just Feb 21 '19 at 12:54
  • @AsmeJust Thanks, that was a backward-incompatible change made just over 2 weeks ago: https://github.com/abo-abo/swiper/commit/28e88ab23a191420a93a4f920ca076674ee53f94 – Basil Feb 21 '19 at 17:45
  • For those stumbling on this page and blindly copy/pasting the top response, only to find out that it doesn't work, make sure you haven't rebound `C-s` to something else in swiper. In my case, I'd rebound it to `swiper-isearch`, so replacing `(swiper . ivy--regex-plus)` with `(swiper-isearch . ivy--regex-plus)` in the accepted answer fixed it. – user4601931 Apr 14 '21 at 03:21
  • @user4601931 Indeed, this Q&A was about `swiper` the command, not `swiper` the package as a whole. `ivy-re-builders-alist` works per-command, so if you're using the `swiper-isearch` command, you should indeed enter that in place of `swiper`. – Basil Apr 14 '21 at 11:08
7

If you want to turn off regex matching in swiper, but keep it active elsewhere, add this to your user-init-file:

(setq ivy-re-builders-alist
      '((swiper . regexp-quote)
        (t      . ivy--regex-fuzzy)))

If you want to deactivate it just once, hit M-r in swiper.

Basil
  • 12,019
  • 43
  • 69
cayhorstmann
  • 171
  • 1
  • 2
  • 2
    +1 for mentioning the handy `M-r` binding. Note, however, that OP only specified they want fuzzy matching disabled; which regexp builder should replace it was left unclear. – Basil May 20 '18 at 18:51