albertlauncher / albert

A fast and flexible keyboard launcher
https://albertlauncher.github.io
Other
7.26k stars 305 forks source link

Tab completion for Terminal plugin #444

Closed schoettl closed 7 years ago

schoettl commented 7 years ago

Could we implement a tab completion for the Terminal plugin?

I'm aware that this is a difficalt topic:

However, a basic completion for commands in the user's $PATH would already be very useful.

Example:

This completion system can be extended at any later time.

How do you think about this idea?

schoettl commented 7 years ago

@ManuelSchneid3r could you give me a hint on where extensions can handle the Tab key? I looked in Calculator extension's handleQuery and placed a qDebug() but it's not triggered... https://github.com/albertlauncher/albert/tree/dev/src/plugins/calculator/src

idkCpp commented 7 years ago

The Tab key isn't handled per se. The items that are returned contain a field where the text is to be autocompleted to. It defaults to the title...

schoettl commented 7 years ago

Oh damn.. now I understand how this calculator Tab feature works.

So the Terminal plugin would have to return a list with programs in the path (maybe in addition to a history list).

idkCpp commented 7 years ago

So the Terminal plugin would have to return a list

I now assumed that you meant to return a list of completion strings. If you didn't mean that then this answer won't help you and furthermore I didn't understand to what you were referring...

The autocomplete mechanism in inherited from the Item class. There on line 57/58 it says:

/** The string to use for completion */
virtual QString completionString() const { return text(); }

You can only override this to return an other string but you cannot return a list. It is not possible to cycle through a list by hitting Tab multiple times. This is impossible by design because hitting Tab changes the input line (that's the point as you may have guessed) and this triggers a subsequent query to be handled and will therefore produce other items that are then displayed. This causes the selection to reset to the first item being selected, so when you hit Tab again, the autocompletion-string of the now selected object will be put into the input line and the process starts over.

schoettl commented 7 years ago

So the Terminal plugin would have to return a list

I now assumed that you meant to return a list of completion strings.

I actually meant the "suggestion list", the list of Item objects :) Thank you for hint to the code!

So, it is possible to implement my suggestions from the top post, but only together with the "suggestion list".

I think the most useful suggestion list is a MRU list combined with a list of programs in the $PATH. completionString's default implementation might already be appropriate.

Maybe I can reuse code from the standard MRU suggestion list.

armnrd commented 7 years ago

@schoettl Did you make any progress with your idea? Tab completion would be really useful to me.

ManuelSchneid3r commented 7 years ago

We had this once. I reimplemented the PATH mathing resulta. However bash aliases will not be part of it. Completion is item based and will complete the whole name. Bash like completion will take some extra effort.

armnrd commented 7 years ago

@ManuelSchneid3r Where is PATH read from? I use zsh as my login shell, and PATH is in ~/.zshenv

albert does not seem to be reading that file. Maybe the terminal plugin should have a PATH setting. Or maybe it should run the login shell and extract PATH from that.

schoettl commented 7 years ago

Sorry, I didn't have time to work on it.

@armnrd I think Manuel is talking about the $PATH variable and about listing all executables found in these paths in the suggestion list. Then, tab completion for programs should work but the more sophisticated shell completion will not (yet).

Albert uses the PATH variable of the shell from which albert is started (often login shell). I don't know when or where your ~/.zshenv is sourced. Maybe it is only sourced for interactive shells? Files that are usually sourced at startup are ~/.xprofile and ~/.profile, so you can try to define your PATH variable there.

armnrd commented 7 years ago

On v0.12.0, TAB completion doesn't seem to work at all after terminal mode has been triggered with >, so maybe that's why $PATH-completed suggestions don't show up.

@schoettl Does $PATH-completion work for you?

ManuelSchneid3r commented 7 years ago

Its not in the releases yet. It will be in v0.13 though. To drop all matches and completions was a short time decision before one of the last releases, since interactive shells, which were needee to find aliases, made tons of problems. The general completion and matches of executables were intended to be reintroduced. Just not in that release. Just as a note: shell aliases of whichever shell will never be part of the terminal extension. They are designed to be used with an interactive shell. To list them an interactive shell is needed. Starting an interactive shell in albert lookup is kind of an abuse and regarding performance pretty heavyweight. Further they are special to each shell. Supporting sh bash zsh ksh ash and whatever shell is out there is just a nightmare. Especially when trying to parse the rc files which is the only way i can think of when interactive shells are not an option.

ManuelSchneid3r commented 7 years ago

cinnamon-20170902-2

Minimial effort :D

schoettl commented 7 years ago

Great, thank you Manuel. I'm looking forward to the next release :) I agree regarding not implementing shell-specific completion in Albert. Also, mixing the suggestions from PATH with the history from the HISTFILE is problematic. I will just use my favorite shell for shell-specific completion and to query history (Ctrl+R together with fzf)!

armnrd commented 7 years ago

That seems rational. I'm looking forward to v0.13. Since albert is a launcher, doing shell expansions isn't a good idea. But I think there should be a good default for path expansion, such as extraction from the login shell at startup. And perhaps the plugin should say where $PATH is read from.

schoettl commented 7 years ago

And perhaps the plugin should say where $PATH is read from.

Albert reads the PATH variable from the environment, not from a specific file. The process that launches Albert passes "exported" environment variables to Albert. Albert cannot know where the PATH variable was set, and it depends on the Linux distribution. The plugin could only display the value of the PATH variable. I think that would be useful.

Path expansion might be useful sometimes but I guess it's not so nice to implement. See idkCpp's first comment on this issue for how tab completion works in Albert. BTW, other command launchers like dmenu and AFAIK Windows's "Run command" also don't support path expansion. Although gmrun does.

armnrd commented 7 years ago

The plugin could only display the value of the PATH variable. I think that would be useful.

That would be good enough.

ManuelSchneid3r commented 7 years ago

Again a minor note: Its still possible to run aliases. They are just not in the results. The last item is generic item that forwards your input to the shell (or term depending on the action chosen). You just have to know and completely type them. Thats the reason why there are two items in the gif above.

armnrd commented 7 years ago

@ManuelSchneid3r Perhaps give the last item a different tint to indicate that it is "special" in this way. It would also be nice if the description was a little different. Just to contrast it with the "plain" item above it.

schoettl commented 7 years ago

I just stumbled over Bash's compgen built-in. This "completion generator" prints all possible completions to stdout.

For example,

bash -c "compgen -G 's*'"

prints all filenames matching the glob s*. It can list commands, aliases, functions, and supports Bash's more sophisticated completion system.

Given that /bin/sh is /bin/bash, this could make a relatively simple yet very powerfull completion system for Albert's terminal plugin.

I just wanted to share this. I think it's worth to consider, as probably a big percentage of users use Bash and the implementation might be pretty clean. .

ManuelSchneid3r commented 7 years ago

Does not work on my system, GNU bash, Version 4.4.12

schoettl commented 7 years ago

bash -c "compgen -G 's*'" was just an example for glob expansion. Maybe you have no flie starting with "s" in your $PWD?

compgen should be available in your Bash, I have the same version.

$ type compgen
compgen is a shell builtin
$ help compgen
compgen: compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist]  [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]
    Display possible completions depending on the options.

    Intended to be used from within a shell function generating possible
    completions.  If the optional WORD argument is supplied, matches against
    WORD are generated.

    Exit Status:
    Returns success unless an invalid option is supplied or an error occurs.