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
use clap::{Args, Parser, Subcommand};
use clap_complete::engine::ArgValueCandidates;
use crate::workspace;
#[derive(Parser)]
#[command(name = "workon", version, about = "Development workspace launcher with Zellij")]
#[command(args_conflicts_with_subcommands = true)]
pub struct Cli {
#[command(subcommand)]
pub command: Option<Command>,
#[command(flatten)]
pub session: SessionArgs,
}
/// Flags for the default session / ephemeral `-w` flow. Flattened onto the root
/// so `workon`, `workon -w`, and `workon -c foo` keep parsing as before; they
/// conflict with the subcommands via `args_conflicts_with_subcommands`.
#[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub struct SessionArgs {
/// Name the session — and, with -w, the worktree. Defaults to the directory name.
#[arg(long)]
pub name: Option<String>,
/// Ephemeral jj workspace mode
#[arg(short = 'w')]
pub workspace: bool,
/// Force new session (delete existing, recover from hung server)
#[arg(long, conflicts_with = "workspace")]
pub new_session: bool,
/// Skip copying gitignored files into the workspace
#[arg(long, requires = "workspace")]
pub skip_copy_ignored: bool,
/// Resume an agent session by ID (printed when a workspace exits)
#[arg(short = 'r', long, requires = "workspace")]
pub resume: Option<String>,
/// Named config to load from `~/.config/workon/configs/<name>.kdl`
#[arg(short = 'c', long = "config")]
pub config: Option<String>,
/// Reserved. Was a `-n` alias for forcing a new session; now an inert
/// no-op so the old reflex can't silently recreate a session. The
/// deliberate spelling is `--new-session`.
#[arg(short = 'n', hide = true)]
pub reserved_n: bool,
}
/// Headless workspace lifecycle: `create -> (attach <-> quit)* -> destroy`.
/// Quitting an `attach` session detaches; the workspace survives until
/// `destroy`.
#[derive(Subcommand)]
pub enum Command {
/// Provision a persistent workspace and print its path (no session)
Create {
/// Nickname for the worktree
#[arg(long)]
name: Option<String>,
/// Named config to record for later `attach`
#[arg(short = 'c', long = "config")]
config: Option<String>,
/// Skip copying gitignored files into the workspace
#[arg(long)]
skip_copy_ignored: bool,
/// Print `{ ws_id, path, db }` as JSON on stdout
#[arg(long)]
json: bool,
},
/// Open an existing workspace in a session (workspace survives on quit)
Attach {
/// Workspace id, --name nickname, or path; omit for the cwd's workspace
#[arg(add = ArgValueCandidates::new(workspace::ref_candidates))]
reference: Option<String>,
/// Override the recorded config
#[arg(short = 'c', long = "config")]
config: Option<String>,
},
/// Tear down a workspace, saving rescued work unless --no-save
Destroy {
/// Workspace id, --name nickname, or path; omit for the cwd's workspace
#[arg(add = ArgValueCandidates::new(workspace::ref_candidates))]
reference: Option<String>,
/// Discard unsaved work instead of bookmarking it
#[arg(long)]
no_save: bool,
/// Print `{ ws_id, saved, dropped_db }` as JSON on stdout
#[arg(long)]
json: bool,
},
/// List workspaces at or under the current directory
List {
/// Print an array of workspace objects as JSON on stdout
#[arg(long)]
json: bool,
},
/// Print a workspace's directory, for `cd "$(workon path REF)"` (no session)
Path {
/// Workspace id, --name nickname, or path; omit for the cwd's workspace
#[arg(add = ArgValueCandidates::new(workspace::ref_candidates))]
reference: Option<String>,
},
}