Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Matching with word boundaries #3963

Closed
4 of 10 tasks
maxaykin opened this issue Aug 9, 2024 · 7 comments · Fixed by #3967
Closed
4 of 10 tasks

Matching with word boundaries #3963

maxaykin opened this issue Aug 9, 2024 · 7 comments · Fixed by #3967
Labels

Comments

@maxaykin
Copy link

maxaykin commented Aug 9, 2024

Checklist

  • I have read through the manual page (man fzf)
  • I have searched through the existing issues
  • For bug reports, I have checked if the bug is reproducible in the latest version of fzf

Output of fzf --version

0.54.3 (c423c49)

OS

  • Linux
  • macOS
  • Windows
  • Etc.

Shell

  • bash
  • zsh
  • fish

Problem / Steps to reproduce

Hello,

recently I started using fzf (mainly with vim which is my primary development editor) and it is really a game-changer for me. Unfortunately, there is a major weakness which I face quite often in my daily work: inability to make fzf query more strict by specifying that its part(s) should be matched against whole word(s), i.e. with word boundary check.

The sequence of actions is usually as follows:

  • in vim: feeding fzf in fuzzy mode with results from 'ag' to find where a term is used in source code
  • finding hundreds or even thousands of lines
  • trying to reduce the number of results by prefixing the pattern with '
  • there are still too many results (e.g. if I look for a variable "Window" there may be many results like "bottom_window" or "InitWindow()")
  • switching to other methods like running 'ag -w' in shell

It would be very helpful to have a way to toggle word boundaries check for a part of query, for example by:

  • prefixing with "
  • surrounding with '
  • introducing regular expressions of some kind

Also it would be very nice to keep fuzzy mode still possible for other parts of the same query.

I know there are a number of similar issues requesting features like toggling "case + non-fuzzy" mode or something. It seems the closest one is #2394. Sadly, it looks like such requests are often rejected, so here are some argument in favor.

In my opinion, now fzf is not just a fuzzy finder, its primary goal is to allow a quick selection of one or few items among many others. It provides different modes and ways for doing that. It is a selector as such, it can switch quickly between fuzzy and non-fuzzy mode, it can stick the search pattern to beginning or end of line and so on. Thus, it is very disappointing if none of those modes and switches help and fzf still fails to limit the number of items in the list enough.

Switching to a different source of data (e.g. running ag with '-w') is too long and inconvenient and it may require several iterations of refining the query pipeline.

As a programmer I have had a quick look at the sources of fzf (though, I haven't used Golang before) and it seems the implementation should not be difficult. Please, consider it.

@junegunn
Copy link
Owner

junegunn commented Aug 10, 2024

  • switching to other methods like running 'ag -w' in shell

Switching to a different source of data (e.g. running ag with '-w') is too long and inconvenient and it may require several iterations of refining the query pipeline.

I think you're looking for change:reload approach explained in https://junegunn.github.io/fzf/tips/ripgrep-integration/

fzf.vim provides this functionality as :RG (all caps) command.

@maxaykin
Copy link
Author

Thank you for the quick response!

I have already been using reload with a binding for viewing git commits via fzf (for switching between all commits and current branch commits) but I missed the idea that the whole query can be passed to external command and that the reload can be initiated on every change of the query string. This way it is even possible to use regexp in the query. Cool! Though, isn't it to expensive to re-run rg/ag on a large set of files after every single keypress (when it changes the query string)?

Anyway, it still looks to me more natural and convenient (considering the existing switches of the extended search mode) and also quicker (no reload of data) and more unified (taking into account different commands in vim where fzf is used) to add just another switch for enabling word boundary for parts of the search query. I have already done that (a draft version) for myself in a local repository of fzf and so far it looks to be working fine. Probably I will stick to this approach.

@junegunn
Copy link
Owner

isn't it to expensive

It depends. It can be more expensive to load everything in memory and run fuzzy matching algorithm which is likely less efficient than the search algorithm of ripgrep in this particular scenario. Anyway, it works really well, and the performance has never been an issue for me. You should try it out yourself.

@maxaykin
Copy link
Author

I have just had a first try of it. Yes, it looks to be working well (though, I executed 'ag' instead of 'rg' with fzf#vim#grep2()). And I agree that the performance depends on scenario: the reload seems to be better with separate independent queries while loading everything at start and then just filtering with fzf may be preferable when you do a research on the same source data (code base) and when on each iteration you inspect results in the preview window and change the query to find something else without returning to vim/shell (this is sometimes the case for me).

However, the approach with reload proposed by you does not allow combining part of queries bound to words with parts that should be matched with fuzzy algorithm. And also I doubt that it is usable in cases when the source of data is not a grep-like command. Anyway, thank you for the very good tool and your help!

Just in case if someone (as me) still wants feature "Matching with word boundaries", here is my draft version in a fork repository: maxaykin@38d37d7

@junegunn
Copy link
Owner

FWIW,

  1. There is an example in ADVANCED.md where you can dynamically switch between fzf mode and ripgrep mode.
  2. You can match literal space by escaping it with a backslash, so I think '\ foo\ can help in some cases.

@junegunn
Copy link
Owner

Just in case if someone (as me) still wants feature "Matching with word boundaries", here is my draft version in a fork repository: maxaykin@38d37d7

No need to duplicate the majority of the code. We can just look at the bonus points to determine if one end is at a word boundary. Also, it better handles non-ASCII characters. See #3967

junegunn added a commit that referenced this issue Aug 13, 2024
@maxaykin
Copy link
Author

No need to duplicate the majority of the code. We can just look at the bonus points to determine if one end is at a word boundary. Also, it better handles non-ASCII characters.

Yes, I suspected that but had not time to dig into the logic (besides, that was the first time I changed Golang source code).
Thank you for your efforts!

junegunn added a commit that referenced this issue Aug 16, 2024
junegunn added a commit that referenced this issue Aug 23, 2024
junegunn added a commit that referenced this issue Aug 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants