1use serde::{Deserialize, Serialize};
7
8pub const MAX_SNIPPET_LINES: usize = 20;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct CodeSnippet {
14 pub content: String,
16 pub truncated: bool,
18}
19
20pub fn truncate_snippet(raw: &str) -> CodeSnippet {
24 truncate_snippet_to(raw, MAX_SNIPPET_LINES)
25}
26
27pub fn truncate_snippet_to(raw: &str, max_lines: usize) -> CodeSnippet {
31 let lines: Vec<&str> = raw.lines().collect();
32 if lines.len() > max_lines {
33 CodeSnippet {
34 content: lines[..max_lines].join("\n"),
35 truncated: true,
36 }
37 } else {
38 CodeSnippet {
39 content: raw.to_owned(),
40 truncated: false,
41 }
42 }
43}
44
45#[cfg(test)]
48mod tests {
49 use super::*;
50
51 #[test]
52 fn short_content_is_not_truncated() {
53 let snippet = truncate_snippet("line 1\nline 2\nline 3");
54 assert!(!snippet.truncated);
55 assert_eq!(snippet.content, "line 1\nline 2\nline 3");
56 }
57
58 #[test]
59 fn exact_limit_is_not_truncated() {
60 let lines: Vec<String> = (1..=MAX_SNIPPET_LINES)
61 .map(|i| format!("line {i}"))
62 .collect();
63 let raw = lines.join("\n");
64 let result = truncate_snippet(&raw);
65 assert!(!result.truncated);
66 assert_eq!(result.content, raw);
67 }
68
69 #[test]
70 fn over_limit_is_truncated() {
71 let lines: Vec<String> = (1..=25).map(|i| format!("line {i}")).collect();
72 let raw = lines.join("\n");
73 let result = truncate_snippet(&raw);
74 assert!(result.truncated);
75 let result_lines: Vec<&str> = result.content.lines().collect();
76 assert_eq!(result_lines.len(), MAX_SNIPPET_LINES);
77 assert_eq!(result_lines[0], "line 1");
78 assert_eq!(
79 result_lines[MAX_SNIPPET_LINES - 1],
80 format!("line {MAX_SNIPPET_LINES}")
81 );
82 }
83}