command_stream/commands/
echo.rs1use crate::commands::CommandContext;
4use crate::utils::CommandResult;
5
6pub async fn echo(ctx: CommandContext) -> CommandResult {
11 let mut no_newline = false;
12 let mut interpret_escapes = false;
13 let mut args = ctx.args.iter().peekable();
14
15 while let Some(arg) = args.peek() {
17 if arg.starts_with('-')
18 && arg.len() > 1
19 && arg
20 .chars()
21 .skip(1)
22 .all(|c| c == 'n' || c == 'e' || c == 'E')
23 {
24 let arg = args.next().unwrap();
25 for c in arg.chars().skip(1) {
26 match c {
27 'n' => no_newline = true,
28 'e' => interpret_escapes = true,
29 'E' => interpret_escapes = false,
30 _ => {}
31 }
32 }
33 } else {
34 break;
35 }
36 }
37
38 let remaining: Vec<_> = args.collect();
40 let output = remaining
41 .iter()
42 .map(|s| s.as_str())
43 .collect::<Vec<_>>()
44 .join(" ");
45
46 let output = if interpret_escapes {
48 output
49 .replace("\\n", "\n")
50 .replace("\\t", "\t")
51 .replace("\\r", "\r")
52 .replace("\\\\", "\\")
53 } else {
54 output
55 };
56
57 if no_newline {
58 CommandResult::success(output)
59 } else {
60 CommandResult::success(format!("{}\n", output))
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[tokio::test]
69 async fn test_echo_simple() {
70 let ctx = CommandContext::new(vec!["hello".to_string(), "world".to_string()]);
71 let result = echo(ctx).await;
72 assert!(result.is_success());
73 assert_eq!(result.stdout, "hello world\n");
74 }
75
76 #[tokio::test]
77 async fn test_echo_empty() {
78 let ctx = CommandContext::new(vec![]);
79 let result = echo(ctx).await;
80 assert!(result.is_success());
81 assert_eq!(result.stdout, "\n");
82 }
83}