1use super::super::i18n::I18n;
2use crate::theme::for_path_tree::get_file_type;
3use std::fs;
4use std::path::Path;
5
6pub struct SaveFile;
7
8impl SaveFile {
9 pub fn generate_by_section(tag: &str, enter_path: &str, i18n: &I18n, cmd: &str) -> String {
11 let mut f = String::new();
12 f.push_str("\n\n---\n\n");
13 f.push_str("> | Property | Value |\n");
14 f.push_str("> | ---: | :--- |\n");
15 f.push_str(&format!(
16 "> | **{}** | `cargo-plot v0.2.0` |\n",
17 i18n.footer_tool()
18 ));
19 f.push_str(&format!(
20 "> | **{}** | `{}` |\n",
21 i18n.footer_input(),
22 enter_path
23 ));
24 f.push_str(&format!("> | **{}** | `{}` |\n", i18n.footer_cmd(), cmd));
25 f.push_str(&format!("> | **{}** | `{}` |\n", i18n.footer_tag(), tag));
26
27 let links = "[Crates.io](https://crates.io/crates/cargo-plot) \\| [GitHub](https://github.com/j-Cis/cargo-plot/releases)";
28 f.push_str(&format!("> | **{}** | {} |\n", i18n.footer_links(), links));
29 f.push_str(&format!(
30 "> | **{}** | `cargo install cargo-plot` |\n",
31 i18n.footer_links()
32 ));
33 f.push_str(&format!(
34 "> | **{}** | `cargo plot --help` |\n",
35 i18n.footer_help()
36 ));
37 f.push_str("\n---\n");
38 f
39 }
40
41 fn write_to_disk(filepath: &str, content: &str, log_name: &str, i18n: &I18n) {
43 let path = Path::new(filepath);
44
45 if let Some(parent) = path.parent()
46 && !parent.as_os_str().is_empty()
47 && !parent.exists()
48 && let Err(e) = fs::create_dir_all(parent)
49 {
50 eprintln!(
51 "{}",
52 i18n.dir_create_err(&parent.to_string_lossy(), &e.to_string())
53 );
54 return;
55 }
56
57 match fs::write(path, content) {
58 Ok(_) => println!("{}", i18n.save_success(log_name, filepath)),
59 Err(e) => eprintln!("{}", i18n.save_err(log_name, filepath, &e.to_string())),
60 }
61 }
62
63 pub fn paths(
65 content: &str,
66 filepath: &str,
67 tag: &str,
68 add_by: bool,
69 i18n: &I18n,
70 cmd: &str,
71 enter_path: &str,
72 ) {
73 let by_section = if add_by {
74 Self::generate_by_section(tag, enter_path, i18n, cmd)
75 } else {
76 String::new()
77 };
78 let internal_tag = if add_by { "" } else { tag };
79 let file_name = Path::new(filepath)
80 .file_name()
81 .unwrap_or_default()
82 .to_string_lossy();
83
84 let markdown_content = format!(
85 "# {}\n\n```plaintext\n{}\n```\n\n{}{}",
86 file_name, content, internal_tag, by_section
87 );
88
89 Self::write_to_disk(
90 filepath,
91 &markdown_content,
92 if i18n.lang == crate::i18n::Lang::Pl {
93 "ścieżki"
94 } else {
95 "paths"
96 },
97 i18n,
98 );
99 }
100
101 pub fn codes(
103 tree_text: &str,
104 paths: &[String],
105 base_dir: &str,
106 filepath: &str,
107 tag: &str,
108 add_by: bool,
109 i18n: &I18n,
110 cmd: &str,
111 enter_path: &str,
112 ) {
113 let by_section = if add_by {
114 Self::generate_by_section(tag, enter_path, i18n, cmd)
115 } else {
116 String::new()
117 };
118 let internal_tag = if add_by { "" } else { tag };
119 let file_name = Path::new(filepath)
120 .file_name()
121 .unwrap_or_default()
122 .to_string_lossy();
123
124 let mut content = String::new();
125 content.push_str(&format!("# {}\n\n", file_name));
126
127 content.push_str("```plaintext\n");
129 content.push_str(tree_text);
130 content.push_str("```\n\n");
131
132 let mut counter = 1;
133
134 for p_str in paths {
135 if p_str.ends_with('/') {
136 continue; }
138
139 let absolute_path = Path::new(base_dir).join(p_str);
140 let ext = absolute_path
141 .extension()
142 .unwrap_or_default()
143 .to_string_lossy()
144 .to_lowercase();
145
146 let lang = get_file_type(&ext).md_lang;
147
148 if is_blacklisted_extension(&ext) {
149 content.push_str(&format!(
150 "### {:03}: `{}`\n\n{}\n\n",
151 counter,
152 p_str,
153 i18n.skip_binary()
154 ));
155 counter += 1;
156 continue;
157 }
158
159 match fs::read_to_string(&absolute_path) {
160 Ok(file_content) => {
161 content.push_str(&format!(
162 "### {:03}: `{}`\n\n```{}\n{}\n```\n\n",
163 counter, p_str, lang, file_content
164 ));
165 }
166 Err(_) => {
167 content.push_str(&format!(
168 "### {:03}: `{}`\n\n{}\n\n",
169 counter,
170 p_str,
171 i18n.read_err()
172 ));
173 }
174 }
175 counter += 1;
176 }
177
178 content.push_str(&format!("\n\n{}{}", internal_tag, by_section));
179 Self::write_to_disk(
180 filepath,
181 &content,
182 if i18n.lang == crate::i18n::Lang::Pl {
183 "kod (cache)"
184 } else {
185 "code (cache)"
186 },
187 i18n,
188 );
189 }
190}
191
192pub fn is_blacklisted_extension(ext: &str) -> bool {
198 let e = ext.to_lowercase();
199
200 matches!(
201 e.as_str(),
202 "png" | "jpg" | "jpeg" | "gif" | "bmp" | "ico" | "svg" | "webp" | "tiff" | "tif" | "heic" | "psd" |
206 "ai" |
207 "exe" | "dll" | "so" | "dylib" | "bin" | "wasm" | "pdb" | "rlib" | "rmeta" | "lib" |
211 "o" | "a" | "obj" | "pch" | "ilk" | "exp" |
212 "jar" | "class" | "war" | "ear" |
213 "pyc" | "pyd" | "pyo" | "whl" |
214 "zip" | "tar" | "gz" | "tgz" | "7z" | "rar" | "bz2" | "xz" | "iso" | "dmg" | "pkg" | "apk" |
218 "sqlite" | "sqlite3" | "db" | "db3" | "mdf" | "ldf" | "rdb" |
222 "pdf" | "doc" | "docx" | "xls" | "xlsx" | "ppt" | "pptx" | "odt" | "ods" | "odp" |
223 "woff" | "woff2" | "ttf" | "eot" | "otf" |
224 "mp3" | "mp4" | "avi" | "mkv" | "wav" | "flac" | "ogg" | "m4a" | "mov" | "wmv" | "flv"
228 )
229}