[Feature] Dynamic transform-pos() Action
- [x] I have read through the manual page (
man fzf) - [x] I have the latest version of fzf
- [x] I have searched through the existing issues
Info
- OS
- [x] Linux
- [ ] Mac OS X
- [ ] Windows
- [ ] Etc.
- Shell
- [ ] bash
- [x] zsh
- [ ] fish
Ask
A new binding transform-pos() which resolves similarly to transform-prompt() or transform-label(). Specifically:
- Resolve the command within the parentheses.
- Use the result as if it was an argument to pos().
User Story
I have a logging which outputs 100k+ logs, for which I am using fzf to parse through. I want to search something, say "codec", select a search result, clear the query, and then go to where that search result is. Each log has a unique line number, so I could go to that line through:
--bind enter:clear-query+transform-pos(grep -n ... {})
My current solution is to use a preview window to see around the log, but that is limited and uses up the preview window, which I'd rather use for other things. I can also print all the input to a file with context lines to make it easier to find the line, but that doesn't fundamentally solve the problem because I still need to go and find the line. I can also restart fzf and dynamically tell it to go to the correct line, but that seems like overkill and is very slow.
#!/usr/bin/env bash
# Switch between Ripgrep launcher mode (CTRL-R) and fzf filtering mode (CTRL-F)
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
INITIAL_QUERY="${*:-}"
IFS=: read -ra selected < <(
FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
fzf --ansi \
--color "hl:-1:underline,hl+:-1:underline:reverse" \
--disabled --query "$INITIAL_QUERY" \
--bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
--bind "ctrl-f:unbind(change,ctrl-f)+change-prompt(2. fzf> )+enable-search+clear-query+rebind(ctrl-r)" \
--bind "ctrl-r:unbind(ctrl-r)+change-prompt(1. ripgrep> )+disable-search+reload($RG_PREFIX {q} || true)+rebind(change,ctrl-f)" \
--prompt '1. Ripgrep> ' \
--delimiter : \
--header '╱ CTRL-R (Ripgrep mode) ╱ CTRL-F (fzf mode) ╱' \
--preview 'bat --color=always {1} --highlight-line {2}' \
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
)
[ -n "${selected[0]}" ] && nvim "${selected[0]}" "+${selected[1]}"
This is an old issue but I just wanted to see if you have tried this script already? it uses ripgrep which is really great for a large amount of files. You could edit it to fit your needs better. You could mark file lines and set a binding to dump them to another tmpfile or function. Maybe I just dont completely understand what you're trying to achieve though
Hey sweetbbak,
That's a neat little script, I quite like it. Unfortunately, it doesn't solve my use case. Here is a specific example:
Say I have a log file of 100k lines. In my actual application, I'm streaming this log as I'm searching, but let's say it's static for now. I search for the word 'codec', and get these results:
10534: ...codec...
14334: ...codec...
15534: ...interesting?_codec...
25534: ...interesting?_codec...
55534: ...codec...
84534: ...interesting?_codec...
87334: ...codec...
Now, I can start a preview window to look at the context around each line I've found, that's pretty easy. I scroll around a bit, and determine that line 25534 is the one I'm looking for. What I'd like to do is just go to that line in the fzf output with:
--bind "ctrl-space:clear-query+transform-pos(cut -d':' -f1 <<< {})"
While it's possible to dump the lines into another file to view them, that slows down my ability to view logs significantly. My purpose in using fzf is specifically so I don't have to use a file and rg to view the logs, and can do so dynamically. The script above can be used to search around, and can be hacked together with the context flag to do vaguely the same thing, but so can a preview window. My goal here is to get a native solution that allows the simplest solution to just jump to the line in question.
I wish I could share some specific code, but unfortunately I am bound by copyright right now.
The problem with this approach is that the filtering runs asynchronously in a separate thread and you don't have the full list right after you clear-query.
# pos(5) doesn't move the cursor to row 5, because the result set has only one item at the moment
# But if you press enter again, it will go to the row
seq 100 | fzf --bind 'enter:clear-query+pos(5)' --query 99
The same holds true for change-query and transform-query.
I see, I was not aware of that. I think that practically precludes this feature for my use case. This would require some sort of sync command that would ensure that a query change could be executed and synced before the next command ran, something like:
enter:clear-query+wait-for-list+transform-pos({})
However, that seems impractical and likely interferes with the established architecture for what seems like a relatively rare use-case. Feel free to close this issue; I will attempt to find a different workaround.
Thank you!
Thanks. I'm going to leave this open for a while and see if we can come up with a better idea to support the use case.
Please see if the --track option I added in 1c7534f suits your needs.
I'll check on the next release. If this works as described, it will also solve a number of other problems relating to scroll locking and active input streams.
Thanks for the implementation!
I have filed one bug related to this item here:
http://go/fzf/issues/3234
Secondarily, would it be possible to have an option to bind to "toggle-track" and "enable-track/disable-track"?
My use-case here is that I'd like to use track in conjunction with --tac to read logs, with standard behaviour being the log scrolling at the bottom. When I enable track, it effectively enters a scroll-lock mode, and when I search for queries, I can just jump to them quickly by clearing the query. When I disable track, I can see the log scrolling by in real time as I perform actions.
Thanks!