lexigram_lib/
file_utils.rs1use std::error::Error;
4use std::fmt::{Display, Formatter};
5use std::io::{BufRead, BufReader, BufWriter, Read, Write, Seek};
6use std::fs::{File, OpenOptions};
7use lexigram_core::CollectJoin;
8
9#[derive(Debug)]
10pub enum SrcTagError {
11 Io(std::io::Error),
12 NoTag,
13 NoClosingTag,
14}
15
16impl From<std::io::Error> for SrcTagError {
17 fn from(err: std::io::Error) -> Self {
18 SrcTagError::Io(err)
19 }
20}
21
22impl Display for SrcTagError {
23 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
24 match self {
25 SrcTagError::Io(e) => e.fmt(f),
26 SrcTagError::NoTag => write!(f, "opening tag not found"),
27 SrcTagError::NoClosingTag => write!(f, "closing tag not found"),
28 }
29 }
30}
31
32impl Error for SrcTagError {
33 fn source(&self) -> Option<&(dyn Error + 'static)> {
34 match self {
35 SrcTagError::Io(e) => Some(e),
36 SrcTagError::NoTag => None,
37 SrcTagError::NoClosingTag => None,
38 }
39 }
40}
41
42pub fn get_tagged_source(filename: &str, tag: &str) -> Result<String, SrcTagError> {
47 let file_tag = format!("[{tag}]");
48 let file = File::open(filename)?;
49 let mut opening_tag_found = false;
50 let mut closing_tag_found = false;
51 let result = BufReader::new(file).lines()
52 .filter_map(|l| l.ok())
53 .skip_while(|l| !l.contains(&file_tag))
54 .inspect(|_| opening_tag_found = true)
55 .skip(2)
56 .take_while(|l| !l.contains(&file_tag))
57 .inspect(|_| closing_tag_found = true)
58 .map(|mut s| {
59 s.truncate(s.trim_end().len());
60 s
61 })
62 .join("\n"); if closing_tag_found {
64 Ok(result)
65 } else if opening_tag_found {
66 Err(SrcTagError::NoClosingTag)
67 } else {
68 Err(SrcTagError::NoTag)
69 }
70}
71
72pub fn replace_tagged_source(filename: &str, tag: &str, new_src: &str) -> Result<(), SrcTagError> {
75 let file_tag = format!("[{tag}]");
76 let file = File::open(filename)?;
77 let mut buf = BufReader::new(file);
78 let mut count = 0;
79 let mut line = String::new();
80 let mut after = String::new();
81 let mut position = 0;
82 loop {
83 line.clear();
84 match buf.read_line(&mut line) {
85 Ok(n) => if n == 0 {
86 return if count == 0 { Err(SrcTagError::NoTag) } else { Err(SrcTagError::NoClosingTag) };
87 }
88 Err(e) => return Err(SrcTagError::Io(e)),
89 }
90 if line.contains(&file_tag) {
91 count += 1;
92 match count {
93 1 => {
94 position = buf.stream_position()?;
95 }
96 2 => {
97 after.push_str(&line);
98 buf.read_to_string(&mut after)?;
99 break;
100 }
101 _ => panic!()
102 }
103 }
104 }
105 let file = OpenOptions::new().write(true).open(filename)?;
106 file.set_len(position)?;
107 let mut buf = BufWriter::new(file);
108 buf.seek(std::io::SeekFrom::End(0))?;
109 write!(&mut buf, "\n{new_src}\n{after}")?;
110 Ok(())
111}