Skip to main content

coding_tools/cli/
ct_outline.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Jonathan Shook
3
4//! The `ct-outline` command grammar (see [`crate::cli`]); the `ct-outline` bin
5//! is a thin parse-and-dispatch wrapper over this `Cli`.
6
7use std::path::PathBuf;
8
9use clap::Parser;
10
11use crate::explain::Format;
12use crate::pattern;
13use crate::pulse::HeartbeatOpts;
14
15#[derive(Parser, Debug)]
16#[command(
17    name = "ct-outline",
18    version,
19    about = "Report the declarations in a file or tree: kind, name, start:end span, and nesting.",
20    long_about = "ct-outline detects declarations heuristically per language (Rust, Python, Markdown) \
21                  and reports each with its kind, name, and 1-based start:end line span (also \
22                  reachable as `ct outline`) — locate a symbol, then read exactly that region with \
23                  ct-view --range. Start lines are exact; an underivable end renders as start:?. \
24                  See `ct-outline --explain` for agent-oriented documentation."
25)]
26pub struct Cli {
27    /// Root to outline; a file outlines just that file, a directory is descended.
28    #[arg(long, default_value = ".")]
29    pub base: PathBuf,
30
31    /// Limit to files whose name matches; '|'-separated alternatives, each substring->glob->regex promoted and anchored.
32    #[arg(long)]
33    pub name: Option<String>,
34
35    /// Restrict to these extensions (comma-separated, no dots), e.g. --ext rs,py. Combined with --name as alternatives.
36    #[arg(long, value_delimiter = ',')]
37    pub ext: Vec<String>,
38
39    /// Include dot-entries (names starting with '.'); default skips them.
40    #[arg(long)]
41    pub hidden: bool,
42
43    /// Follow symlinks while traversing.
44    #[arg(long)]
45    pub follow: bool,
46
47    /// Walk gitignored / .ignore files too (the .git directory is always skipped); by default the walk skips what git would.
48    #[arg(long)]
49    pub no_ignore: bool,
50
51    /// Keep entries whose name matches (substring->glob->regex promoted, anchored to the whole declaration name).
52    #[arg(long = "match")]
53    pub pattern: Option<String>,
54
55    /// Pin how --match/--name patterns are interpreted (promotion off): literal, glob, or regex.
56    #[arg(long, value_enum)]
57    pub mode: Option<pattern::Mode>,
58
59    /// Keep entries of these kinds (comma-separated), e.g. --kind fn,struct. Kinds are per-language keywords.
60    #[arg(long, value_delimiter = ',')]
61    pub kind: Vec<String>,
62
63    /// Keep entries nested at most N levels deep (1 = top-level only).
64    #[arg(long)]
65    pub depth: Option<usize>,
66
67    /// Output one grep-friendly row per matched entry: path:start:end:kind:name.
68    #[arg(long)]
69    pub flat: bool,
70
71    /// Question this outline answers, framing it as a test; printed as a "== ... ==" banner unless --quiet.
72    #[arg(long)]
73    pub question: Option<String>,
74
75    /// Verdict expectation over the matched-entry count: any|none|N|=N|+N|-N (default: any).
76    #[arg(long)]
77    pub expect: Option<String>,
78
79    /// Template written to stdout after the outline. Tokens: {RESULT} {QUESTION} {COUNT} {BASE} {MATCHES}.
80    #[arg(long, alias = "emit-stdout")]
81    pub emit: Option<String>,
82
83    /// Template written to stderr after the outline (same tokens as --emit).
84    #[arg(long)]
85    pub emit_stderr: Option<String>,
86
87    /// Print nothing; report via exit status (and --emit, which still fires).
88    #[arg(long)]
89    pub quiet: bool,
90
91    /// Emit a structured JSON result instead of text (overrides the text modes and --emit).
92    #[arg(long)]
93    pub json: bool,
94
95    /// Abort with exit 2 if the run exceeds SECS seconds (fractional allowed).
96    #[arg(long, value_name = "SECS")]
97    pub timeout: Option<f64>,
98
99    #[command(flatten)]
100    pub heartbeat: HeartbeatOpts,
101
102    /// Print agent usage docs (md or json) and exit.
103    #[arg(long, value_enum, num_args = 0..=1, default_missing_value = "md")]
104    pub explain: Option<Format>,
105}