plot/lib/logic/
file_markdown_docs.rs1use std::{
2 fs,
3 path::{Path, PathBuf},
4};
5
6use console::strip_ansi_codes;
7
8#[allow(clippy::upper_case_acronyms)]
9enum ScOrCs {
10 SOTC,
11 COTS,
12}
13
14use crate::lib::logic::{LangMapper, PathNode, TableOutput, TagTime};
15
16pub struct DocMarkdown {
17 cwd: PathNode,
18 wrk: PathNode,
19 table: TableOutput,
20 timetag: TagTime,
21 content: String,
22}
23
24impl DocMarkdown {
25 pub fn new(content: impl Into<String>, table: TableOutput, cwd: PathNode, wrk: PathNode, timetag: TagTime) -> Self {
26 let raw = content.into();
27
28 let clean_content = strip_ansi_codes(&raw).into_owned().replace('\t', " ");
29
30 Self { cwd, wrk, table, timetag, content: clean_content }
31 }
32
33 fn structure_of_the_content_render(&self, title: Option<&str>) -> String {
38 let title_str = title.map_or(String::new(), |t| format!("{} ", t));
39 format!(
40 "# {}(STRUCTURE OF THE CONTENT v:{})\n\n```plaintext\n{}\n```\n",
41 title_str, self.timetag.0, self.content
42 )
43 }
44
45 fn content_of_the_structure_render(&self, code_blocks: &str, title: Option<&str>) -> String {
46 let title_str = title.map_or(String::new(), |t| format!("{} ", t));
47 format!(
48 "# {}(CONTENT OF THE STRUCTURE v:{})\n\n```plaintext\n{}\n```\n\n{}",
49 title_str, self.timetag.0, self.content, code_blocks
50 )
51 }
52
53 pub fn content_of_the_structure_build(&self, target_dir: &Path) -> String {
54 let mut content = String::new();
55
56 let (rows_to_show, index_offset) = if let Some(size) = self.table.trim_size {
57 let start = self.table.trim_page.saturating_sub(1) * size;
58 (self.table.data.rows.iter().skip(start).take(size).collect::<Vec<_>>(), start)
59 } else {
60 (self.table.data.rows.iter().collect::<Vec<_>>(), 0)
61 };
62
63 for (i, row) in rows_to_show.iter().enumerate() {
64 let actual_idx = index_offset + i + 1;
65 let p_str = &row.path;
66
67 if p_str.ends_with('/') {
68 continue;
69 }
70
71 let clean_rel = p_str.strip_prefix("./").unwrap_or(p_str);
72 let absolute_path = target_dir.join(clean_rel);
73
74 let ext = absolute_path.extension().unwrap_or_default().to_string_lossy().to_string();
75
76 let lang = LangMapper::get_md_lang(&ext);
77
78 if LangMapper::is_blacklisted(&ext) {
79 content.push_str(&format!(
80 "## {:03}: `{}`\n\n> *(Plik binarny/graficzny - pominięto zawartość)*\n\n",
81 actual_idx, p_str
82 ));
83 continue;
84 }
85
86 match fs::read_to_string(&absolute_path) {
87 Ok(file_content) => {
88 let safe_content = file_content.replace('\t', " ");
89 content.push_str(&format!(
90 "## {:03}: `{}`\n\n```{}\n{}\n```\n\n",
91 actual_idx, p_str, lang, safe_content
92 ));
93 }
94 Err(_) => {
95 content.push_str(&format!(
96 "## {:03}: `{}`\n\n> *(Błąd odczytu / plik nie jest UTF-8)*\n\n",
97 actual_idx, p_str
98 ));
99 }
100 }
101 }
102
103 content
104 }
105
106 pub fn structure_of_the_content_save_as(&self, relpath: &str, title: Option<&str>) -> std::io::Result<()> {
111 let file_path = self.path_build(relpath, ScOrCs::SOTC)?;
112 let content = self.structure_of_the_content_render(title);
113
114 Self::fs_write(&file_path, content)?;
115 Ok(())
116 }
117
118 pub fn content_of_the_structure_save_as(&self, relpath: &str, title: Option<&str>) -> std::io::Result<()> {
119 let file_path = self.path_build(relpath, ScOrCs::COTS)?;
120 let code_blocks = self.content_of_the_structure_build(&self.wrk.buf);
121 let content = self.content_of_the_structure_render(&code_blocks, title);
122
123 Self::fs_write(&file_path, content)?;
124 Ok(())
125 }
126
127 fn fs_write(file_path: &PathBuf, content: String) -> std::io::Result<()> {
132 fs::write(file_path, content)?;
133 println!("📦 Zapisano archiwum kodu do: {}", file_path.display());
134 Ok(())
135 }
136
137 fn path_build(&self, relpath: &str, suffix: ScOrCs) -> std::io::Result<PathBuf> {
138 let base_dir_path: PathBuf = self.cwd.buf.join(relpath);
139
140 let stem = base_dir_path.file_stem().unwrap_or_else(|| std::ffi::OsStr::new("output")).to_string_lossy();
141
142 let suffix_str = match suffix {
143 ScOrCs::COTS => "COTS",
144 ScOrCs::SOTC => "SOTC",
145 };
146
147 let file_name = format!("{}_{}_{}.md", stem, self.timetag.0, suffix_str);
148
149 let file_path = base_dir_path.with_file_name(file_name);
150
151 if let Some(parent) = file_path.parent() {
152 std::fs::create_dir_all(parent)?;
153 }
154
155 Ok(file_path)
156 }
157}