chshersh / tool-sync

🧰 Download pre-built binaries of all your favourite tools with a single command
https://crates.io/crates/tool-sync
Mozilla Public License 2.0
69 stars 16 forks source link

Shell completion script #133

Closed MitchellBerend closed 1 year ago

MitchellBerend commented 1 year ago

The clap documentation points to clap_completion as a related project. Just like tool-sync can generate a default .tool.toml I think it's a good idea for it to be able to generate shell completion scipts for commonly used shells (Bash, fish, zsh for example). clap_complete supports these out of the box.

It would add a new dependency to the project, but I think for what it provides that is more than worth it. I think implementing this should be straight forward, but the help text for this command should also contain instructions as to how this completion should be used.

Edit: blocked by #136 Unblocked by @SanchithHegde

chshersh commented 1 year ago

I don't mind adding a separate dependency. Shell completion is a nice feature 👍🏻

I haven't used this crate though. How exactly does it work? Does it produce separate artifacts?


On a similar note, tool-sync itself can't configure shell completion of tools upon installation which is a bit sad 😞 And I currently don't know the best way to do this.

MitchellBerend commented 1 year ago

Does it produce separate artifacts?

The way I use it right now is that it just prints the script to stdout. I added the like eval "$(tool completion)" to my ~/.bashrc so it is persistent. Im not sure if this is the standard way for cli auto completion but the github cli has the user add the completion script to their ~/.bashprofile.

$ gh completion --help
Generate shell completion scripts for GitHub CLI commands.

When installing GitHub CLI through a package manager, it's possible that
no additional shell configuration is necessary to gain completion support. For
Homebrew, see <https://docs.brew.sh/Shell-Completion>

If you need to set up completions manually, follow the instructions below. The exact
config file locations might vary based on your system. Make sure to restart your
shell before testing whether completions are working.

### bash

First, ensure that you install `bash-completion` using your package manager.

After, add this to your `~/.bash_profile`:

    eval "$(gh completion -s bash)"
...

I think clap_completion allows for a selection of options like the actual commands, flags or files in the cwd. Im still playing around with this myself so I can't give a definitive answer on how polished suggestions can be.

MitchellBerend commented 1 year ago

There are some follow up questions that need to be addressed before this is actually implemented all the way.

clap_complete assumes the name of the tool will be the same as the name defined in the Cargo.toml, this is currently tool-sync but the binary is called tool.

I personally rename the binary by hand so this will work for me as is, but for other users that might not be the case. A decision should be made on this naming convention before more work is done.

I also did not find a way to create a custom list for suggestions for the install command, this could be solved by making a new enum that contains all the hardcoded tools. This would accrue a decent amount of maintenance load though since this enum, besides the actual hardcoded tools and config template, also has to be kept up to date.

I found this issue that talks about a similar feature so I don't think this is currently possible.

chshersh commented 1 year ago

The way I use it right now is that it just prints the script to stdout. I added the like eval "$(tool completion)" to my ~/.bashrc

That's great to hear! 👏🏻 This is how it works in Haskell as well and how I enable completion on my own too 🙂

clap_complete assumes the name of the tool will be the same as the name defined in the Cargo.toml, this is currently tool-sync but the binary is called tool.

This is unfortunate 😞 Not sure what to do with this now. So, I guess we'll wait for the upstream issue resolution.

MitchellBerend commented 1 year ago

For transparency's sake, it is possible to set a custom binary name for clap_complete by passing a String or &str to the generate function.

MitchellBerend commented 1 year ago

Since #136 is resolved thanks to @SanchithHegde, this issue can also be implemented.

There is still the outstanding issue of how the naming convention should be for referring to tool-sync. I think it would be better if we used tool-sync as the name this would be less ambiguous. This would mean a change to the ci configuration and also updating the README.md.

We can also keep tool as the name but, if that is the path forward, the Cargo.toml name should also reflect this. That would also mean a minor change in the src/main.rs file since that refers to the library name.

Other naming conventions are also welcome of course but these came to mind quickly.

Changing the name later would also mean a breaking change.

chshersh commented 1 year ago

@MitchellBerend The conversation about naming conventions is spread across multiple places so I'm going to reply here.

I've replied about the convention for the environment variables names in the corresponding issue:

Could you clarify a bit more about the problem with the naming convention? I'm happy to call the binary tool (especially considering the fact that shell completion works great with that) and use tool-sync in all other places when we refer to the CLI tool / project to avoid ambiguity. Both crate and repository already have the name tool-sync so I would happily accept any changes to README.md to make the situation clearer 🙂

MitchellBerend commented 1 year ago

Could you clarify a bit more about the problem with the naming convention?

Because the completion script needs to actually be ran every time a new shell without a parent is spawned my question was if we are using the name tool or tool-sync. If the user renames the binary themselves this autocomplete feature breaks for them.

The way I'm reading your comment you want this to be tool?

chshersh commented 1 year ago

@MitchellBerend Thanks for clarifying! I see the problem now 🙂

I would like to keep the name tool indeed. I'm not aware of any other tool that is named just tool so this seems good to me 😅 We can put a warning in the README.md saying that autocompletion won't work if you rename the binary.

It would be better if clap supported several names for the autocompletion as potential common aliases for the tool.

It would be even better if users could configure the name for themselves so we don't need to support all possible use cases in our repo.

But looks like the two last options are not possible, if I'm reading your comments correctly.

MitchellBerend commented 1 year ago

It would be better if clap supported several names for the autocompletion as potential common aliases for the tool.

I think we can support this by adding an optional flag possibly. There needs to be a special output to the stderr maybe since the command that gets run at first shell start up needs to hold only the completion script.

Something like


fn generate_custom_completion(bin_name: String, shell: clap_complete::Shell) {
    let cmd = Cli::commands();
    eprintln!(format!(r###"Add this to your ./bashrc:\n\teval "$({bin_name} completion --rename {bin_name})""###));

    clap_complete::generate(shell, &mut cmd, bin_name, std::io::stdout());
}

Edit: corrected eprintln suggestion

MitchellBerend commented 1 year ago

There needs to be a special output to the stderr maybe since the command that gets run at first shell start up needs to hold only the completion script.

This ended up being pretty easy to implement but there are still a few issues.

  1. Elvish shell does not give a suggestion as to how the completion script should be added.
  2. The match statement looks very messy to me, maybe the src/lib is not the right file to implement this.
mitchell@mitchell-workstation:~/rust/tool-sync$ cargo run -- completion bash --rename asdfasdf -- $1 > /dev/null 
    Finished dev [unoptimized + debuginfo] target(s) in 0.04s
     Running `target/debug/tool completion bash --rename asdfasdf --`
First, ensure that you install `bash-completion` using your package manager.

After, add this to your `~/.bash_profile`:

`eval "$(asdfasdf completion bash --rename asdfasdf)"`

----------------------------------------------------------------------------------------------------------------------------------------------------------------

mitchell@mitchell-workstation:~/rust/tool-sync$ cargo run -- completion fish --rename asdfasdf -- $1 > /dev/null 
    Finished dev [unoptimized + debuginfo] target(s) in 0.04s
     Running `target/debug/tool completion fish --rename asdfasdf --`
Generate a `tool.fish` completion script:

`asdfasdf completion fish --rename asdfasdf > ~/.config/fish/completions/asdfasdf.fish`

----------------------------------------------------------------------------------------------------------------------------------------------------------------

mitchell@mitchell-workstation:~/rust/tool-sync$ cargo run -- completion zsh --rename asdfasdf -- $1 > /dev/null 
    Finished dev [unoptimized + debuginfo] target(s) in 0.04s
     Running `target/debug/tool completion zsh --rename asdfasdf --`
Generate a `_asdfasdf` completion script and put it somewhere in your `$fpath`:
`asdfasdf completion zsh --rename asdfasdf > /usr/local/share/zsh/site-functions/_asdfasdf`

Ensure that the following is present in your `~/.zshrc`:

`autoload -U compinit`

`compinit -i`

----------------------------------------------------------------------------------------------------------------------------------------------------------------

mitchell@mitchell-workstation:~/rust/tool-sync$ cargo run -- completion powershell --rename asdfasdf -- $1 > /dev/null 
    Finished dev [unoptimized + debuginfo] target(s) in 0.04s
     Running `target/debug/tool completion powershell --rename asdfasdf --`
Open your profile script with:

`mkdir -Path (Split-Path -Parent $profile) -ErrorAction SilentlyContinue`
`notepad $profile`

Add the line and save the file:

`Invoke-Expression -Command $(asdfasdf completion powershell --rename asdfasdf | Out-String)`

----------------------------------------------------------------------------------------------------------------------------------------------------------------

mitchell@mitchell-workstation:~/rust/tool-sync$ cargo run -- completion elvish --rename asdfasdf -- $1 > /dev/null 
    Finished dev [unoptimized + debuginfo] target(s) in 0.04s
     Running `target/debug/tool completion elvish --rename asdfasdf --`
This suggestion is missing, if you use this and know how to implement this please file an issue over at https://github.com/chshersh/tool-sync/issues