Skip to main content

limit_cli/tui/
activity.rs

1//! Activity message formatting for TUI
2//!
3//! Formats tool execution messages for display in the activity feed.
4
5/// Format a tool activity message based on tool name and arguments
6pub fn format_activity_message(tool_name: &str, args: &serde_json::Value) -> String {
7    match tool_name {
8        "file_read" => format_file_read(args),
9        "file_write" => format_file_write(args),
10        "file_edit" => format_file_edit(args),
11        "bash" => format_bash(args),
12        "git_status" => "Checking git status...".to_string(),
13        "git_diff" => "Checking git diff...".to_string(),
14        "git_log" => "Checking git log...".to_string(),
15        "git_add" => "Staging files...".to_string(),
16        "git_commit" => "Creating commit...".to_string(),
17        "git_push" => "Pushing to remote...".to_string(),
18        "git_pull" => "Pulling from remote...".to_string(),
19        "git_clone" => format_git_clone(args),
20        "grep" => format_grep(args),
21        "ast_grep" => format_ast_grep(args),
22        "lsp" => format_lsp(args),
23        _ => format!("Executing {}...", tool_name),
24    }
25}
26
27/// Format file read operation
28fn format_file_read(args: &serde_json::Value) -> String {
29    args.get("path")
30        .and_then(|p| p.as_str())
31        .map(|p| format!("Reading {}...", truncate_path(p, 150)))
32        .unwrap_or_else(|| "Reading file...".to_string())
33}
34
35/// Format file write operation
36fn format_file_write(args: &serde_json::Value) -> String {
37    args.get("path")
38        .and_then(|p| p.as_str())
39        .map(|p| format!("Writing {}...", truncate_path(p, 150)))
40        .unwrap_or_else(|| "Writing file...".to_string())
41}
42
43/// Format file edit operation
44fn format_file_edit(args: &serde_json::Value) -> String {
45    args.get("path")
46        .and_then(|p| p.as_str())
47        .map(|p| format!("Editing {}...", truncate_path(p, 150)))
48        .unwrap_or_else(|| "Editing file...".to_string())
49}
50
51/// Format bash command
52fn format_bash(args: &serde_json::Value) -> String {
53    args.get("command")
54        .and_then(|c| c.as_str())
55        .map(|c| format!("Running {}...", truncate_command(c, 150)))
56        .unwrap_or_else(|| "Executing command...".to_string())
57}
58
59/// Format git clone operation
60fn format_git_clone(args: &serde_json::Value) -> String {
61    args.get("url")
62        .and_then(|u| u.as_str())
63        .map(|u| format!("Cloning {}...", truncate_path(u, 150)))
64        .unwrap_or_else(|| "Cloning repository...".to_string())
65}
66
67/// Format grep search
68fn format_grep(args: &serde_json::Value) -> String {
69    args.get("pattern")
70        .and_then(|p| p.as_str())
71        .map(|p| format!("Searching for '{}'...", truncate_command(p, 150)))
72        .unwrap_or_else(|| "Searching...".to_string())
73}
74
75/// Format AST grep search
76fn format_ast_grep(args: &serde_json::Value) -> String {
77    args.get("pattern")
78        .and_then(|p| p.as_str())
79        .map(|p| format!("AST searching '{}'...", truncate_command(p, 150)))
80        .unwrap_or_else(|| "AST searching...".to_string())
81}
82
83/// Format LSP operation
84fn format_lsp(args: &serde_json::Value) -> String {
85    args.get("command")
86        .and_then(|c| c.as_str())
87        .map(|c| format!("Running LSP {}...", c))
88        .unwrap_or_else(|| "Running LSP...".to_string())
89}
90
91/// Truncate a path for display, showing the end
92fn truncate_path(s: &str, max_len: usize) -> String {
93    if s.len() <= max_len {
94        s.to_string()
95    } else {
96        format!("...{}", &s[s.len().saturating_sub(max_len - 3)..])
97    }
98}
99
100/// Truncate a command for display, showing the beginning
101fn truncate_command(s: &str, max_len: usize) -> String {
102    if s.len() <= max_len {
103        s.to_string()
104    } else {
105        format!("{}...", &s[..max_len.saturating_sub(3)])
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112    use serde_json::json;
113
114    #[test]
115    fn test_format_file_read() {
116        let args = json!({"path": "/some/long/path/to/file.txt"});
117        let msg = format_activity_message("file_read", &args);
118        assert!(msg.contains("Reading"));
119    }
120
121    #[test]
122    fn test_format_bash() {
123        let args = json!({"command": "echo hello"});
124        let msg = format_activity_message("bash", &args);
125        assert!(msg.contains("Running"));
126    }
127
128    #[test]
129    fn test_format_unknown_tool() {
130        let args = json!({});
131        let msg = format_activity_message("unknown_tool", &args);
132        assert_eq!(msg, "Executing unknown_tool...");
133    }
134
135    #[test]
136    fn test_truncate_path() {
137        assert_eq!(truncate_path("short", 10), "short");
138        assert_eq!(
139            truncate_path("very_long_path_to_file.txt", 14),
140            "...to_file.txt"
141        );
142    }
143
144    #[test]
145    fn test_truncate_command() {
146        assert_eq!(truncate_command("short", 10), "short");
147        assert_eq!(truncate_command("very_long_command_here", 10), "very_lo...");
148    }
149
150    #[test]
151    fn test_git_commands() {
152        assert_eq!(
153            format_activity_message("git_status", &json!({})),
154            "Checking git status..."
155        );
156        assert_eq!(
157            format_activity_message("git_diff", &json!({})),
158            "Checking git diff..."
159        );
160        assert_eq!(
161            format_activity_message("git_add", &json!({})),
162            "Staging files..."
163        );
164        assert_eq!(
165            format_activity_message("git_commit", &json!({})),
166            "Creating commit..."
167        );
168    }
169
170    #[test]
171    fn test_file_operations() {
172        let args = json!({"path": "/test.txt"});
173        assert!(format_activity_message("file_read", &args).contains("Reading"));
174        assert!(format_activity_message("file_write", &args).contains("Writing"));
175        assert!(format_activity_message("file_edit", &args).contains("Editing"));
176    }
177}