Skip to main content

lean_ctx_patterns/
glab.rs

1// SPDX-License-Identifier: Apache-2.0
2
3pub fn try_glab_pattern(cmd: &str, output: &str) -> Option<String> {
4    let parts: Vec<&str> = cmd.split_whitespace().collect();
5    if parts.is_empty() || parts[0] != "glab" {
6        return None;
7    }
8    if parts.len() < 2 {
9        return None;
10    }
11
12    match parts[1] {
13        "issue" => try_glab_issue(parts.get(2).copied(), output),
14        "mr" => try_glab_mr(parts.get(2).copied(), output),
15        "ci" => try_glab_ci(parts.get(2).copied(), output),
16        _ => None,
17    }
18}
19
20fn try_glab_issue(subcommand: Option<&str>, output: &str) -> Option<String> {
21    match subcommand.unwrap_or("") {
22        "list" => Some(compress_table_output("glab issues", output)),
23        "view" => Some(compress_detail_output("issue", output)),
24        _ => None,
25    }
26}
27
28fn try_glab_mr(subcommand: Option<&str>, output: &str) -> Option<String> {
29    match subcommand.unwrap_or("") {
30        "list" => Some(compress_table_output("glab MRs", output)),
31        "view" => Some(compress_detail_output("MR", output)),
32        _ => None,
33    }
34}
35
36fn try_glab_ci(subcommand: Option<&str>, output: &str) -> Option<String> {
37    match subcommand.unwrap_or("") {
38        "status" | "list" | "view" => Some(compress_ci_output(output)),
39        _ => None,
40    }
41}
42
43fn compress_table_output(label: &str, output: &str) -> String {
44    let lines: Vec<&str> = output.lines().collect();
45    if lines.is_empty() {
46        return format!("{label}: (empty)");
47    }
48    let count = lines.len().saturating_sub(1);
49    let mut result = format!("{label} ({count}):\n");
50    for line in &lines {
51        let trimmed = line.trim();
52        if !trimmed.is_empty() {
53            result.push_str(&format!("  {trimmed}\n"));
54        }
55    }
56    result
57}
58
59fn compress_detail_output(kind: &str, output: &str) -> String {
60    let mut result = String::new();
61    let mut in_body = false;
62    let mut body_lines = 0;
63    const MAX_BODY_LINES: usize = 30;
64
65    for line in output.lines() {
66        let trimmed = line.trim();
67        if trimmed.starts_with("title:")
68            || trimmed.starts_with("state:")
69            || trimmed.starts_with("author:")
70            || trimmed.starts_with("labels:")
71            || trimmed.starts_with("milestone:")
72            || trimmed.starts_with("assignees:")
73            || trimmed.starts_with("created:")
74            || trimmed.starts_with("updated:")
75        {
76            result.push_str(&format!("{trimmed}\n"));
77            in_body = false;
78        } else if trimmed == "--" || trimmed.starts_with("---") {
79            in_body = true;
80            result.push_str("---\n");
81        } else if in_body {
82            body_lines += 1;
83            if body_lines <= MAX_BODY_LINES {
84                result.push_str(&format!("{line}\n"));
85            } else if body_lines == MAX_BODY_LINES + 1 {
86                result.push_str(&format!("... ({kind} body truncated)\n"));
87            }
88        } else if !trimmed.is_empty() {
89            result.push_str(&format!("{trimmed}\n"));
90        }
91    }
92    result
93}
94
95fn compress_ci_output(output: &str) -> String {
96    let mut result = String::from("CI pipeline:\n");
97    for line in output.lines() {
98        let trimmed = line.trim();
99        if trimmed.is_empty() {
100            continue;
101        }
102        result.push_str(&format!("  {trimmed}\n"));
103    }
104    result
105}