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 Delete {
36 name: String,
38 },
39 View {
41 name: String,
43 },
44 Copy {
46 name: String,
48 },
49}
50
51pub fn add_block(name: &str, content: &str) -> Result<()> {
52 let mut file = std::fs::OpenOptions::new()
53 .append(true)
54 .create(true)
55 .open(get_save_file_path())?;
56
57 writeln!(file, "# {}", name)?;
58 writeln!(file, "{}", content)?;
59 writeln!(file)?;
60
61 println!("Block '{}' added successfully.", name);
62 Ok(())
63}
64
65pub fn list_blocks() -> Result<()> {
66 let file = File::open(get_save_file_path())?;
67 let reader = BufReader::new(file);
68
69 for line in reader.lines() {
70 let line = line?;
71
72 if let Some(strip) = line.strip_prefix("# ") {
73 println!("{}", strip);
74 }
75 }
76
77 Ok(())
78}
79
80pub fn replace_from_backup() -> Result<()> {
81 let (backup_textareas, backup_textareas_titles) = load_textareas(get_save_backup_file_path())?;
82 save_textareas(
83 &backup_textareas,
84 &backup_textareas_titles,
85 get_save_file_path(),
86 )
87}
88
89pub fn view_block(name: &str) -> Result<()> {
90 let file = File::open(get_save_file_path())?;
91 let reader = BufReader::new(file);
92 let mut blocks = Vec::new();
93 let mut current_block = Vec::new();
94 let mut current_name = String::new();
95
96 for line in reader.lines() {
97 let line = line?;
98 if let Some(strip) = line.strip_prefix("# ") {
99 if !current_name.is_empty() {
100 blocks.push((current_name, current_block));
101 current_block = Vec::new();
102 }
103 current_name = strip.to_string();
104 } else {
105 current_block.push(line);
106 }
107 }
108
109 if !current_name.is_empty() {
110 blocks.push((current_name, current_block));
111 }
112
113 for (block_name, block_content) in blocks {
114 if block_name == name {
115 for line in block_content {
116 println!("{}", line);
117 }
118 }
119 }
120 Ok(())
121}
122
123pub fn copy_block(name: &str) -> Result<()> {
124 let file = File::open(get_save_file_path())?;
125 let reader = BufReader::new(file);
126 let mut blocks = Vec::new();
127 let mut current_block = Vec::new();
128 let mut current_name = String::new();
129 let mut matched_name: Option<String> = None;
130
131 for line in reader.lines() {
132 let line = line?;
133 if let Some(strip) = line.strip_prefix("# ") {
134 if !current_name.is_empty() {
135 blocks.push((current_name, current_block));
136 current_block = Vec::new();
137 }
138 current_name = strip.to_string();
139 } else {
140 current_block.push(line);
141 }
142 }
143
144 if !current_name.is_empty() {
145 blocks.push((current_name, current_block));
146 }
147
148 for (block_name, block_content) in blocks {
149 if block_name == name {
150 let result_ctx = EditorClipboard::new();
151
152 if result_ctx.is_err() {
153 bail!("Failed to create clipboard context for copy block");
154 }
155
156 let mut ctx = result_ctx.unwrap();
157
158 let is_success = ctx.set_contents(block_content.join("\n"));
159
160 if is_success.is_err() {
161 bail!(format!(
162 "Failed to copy contents of block {} to system clipboard",
163 block_name
164 ));
165 }
166 matched_name = Some(block_name);
167 break;
168 }
169 }
170 match matched_name {
171 Some(name) => println!("Successfully copied contents from block {}", name),
172 None => println!("Didn't find the block. Please try again. You can use `thoth list` to find the name of all blocks")
173 };
174
175 Ok(())
176}
177
178pub fn delete_block(name: &str) -> Result<()> {
179 let file = File::open(get_save_file_path())?;
180 let reader = BufReader::new(file);
181 let mut blocks = Vec::new();
182 let mut current_block = Vec::new();
183 let mut current_name = String::new();
184
185 for line in reader.lines() {
186 let line = line?;
187 if let Some(strip) = line.strip_prefix("# ") {
188 if !current_name.is_empty() {
189 blocks.push((current_name, current_block));
190 current_block = Vec::new();
191 }
192 current_name = strip.to_string();
193 } else {
194 current_block.push(line);
195 }
196 }
197
198 if !current_name.is_empty() {
199 blocks.push((current_name, current_block));
200 }
201
202 let mut file = File::create(get_save_file_path())?;
203 let mut deleted = false;
204
205 for (block_name, block_content) in blocks {
206 if block_name != name {
207 writeln!(file, "# {}", block_name)?;
208 for line in block_content {
209 writeln!(file, "{}", line)?;
210 }
211 writeln!(file)?;
212 } else {
213 deleted = true;
214 }
215 }
216
217 if deleted {
218 println!("Block '{}' deleted successfully.", name);
219 } else {
220 println!("Block '{}' not found.", name);
221 }
222
223 Ok(())
224}