Skip to main content

keep_running/
cli.rs

1use clap::{CommandFactory, Parser, Subcommand};
2use clap_complete::{generate, Shell};
3
4const KEYBINDINGS_HELP: &str = "\
5Keybindings (inside an attached session):
6  Ctrl+a d        Detach from the session (leave it running)
7  Ctrl+a k        Kill the session
8  Ctrl+a Ctrl+a   Send a literal Ctrl+a to the program";
9
10const TOP_LEVEL_HELP: &str = "\
11Shortcuts:
12  keep-running                  list running sessions
13  keep-running <name>           attach to a session (prefix match works)
14
15Keybindings (inside an attached session):
16  Ctrl+a d        Detach from the session (leave it running)
17  Ctrl+a k        Kill the session
18  Ctrl+a Ctrl+a   Send a literal Ctrl+a to the program";
19
20#[derive(Parser)]
21#[command(name = "keep-running")]
22#[command(about = "Human-friendly terminal session manager with dtach-style detach")]
23#[command(after_help = TOP_LEVEL_HELP)]
24#[command(after_long_help = TOP_LEVEL_HELP)]
25#[command(version)]
26pub struct Cli {
27    #[command(subcommand)]
28    pub command: Option<Commands>,
29
30    /// Session name for shortcut attach (e.g., `keep-running fuzzy-penguin`)
31    #[arg(value_name = "SESSION")]
32    pub session: Option<String>,
33}
34
35#[derive(Subcommand)]
36pub enum Commands {
37    /// Start a new session with the given command
38    #[command(trailing_var_arg = true)]
39    #[command(after_help = KEYBINDINGS_HELP)]
40    #[command(after_long_help = KEYBINDINGS_HELP)]
41    Run {
42        /// Session name (auto-generated if not specified)
43        #[arg(short, long)]
44        name: Option<String>,
45
46        /// Command to run
47        #[arg(required = true)]
48        command: Vec<String>,
49    },
50
51    /// Start a new session with your default shell
52    Shell {
53        /// Session name (auto-generated if not specified)
54        #[arg(short, long)]
55        name: Option<String>,
56    },
57
58    /// Attach to an existing session
59    Attach {
60        /// Session name (or prefix)
61        session: String,
62    },
63
64    /// List all running sessions
65    #[command(alias = "ls")]
66    List,
67
68    /// Kill a running session
69    Kill {
70        /// Session name (or prefix)
71        session: String,
72    },
73
74    /// Start a session daemon without attaching (for scripts/testing)
75    Start {
76        /// Session name (auto-generated if not specified)
77        #[arg(short, long)]
78        name: Option<String>,
79
80        /// Command to run
81        #[arg(required = true, trailing_var_arg = true)]
82        command: Vec<String>,
83    },
84
85    /// Generate shell completions
86    Completions {
87        /// Shell to generate completions for
88        #[arg(value_enum)]
89        shell: Shell,
90    },
91}
92
93pub fn parse() -> Cli {
94    Cli::parse()
95}
96
97pub fn print_completions(shell: Shell) {
98    let mut cmd = Cli::command();
99    generate(shell, &mut cmd, "keep-running", &mut std::io::stdout());
100}