Open fab4100 opened 6 days ago
The reason we only allow a prefix is to make readtags
perform fast binary search over huge tags files. I've tested your patch, but the performance difference is quite noticeable for a tags file of hundreds of MBs.
Thanks for the referenced issue, I missed that somehow. It would be nice to have a homogeneous interface between Tags
and BTags
while still get the benefit of readtags
. My proposal above is actually not homogeneous since the query would need to be sanitized first to get a POSIX compatible extended regex that is passed to readtags
for pre-filter and actual user query should be passed as initial prompt to fzf
call for post-filter. I will do some more benchmarking to see if something like that is possible using readtags
as a pre-filter.
It would be nice to have a homogeneous interface between
Tags
andBTags
while still get the benefit ofreadtags
.
I don't think it's possible. You can't avoid scanning through the whole list for non-prefix queries.
If performance is not a concern for you, you can redefine Tags
command like so in your configuration file.
command! -bang -nargs=* Tags call fzf#vim#tags('', fzf#vim#with_preview({ "options": ['--query', <q-args>], "placeholder": "--tag {2}:{-1}:{3..}" }), <bang>0)
Original definition:
https://github.com/junegunn/fzf.vim/blob/c5ce7908ee86af7d4090d2007086444afb6ec1c9/plugin/fzf.vim#L65
I believe you are correct. Using readtags
with a regex as pre-filter is not viable from performance point of view. For people who use rg
already and are willing to sacrifice some performance, it may be an option to use as the source filter in fzf#vim#tags(query, ...)
.
Here are a few test results (the first test result corresponds to the implementation I use in the commit above):
Linux kernel tags file:
du tags = 1.2G tags
query = 'munmap'
GOLD: readtags -t tags -e -p - "${query}"
real 0m0.001s
user 0m0.000s
sys 0m0.001s
Matches: 6
TEST: readtags -t tags -e -Q "(#/^[^[:space:]]*${query}\$/ \$name)" -l
real 0m9.632s
user 0m9.554s
sys 0m0.070s
Matches: 44
TEST: readtags -t tags -e -Q "(#/^${query}/ \$name)" -l
real 0m4.300s
user 0m4.238s
sys 0m0.060s
Matches: 6
TEST: rg ^${query} tags
real 0m0.218s
user 0m0.162s
sys 0m0.056s
Matches: 7
TEST: rg ${query} tags
real 0m0.215s
user 0m0.158s
sys 0m0.056s
Matches: 85
TEST: grep ^${query} tags
real 0m0.440s
user 0m0.360s
sys 0m0.080s
Matches: 6
Some other large project (tags file one order of magnitude smaller than Linux kernel):
du tags = 82M tags
query = 'BulkData'
GOLD: readtags -t tags -e -p - "${query}"
real 0m0.001s
user 0m0.001s
sys 0m0.000s
Matches: 31
TEST: readtags -t tags -e -Q "(#/^[^[:space:]]*${query}\$/ \$name)" -l
real 0m0.417s
user 0m0.414s
sys 0m0.003s
Matches: 49
TEST: readtags -t tags -e -Q "(#/^${query}/ \$name)" -l
real 0m0.289s
user 0m0.289s
sys 0m0.000s
Matches: 31
TEST: rg ^${query} tags
real 0m0.012s
user 0m0.006s
sys 0m0.006s
Matches: 31
TEST: rg ${query} tags
real 0m0.012s
user 0m0.000s
sys 0m0.012s
Matches: 4112
TEST: grep ^${query} tags
real 0m0.046s
user 0m0.046s
sys 0m0.000s
Matches: 31
If I understand your suggestion w/r/t redefining the Tags
command, it would result in calling tags.pl
with an empty query. For a tags file of the size of Linux kernel, this would result in:
TEST: perl ../bin/tags.pl "" tags | rg ^${query}
real 0m8.072s
user 0m7.957s
sys 0m0.659s
Matches: 7
whereas using rg
as a source filter in fzf#vim#tags(query, ...)
would result in something in the order of
TEST: rg ^${query} tags
real 0m0.218s
user 0m0.162s
sys 0m0.056s
Matches: 7
which I could consider as performance trade-off at the benefit of homogeneous Tags/BTags
interface (but not really the perl
solution above).
From your perspective, is it possible to support a custom 'source'
filter in fzf#vim#tags(query, ...)
to avoid copy-pasting fzf#vim#tags(query, ...)
to my personal config just to change that line?
The
BTags
command is declared with optional[QUERY]
while theTags
command is declared with optional[PREFIX]
. The query behavior inBTags
source generator is less restrictive compared toTags
whose source is generated using thereadtags
external command, where tags are only listed ifPREFIX
is an exact match. This commit relaxes the exact prefix match whenreadtags
is used to allow for a fuzzy prefix similar to the source generator ofBTags
. Thefzf
fuzzy score ranking in thes:tags_sink
will still rank the best fuzzy match on top, same as if the match was exact like in the current implementation.The changes in this commit are useful for tags that contain some scope prefixes like the functions
s:tags_sink
orfzf#vim#tags
in vim-script code, in combination with a key mapping of the formIf the cursor is placed on the word "tags" in this example
fzf#vim#tags
, the relaxedTags
query call will list the tags entry if<cword>
expands to "tags", while the current implementation will not. Inconsistently, theBTags
call will list the tags entry with its current implementation.