Description
As discussed in #2891 the current behaviour of completions for opening a file is frustrating when dealing with directories. There is no currently no straightforward way to select a directory without finishing the completion. Pressing Enter when the directory is highlighted leads to micro trying to open the directory and receiving the Error: X is a directory and cannot be opened message.
As requested, this issue is to discuss ways in which this could improved. My preference would be to adopt the zsh behaviour, whereby pressing either / or Enter when a directory is highlighted only adds that directory to the current target path, instead of attempting to open it. The user can then press tab again to attempt completion within the sub-directory the path points to.
Does anyone else have another suggestion?
Activity
8the current behaviour of completions for opening a file is frustrating when dealing with directories. There is no currently no straightforward way to select a directory without finishing the completion.
Yeah, I can confirm this is annoying.
I usually work around this by deleting the / character via Backspace and pressing Tab again, in order to "reset" autocompletion.
My suggestion would be to add a new action
AcceptCompletionthat keeps the currently selected completion and clears the suggestions. So when you hit a directory you want to go into you would triggerAcceptCompletionand then keep pressing tab to complete files from inside the selected directory.
I was also thinking about exactly the same (although with a different name, e.g. RefreshAutocomplete or CommitAutocomplete :)).
We could then change the default keybinding for Enter in InfoBuf to
AcceptCompletion|ExecuteCommand
I thought about this too. But if the idea is that this AcceptCompletion action will work generically for any autocompletions, not just for directories, then e.g.: there are files (not directories) foo1, foo2, foo3, the user types open f and presses Tab to cycle through those files, the user selects for example foo2, and presses Enter and expects the file foo2 to open, but nothing happens (the user has to press Enter once again)?
So maybe it's better to just bind AcceptCompletion (alone, not chained) e.g. to Alt-Tab or whatever by default?
(although I think chained actions don't currently work in InfoBufs so that needs to be fixed first).
No they don't (and that's a shame).
We are talking about the open <filepath> command inside micro right?
Would handling this in the OpenCmd() work? Like check if the path is directory or not and do InfoBar.Prompt again (with the path) if it is.
open <filepath> is not the only case we are talking about.
~/src/micro % grep -r FileComplete
runtime/help/plugins.md: - `FileComplete`: autocomplete using files in the current directory
internal/buffer/autocomplete.go:// FileComplete autocompletes filenames
internal/buffer/autocomplete.go:func FileComplete(b *Buffer) ([]string, []string) {
internal/action/infopane.go: b.Autocomplete(buffer.FileComplete)
internal/action/command.go: "save": {(*BufPane).SaveCmd, buffer.FileComplete},
internal/action/command.go: "vsplit": {(*BufPane).VSplitCmd, buffer.FileComplete},
internal/action/command.go: "hsplit": {(*BufPane).HSplitCmd, buffer.FileComplete},
internal/action/command.go: "tab": {(*BufPane).NewTabCmd, buffer.FileComplete},
internal/action/command.go: "cd": {(*BufPane).CdCmd, buffer.FileComplete},
internal/action/command.go: "open": {(*BufPane).OpenCmd, buffer.FileComplete},
cmd/micro/initlua.go: ulua.L.SetField(pkg, "FileComplete", luar.New(ulua.L, buffer.FileComplete))I see what you mean.
So maybe it's better to just bind
AcceptCompletion(alone, not chained) e.g. to Alt-Tab or whatever by default?
Probably not alt-tab, since that switches windows on...Windows and also some DEs.
I think having an action for "accepting" completion is neat, but it seems like it will need a separate keybind.
Would handling this in the
OpenCmd()work? Like check if the path is directory or not and doInfoBar.Promptagain (with the path) if it is.
I still feel like "catching" it inside the cmd functions and re-prompting the user with the given path feels the most "natural" to me. (It might not be the most elegant solution but the most straightforward one I think)
Given not all the commands that use FileComplete act the same way (where some expects directory and some expects file)
I still feel like "catching" it inside the cmd functions
Those cmd functions are still not the only case when filename autocompletion is used. It is used by default in any "non-command" prompts (e.g. when saving an unnamed file via Ctrl-S): https://github.com/micro-editor/micro/blob/master/internal/action/infopane.go#L215. Also it is exported to Lua, so that commands registered by plugins can also use it.
Given not all the commands that use FileComplete act the same way (where some expects directory and some expects file)
They all expect a path. A path consists of directories.
Those cmd functions are still not the only case when filename autocompletion [...].
Not all of them needs "catch + retry" (e.g. cd) and doesn't have to be tied to FileComplete. it just happens that most of the commands that use FileComplete would benefit from it (and also share the same/similar logic)
Also it is exported to Lua, so that commands registered by plugins can also use it.
I would imagine it is unlikely for plugins to pass invalid path or path that requires further auto-complete to those commands.
Given not all the commands that use FileComplete act the same way (where some expects directory and some expects file)
They all expect a path. A path consists of directories.
I meant in the sense of what type of path is expected. For example catching/AcceptAutocomplete a file path wouldn't make sense to open while a dir path would.
The problem with AcceptCompletion (in this case) is you either need to
- Remember an extra new keybind and when you should call it
- Share existing keybind and need an extra keypress every time since it can't tell which entries are valid and which ones require further completion (to that command).
I think what I suggested would align closer to what OP wants (and it's also better UX wise).
Ideally this should be the command completor's job (maybe allow filter submission) but changing how it works now would break many things.
I feel quite strongly that handling this inside the commands is not the right approach.
The problem with AcceptCompletion (in this case) is you either need to
- Remember an extra new keybind and when you should call it
- Share existing keybind and need an extra keypress every time since it can't tell which entries are valid and which ones require further completion (to that command).
Even if we did let the commands pick whether or not further completion is required that would only solve the problem for the commands that expect only regular files. Commands that can accept a directory would still need some other way to complete nested directories. I also think it would be confusing to get thrown right back to the prompt after entering a directory when you're not using autocompletion. I would rather just have an error message in that case.
A major benefit of the proposed AcceptCompletion action is that it can be used with all completions, not just FileComplete. I've looked for an action like it to use with the jlabbrev plugin 1 before, and it would probably find some use with the LSP plugins too (autocompleting nested modules/namespaces has all the same issues as file paths). Actions also compose nicely: you can eg. overload Enter (like many other editors do), and it's easy to opt in/out through bindings.json.
I thought about this too. But if the idea is that this AcceptCompletion action will work generically for any autocompletions, not just for directories, then e.g.: there are files (not directories) foo1, foo2, foo3, the user types open f and presses Tab to cycle through those files, the user selects for example foo2, and presses Enter and expects the file foo2 to open, but nothing happens (the user has to press Enter once again)? So maybe it's better to just bind AcceptCompletion (alone, not chained) e.g. to Alt-Tab or whatever by default?
I actually already let a slop generator implement it for me to try and it felt pretty nice to use. 2 I didn't mind pressing Enter twice when there are multiple completions in the InfoBuf. I wouldn't want to have the same behavior in regular buffers though so for consistency it's probably better to bind it to something else by default. Shift+Enter should be familiar for people coming from eg. VS Code, but we would need to wait for #4174 to make it work properly in most terminal emulators.
Footnotes
-
jlabbrev requires you to have the full abbreviation typed for it to replace it with the corresponding unicode character when autocompleting, but cycling through suggestions takes precedence if they're present. I've been relying on pressing Esc or Space > Backspace to get rid of the suggestions, but a more convenient binding would be welcome. ↩
-
https://github.com/Andriamanitra/micro/commit/3554fc8d2ae2af1f2db3e91c0a5aa0531c1de283 -- I don't understand the code, it's probably garbage, but it does work! ↩
My suggestion would be to add a new action
AcceptCompletionthat keeps the currently selected completion and clears the suggestions. So when you hit a directory you want to go into you would triggerAcceptCompletionand then keep pressing tab to complete files from inside the selected directory. We could then change the default keybinding for Enter in InfoBuf toAcceptCompletion|ExecuteCommand(although I think chained actions don't currently work in InfoBufs so that needs to be fixed first).