diff --git a/Cargo.lock b/Cargo.lock index 1844466..49825b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,6 +58,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", + "shell-words", "simplelog", "syntect", "textwrap", @@ -1653,6 +1654,12 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + [[package]] name = "signal-hook" version = "0.3.17" diff --git a/Cargo.toml b/Cargo.toml index e432353..09661ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ ansi_colours = "1.2.2" reqwest-eventsource = "0.5.0" simplelog = "0.12.1" log = "0.4.20" +shell-words = "1.1.0" [dependencies.reqwest] version = "0.11.14" diff --git a/README.md b/README.md index 8d5bfbc..fe6f0dd 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ The Chat REPL supports: .exit session End the current session .set Modify the configuration parameters .copy Copy the last reply to the clipboard -.read Import from file and submit +.read Read files into the message and submit .exit Exit the REPL Type ::: to begin multi-line editing, type ::: to end it. diff --git a/src/repl/mod.rs b/src/repl/mod.rs index 511e069..df4d1c2 100644 --- a/src/repl/mod.rs +++ b/src/repl/mod.rs @@ -36,7 +36,7 @@ const REPL_COMMANDS: [(&str, &str); 13] = [ (".exit session", "End the current session"), (".set", "Modify the configuration parameters"), (".copy", "Copy the last reply to the clipboard"), - (".read", "Import from file and submit"), + (".read", "Read files into the message and submit"), (".exit", "Exit the REPL"), ]; @@ -185,15 +185,28 @@ impl Repl { .with_context(|| "Failed to copy the last output")?; } ".read" => match args { - Some(file) => { - let mut content = String::new(); - let mut file = - std::fs::File::open(file).with_context(|| "Unable to open file")?; - file.read_to_string(&mut content) - .with_context(|| "Unable to read file")?; + Some(args) => { + let (files, text) = match args.split_once(" -- ") { + Some((files, text)) => (files.trim(), text.trim()), + None => (args, ""), + }; + let files = shell_words::split(files).with_context(|| "Invalid files")?; + let mut texts = vec![]; + if !text.is_empty() { + texts.push(text.to_string()); + } + for file_path in files.into_iter() { + let mut text = String::new(); + let mut file = std::fs::File::open(&file_path) + .with_context(|| format!("Unable to open file '{file_path}'"))?; + file.read_to_string(&mut text) + .with_context(|| format!("Unable to read file '{file_path}'"))?; + texts.push(text); + } + let content = texts.join("\n"); self.ask(&content)?; } - None => println!("Usage: .read "), + None => println!("Usage: .read ...[ -- ...]"), }, ".exit" => match args { Some("role") => {