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