Skip to content

Commit 8879b44

Browse files
committed
remove clean file, minor refactoring
1 parent 9e53c22 commit 8879b44

File tree

2 files changed

+47
-80
lines changed

2 files changed

+47
-80
lines changed

crates/q_cli/src/cli/chat/tools/fs_write.rs

Lines changed: 34 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::borrow::Cow;
22
use std::io::Write;
3+
use std::path::Path;
34

45
use crossterm::queue;
56
use crossterm::style::{
@@ -25,7 +26,6 @@ use super::{
2526
stylize_output_if_able,
2627
terminal_width_required_for_line_count,
2728
};
28-
use crate::cli::chat::tools::supports_truecolor;
2929

3030
#[derive(Debug, Clone, Deserialize)]
3131
#[serde(tag = "command")]
@@ -55,19 +55,6 @@ pub enum FsWrite {
5555
}
5656

5757
impl FsWrite {
58-
/// Helper function to clean file content:
59-
/// 1. Ensures the file ends with a newline
60-
/// 2. Removes trailing whitespace from each line
61-
fn clean_file_content(content: String) -> String {
62-
let mut cleaned = content
63-
.lines()
64-
.map(|line| line.trim_end())
65-
.collect::<Vec<_>>()
66-
.join("\n");
67-
cleaned.push('\n');
68-
cleaned
69-
}
70-
7158
pub async fn invoke(&self, ctx: &Context, updates: &mut impl Write) -> Result<InvokeOutput> {
7259
let fs = ctx.fs();
7360
let cwd = ctx.env().current_dir()?;
@@ -89,8 +76,7 @@ impl FsWrite {
8976
style::Print("\n"),
9077
)?;
9178

92-
let cleaned_text = Self::clean_file_content(file_text);
93-
fs.write(&path, cleaned_text.as_bytes()).await?;
79+
write_to_file(ctx, path, file_text).await?;
9480
Ok(Default::default())
9581
},
9682
FsWrite::StrReplace { path, old_str, new_str } => {
@@ -109,8 +95,7 @@ impl FsWrite {
10995
0 => Err(eyre!("no occurrences of \"{old_str}\" were found")),
11096
1 => {
11197
let file = file.replacen(old_str, new_str, 1);
112-
let cleaned_file = Self::clean_file_content(file);
113-
fs.write(path, cleaned_file).await?;
98+
fs.write(path, file).await?;
11499
Ok(Default::default())
115100
},
116101
x => Err(eyre!("{x} occurrences of old_str were found when only 1 is expected")),
@@ -141,18 +126,12 @@ impl FsWrite {
141126
i += line_len;
142127
}
143128
file.insert_str(i, new_str);
144-
let cleaned_file = Self::clean_file_content(file);
145-
fs.write(&path, &cleaned_file).await?;
129+
write_to_file(ctx, &path, file).await?;
146130
Ok(Default::default())
147131
},
148132
FsWrite::Append { path, new_str } => {
149133
let path = sanitize_path_tool_arg(ctx, path);
150134

151-
// Return an error if the file doesn't exist
152-
if !fs.exists(&path) {
153-
bail!("The file does not exist: {}", path.display());
154-
}
155-
156135
queue!(
157136
updates,
158137
style::Print("Appending to: "),
@@ -162,15 +141,12 @@ impl FsWrite {
162141
style::Print("\n"),
163142
)?;
164143

165-
let mut file_content = fs.read_to_string(&path).await.unwrap_or_default();
166-
if !file_content.ends_with_newline() {
167-
file_content.push('\n');
168-
}
169-
file_content.push_str(new_str);
170-
if !file_content.ends_with_newline() {
171-
file_content.push('\n');
144+
let mut file = fs.read_to_string(&path).await?;
145+
if !file.ends_with_newline() {
146+
file.push('\n');
172147
}
173-
fs.write(&path, file_content).await?;
148+
file.push_str(new_str);
149+
write_to_file(ctx, path, file).await?;
174150
Ok(Default::default())
175151
},
176152
}
@@ -190,7 +166,7 @@ impl FsWrite {
190166
Default::default()
191167
};
192168
let new = stylize_output_if_able(ctx, &relative_path, &file_text);
193-
print_diff(ctx, updates, &prev, &new, 1)?;
169+
print_diff(updates, &prev, &new, 1)?;
194170
Ok(())
195171
},
196172
FsWrite::Insert {
@@ -213,7 +189,7 @@ impl FsWrite {
213189

214190
let old = stylize_output_if_able(ctx, &relative_path, &old);
215191
let new = stylize_output_if_able(ctx, &relative_path, &new);
216-
print_diff(ctx, updates, &old, &new, start_line)?;
192+
print_diff(updates, &old, &new, start_line)?;
217193
Ok(())
218194
},
219195
FsWrite::StrReplace { path, old_str, new_str } => {
@@ -225,15 +201,15 @@ impl FsWrite {
225201
};
226202
let old_str = stylize_output_if_able(ctx, &relative_path, old_str);
227203
let new_str = stylize_output_if_able(ctx, &relative_path, new_str);
228-
print_diff(ctx, updates, &old_str, &new_str, start_line)?;
204+
print_diff(updates, &old_str, &new_str, start_line)?;
229205

230206
Ok(())
231207
},
232208
FsWrite::Append { path, new_str } => {
233209
let relative_path = format_path(cwd, path);
234210
let start_line = ctx.fs().read_to_string_sync(&relative_path)?.lines().count() + 1;
235211
let file = stylize_output_if_able(ctx, &relative_path, new_str);
236-
print_diff(ctx, updates, &Default::default(), &file, start_line)?;
212+
print_diff(updates, &Default::default(), &file, start_line)?;
237213
Ok(())
238214
},
239215
}
@@ -305,6 +281,15 @@ impl FsWrite {
305281
}
306282
}
307283

284+
/// Writes `content` to `path`, adding a newline if necessary.
285+
async fn write_to_file(ctx: &Context, path: impl AsRef<Path>, mut content: String) -> Result<()> {
286+
if !content.ends_with_newline() {
287+
content.push('\n');
288+
}
289+
ctx.fs().write(path.as_ref(), content).await?;
290+
Ok(())
291+
}
292+
308293
/// Returns a prefix/suffix pair before and after the content dictated by `[start_line, end_line]`
309294
/// within `content`. The updated start and end lines containing the original context along with
310295
/// the suffix and prefix are returned.
@@ -365,7 +350,6 @@ fn get_lines_with_context(
365350
/// Prints a git-diff style comparison between `old_str` and `new_str`.
366351
/// - `start_line` - 1-indexed line number that `old_str` and `new_str` start at.
367352
fn print_diff(
368-
ctx: &Context,
369353
updates: &mut impl Write,
370354
old_str: &StylizedFile,
371355
new_str: &StylizedFile,
@@ -387,15 +371,15 @@ fn print_diff(
387371
let new_line_num_width = terminal_width_required_for_line_count(max_new_i);
388372

389373
// Now, print
390-
fn fmt_i(i: Option<usize>, start_line: usize) -> String {
374+
fn fmt_index(i: Option<usize>, start_line: usize) -> String {
391375
match i {
392376
Some(i) => (i + start_line).to_string(),
393377
_ => " ".to_string(),
394378
}
395379
}
396380
for change in diff.iter_all_changes() {
397-
// Colors
398-
let (text_color, gutter_bg_color, line_bg_color) = match (change.tag(), supports_truecolor(ctx)) {
381+
// Define the colors per line.
382+
let (text_color, gutter_bg_color, line_bg_color) = match (change.tag(), new_str.truecolor) {
399383
(similar::ChangeTag::Equal, true) => (style::Color::Reset, new_str.gutter_bg, new_str.line_bg),
400384
(similar::ChangeTag::Delete, true) => (
401385
style::Color::Reset,
@@ -407,19 +391,21 @@ fn print_diff(
407391
style::Color::Rgb { r: 40, g: 67, b: 43 },
408392
style::Color::Rgb { r: 24, g: 38, b: 30 },
409393
),
410-
(similar::ChangeTag::Equal, false) => (style::Color::Reset, style::Color::Reset, style::Color::Reset),
411-
(similar::ChangeTag::Delete, false) => (style::Color::Red, style::Color::Reset, style::Color::Reset),
412-
(similar::ChangeTag::Insert, false) => (style::Color::Green, style::Color::Reset, style::Color::Reset),
394+
(similar::ChangeTag::Equal, false) => (style::Color::Reset, new_str.gutter_bg, new_str.line_bg),
395+
(similar::ChangeTag::Delete, false) => (style::Color::Red, new_str.gutter_bg, new_str.line_bg),
396+
(similar::ChangeTag::Insert, false) => (style::Color::Green, new_str.gutter_bg, new_str.line_bg),
413397
};
414-
// Change tag character
398+
// Define the change tag character to print, if any.
415399
let sign = match change.tag() {
416400
similar::ChangeTag::Equal => " ",
417401
similar::ChangeTag::Delete => "-",
418402
similar::ChangeTag::Insert => "+",
419403
};
420404

421-
let old_i_str = fmt_i(change.old_index(), start_line);
422-
let new_i_str = fmt_i(change.new_index(), start_line);
405+
let old_i_str = fmt_index(change.old_index(), start_line);
406+
let new_i_str = fmt_index(change.new_index(), start_line);
407+
408+
// Print the gutter and line numbers.
423409
queue!(updates, style::SetBackgroundColor(gutter_bg_color))?;
424410
queue!(
425411
updates,
@@ -448,6 +434,7 @@ fn print_diff(
448434
new_line_num_width = new_line_num_width
449435
))
450436
)?;
437+
// Print the line.
451438
queue!(
452439
updates,
453440
style::SetForegroundColor(style::Color::Reset),
@@ -502,8 +489,6 @@ fn line_number_at(file: impl AsRef<str>, needle: impl AsRef<str>) -> Option<(usi
502489
mod tests {
503490
use std::sync::Arc;
504491

505-
use similar::DiffableStr;
506-
507492
use super::*;
508493

509494
const TEST_FILE_CONTENTS: &str = "\
@@ -856,29 +841,6 @@ mod tests {
856841
assert_eq!(truncate_str(s, 0), "<...Truncated>");
857842
}
858843

859-
#[test]
860-
fn test_clean_file_content() {
861-
// Test removing trailing whitespace
862-
let content = "Hello world! \nThis is a test \nWith trailing spaces ";
863-
let expected = "Hello world!\nThis is a test\nWith trailing spaces\n";
864-
assert_eq!(FsWrite::clean_file_content(content.to_string()), expected);
865-
866-
// Test ensuring ending newline
867-
let content = "Hello world!\nNo ending newline";
868-
let expected = "Hello world!\nNo ending newline\n";
869-
assert_eq!(FsWrite::clean_file_content(content.to_string()), expected);
870-
871-
// Test with content already having ending newline
872-
let content = "Hello world!\nWith ending newline\n";
873-
let expected = "Hello world!\nWith ending newline\n";
874-
assert_eq!(FsWrite::clean_file_content(content.to_string()), expected);
875-
876-
// Test with empty string
877-
let content = "";
878-
let expected = "\n";
879-
assert_eq!(FsWrite::clean_file_content(content.to_string()), expected);
880-
}
881-
882844
#[test]
883845
fn test_lines_with_context() {
884846
let content = "Hello\nWorld!\nhow\nare\nyou\ntoday?";

crates/q_cli/src/cli/chat/tools/mod.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -294,14 +294,17 @@ fn stylize_output_if_able(ctx: &Context, path: impl AsRef<Path>, file_text: &str
294294
}
295295
}
296296
StylizedFile {
297+
truecolor: false,
297298
content: file_text.to_string(),
298299
gutter_bg: style::Color::Reset,
299300
line_bg: style::Color::Reset,
300301
}
301302
}
302303

304+
/// File contents that are potentially stylized with truecolor escape codes.
303305
#[derive(Debug)]
304306
struct StylizedFile {
307+
truecolor: bool,
305308
content: String,
306309
gutter_bg: style::Color,
307310
line_bg: style::Color,
@@ -310,6 +313,7 @@ struct StylizedFile {
310313
impl Default for StylizedFile {
311314
fn default() -> Self {
312315
Self {
316+
truecolor: false,
313317
content: Default::default(),
314318
gutter_bg: style::Color::Reset,
315319
line_bg: style::Color::Reset,
@@ -335,26 +339,27 @@ fn stylized_file(path: impl AsRef<Path>, file_text: impl AsRef<str>) -> Result<S
335339
.wrap_err_with(|| format!("missing extension: {}", extension))?;
336340

337341
let theme = &ts.themes["base16-ocean.dark"];
338-
let mut h = HighlightLines::new(syntax, theme);
342+
let mut highlighter = HighlightLines::new(syntax, theme);
339343
let file_text = file_text.as_ref().lines();
340-
let (line_bg, gutter_bg) = match (theme.settings.background, theme.settings.gutter) {
341-
(Some(line_bg), Some(gutter_bg)) => (line_bg, gutter_bg),
342-
(Some(line_bg), None) => (line_bg, line_bg),
343-
_ => bail!("missing theme"),
344-
};
345-
346344
let mut file = String::new();
347345
for line in file_text {
348346
let mut ranges = Vec::new();
349-
ranges.append(&mut h.highlight_line(line, ps)?);
347+
ranges.append(&mut highlighter.highlight_line(line, ps)?);
350348
let mut escaped_line = as_24_bit_terminal_escaped(&ranges[..], false);
351349
escaped_line.push_str(&format!(
352350
"{}\n",
353351
crossterm::terminal::Clear(crossterm::terminal::ClearType::UntilNewLine),
354352
));
355353
file.push_str(&escaped_line);
356354
}
355+
356+
let (line_bg, gutter_bg) = match (theme.settings.background, theme.settings.gutter) {
357+
(Some(line_bg), Some(gutter_bg)) => (line_bg, gutter_bg),
358+
(Some(line_bg), None) => (line_bg, line_bg),
359+
_ => bail!("missing theme"),
360+
};
357361
Ok(StylizedFile {
362+
truecolor: true,
358363
content: file,
359364
gutter_bg: syntect_to_crossterm_color(gutter_bg),
360365
line_bg: syntect_to_crossterm_color(line_bg),

0 commit comments

Comments
 (0)