Hi,
I'd like to be able to have lf jump automatically to a file (or enter the directory) if the contents of the search prompt matches a unique entry, unambiguously.
Thanks.
That would be sth like the ranger's f command I talked about a while ago. I'd like to see it as well.
I wondered if this would be possible with some scripting, instead of introducing another builtin command? Sth like (pseudocode) var path=lf.search(<entered_letters>); if $path { lf.cd($path) }, but (probably much) more robust.
@KenjiTakahashi I remember you mentioned this before. I have been thinking about this for a while. Ranger also has something like directory flattening. If you combine these two features you can get a basic fuzzy finder like fzf or ctrlp. I have only used ctrlp briefly before but I understand these tools are very common. I wonder if instead we should try to integrate fzf within a custom command which you can simply bind to a key. To me they seem like two different ways to work with files so maybe it is better they are left as separate tools.
I'm already using fzy, and there are a few things that make it unpractical:
lf itself considering I don't want fuzzy matching (just substring matching)tmux and dvtm are supported by fzy right now)Here's my binding:
cmd fzy ${{
path=$(ls -a1 | fzy-tmux)
if [ -z "${path}" ]; then
exit
fi
if [ ! -d "${path}" ]; then
path=$(readline -e "$(dirname "${path}")")
fi
lf -remote "send ${id} cd '${path}'"
}}
map F fzy
@lenormf why do you need to use fzy-tmux instead of fzy? I have just tried to use it with fzy and it seems to work fine without a multiplexer and does not create a new window. Spawning a process should not be heavy for sh or bash. I think the real overhead is populating the list which in your example command shouldn't be a problem since you use ls. If you want to use find for recursive matching you can also limit the depth with -maxdepth option.
I wanted to make it so I would be able to move around in the main pane containing the lf instance before picking a candidate in the fzy pane, but apparently that's not possible. So I've changed fzy-tmux with fzy -l $(tput lines).
I try not to spawn too many process in my configuration in case I (or someone) ever needs it on cygwin, on which a fork is a very expensive operation in terms of time. Not really a deal breaker, but I try to think about it when scripting is involved.
Also -maxdepth is not portable with find, so I didn't have a choice to use ls for listing the working directory.
This is not to discard this feature request. We might at some point add a find command to lf but I feel like ranger's find command has a drawback. When you type a key you need to see if you have matched something or not before pushing another key or otherwise you might accidentally do unintended operations. If anything I would rather prefer a more basic single key initial matching as in vim.
@KenjiTakahashi I haven't given much thought about how to implement this yet but I doubt it would be possible with scripting. We need to do some single key handling while also keep showing the ui.
Yeah, I meant it for a possible "quick win", similar to ranger's (where, as you say, it doesn't really show you what's going on during the typing), but maybe it's no good.
If we want to go fancy, we could implement sth like vim's s command (see https://github.com/justinmk/vim-sneak). I.e. when you type a letter, all instances of such letter get highlighted, when you type another one, such pairs are highlighted, etc. That might be nice :-).
I'm a heavy user of s in vim, so I might be biased, though.
I wanted to make it so I would be able to move around in the main pane containing the lf instance before picking a candidate in the fzy pane, but apparently that's not possible
ERRATA: it is possible, I updated my configuration as follows (needs an extra GNU package on mac because it doesn't ship with readlink by default…):
cmd fzy ${{
send_path() {
path=$(readlink -e "${1}")
if [ -z "${path}" ]; then
exit
fi
if [ ! -d "${path}" ]; then
path=$(dirname "${path}")
fi
lf -remote "send ${id} cd '${path}'"
}
if [ -n "${DVTM}" ]; then
{
send_path "$(ls -a1 | fzy-dvtm -l $(tput lines))";
} </dev/null 2>&1 >/dev/null &
elif [ -n "${TMUX}" ]; then
{
send_path "$(ls -a1 | fzy-tmux -l $(tput lines))";
} </dev/null 2>&1 >/dev/null &
else
send_path "$(ls -a1 | fzy -l $(tput lines))"
fi
}}
map F fzy
Supports tmux, dvtm, or no multiplexer at all, and can be adapted to fzf easily (although I haven't tested with fzf).
Ok so I have added 4 commands for finding, namely find, find-back, find-next and find-prev, and two options, namely findlen and anchorfind. Default behavior is set to easily jump to files starting with a character, which is somewhat similar to some of the gui file managers. When findlen is set to zero, it waits until there is only a single match, so ranger's behavior, with the exception of opening the file automatically, can be set with:
set findlen 0
set noanchorfind
There are still a few things on my mind. Currently find commands shares some of the search options, namely wrapscan, ignorecase, and smartcase which I'm still not quite sure. Regarding fuzzy finding, it may not be accurate enough without ranking the choices, so maybe it is better to skip it for now to keep it simple.
Once we finalize these commands and options, I'm thinking of adding a section to the documentation. Then we can close this issue.
I like the way the search matches results, it feels more accurate than rangers implementation.
Is it possible to develop the search so that it jumps to the match while you are typing?
Also, is it possible to somehow get it to work with less keystrokes? For example, the arrow keys could immediately end the search and perform their normal function. I'm asking because I use typeahead a lot in gui filemanagers and scout for similar reason in ranger. The current search is excellent for single use, but gets quickly too slow if you try to navigate through multiple directories with it.
@Chrysostomus Sorry for the late reply.
For reference, this is incsearch in vim. I have been thinking about adding it for a while. We need to change the implementation to handle key inputs differently. Also I think it is better to have this feature with an option so it won't search for every file in the directory at each keystroke for regular uses.
For arrow keys, I need to check the code to see if this is possible. Also maybe we should think about it for a while to see if that would conflict with some other use cases. For example, some people like to assign up and down keys for cmd-history-next and cmd-history-prev though searches are not included in the history anymore.
Also, unfortunately I will be quite busy in the upcoming days and I won't have access to computers in october so it may take a while until I find a chance to work on this.
No hurry! I agree that this should be optional feature.
@Chrysostomus I have now implemented incsearch option. Arrow keys do not finish the search for now. The problem is that there is no such thing as an arrow key but there are only cmd- commands assigned to arrow keys. For now you can try to assign arrow keys to cmd-enter to finish the search as such:
cmap <up> cmd-enter
cmap <down> cmd-enter
This kind of works but it does not move the selected file in the first push but only finishes the search so it is a little bit unusual. We can try to add some new command line commands such as cmd-up and cmd-down to finish the search and move the selected file up or down with a single push but then we would need to add such commands for other movements as well. So maybe I was thinking we might allow assigning normal commands with cmap instead as follows:
cmap <up> up
cmap <down> down
Semantically this should mean to finish the search immediately and do the command afterwards. I need to check to see if this is possible or not. Also I'm not sure how this would interact with the rest of the command line functionality yet.
@Chrysostomus It seems that normal commands can already be assigned in cmap and I have just added some logic to get back to normal mode for commands without cmd- prefix. Now the following mappings I mentioned above finish the search and start moving the selected file:
cmap <up> up
cmap <down> down
I will be trying this for a while to see if I have broken something or not. Then we can actually close this issue.
Awesome! Thank you
Great, thanks.
I have added a section "Searching Files" to the documentation. Closing this issue now.
I had to disable normal commands with cmap since there have been a few crucial bugs that I couldn't fix. We may have to implement arrow keys in another way instead of letting normal commands with cmap. I'm reopening this issue in the meantime. Sorry for inconvenience.
I have now pushed another commit to allow cmap with some movement commands only, specifically up, down, half-up, half-down, page-up, page-down, updir, and open. This should not have the same issues as before. I will be trying this in the next couple of days to make sure. Closing this issue now.
I'm already using
fzy, and there are a few things that make it unpractical:
- it spawns a process, which if kind of heavy, whereas searching is a feature that should best stay within
lfitself considering I don't want fuzzy matching (just substring matching)- it requires another window to be created to display the list
- you need to be using a multiplexer (
tmuxanddvtmare supported byfzyright now)Here's my binding:
cmd fzy ${{ path=$(ls -a1 | fzy-tmux) if [ -z "${path}" ]; then exit fi if [ ! -d "${path}" ]; then path=$(readline -e "$(dirname "${path}")") fi lf -remote "send ${id} cd '${path}'" }} map F fzy
I would like to add that using fzy's -l $(( $(tput lines) - 1 )) argument gives a more LF-integrated solution at my point of view (the whole screen is taken, so we don't feel we are outside LF this way).
Also, I wanted to be able to select a file if I searched for its filename using fzy. Here is my version of @lenormf's first fzy script, if anyone's interested.
cmd fzy ${{
path=$(ls -a1 | fzy -l "$(( $(tput lines) - 1 ))")
[ -z "$path" ] && exit
[ -d "$path" ] && cmd='cd' || cmd='select'
lf -remote "send $id $cmd '$path'"
}}
map f fzy
Most helpful comment
Ok so I have added 4 commands for finding, namely
find,find-back,find-nextandfind-prev, and two options, namelyfindlenandanchorfind. Default behavior is set to easily jump to files starting with a character, which is somewhat similar to some of the gui file managers. Whenfindlenis set to zero, it waits until there is only a single match, so ranger's behavior, with the exception of opening the file automatically, can be set with:There are still a few things on my mind. Currently find commands shares some of the search options, namely
wrapscan,ignorecase, andsmartcasewhich I'm still not quite sure. Regarding fuzzy finding, it may not be accurate enough without ranking the choices, so maybe it is better to skip it for now to keep it simple.Once we finalize these commands and options, I'm thinking of adding a section to the documentation. Then we can close this issue.