akavel / up

Ultimate Plumber is a tool for writing Linux pipes with instant live preview

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add tab completion functionality

robertfronzo opened this issue · comments

Including the ability to tab complete would make this tool truly perfect.

Great job either way, love this idea!

So. First of all, this is generally an awesome idea, and I'm totally for it, as a user of the tool myself.

Now, the big question is, how to do this in a reasonable way?

Notably:

  • in bash, completion is a horrid mess of actual bash scripts registering as callback hooks; supporting full bash completion would require actually running bash and calling appropriate hooks in some way, assuming it's possible at all;
  • per #2, up now supports more "engines"/shells than just bash, so the completion feature would have to somehow be compatible with not only bash, but others too;
  • up is a small tool, and I would hope for any new feature to be small and simple too, so as to not dwarf the existing codebase; though external libraries are OK here as long as the footprint of the integration glue stays small.

With the above limitations, I just don't know how it could be done as of now. If you have some ideas, the issue is open to discussion and sharing. (Though I reserve right to hide comments if I don't see them as substantial contributions.) One vague thought that occurred to me now is that maybe some "language server protocol" integration could help here; though I'm not sure. Still, if yes, I would want this to be done via linking some external Go library, so as not to add langserver protocol implementation code into up codebase itself. With all this said, I'm not currently planning to explore this direction myself, so I'm going to mark it as "help-wanted". As per my usual stance in this situation:

If someone wants to jump in and help, I'm super happy to provide mentoring, design discussion and guidance! ❤️ The process will be easiest for us both if you start talking to me here even before you start working on this. Also it's ok to fail — I won't be regretful if you don't complete the task even after we've put a lot of our time into it. I am more than sure we both will learn a lot from this anyway!

See also a new WIP development in this area: Oil Dev Log #8: Shell Protocol Designs (via).

Bash only answer.

Getting completion in bash is not a mess at all, it does have limitation but the complexity is very low.

here's a real life example using a function, I decorated it to output the current word and the completion. that function is used to complete a command called 'tmuxake'

_tmuxake_completion ()
{
    completion_list="toggle full attach detach break import push pop close position check kill status status2";
    local cur;
    COMPREPLY=();
    cur="${COMP_WORDS[COMP_CWORD]}";
    COMPREPLY=($(compgen -W "${completion_list}" -- ${cur}));
    declare -p COMPREPLY;
    return 0
}

To run the tab completion "manually", we need to find which function is registered for the 'tmuxake' command

run: complete | rg tmuxake
output:
complete -o nospace -F _tmuxake_completion tmuxake

We can then emulate bash's completion by running the completion function

run: COMP_WORDS=('s' 'p') ; COMP_CWORD=1 _tmuxake_completion
output:
declare -a COMPREPLY=([0]="push" [1]="pop" [2]="position")

Non Bash opinion:

It's more than understandable that one doesn't want Bash to creep (although I guess bash is used by 90%+ of all users) in up's code.

I wouldn't mind writing extra scripts for up to support completion for specific needs, that would eliminate the problem with different shells because that becomes the responsibility of the user not the up's developer.

It may sound like a lot of work for the user but it's a balance and sometimes using up and writing "completion" scripts is well worth it. And one doesn't have to support everything. Here's my use case:

I have integrated up in my file manager so I can filter a file list with normal shell commands, grep ... . I rarely need help with the core utilities and if I do then it's worth reading the manual.

screenshot_2023-06-16_11-17-19

Some of the features I'd like to add to my file manager are very simple to implement with a pipe, say only mp3s that have a specific singer. writing a filter that let's only specific singers through is in the Unix spirit.

The problem is remembering the name of the scripts, if I have ten scripts for filtering mp3s then it's ten commands to remember, in the shell: mp3_filter_[TAB] would help tremendously, when using 'up', I need to open another shell!

It's of course more complicate than just a single word completion, what about too many completions to list simply?, what about commands that do completion by starting another program (I have one that uses fzf), and many more problems still unforeseen.

I could add the functionality above in different ways but it's up's interactivity that's it's attractive and it's so easy to create new filters!

Here's an example of a filter that only lets files over or under a specified size to go through, I can reuse it everywhere (if I remember its name), in up, in the shell, in every program that runs other programs.

#!/bin/env perl
my ($less, $size) = $ARGV[0] =~ /(-?)([0-9]+)/ ;
do { chomp ; print $less ? (-s $_ <= $size && "$_\n") : (-s $_ > $size && "$_\n") } for <STDIN>

IMHO:

  • it all get standardized with a great API, I'll have re-incarnated twice before it's true, too many people involved
  • use more of the shell or be part of the shell, one is difficult and the other replaces "supporting shells" to "being supported by shells", we're back were we started.
  • offer yet another completion specific to 'up', probably the only realistic possibility