1use crate::console::{ConsoleOptions, Renderable, RenderResult};
4use crate::segment::Segment;
5use crate::style::Style;
6use std::fs;
7use std::path::PathBuf;
8use std::time::SystemTime;
9
10#[derive(Debug, Clone)]
12pub struct FileProxy {
13 path: PathBuf,
14 content: String,
15 last_modified: Option<SystemTime>,
16 max_lines: Option<usize>,
17 style: Style,
18}
19
20impl FileProxy {
21 pub fn new(path: impl Into<PathBuf>) -> Self {
22 let path = path.into();
23 let content = fs::read_to_string(&path).unwrap_or_default();
24 let last_modified = fs::metadata(&path).ok().and_then(|m| m.modified().ok());
25 Self {
26 path,
27 content,
28 last_modified,
29 max_lines: None,
30 style: Style::new(),
31 }
32 }
33
34 pub fn max_lines(mut self, max: usize) -> Self {
36 self.max_lines = Some(max);
37 self
38 }
39
40 pub fn style(mut self, style: Style) -> Self {
42 self.style = style;
43 self
44 }
45
46 pub fn refresh(&mut self) -> bool {
48 if let Ok(meta) = fs::metadata(&self.path) {
49 if let Ok(modified) = meta.modified() {
50 if self.last_modified.map_or(true, |last| modified > last) {
51 if let Ok(content) = fs::read_to_string(&self.path) {
52 self.content = content;
53 self.last_modified = Some(modified);
54 return true;
55 }
56 }
57 }
58 }
59 false
60 }
61
62 pub fn content(&self) -> &str {
64 &self.content
65 }
66}
67
68impl Renderable for FileProxy {
69 fn render(&self, _options: &ConsoleOptions) -> RenderResult {
70 let lines: Vec<&str> = self.content.lines().collect();
71 let displayed = if let Some(max) = self.max_lines {
72 &lines[..lines.len().min(max)]
73 } else {
74 &lines
75 };
76
77 let seg_lines: Vec<Vec<Segment>> = displayed
78 .iter()
79 .map(|line| vec![Segment::new(line.to_string())])
80 .collect();
81
82 RenderResult {
83 lines: seg_lines,
84 items: Vec::new(),
85 }
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92 use std::io::Write;
93
94 #[test]
95 fn test_file_proxy() {
96 let dir = std::env::temp_dir();
97 let path = dir.join("rusty_rich_test_file_proxy.txt");
98 let mut f = std::fs::File::create(&path).unwrap();
99 write!(f, "line1\nline2\nline3").unwrap();
100 drop(f);
101
102 let proxy = FileProxy::new(&path).max_lines(2);
103 let content = proxy.content();
104 assert!(content.contains("line1"));
105
106 let _ = std::fs::remove_file(&path);
107 }
108}