ggreer / the_silver_searcher

A code-searching tool similar to ack, but faster.
http://geoff.greer.fm/ag/
Apache License 2.0
26.2k stars 1.43k forks source link

Sort results in custom fashion #1394

Open connorbeckerle opened 4 years ago

connorbeckerle commented 4 years ago

I use ag a lot with fzf.vim to search through codebases. It works great most of the time. However, a frustrating UI thing with it is that it sorts results so that matches earlier in the line are higher priority, which makes sense on its own, but frequently means my tests/ dir is always higher priority in the results than actual source code in my long_app_name/ dir, since it automatically has a shorter prefix. So it would be nice to apply some sort of custom sorting rule; for instance, to give things matching regex "^tests/.*" -10 to their priority or something like that. Is that at all possible or is there an existing workaround?

What I currently do is remember to prefix the app name to my search, which isn't the worst thing in the world but I thought I'd ask about this.

bdlangton commented 2 years ago

I've been working on a way to do this. There are a couple of drawbacks to this method that I haven't figured out how to resolve yet

  1. It uses regex, so . will match any character, not just periods. I thought passing -Q to ag would fix it, but it isn't working.
  2. If you search multiple words separated by space, those words have to be next to each other to match. For example, without this customization, if I had a file like app/models/account.rb I could search account app and it would match. With this new filter it doesn't match.
  3. It's also slightly slower to filter results.

FZF_AWK_FILTER is key to determine which paths you want to prioritize. You can add on or take off some else if's depending on how many different paths you want to prioritize. I just prepend a number starting with 1 and counting up. Then prepend a 9 to everything that didn't match a previous filter. Then it sorts the results. Then I use awk again to remove the prepended numbers.

You could try using a different filter than ag, and obviously might not want to use all the flags that I use. I also just realized this probably will need modified if you have file paths that have spaces.

It'd be nice to be able to still use the normal filtering on change:reload but still pipe it through awk. I'm not sure how to do that yet.

let $FZF_AWK_FILTER='awk ''{if (/app\/models\//) {print "1 " $0} else if (/app\//) {print "2 " $0} else if (/spec\//) {print "3 " $0} else {print "9 " $0}}'' | sort -n | awk ''{print $2}'''
let $FZF_DEFAULT_COMMAND="ag -U --column --hidden -W 120 -S -g '' | " . $FZF_AWK_FILTER

function! FzfFiles(query, awk_filter)
  let command_fmt = "ag -U --column --hidden -W 120 -S -g '%s' | %s"
  let reload_command = printf(command_fmt, '{q}', a:awk_filter)
  let spec = {'options': ['--phony', '--bind', 'change:reload:'.reload_command]}
  call fzf#vim#files(a:query, fzf#vim#with_preview(spec))
endfunction

command! -nargs=? -bang Files call FzfFiles(<q-args>, $FZF_AWK_FILTER)