use std::io::{Read, Write, Seek};
use std::fs::File;
use clap::Parser;
use std::process::Stdio;
use inquire::Confirm;
#[derive(Parser)]
pub struct EditArgs {
#[arg(value_hint=clap::ValueHint::FilePath, help = "The file to create or edit")]
pub file: String,
#[arg(num_args=1.., trailing_var_arg=true, help = "The edit instructions for gpt")]
pub instruction: Vec<String>,
#[arg(short, long, help="Create a new file, do not read the original", action = clap::ArgAction::SetTrue)]
pub new: bool,
#[arg(value_hint=clap::ValueHint::ExecutablePath, env = "EXTERNAL_DIFF", long, default_value = "diff", help = "Diff tool to use")]
pub diff: String,
#[arg(short, long, help="Show the messages send", action = clap::ArgAction::SetTrue, hide=true)]
pub debug: bool,
#[arg(short = 'y', long, help="Do not ask for confirmation", action = clap::ArgAction::SetTrue)]
pub noconfirm: bool,
#[arg(short, long, help = "Model to use", default_value = "gpt-3.5-turbo-16k")]
pub model: String,
}
pub async fn edit_mode(args: &EditArgs, client: openai_rust::Client) {
let instruction = args.instruction.join(" ");
let mut file = File::options().create(true).read(true).write(true).append(false).open(&args.file).expect("Failed to open file");
let mut original = String::new();
file.read_to_string(&mut original).unwrap();
let messages = if original.is_empty() || args.new {
vec![
openai_rust::chat::Message {
role: "system".to_owned(),
content: "The user will give you instructions for a program. You shall reply only with the content of that program without further instructions. Do not use codeblocks.".to_owned(),
},
openai_rust::chat::Message {
role: "user".to_owned(),
content: instruction,
},
]
} else {
vec![
openai_rust::chat::Message {
role: "system".to_owned(),
content: "Apply changes to the text or code supplied by the user.".to_owned(),
},
openai_rust::chat::Message {
role: "user".to_owned(),
content: original,
},
openai_rust::chat::Message {
role: "user".to_owned(),
content: instruction,
},
]
};
if args.debug {
println!("{:?}", messages);
}
let chat_args = openai_rust::chat::ChatArguments::new(args.model.clone(), messages);
let response = client.create_chat(chat_args).await.expect("Failed to get a response from openai");
if !args.new {
let mut diff_proc = std::process::Command::new(&args.diff)
.stdin(Stdio::piped())
.stdout(Stdio::inherit())
.arg(&args.file)
.arg("-")
.arg("--color=auto")
.spawn()
.expect("Failed to spawn diff process");
diff_proc.stdin.take().expect("Could not get stdin of diff process")
.write(response.to_string().as_bytes())
.expect("Failed to write to stdin of diff process");
diff_proc.wait().expect("Failed to wait for diff process");
}
if !args.new && !args.noconfirm {
let ans = Confirm::new("Do you want to apply these changes?")
.with_default(false)
.prompt();
match ans {
Ok(true) => {},
Err(_) | Ok(false) => return,
}
}
file.rewind().expect("Failed to rewind file");
file.set_len(0).expect("Failed to truncate file");
file.write(response.to_string().as_bytes()).expect("Failed to write to file");
println!("File written");
}