sift_queue/cli/commands/
list.rs1use crate::cli::formatters;
2use crate::queue::{Item, Queue};
3use crate::ListArgs;
4use anyhow::Result;
5use std::collections::HashSet;
6use std::io::Write;
7use std::path::PathBuf;
8use std::process::{Command, Stdio};
9
10pub fn execute(args: &ListArgs, queue_path: PathBuf) -> Result<i32> {
12 let queue = Queue::new(queue_path);
13
14 let mut items: Vec<Item> = if args.ready {
15 queue.ready()
16 } else if let Some(status) = args.status.as_deref() {
17 queue.filter(Some(status))
18 } else if args.all {
19 queue.filter(None)
20 } else {
21 queue
22 .all()
23 .into_iter()
24 .filter(|item| item.status != "closed")
25 .collect()
26 };
27
28 if let Some(ref filter_expr) = args.filter {
30 let expr = format!("[.[] | {}]", filter_expr);
31 match jq_filter(&items, &expr) {
32 Some(filtered) => items = filtered,
33 None => return Ok(1),
34 }
35 }
36
37 if let Some(ref sort_path) = args.sort {
39 let expr = format!("sort_by({} // infinite)", sort_path);
40 match jq_filter(&items, &expr) {
41 Some(sorted) => items = sorted,
42 None => return Ok(1),
43 }
44 } else {
45 items.sort_by_key(|item| {
46 (
47 item.priority.unwrap_or(5),
48 item.created_at.clone(),
49 item.id.clone(),
50 )
51 });
52 }
53
54 if args.reverse {
56 items.reverse();
57 }
58
59 if args.json {
60 let values: Vec<serde_json::Value> =
61 items.iter().map(|i: &Item| i.to_json_value()).collect();
62 let json = serde_json::to_string_pretty(&values)?;
63 println!("{}", json);
64 } else if items.is_empty() {
65 eprintln!("No items found");
66 } else {
67 let pending_ids: HashSet<String> = queue
68 .filter(Some("pending"))
69 .iter()
70 .map(|i| i.id.clone())
71 .collect();
72 for item in &items {
73 formatters::print_item_summary(item, Some(&pending_ids));
74 }
75 eprintln!("{} item(s)", items.len());
76 }
77
78 Ok(0)
79}
80
81fn jq_filter(items: &[Item], expr: &str) -> Option<Vec<Item>> {
83 let json_values: Vec<serde_json::Value> =
84 items.iter().map(|i: &Item| i.to_json_value()).collect();
85 let json = serde_json::to_string(&json_values).ok()?;
86
87 let mut child = Command::new("jq")
88 .arg("-e")
89 .arg(expr)
90 .stdin(Stdio::piped())
91 .stdout(Stdio::piped())
92 .stderr(Stdio::piped())
93 .spawn()
94 .map_err(|e| {
95 eprintln!("Error: Failed to run jq: {}", e);
96 })
97 .ok()?;
98
99 if let Some(ref mut stdin) = child.stdin {
100 stdin.write_all(json.as_bytes()).ok()?;
101 }
102 drop(child.stdin.take());
104
105 let output = child.wait_with_output().ok()?;
106
107 if !output.status.success() {
108 let stderr = String::from_utf8_lossy(&output.stderr);
109 eprintln!("Error: Filter failed: {}", stderr.trim());
110 return None;
111 }
112
113 let parsed: Vec<serde_json::Value> = serde_json::from_slice(&output.stdout).ok()?;
114 Some(
115 parsed
116 .into_iter()
117 .filter_map(|v| serde_json::from_value::<Item>(v).ok())
118 .collect(),
119 )
120}