1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
//! `shellcomp` is a deployment layer for shell completion scripts in Rust CLI projects.
//!
//! It does **not** generate completions. Instead, it focuses on the operational work around
//! completions:
//!
//! - choosing managed default install paths,
//! - writing completion files idempotently,
//! - wiring shell startup files when necessary,
//! - detecting current activation state,
//! - removing managed files and managed startup blocks,
//! - returning structured reports and structured failures for caller-side rendering.
//!
//! Pair it with `clap_complete` or any other generator when you need to render the script bytes.
//!
//! # Scope And Non-Goals
//!
//! `shellcomp` intentionally keeps a narrow scope:
//!
//! - it is **not** a shell completion generator;
//! - it is **not** a generic shell configuration manager;
//! - it does **not** attempt to understand arbitrary user shell customizations;
//! - it only modifies completion files it was asked to manage and startup blocks it can identify
//! with stable markers.
//!
//! This is why the crate can stay small while still being production-usable.
//!
//! # Supported Shells
//!
//! Production support currently covers [`Shell::Bash`], [`Shell::Zsh`], [`Shell::Fish`],
//! [`Shell::Powershell`], and [`Shell::Elvish`]. [`Shell::Other`] remains the explicit escape
//! hatch for unsupported shells.
//!
//! Managed behavior for the supported shells:
//!
//! - [`Shell::Bash`]: writes to the XDG data completion directory, then prefers a system
//! `bash-completion` loader and falls back to a managed `~/.bashrc` block when no loader is
//! detected.
//! - [`Shell::Zsh`]: writes `_binary-name` into the managed zsh completion directory and maintains
//! a managed `~/.zshrc` block that updates `fpath` and runs `compinit -i` when needed.
//! - [`Shell::Fish`]: writes directly into Fish's native completions directory and does not manage
//! a shell startup file.
//! - [`Shell::Powershell`]: writes a managed completion script file and maintains a managed
//! `CurrentUserAllHosts` profile block.
//! - [`Shell::Elvish`]: writes a managed completion script file and maintains a managed `rc.elv`
//! block.
//!
//! # Public API
//!
//! The crate is intentionally small:
//!
//! - [`default_install_path`] resolves the managed target path for a shell and binary name.
//! - [`install`] writes the completion file and returns an [`InstallReport`].
//! - [`install_with_policy`] lets callers opt into or out of managed activation explicitly.
//! - [`detect_activation`] inspects the managed setup and returns an [`ActivationReport`].
//! - [`detect_activation_at_path`] inspects activation for an explicit completion file path.
//! - [`uninstall`] removes the managed file and returns a [`RemoveReport`].
//! - [`uninstall_with_policy`] lets callers control whether activation cleanup should be managed.
//! - [`migrate_managed_blocks`] removes known legacy markers and rewrites the equivalent
//! `shellcomp`-managed startup block.
//! - [`render_clap_completion`] is available behind the `clap` feature for users who want the
//! crate to render completion bytes from `clap::CommandFactory`.
//! - [`render_clap_completion_from_command`] is available behind the `clap` feature for users who
//! want to tweak a prebuilt `clap::Command` before rendering.
//! - [`clap_complete`] is re-exported behind the `clap` feature so callers can use
//! `shellcomp::clap_complete::Shell` without pulling conflicting top-level `Shell` names into
//! the same scope manually.
//!
//! # Reading Reports
//!
//! The public report types are designed so callers can render UX without parsing display strings:
//!
//! - [`InstallReport::file_change`] tells you whether the completion file was created, updated, or
//! already matched.
//! - [`ActivationReport::mode`] tells you *how* the shell will load the completion.
//! - [`ActivationReport::availability`] tells you whether it is active now, available after a new
//! shell, available after sourcing a file, or still requires manual work.
//! - [`ActivationPolicy`] lets callers choose whether installation to a custom path should still
//! attempt managed shell wiring when the shell supports it.
//! - [`RemoveReport::cleanup`] separates startup wiring cleanup from completion file removal so a
//! caller can preserve partial progress.
//! - [`FailureReport`] carries structured failure kind, relevant paths, and suggested next steps.
//!
//! # Typical Integration Flow
//!
//! 1. Render a completion script with your preferred generator.
//! 2. Call [`install`] to place the script into a managed location.
//! 3. Show the returned [`ActivationReport`] to the user.
//! 4. Optionally call [`detect_activation`] later to re-check availability.
//! 5. Call [`uninstall`] to remove both the completion file and any managed activation wiring.
//!
//! # Install Example
//!
//! ```no_run
//! use shellcomp::{InstallRequest, Shell, install};
//!
//! let script = b"complete -F _demo demo\n";
//! let report = install(InstallRequest {
//! shell: Shell::Bash,
//! program_name: "demo",
//! script,
//! path_override: None,
//! })?;
//!
//! println!("installed to {}", report.target_path.display());
//! println!("activation: {:?}", report.activation);
//! # Ok::<(), shellcomp::Error>(())
//! ```
//!
//! # clap Integration Example
//!
//! With the `clap` feature enabled, you can keep the generator-facing shell value under
//! `shellcomp::clap_complete::Shell` and convert it into [`Shell`] only when you call the
//! deployment API.
//!
//! ```no_run
//! # #[cfg(feature = "clap")]
//! # fn install_zsh_completion() -> shellcomp::Result<()> {
//! # use clap::Parser;
//! # use shellcomp::{InstallRequest, install, render_clap_completion};
//! #
//! # #[derive(Parser)]
//! # struct Cli {
//! # #[arg(long)]
//! # verbose: bool,
//! # }
//! #
//! # let generator_shell = shellcomp::clap_complete::Shell::Zsh;
//! # let script = render_clap_completion::<Cli>(generator_shell, "demo")?;
//! # let report = install(InstallRequest {
//! # shell: generator_shell.into(),
//! # program_name: "demo",
//! # script: &script,
//! # path_override: None,
//! # })?;
//! #
//! # println!("installed to {}", report.target_path.display());
//! # Ok::<(), shellcomp::Error>(())
//! # }
//! ```
//!
//! # Custom Path Example
//!
//! Passing [`InstallRequest::path_override`] usually tells `shellcomp` to skip startup wiring and
//! report manual activation explicitly. The one exception is an override that exactly matches the
//! shell's managed default path, which still keeps the default activation semantics.
//!
//! ```no_run
//! use std::path::PathBuf;
//!
//! use shellcomp::{ActivationMode, Availability, InstallRequest, Shell, install};
//!
//! let report = install(InstallRequest {
//! shell: Shell::Fish,
//! program_name: "demo",
//! script: b"complete -c demo\n",
//! path_override: Some(PathBuf::from("/tmp/demo.fish")),
//! })?;
//!
//! assert_eq!(report.activation.mode, ActivationMode::Manual);
//! assert_eq!(report.activation.availability, Availability::ManualActionRequired);
//! # Ok::<(), shellcomp::Error>(())
//! ```
//!
//! # Structured Error Handling
//!
//! High-level operational failures are returned as [`Error::Failure`] with a stable
//! [`FailureKind`]. That lets callers keep their own presentation layer while still branching on
//! machine-readable failure categories.
//!
//! ```rust
//! use std::path::PathBuf;
//!
//! use shellcomp::{Error, FailureKind, InstallRequest, Shell, install};
//!
//! let error = install(InstallRequest {
//! shell: Shell::Fish,
//! program_name: "demo",
//! script: b"complete -c demo\n",
//! path_override: Some(PathBuf::from("/")),
//! })
//! .expect_err("path without parent should fail structurally");
//!
//! let report = error
//! .as_failure()
//! .expect("path without parent should fail structurally");
//! assert_eq!(report.kind, FailureKind::InvalidTargetPath);
//! ```
//!
//! Not every error becomes [`Error::Failure`]: immediate validation problems like
//! [`Error::InvalidProgramName`] are returned directly.
//!
//! # Idempotency
//!
//! Repeating the same install or uninstall operation is expected to be safe:
//!
//! - identical completion file writes return [`FileChange::Unchanged`];
//! - repeated removals return [`FileChange::Absent`];
//! - managed startup blocks are updated in place and removed by stable markers.
//!
//! This makes the crate suitable for CLI commands that users may run multiple times.
pub
pub
pub use render_clap_completion;
pub use render_clap_completion_from_command;
/// Re-exported `clap_complete` shell type for callers that want a namespaced integration surface.
///
/// This lets downstream code write `shellcomp::clap_complete::Shell` without importing a second
/// top-level `Shell` symbol.
pub use ;
pub use ;
pub use ;