Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Init shell completions through es init #78

Merged
merged 1 commit into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading