Skip to main content

cgraph/
cli.rs

1//! Command-line syntax only; process startup remains in `main`.
2
3use std::{ffi::OsString, path::PathBuf};
4
5use clap::{Parser, Subcommand};
6
7#[derive(Debug, Parser)]
8#[command(name = "cgraph", version, about)]
9pub struct Cli {
10    /// Language server executable. If omitted, cgraph detects common project types.
11    #[arg(long, global = true, value_name = "PROGRAM", conflicts_with = "no_lsp")]
12    pub lsp: Option<OsString>,
13
14    /// Argument passed to the configured language server.
15    #[arg(
16        long = "lsp-arg",
17        global = true,
18        value_name = "ARG",
19        allow_hyphen_values = true,
20        requires = "lsp"
21    )]
22    pub lsp_args: Vec<OsString>,
23
24    /// Workspace directory supplied to the language server.
25    #[arg(long, global = true, value_name = "PATH", default_value = ".")]
26    pub workspace: PathBuf,
27
28    /// Disable automatic language server startup.
29    #[arg(long, global = true, conflicts_with = "lsp")]
30    pub no_lsp: bool,
31
32    /// Listen for editor IPC clients on this Unix socket path.
33    #[arg(long, global = true, value_name = "PATH")]
34    pub ipc_socket: Option<PathBuf>,
35
36    #[command(subcommand)]
37    pub command: Option<Command>,
38}
39
40#[derive(Debug, Subcommand)]
41pub enum Command {
42    /// Show a function call hierarchy.
43    Call {
44        /// Function or method to use as the root node.
45        symbol: String,
46    },
47    /// Show a type hierarchy.
48    Type {
49        /// Type to use as the root node.
50        symbol: String,
51    },
52}
53
54#[cfg(test)]
55mod tests {
56    use super::{Cli, Command};
57    use clap::Parser;
58
59    #[test]
60    fn parses_call_query() {
61        let cli = Cli::try_parse_from(["cgraph", "call", "Foo::Bar"]).unwrap();
62
63        assert!(matches!(
64            cli.command,
65            Some(Command::Call { symbol }) if symbol == "Foo::Bar"
66        ));
67    }
68
69    #[test]
70    fn accepts_an_empty_canvas() {
71        let cli = Cli::try_parse_from(["cgraph"]).unwrap();
72
73        assert!(cli.command.is_none());
74    }
75
76    #[test]
77    fn parses_language_server_options_after_subcommand() {
78        let cli = Cli::try_parse_from([
79            "cgraph",
80            "type",
81            "Student",
82            "--lsp",
83            "rust-analyzer",
84            "--workspace",
85            "/tmp/project",
86        ])
87        .unwrap();
88
89        assert_eq!(
90            cli.lsp.as_deref(),
91            Some(std::ffi::OsStr::new("rust-analyzer"))
92        );
93        assert_eq!(cli.workspace, std::path::Path::new("/tmp/project"));
94    }
95
96    #[test]
97    fn parses_an_ipc_socket_path() {
98        let cli = Cli::try_parse_from([
99            "cgraph",
100            "--ipc-socket",
101            "/run/user/1000/cgraph.sock",
102            "call",
103            "main",
104        ])
105        .unwrap();
106
107        assert_eq!(
108            cli.ipc_socket.as_deref(),
109            Some(std::path::Path::new("/run/user/1000/cgraph.sock"))
110        );
111    }
112}