git_worktree_manager/
messages.rs1pub fn worktree_not_found(branch: &str) -> String {
5 format!(
6 "No worktree found for branch '{}'. Use 'gw list' to see available worktrees.",
7 branch
8 )
9}
10
11pub fn target_not_found(target: &str) -> String {
12 format!(
13 "No worktree matches '{}' (tried name, branch, path). Use 'gw list' to see available worktrees.",
14 target
15 )
16}
17
18pub fn branch_not_found(branch: &str) -> String {
19 format!("Branch '{}' not found", branch)
20}
21
22pub fn invalid_branch_name(error_msg: &str) -> String {
23 format!(
24 "Invalid branch name: {}\nHint: Use alphanumeric characters, hyphens, and slashes. \
25 Avoid special characters like emojis, backslashes, or control characters.",
26 error_msg
27 )
28}
29
30pub fn cannot_determine_branch() -> String {
31 "Cannot determine current branch".to_string()
32}
33
34pub fn cannot_determine_base_branch() -> String {
35 "Cannot determine base branch. Specify with --base or checkout a branch first.".to_string()
36}
37
38pub fn missing_metadata(branch: &str) -> String {
39 format!(
40 "Missing metadata for branch '{}'. Was this worktree created with 'gw new'?",
41 branch
42 )
43}
44
45pub fn worktree_dir_not_found(path: &str) -> String {
46 format!("Worktree directory does not exist: {}", path)
47}
48
49pub fn cannot_delete_main_worktree() -> String {
50 "Cannot delete main repository worktree".to_string()
51}
52
53pub fn detached_head_warning() -> String {
54 "Worktree is detached or branch not found. Specify branch with --branch or skip with --force."
55 .to_string()
56}
57
58pub fn deleting_local_branch(branch: &str) -> String {
63 format!("Deleting local branch: {}", branch)
64}
65
66pub fn deleting_remote_branch(branch: &str) -> String {
67 format!("Deleting remote branch: origin/{}", branch)
68}
69
70pub fn removing_worktree(path: &std::path::Path) -> String {
71 format!("Removing worktree: {}", path.display())
72}
73
74pub fn starting_ai_tool_foreground(tool_name: &str) -> String {
75 format!("Starting {} (Ctrl+C to exit)...", tool_name)
76}
77
78pub fn starting_ai_tool_in(tool_name: &str) -> String {
79 format!("Starting {} in:", tool_name)
80}
81
82pub fn resuming_ai_tool_in(tool_name: &str) -> String {
83 format!("Resuming {} in:", tool_name)
84}
85
86pub fn switched_to_worktree(path: &std::path::Path) -> String {
87 format!("Switched to worktree: {}", path.display())
88}
89
90pub fn worktree_unlocking_stale(path: &str, pid: u32) -> String {
91 format!("info: stale lock from dead pid {pid} on {path} — unlocking")
92}
93
94pub fn worktree_locked_live_pid(path: &str, pid: u32) -> String {
95 format!(
96 "Worktree {path} is locked by pid {pid} which is still running — \
97 refusing to unlock. Stop that process or unlock manually with \
98 `git worktree unlock {path}`."
99 )
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn test_worktree_not_found() {
108 let msg = worktree_not_found("feature-x");
109 assert!(msg.contains("feature-x"));
110 assert!(msg.contains("gw list"));
111 assert!(msg.contains("No worktree found"));
112 }
113
114 #[test]
115 fn test_target_not_found() {
116 let msg = target_not_found("my-target");
117 assert!(msg.contains("my-target"));
118 assert!(msg.contains("name, branch, path"));
119 assert!(msg.contains("gw list"));
120 }
121
122 #[test]
123 fn test_branch_not_found() {
124 let msg = branch_not_found("my-branch");
125 assert!(msg.contains("my-branch"));
126 assert!(msg.contains("not found"));
127 }
128
129 #[test]
130 fn test_invalid_branch_name() {
131 let msg = invalid_branch_name("contains spaces");
132 assert!(msg.contains("contains spaces"));
133 assert!(msg.contains("Invalid branch name"));
134 assert!(msg.contains("Hint"));
135 assert!(msg.contains("alphanumeric"));
136 }
137
138 #[test]
139 fn test_cannot_determine_branch() {
140 let msg = cannot_determine_branch();
141 assert!(msg.contains("Cannot determine current branch"));
142 }
143
144 #[test]
145 fn test_cannot_determine_base_branch() {
146 let msg = cannot_determine_base_branch();
147 assert!(msg.contains("Cannot determine base branch"));
148 assert!(msg.contains("--base"));
149 }
150
151 #[test]
152 fn test_missing_metadata() {
153 let msg = missing_metadata("feat-login");
154 assert!(msg.contains("feat-login"));
155 assert!(msg.contains("Missing metadata"));
156 assert!(msg.contains("gw new"));
157 }
158
159 #[test]
160 fn test_worktree_dir_not_found() {
161 let msg = worktree_dir_not_found("/tmp/worktree");
162 assert!(msg.contains("/tmp/worktree"));
163 assert!(msg.contains("does not exist"));
164 }
165
166 #[test]
167 fn test_cannot_delete_main_worktree() {
168 let msg = cannot_delete_main_worktree();
169 assert!(msg.contains("Cannot delete main repository worktree"));
170 }
171
172 #[test]
173 fn test_detached_head_warning() {
174 let msg = detached_head_warning();
175 assert!(msg.contains("detached"));
176 assert!(msg.contains("--branch"));
177 assert!(msg.contains("--force"));
178 }
179
180 #[test]
181 fn test_deleting_local_branch() {
182 let msg = deleting_local_branch("feat-x");
183 assert!(msg.contains("Deleting local branch: feat-x"));
184 }
185
186 #[test]
187 fn test_deleting_remote_branch() {
188 let msg = deleting_remote_branch("feat-x");
189 assert!(msg.contains("origin/feat-x"));
190 }
191
192 #[test]
193 fn test_removing_worktree() {
194 let msg = removing_worktree(std::path::Path::new("/tmp/wt"));
195 assert!(msg.contains("Removing worktree:"));
196 assert!(msg.contains("/tmp/wt"));
197 }
198
199 #[test]
200 fn test_starting_ai_tool_foreground() {
201 let msg = starting_ai_tool_foreground("claude");
202 assert!(msg.contains("Starting claude"));
203 assert!(msg.contains("Ctrl+C"));
204 }
205
206 #[test]
207 fn test_starting_ai_tool_in() {
208 let msg = starting_ai_tool_in("claude");
209 assert_eq!(msg, "Starting claude in:");
210 }
211
212 #[test]
213 fn test_resuming_ai_tool_in() {
214 let msg = resuming_ai_tool_in("claude");
215 assert_eq!(msg, "Resuming claude in:");
216 }
217
218 #[test]
219 fn test_switched_to_worktree() {
220 let msg = switched_to_worktree(std::path::Path::new("/tmp/wt"));
221 assert!(msg.contains("Switched to worktree:"));
222 assert!(msg.contains("/tmp/wt"));
223 }
224}