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
//! Command-line argument types.
use clap::{Parser, Subcommand, ValueEnum};
/// Top-level CLI argument structure parsed by clap.
#[derive(Debug, Parser)]
#[command(
name = "colorant",
version,
about = "Per-directory terminal theme switcher with system dark/light mode support"
)]
pub struct Cli {
/// The subcommand the user invoked.
#[command(subcommand)]
pub command: Command,
}
/// One of colorant's subcommands. Each variant maps to a `run` function in
/// `crate::commands`.
#[derive(Debug, Subcommand)]
pub enum Command {
/// Find the nearest .colorantrc and apply its theme. No-op on unsupported
/// terminals. Falls back to the global default theme (if configured) or
/// resets the terminal when no .colorantrc is found.
Apply,
/// Reset terminal colors to defaults.
Reset,
/// Print the .colorantrc path that would be applied for the current dir.
Current,
/// Print a shell-specific integration snippet.
///
/// Typical use: `eval "$(colorant init zsh)"` in ~/.zshrc.
Init {
#[arg(value_enum)]
shell: Shell,
},
/// Manage themes from bundled and remote sources. With a subcommand,
/// runs that operation non-interactively (`list`, `search`, `sync`,
/// `apply`, `install`, `path`). With no subcommand, opens an
/// interactive TUI that browses every known source with a live
/// preview, lets you filter and pick, and writes the chosen
/// `extends` keys into the cwd's `.colorantrc` on apply.
Themes {
#[command(subcommand)]
action: Option<ThemesAction>,
},
/// Diagnose silent failures in a .colorantrc: unknown keys, invalid
/// colors, missing extends palettes, and so on. Without `path`, walks
/// up from the current directory like `colorant current`.
Doctor {
/// Path to a specific `.colorantrc` to check.
path: Option<std::path::PathBuf>,
},
/// Print the resolved colors that would apply for the current
/// directory, with hex codes and 24-bit swatches. Defaults to the
/// current OS dark/light mode; pass `--all` to print both modes.
Show {
/// Print both dark and light resolutions instead of just the
/// current mode.
#[arg(long)]
all: bool,
},
}
/// Sub-actions for the `themes` command group.
#[derive(Debug, Subcommand)]
pub enum ThemesAction {
/// List themes from one or all sources, marking which are already
/// installed locally.
List {
/// Restrict to a single source (e.g. `bundled`, `gogh`). Omit to
/// list every source.
#[arg(long)]
source: Option<String>,
/// Only show themes that are installed in the local themes dir.
#[arg(long)]
installed: bool,
},
/// Copy bundled palettes into the user's themes directory.
///
/// Use a specific name to install just that palette, or `--all` to
/// install every bundled palette. By default refuses to overwrite
/// existing files — pass `--force` to overwrite.
Install {
/// Name of a single bundled palette to install.
///
/// Mutually exclusive with `--all`. Without either, the command
/// errors with a hint pointing at both options — the validation
/// lives in `commands::themes::run_install` so the message can be
/// helpful, since clap's `required_unless_present` only reports a
/// generic "argument required" error.
name: Option<String>,
/// Install every bundled palette.
#[arg(long, conflicts_with = "name")]
all: bool,
/// Overwrite existing palette files.
#[arg(long, short)]
force: bool,
},
/// Print the configured themes directory.
Path,
/// Search for themes by name across known sources (bundled + remote).
/// Remote sources must be `sync`'d first for their themes to show up.
Search {
/// Substring to match (case-insensitive).
query: String,
/// Restrict to a single source (e.g. `bundled`, `gogh`).
#[arg(long)]
source: Option<String>,
},
/// Refresh the cached catalog for remote sources (`gogh`). Network
/// only happens during this command.
Sync {
/// Restrict to a single source. Omit to sync every remote.
#[arg(long)]
source: Option<String>,
},
/// Apply themes to the current directory's `.colorantrc`, writing
/// `extends` / `extends.dark` / `extends.light` as needed. Themes
/// that aren't yet installed (bundled or fetched from a remote) are
/// installed automatically. Other keys in the rc are preserved.
Apply {
/// Theme to apply to both modes (`extends = <name>`). Optional;
/// pass `--dark`/`--light` instead to set them separately.
/// Source can be specified via `gogh:<name>` syntax.
#[arg(conflicts_with_all = ["dark", "light"])]
name: Option<String>,
/// Theme for dark mode (`extends.dark = <name>`).
#[arg(long)]
dark: Option<String>,
/// Theme for light mode (`extends.light = <name>`).
#[arg(long)]
light: Option<String>,
},
}
/// The shell selector accepted by `colorant init <shell>`.
#[derive(Debug, Copy, Clone, ValueEnum)]
pub enum Shell {
/// Zsh — emits an `add-zsh-hook chpwd/precmd` snippet.
Zsh,
}