1use crate::{
2 get_save_backup_file_path, load_textareas, save_textareas, EditorClipboard, ThemeMode,
3 ThothConfig,
4};
5use anyhow::{bail, Result};
6use std::{
7 fs::File,
8 io::{BufRead, BufReader, Write},
9};
10
11use std::env;
12
13use clap::{Parser, Subcommand};
14
15use crate::get_save_file_path;
16#[derive(Parser)]
17#[command(author = env!("CARGO_PKG_AUTHORS"), version = env!("CARGO_PKG_VERSION"), about, long_about = None, rename_all = "snake_case")]
18pub struct Cli {
19 #[command(subcommand)]
20 pub command: Option<Commands>,
21}
22
23#[derive(Subcommand)]
24#[command(rename_all = "snake_case")]
25pub enum Commands {
26 Add {
28 name: String,
30 content: Option<String>,
32 },
33 List,
35 LoadBackup,
37 ReadClipboard,
39 Delete {
41 name: String,
43 },
44 View {
46 name: String,
48 },
49 Copy {
51 name: String,
53 },
54 Theme {
56 mode: String,
58 },
59 GetTheme,
61}
62
63pub fn set_theme(mode: &str) -> Result<()> {
64 let mode_lowercase = mode.to_lowercase();
65
66 let mut config = ThothConfig::load()?;
67
68 match mode_lowercase.as_str() {
69 "light" => {
70 config.set_theme(ThemeMode::Light)?;
71 println!("Theme set to light mode");
72 }
73 "dark" => {
74 config.set_theme(ThemeMode::Dark)?;
75 println!("Theme set to dark mode");
76 }
77 _ => {
78 bail!("Invalid theme mode. Use 'light' or 'dark'");
79 }
80 }
81
82 Ok(())
83}
84
85pub fn get_theme() -> Result<()> {
86 let config = ThothConfig::load()?;
87
88 match config.theme {
89 ThemeMode::Light => println!("Current theme: light"),
90 ThemeMode::Dark => println!("Current theme: dark"),
91 }
92
93 Ok(())
94}
95
96pub fn read_clipboard_backup() -> Result<()> {
97 let file_path = crate::get_clipboard_backup_file_path();
98 if !file_path.exists() {
99 println!("No clipboard backup file found at {}", file_path.display());
100 return Ok(());
101 }
102
103 let content = std::fs::read_to_string(&file_path)?;
104 if content.is_empty() {
105 println!("Clipboard backup file exists but is empty.");
106 } else {
107 println!("{}", content);
108 }
109 Ok(())
110}
111
112pub fn add_block(name: &str, content: &str) -> Result<()> {
113 let mut file = std::fs::OpenOptions::new()
114 .append(true)
115 .create(true)
116 .open(get_save_file_path())?;
117
118 writeln!(file, "# {}", name)?;
119 writeln!(file, "{}", content)?;
120 writeln!(file)?;
121
122 println!("Block '{}' added successfully.", name);
123 Ok(())
124}
125
126pub fn list_blocks() -> Result<()> {
127 let file = File::open(get_save_file_path())?;
128 let reader = BufReader::new(file);
129
130 for line in reader.lines() {
131 let line = line?;
132
133 if let Some(strip) = line.strip_prefix("# ") {
134 println!("{}", strip);
135 }
136 }
137
138 Ok(())
139}
140
141pub fn replace_from_backup() -> Result<()> {
142 let (backup_textareas, backup_textareas_titles) = load_textareas(get_save_backup_file_path())?;
143 save_textareas(
144 &backup_textareas,
145 &backup_textareas_titles,
146 get_save_file_path(),
147 )
148}
149
150pub fn view_block(name: &str) -> Result<()> {
151 let file = File::open(get_save_file_path())?;
152 let reader = BufReader::new(file);
153 let mut blocks = Vec::new();
154 let mut current_block = Vec::new();
155 let mut current_name = String::new();
156
157 for line in reader.lines() {
158 let line = line?;
159 if let Some(strip) = line.strip_prefix("# ") {
160 if !current_name.is_empty() {
161 blocks.push((current_name, current_block));
162 current_block = Vec::new();
163 }
164 current_name = strip.to_string();
165 } else {
166 current_block.push(line);
167 }
168 }
169
170 if !current_name.is_empty() {
171 blocks.push((current_name, current_block));
172 }
173
174 for (block_name, block_content) in blocks {
175 if block_name == name {
176 for line in block_content {
177 println!("{}", line);
178 }
179 }
180 }
181 Ok(())
182}
183
184pub fn copy_block(name: &str) -> Result<()> {
185 let file = File::open(get_save_file_path())?;
186 let reader = BufReader::new(file);
187 let mut blocks = Vec::new();
188 let mut current_block = Vec::new();
189 let mut current_name = String::new();
190 let mut matched_name: Option<String> = None;
191
192 for line in reader.lines() {
193 let line = line?;
194 if let Some(strip) = line.strip_prefix("# ") {
195 if !current_name.is_empty() {
196 blocks.push((current_name, current_block));
197 current_block = Vec::new();
198 }
199 current_name = strip.to_string();
200 } else {
201 current_block.push(line);
202 }
203 }
204
205 if !current_name.is_empty() {
206 blocks.push((current_name, current_block));
207 }
208
209 for (block_name, block_content) in blocks {
210 if block_name == name {
211 let result_ctx = EditorClipboard::new();
212
213 if result_ctx.is_err() {
214 bail!("Failed to create clipboard context for copy block");
215 }
216
217 let mut ctx = result_ctx.unwrap();
218
219 let is_success = ctx.set_contents(block_content.join("\n"));
220
221 if is_success.is_err() {
222 bail!(format!(
223 "Failed to copy contents of block {} to system clipboard",
224 block_name
225 ));
226 }
227 matched_name = Some(block_name);
228 break;
229 }
230 }
231 match matched_name {
232 Some(name) => println!("Successfully copied contents from block {}", name),
233 None => println!("Didn't find the block. Please try again. You can use `thoth list` to find the name of all blocks")
234 };
235
236 Ok(())
237}
238
239pub fn delete_block(name: &str) -> Result<()> {
240 let file = File::open(get_save_file_path())?;
241 let reader = BufReader::new(file);
242 let mut blocks = Vec::new();
243 let mut current_block = Vec::new();
244 let mut current_name = String::new();
245
246 for line in reader.lines() {
247 let line = line?;
248 if let Some(strip) = line.strip_prefix("# ") {
249 if !current_name.is_empty() {
250 blocks.push((current_name, current_block));
251 current_block = Vec::new();
252 }
253 current_name = strip.to_string();
254 } else {
255 current_block.push(line);
256 }
257 }
258
259 if !current_name.is_empty() {
260 blocks.push((current_name, current_block));
261 }
262
263 let mut file = File::create(get_save_file_path())?;
264 let mut deleted = false;
265
266 for (block_name, block_content) in blocks {
267 if block_name != name {
268 writeln!(file, "# {}", block_name)?;
269 for line in block_content {
270 writeln!(file, "{}", line)?;
271 }
272 writeln!(file)?;
273 } else {
274 deleted = true;
275 }
276 }
277
278 if deleted {
279 println!("Block '{}' deleted successfully.", name);
280 } else {
281 println!("Block '{}' not found.", name);
282 }
283
284 Ok(())
285}