Skip to content
Open
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
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ bin-dir = "{ name }-{ version }-windows-x64/{ bin }{ binary-ext }"
anyhow = "1.0.102"
bitflags = "2.11.0"
clap = { version = "4.6.1", features = ["derive", "color", "env"] }
clap_complete = "4.6"
crossbeam-channel = "0.5.15"
dashmap = "6.2.1"
dirs = "6.0.0"
Expand Down
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@
# ABI mismatch causes silent runtime corruption. Verify after nixpkgs updates.
pkgs.onnxruntime
];
nativeBuildInputs = [ pkgs.pkg-config ];
nativeBuildInputs = [
pkgs.pkg-config
pkgs.installShellFiles
];
cargoBuildOptions =
x:
x
Expand All @@ -67,6 +70,14 @@
"codanna"
];
ORT_SKIP_DOWNLOAD = "1";
# Generate shell completions from the just-built binary (naersk runs
# postInstall only on the top-level build, not the deps build).
postInstall = ''
installShellCompletion --cmd codanna \
--bash <($out/bin/codanna completions bash) \
--zsh <($out/bin/codanna completions zsh) \
--fish <($out/bin/codanna completions fish)
'';
};
}
);
Expand Down
15 changes: 15 additions & 0 deletions src/cli/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use clap::{
Parser, Subcommand,
builder::styling::{AnsiColor, Effects, Styles},
};
use clap_complete::Shell;
use std::path::PathBuf;

fn clap_cargo_style() -> Styles {
Expand Down Expand Up @@ -69,6 +70,8 @@ fn create_custom_help() -> String {
help.push_str(" parse Output AST nodes in JSONL format\n");
help.push_str(" plugin Manage Claude Code plugins\n");
help.push_str(" documents Index and search document collections\n");
help.push_str(" profile Initialize and manage project profiles\n");
help.push_str(" completions Generate shell completion scripts\n");
help.push_str(" help Print this message or the help of the given subcommand(s)\n\n");

help.push_str("See 'codanna help <command>' for more information on a specific command.\n\n");
Expand Down Expand Up @@ -349,6 +352,18 @@ pub enum Commands {
#[command(subcommand)]
action: crate::profiles::commands::ProfileAction,
},

/// Generate shell completion scripts
#[command(
about = "Generate shell completion scripts",
long_about = "Generate a shell completion script for the given shell and print it to stdout.\n\nRedirect the output to your shell's completion directory, or source it directly in the current session.",
after_help = "Examples:\n codanna completions bash > ~/.local/share/bash-completion/completions/codanna\n codanna completions zsh > ~/.zsh/completions/_codanna\n codanna completions fish > ~/.config/fish/completions/codanna.fish\n source <(codanna completions bash) # current session only"
)]
Completions {
/// Shell to generate completions for
#[arg(value_enum)]
shell: Shell,
},
}

/// Plugin management actions
Expand Down
13 changes: 13 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,16 @@ fn seed_indexer_with_config_paths(
async fn main() {
let cli = Cli::parse();

// Shell completions are pure stdout output: emit and exit before any
// config loading, index opening, or provider setup runs.
if let Commands::Completions { shell } = &cli.command {
use clap::CommandFactory;
let mut cmd = Cli::command();
let bin_name = cmd.get_name().to_string();
clap_complete::generate(*shell, &mut cmd, bin_name, &mut std::io::stdout());
return;
}

// For index command, auto-initialize if needed (but not when using --config)
if matches!(cli.command, Commands::Index { .. }) && cli.config.is_none() {
if Settings::check_init().is_err() {
Expand Down Expand Up @@ -785,6 +795,9 @@ async fn main() {
Commands::Profile { action } => {
codanna::cli::commands::profile::run(action);
}

// Handled immediately after argument parsing, before any setup runs.
Commands::Completions { .. } => unreachable!("completions are emitted before dispatch"),
}
}

Expand Down