lando / cli

The cli part of Lando
https://docs.lando.dev/cli
GNU General Public License v3.0
30 stars 33 forks source link

Tab Completion for bash #203

Open generalredneck opened 5 years ago

generalredneck commented 5 years ago

Feature Request

As a lando user, I would like to be able to press the <TAB> key and have a list of options I can select from so that typing out commands is faster.

This would probably take the form of a simple bash completions script. I don't have the gist of it but something along the lines of the following script in it's simplest form put into /etc/bash_completion.d/


#/usr/bin/env bash
_dothis_completions()
{
  COMPREPLY=($(compgen -W "$(lando)" "${COMP_WORDS[1]}"))
}

complete -F _dothis_completions lando
dustinleblanc commented 5 years ago

Cool idea @generalredneck! This is definitely not high priority, but might be a nice to have. I am going to put this in carbonite for now, but if you want to do some research and we get some general ideas going around from @pirog and @serundeputy, maybe it can be included in the future

pirog commented 5 years ago

I support this but i also have no ideas on how to accomplish this and no desire to do any work to make it happen ;) aka someone else is going to have to take the lead here!

generalredneck commented 5 years ago

I'll see what I can do. I don't know how to alter the deb package to do the install... be a learning speriance.

pirog commented 5 years ago

@generalredneck im guessing these are going to be the relevant files you will want to look at

tylers-username commented 5 years ago

I played around with https://github.com/f/omelette as a plugin for proof of concept. It is lightweight, has zero dependencies, is cross-platform compatible and works with both zsh and bash. If anything, it may serve as inspiration for how to proceed if the Lando team builds the feature out from a scratch.

Edit: Looks like yargs, which is already included in Lando, has this built-in for bash.

jcheek commented 5 years ago

I played around with https://github.com/f/omelette as a plugin for proof of concept. It is lightweight, has zero dependencies, is cross-platform compatible and works with both zsh and bash. If anything, it may serve as inspiration for how to proceed if the Lando team builds the feature out from a scratch.

@tylerssn do you have anything concrete yet? I'd be willing to do a little bit of coding to help make this happen, although I'm a novice at node.

tylers-username commented 5 years ago

Given that yargs is already included in Lando and that Lando is not in the autocompletion business - Omelette may be a bit much to integrate at the moment, despite it's lightweight and platform compatibility.

Yargs gives us bash autocompletion and Zsh can support it as well with the following two lines:

# Enable bash completion support in Zsh
autoload -U +X bashcompinit && bashcompinit
eval "$(lando completion)"
# Or, in development: eval "$(./bin/lando.js completion)"

To see a functional proof of concept in Lando:

  1. Modify bin/lando.js:22 from const yargs = require('yargs') to const yargs = require('yargs').completion(); This makes bin/lando.js completion available to bash and you can see Lando tooling is populating at bin/lando.js --get-yargs-completions.
  2. Now that Lando is serving auto completed tooling, tell bash how to use it: bin/lando.js completion >> ~/.bashrc && source ~/.bashrc.

(Zsh users will need to execute bash bin/lando.js completion >> ~/.zshrc && source ~/.zshrc

You can now execute bin/lando.js <tab> and should see Lando tooling populating.

Obstacles for integration with Lando:

  1. Autocompleted commands such as destroy [appserver] are treated as two separate commands. I think this can be overcome by using the callback in .completion() to modify the suggestion handler.

  2. Automating ~/.bashrc setup. I think this can be tackled with a tooling command such as lando --autocomplete=on|off and using RegEx to identify/replace/remove the required script.

    # ~/.bashrc
    
    #### Lando Autocomplete Identifier ####
    {output of bin/lando.js  completion}
    #### Lando Autocomplete Identifier ####
  3. Autocompleting command options. Currently my example works on commands but it does not work on their options. I believe there is a solution to this and it is described here, we just need to decide the best method of implementation.

tylers-username commented 5 years ago

@jcheek - Here's a working implementation that someone can take from here. I won't be spending much more time on it after this weekend.

Features:

Setup:

  1. Add lando-autocomplete to the plugins directory.
  2. Add this to ./plugins/lando-autocomplete/index.js

    'use strict';
    
    const _ = require('lodash');
    
    const getCommandArgumentCompletion = (tasksList, userInput) => {
     let commands = [];
     _.forEach(_.sortBy(tasksList, 'command'), task => {
       const isCommandMatch = userInput !== task.name;
       if (isCommandMatch) {
         return;
       }
       commands = task.completion;
     });
    
     const missingCompletion = !commands instanceof Array;
     if (missingCompletion) {
       console.log('Missing completion');
       return;
     }
    
     return commands;
    };
    
    const getCommandCompletion = tasksList => {
     const commands = [];
     _.forEach(_.sortBy(tasksList, 'command'), task => {
       commands.push(task.name);
     });
    
     return commands;
    };
    
    module.exports = lando => {
     const pluginAddedObserverCount = 1;
     // Suppress max listener warnings
     lando.events.setMaxListeners(lando.events.getMaxListeners() + pluginAddedObserverCount);
    
    // Register completion feature
     lando.events.on('post-bootstrap', 99999, lando => {
       return new Promise((resolve, reject) => {
         resolve(require('yargs').completion(
           'completion',
           'For use by bash auto-complete',
           (userInput, argv) => new Promise((resolve, reject) => {
    
             // If user is tab completing bin/lando.js <tab>, do this.
             if (!userInput) {
               resolve(getCommandCompletion(lando.tasks.tasks));
             }
    
            // If user is tab completing bin/lando.js command <tab>, do this.
            resolve(getCommandArgumentCompletion(lando.tasks.tasks, userInput));
            })
        ));
       });
     });
    };
  3. Add lando-autocomplete to config.yml's plugin list.

Key Issue: I have a promise mess. bin/lando.js --get-yargs-completion and bin/lando.js --get-yargs-completion version always list all available tasks and version suggestions as expected. However, intermittently, bin/lando.js <tab> does not list any commands. I belive this is because Lando is exiting before the promise is fulfilled. bin/lando.js version <tab> does not have this issue.

edurenye commented 5 years ago

For Ubuntu 18.10 I added the plugin in ~/.lando/plugins following the instructions, added the plugin in ~/.lando/config.yml It detected the plugin, but I got an error, it could not find lodash dependency, so I added it with npm install -g lodash and replaced const _ = require('lodash'); for const _ = require('/usr/lib/node_modules/lodash');

But then I had the following error: error: Problem loading plugin lando-autocomplete from /home/user/.lando/plugins/lando-autocomplete/index.js: TypeError: process.binding(...).internalModuleReadFile is not a function at Object.fs.internalModuleReadFile.fs.internalModuleReadJSON (pkg/prelude/bootstrap.js:1127:36) at internalModuleReadJSON (internal/modules/cjs/loader.js:31:68) at readPackage (internal/modules/cjs/loader.js:156:16) at tryPackage (internal/modules/cjs/loader.js:172:13) at Function.Module._findPath (internal/modules/cjs/loader.js:282:18) at Function.Module._resolveFilename (internal/modules/cjs/loader.js:589:25) at Function.Module._resolveFilename (pkg/prelude/bootstrap.js:1270:44) at Function.Module._load (internal/modules/cjs/loader.js:518:25) at Module.require (internal/modules/cjs/loader.js:648:17) at Module.require (pkg/prelude/bootstrap.js:1157:31) at require (internal/modules/cjs/helpers.js:20:18) at Object.<anonymous> (/home/user/.lando/plugins/lando-autocomplete/index.js:3:11) at Module._compile (internal/modules/cjs/loader.js:700:30) at Module._compile (pkg/prelude/bootstrap.js:1213:32) at Object.Module._extensions..js (internal/modules/cjs/loader.js:711:10) at Module.load (internal/modules/cjs/loader.js:610:32)

I was using rc13 version of lando.

edurenye commented 5 years ago

Looks like this is fixed in the version 4.3.7 of pkg: https://github.com/zeit/pkg/pull/461 So Lando needs to update this dependency.

tylers-username commented 5 years ago

@edurenye - My example was more than likely built on RC1 so you'd certainly have to make some changes to get this into a working state.

edurenye commented 5 years ago

That problem with node that was also showing up in the rc1 is gone now, the plugin is loaded fine without errors. I use zsh, so I proceeded with the following. I added the plugin and everything I did before. Now the line to change is in lib/cli.js instead of bin/lando.js, I replaced in line 110: return require('yargs').help(false).version(false).argv; for: return require('yargs').help(false).version(false).completion().argv; Run: ~/lando/bin/lando.js completion >> ~/.zshrc && source ~/.zshrc

This added the following to ~/.zshrc ###-begin-lando.js-completions-### # # yargs command completion script # # Installation: .//home/user/lando/bin/lando.js completion >> ~/.bashrc # or .//home/user/lando/bin/lando.js completion >> ~/.bash_profile on OSX. # _yargs_completions() { local cur_word args type_list

`cur_word="${COMP_WORDS[COMP_CWORD]}"
args=("${COMP_WORDS[@]}")`

`# ask yargs to generate completions.`
`type_list=$(.//home/user/lando/bin/lando.js --get-yargs-completions "${args[@]}")`

`COMPREPLY=( $(compgen -W "${type_list}" -- ${cur_word}) )`

`# if no match was found, fall back to filename completion`
`if [ ${#COMPREPLY[@]} -eq 0 ]; then
  COMPREPLY=( $(compgen -f -- "${cur_word}" ) )
fi`

`return 0`

} complete -F _yargs_completions lando.js ###-end-lando.js-completions-### Although the autocomplete does not work and ~/lando/bin/lando.js --get-yargs-completions just gives me "completion" but tabbing does not give me even that.

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions and please check out this if you are wondering why we auto close issues.

edurenye commented 5 years ago

Do not close this issue, this is a really interesting feature

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions and please check out this if you are wondering why we auto close issues.

pirog commented 5 years ago

unstale

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions and please check out this if you are wondering why we auto close issues.

tylers-username commented 5 years ago

@edurenye - if it helps, testing this was tricky in the dev env when calling bin/lando.js. If I recall correctly, I had to create an alias such as landoDev to the Lando bin file in order for Zsh and Bash to start completing.

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions and please check out this if you are wondering why we auto close issues.

allanlaal commented 2 years ago

please reopen this :) (and delete stalebot - it just spams and makes us spam issues with non-content)

reynoldsalec commented 2 years ago

From maintainer convos I know that we're looking at moving to a different CLI construction tool with Lando 4.x, probably in the next year. Added relevant tags and re-opened.

stale[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions and please check out this if you are wondering why we auto close issues.

edurenye commented 1 year ago

Will the use of oclif help fix this? Should we move this issue to https://github.com/lando/cli ?

pirog commented 1 year ago

@edurenye i do think OCLIF has some utils around tab completion however. i think the difficulty is going to be around completion of commands that differ from app to app.