Skip to content

Commit

Permalink
Init shell completions through es init
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasPickering committed Oct 8, 2024
1 parent feea127 commit 77503eb
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 52 deletions.
5 changes: 2 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@

### Added

- Add shell completions, accessed by enabling the `COMPLETE` environment variable [#6](https://github.com/LucasPickering/env-select/issues/6)
- For example, adding `COMPLETE=fish es | source` to your `fish.config` will enable completions for fish
- [See docs](https://env-select.lucaspickering.me/book/user_guide/shell_completions.html) for more info and a list of supported shells
- Add shell completions [#6](https://github.com/LucasPickering/env-select/issues/6)
- These will be automatically loaded as part of the existing shell integrations, so if you already have `es init | source` or similar in your shell init file, you don't need to change anything
- Add command aliases
- `es r` alias for `es run`, `es s` for `es set`

Expand Down
1 change: 0 additions & 1 deletion docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
- [Inheritance & Cascading Configs](./user_guide/inheritance.md)
- [Side Effects](./user_guide/side_effects.md)
- [`es run` and Shell Interactions](./user_guide/run_advanced.md)
- [Shell Completions](./user_guide/shell_completions.md)

# API Reference

Expand Down
2 changes: 1 addition & 1 deletion docs/src/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ See [the artifacts page](/artifacts) to download and install `es` using your pre

While not strictly required, it's highly recommended to install the `es` shell function. This wraps the `es` binary command, allowing it to automatically modify your current shell environment with the `es set` subcommand. Otherwise, you'll have to manually pipe the output of `es set` to `source`.

> If you only plan to use the `es run` command, this is **not relevant**.
> If you only plan to use the `es run` command, and don't care about shell tab completions, this is **not relevant**.
This is necessary because a child process is not allowed to modify its parent's environment. That means the `es` process cannot modify the environment of the invoking shell. The wrapping shell function takes the output of `es` and runs it in that shell session to update the environment.

Expand Down
43 changes: 0 additions & 43 deletions docs/src/user_guide/shell_completions.md

This file was deleted.

25 changes: 22 additions & 3 deletions src/commands/init.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
use crate::commands::{CommandContext, SubcommandTrait};
use crate::{
commands::{CommandContext, SubcommandTrait},
Args, COMMAND_NAME,
};
use anyhow::Context;
use clap::Parser;
use clap::{CommandFactory, Parser};
use clap_complete::CompleteEnv;
use std::env;

/// Configure the shell environment for env-select. Intended to be piped
/// to `source` as part of your shell startup.
#[derive(Clone, Debug, Parser)]
pub struct InitCommand;
pub struct InitCommand {
/// Don't include completion script in output
#[clap(long, hide = true)] // Only for testing
no_completions: bool,
}

impl SubcommandTrait for InitCommand {
fn execute(self, context: CommandContext) -> anyhow::Result<()> {
Expand All @@ -14,6 +23,16 @@ impl SubcommandTrait for InitCommand {
.init_script()
.context("Error generating shell init script")?;
print!("{script}");

// Print the command to enable shell completions as well. CompleteEnv
// doesn't expose the inner machinery that would allow us to print the
// line directly, so we have to enable the env var that triggers it
if !self.no_completions {
env::set_var("COMPLETE", context.shell.kind.to_string());
CompleteEnv::with_factory(Args::command)
.try_complete([COMMAND_NAME], None)?;
}

Ok(())
}
}
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ use log::{error, LevelFilter};
use clap_complete::CompleteEnv;
use std::{path::PathBuf, process::ExitCode};

const COMMAND_NAME: &str = "es";

/// A utility to select between predefined values or sets of environment
/// variables.
#[derive(Debug, Parser)]
#[clap(bin_name = "es", author, version, about, long_about = None)]
#[clap(bin_name = COMMAND_NAME, author, version, about, long_about = None)]
pub struct Args {
#[command(subcommand)]
command: Commands,
Expand Down
7 changes: 7 additions & 0 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ pub fn execute_script(
es.args(["-s", shell_kind]);
}
es.arg("init");
if shell_kind == "zsh" {
// Completion script doesn't work with zsh because the compdef command
// isn't present by default. I tried loading it with compinit but that
// has other issues. This is a shortcut. We aren't trying to test
// completion anyway, it's just a bonus.
es.arg("--no-completions");
}
let assert = es.assert().success();

// Inject the function source into the script
Expand Down

0 comments on commit 77503eb

Please sign in to comment.