Tab Completion for bash
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
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
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!
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.
@generalredneck im guessing these are going to be the relevant files you will want to look at
- Linux package scripts and static assets - https://github.com/lando/lando/tree/master/installer/linux
- Linux build script - https://github.com/lando/lando/blob/master/scripts/build-linux.sh
- Pkg building commands - https://docs.devwithlando.io/dev/building.html
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.
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.
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:
- Modify
bin/lando.js:22fromconst yargs = require('yargs')toconst yargs = require('yargs').completion();This makesbin/lando.js completionavailable to bash and you can see Lando tooling is populating atbin/lando.js --get-yargs-completions. - 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:
-
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. -
Automating
~/.bashrcsetup. I think this can be tackled with a tooling command such aslando --autocomplete=on|offand using RegEx to identify/replace/remove the required script.# ~/.bashrc #### Lando Autocomplete Identifier #### {output of bin/lando.js completion} #### Lando Autocomplete Identifier #### -
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.
@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:
- Observes tasks listed in
lando.tasksand provides completion suggestions by name. - Allows tasks to provide their own suggestions by reading a new string array property from Lando tasks called
completion. Example:# plugins/lando-core/tasks/version.js module.exports = lando => ({ command: 'version', completion: ['suggestionOne', 'suggestionTwo'], describe: 'Display the lando version', run: () => { console.log('v' + lando.config.version); }, }); bin/lando.js <tab>- Lists all commands by
task.nameas completion suggestions. - Testable with
bin/lando.js --get-yargs-completionorbin/lando.js <tab>
- Lists all commands by
bin/lando.js {task.name} <tab>- List suggestions made available by
task.completion. This is a property that can be added to any task. To test this out modifyplugins/lando-core/tasks/version.jsso that it has propertycompletion: ['suggestionOne', 'suggestionTwo']. - Testable with
bin/lando.js --get-yargs-completion versionorbin/lando.js version <tab>.
- List suggestions made available by
Setup:
- Add
lando-autocompleteto the plugins directory. - 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)); }) )); }); }); }; - Add
lando-autocompleteto 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.
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.
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.
@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.
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.
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.
Do not close this issue, this is a really interesting feature
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.
unstale
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 - 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.
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.
please reopen this :) (and delete stalebot - it just spams and makes us spam issues with non-content)
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.
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.
Will the use of oclif help fix this? Should we move this issue to https://github.com/lando/cli ?
@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.