A file-based task manager
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

tsk-42: fzf picker for queue switch

Mirrors `tsk switch` (namespace) — `tsk queue switch` now takes an
optional name and fzf-picks when omitted, with a `<new>` sentinel that
creates the queue (can-pull=false) on the fly. Generalized the picker
helper so namespace and queue share one code path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

+34 -18
+34 -18
src/lib.rs
··· 320 320 #[arg(short = 'p', default_value_t = false)] 321 321 can_pull: bool, 322 322 }, 323 - Switch { name: String }, 323 + /// Switch active queue. With no name, fzf-picks from existing queues 324 + /// (plus a `<new>` sentinel for creating one on the fly). 325 + Switch { name: Option<String> }, 324 326 } 325 327 326 328 #[derive(Subcommand)] ··· 976 978 ws.create_queue(&name, Some(can_pull))?; 977 979 println!("Created queue '{name}' (can-pull={can_pull})"); 978 980 } 979 - QueueAction::Switch { name } => ws.switch_queue(&name)?, 981 + QueueAction::Switch { name } => return resolve_and_switch_queue(&ws, name), 980 982 } 981 983 Ok(()) 982 984 } ··· 986 988 fn resolve_and_switch_namespace(ws: &Workspace, name: Option<String>) -> Result<()> { 987 989 let target = match name { 988 990 Some(n) => n, 989 - None => pick_namespace(ws)?, 991 + None => pick_with_new(&ws.list_namespaces()?, &ws.namespace(), "namespace")?, 990 992 }; 991 993 ws.switch_namespace(&target)?; 992 994 println!("Switched to namespace '{target}'"); 993 995 Ok(()) 994 996 } 995 997 996 - fn pick_namespace(ws: &Workspace) -> Result<String> { 997 - let cur = ws.namespace(); 998 - let existing = ws.list_namespaces()?; 999 - let entries = namespace_picker_entries(&existing, &cur); 1000 - let picked = fzf::select::<_, String, _>(entries, ["--prompt=namespace> "])? 1001 - .ok_or_else(|| errors::Error::Parse("No namespace selected".into()))?; 998 + fn resolve_and_switch_queue(ws: &Workspace, name: Option<String>) -> Result<()> { 999 + let target = match name { 1000 + Some(n) => n, 1001 + None => { 1002 + let picked = pick_with_new(&ws.list_queues()?, &ws.queue(), "queue")?; 1003 + if !ws.list_queues()?.iter().any(|q| q == &picked) { 1004 + ws.create_queue(&picked, None)?; 1005 + } 1006 + picked 1007 + } 1008 + }; 1009 + ws.switch_queue(&target)?; 1010 + println!("Switched to queue '{target}'"); 1011 + Ok(()) 1012 + } 1013 + 1014 + fn pick_with_new(existing: &[String], current: &str, label: &str) -> Result<String> { 1015 + let entries = picker_entries(existing, current); 1016 + let picked = fzf::select::<_, String, _>(entries, [format!("--prompt={label}> ")])? 1017 + .ok_or_else(|| errors::Error::Parse(format!("No {label} selected")))?; 1002 1018 let picked = strip_picker_marker(&picked); 1003 1019 if picked == NEW_NS_SENTINEL { 1004 - let name = prompt_line("New namespace name: ")?; 1020 + let name = prompt_line(&format!("New {label} name: "))?; 1005 1021 if name.is_empty() { 1006 - return Err(errors::Error::Parse("Empty namespace name".into())); 1022 + return Err(errors::Error::Parse(format!("Empty {label} name"))); 1007 1023 } 1008 1024 Ok(name) 1009 1025 } else { ··· 1011 1027 } 1012 1028 } 1013 1029 1014 - /// Build the fzf input lines for namespace selection: every existing 1015 - /// namespace (active marked with `* `, others with ` `) plus a trailing 1016 - /// `<new>` sentinel for creating one on the fly. The active namespace is 1017 - /// always present even when no refs have been written yet. 1018 - fn namespace_picker_entries(existing: &[String], current: &str) -> Vec<String> { 1030 + /// Build the fzf input lines: every existing entry (active marked with 1031 + /// `* `, others with ` `) plus a trailing `<new>` sentinel for creating 1032 + /// one on the fly. The active entry is always present even when no refs 1033 + /// have been written yet. 1034 + fn picker_entries(existing: &[String], current: &str) -> Vec<String> { 1019 1035 let mut entries: Vec<String> = existing 1020 1036 .iter() 1021 1037 .map(|n| { ··· 1064 1080 1065 1081 #[test] 1066 1082 fn picker_marks_current_and_appends_sentinel() { 1067 - let entries = namespace_picker_entries( 1083 + let entries = picker_entries( 1068 1084 &["alpha".to_string(), "tsk".to_string()], 1069 1085 "tsk", 1070 1086 ); ··· 1073 1089 1074 1090 #[test] 1075 1091 fn picker_includes_current_when_missing_from_list() { 1076 - let entries = namespace_picker_entries(&[], "tsk"); 1092 + let entries = picker_entries(&[], "tsk"); 1077 1093 assert_eq!(entries, vec!["* tsk", "<new>"]); 1078 1094 } 1079 1095