tokenize_cli/
context_generator.rs1use std::{
2 fs::File,
3 io::{self, BufWriter, Write},
4 sync::{Arc, Mutex},
5};
6
7use ignore::{WalkParallel, WalkState};
8use log::warn;
9
10use crate::{config::Config, file_data::FileData};
11
12pub struct ContextGenerator<'a> {
13 config: &'a Config,
14 writer: Arc<Mutex<BufWriter<File>>>,
15}
16
17impl<'a> ContextGenerator<'a> {
18 pub fn new(config: &'a Config) -> io::Result<Self> {
19 if config.out_file.exists() {
20 warn!(
21 "out file {} already exists and will be overwritten",
22 config.out_file.display()
23 );
24 }
25
26 let out_file = File::create(config.out_file.clone())?;
27 let writer = Arc::new(Mutex::new(BufWriter::new(out_file)));
28
29 Ok(ContextGenerator { config, writer })
30 }
31}
32
33impl ContextGenerator<'_> {
34 pub fn generate(&mut self, walker: WalkParallel) -> io::Result<()> {
35 let default_prompt = include_bytes!("../assets/initial_prompt.md");
36 {
38 let mut w = self.writer.lock().unwrap();
39 w.write_all(default_prompt)?;
40 }
41
42 let writer = Arc::clone(&self.writer);
43 let out_filename = self.config.out_file.file_name();
44 walker.run(|| {
45 let writer = Arc::clone(&writer);
47 Box::new(move |res| {
48 if let Err(err) = &res {
49 warn!("Walk error: {err}");
50 return WalkState::Continue;
51 }
52 let entry = res.unwrap();
53
54 if !entry.file_type().is_some_and(|ft| ft.is_file()) {
55 return WalkState::Continue;
56 }
57 let path = entry.into_path();
58
59 if path.file_name() == out_filename {
60 return WalkState::Continue;
61 }
62
63 if let Err(e) = (|| -> io::Result<()> {
64 let fd = FileData::read(&path)?;
65 fd.write(&mut *writer.lock().unwrap())?;
66 Ok(())
67 })() {
68 warn!("{}: {e}", path.display());
69 }
70
71 WalkState::Continue
72 })
73 });
74
75 Ok(())
76 }
77}