feat: add `.copy` command (#119)

pull/124/head
sigoden 1 year ago committed by GitHub
parent cf03952c7b
commit 00ce157571
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

228
Cargo.lock generated

@ -22,6 +22,7 @@ name = "aichat"
version = "0.8.0" version = "0.8.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arboard",
"atty", "atty",
"base64", "base64",
"bincode", "bincode",
@ -29,7 +30,6 @@ dependencies = [
"bytes", "bytes",
"chrono", "chrono",
"clap", "clap",
"copypasta",
"crossbeam", "crossbeam",
"crossterm 0.26.1", "crossterm 0.26.1",
"ctrlc", "ctrlc",
@ -117,6 +117,24 @@ version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
[[package]]
name = "arboard"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6041616acea41d67c4a984709ddab1587fd0b10efe5cc563fee954d2f011854"
dependencies = [
"clipboard-win",
"log",
"objc",
"objc-foundation",
"objc_id",
"once_cell",
"parking_lot",
"thiserror",
"winapi",
"x11rb",
]
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.5.2" version = "0.5.2"
@ -277,11 +295,12 @@ checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
[[package]] [[package]]
name = "clipboard-win" name = "clipboard-win"
version = "3.1.1" version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fdf5e01086b6be750428ba4a40619f847eb2e95756eee84b18e06e5f0b50342" checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362"
dependencies = [ dependencies = [
"lazy-bytes-cast", "error-code",
"str-buf",
"winapi", "winapi",
] ]
@ -301,20 +320,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "copypasta"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "133fc8675ee3a4ec9aa513584deda9aa0faeda3586b87f7f0f2ba082c66fb172"
dependencies = [
"clipboard-win",
"objc",
"objc-foundation",
"objc_id",
"smithay-clipboard",
"x11-clipboard",
]
[[package]] [[package]]
name = "core-foundation" name = "core-foundation"
version = "0.9.3" version = "0.9.3"
@ -523,21 +528,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "dlib"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794"
dependencies = [
"libloading",
]
[[package]]
name = "downcast-rs"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]] [[package]]
name = "dyn-clone" name = "dyn-clone"
version = "1.0.11" version = "1.0.11"
@ -580,6 +570,16 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "error-code"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21"
dependencies = [
"libc",
"str-buf",
]
[[package]] [[package]]
name = "eventsource-stream" name = "eventsource-stream"
version = "0.2.3" version = "0.2.3"
@ -958,12 +958,6 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "lazy-bytes-cast"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10257499f089cd156ad82d0a9cd57d9501fa2c989068992a97eb3c27836f206b"
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@ -976,16 +970,6 @@ version = "0.2.142"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
[[package]]
name = "libloading"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
]
[[package]] [[package]]
name = "link-cplusplus" name = "link-cplusplus"
version = "1.0.8" version = "1.0.8"
@ -1035,15 +1019,6 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memmap2"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "memoffset" name = "memoffset"
version = "0.6.5" version = "0.6.5"
@ -1513,12 +1488,6 @@ dependencies = [
"windows-sys 0.42.0", "windows-sys 0.42.0",
] ]
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
@ -1665,34 +1634,6 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "smithay-client-toolkit"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454"
dependencies = [
"bitflags",
"dlib",
"lazy_static",
"log",
"memmap2",
"nix 0.24.3",
"pkg-config",
"wayland-client",
"wayland-cursor",
"wayland-protocols",
]
[[package]]
name = "smithay-clipboard"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a345c870a1fae0b1b779085e81b51e614767c239e93503588e54c5b17f4b0e8"
dependencies = [
"smithay-client-toolkit",
"wayland-client",
]
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.4.9" version = "0.4.9"
@ -1715,6 +1656,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "str-buf"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0"
[[package]] [[package]]
name = "strip-ansi-escapes" name = "strip-ansi-escapes"
version = "0.1.1" version = "0.1.1"
@ -2139,79 +2086,6 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "wayland-client"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715"
dependencies = [
"bitflags",
"downcast-rs",
"libc",
"nix 0.24.3",
"scoped-tls",
"wayland-commons",
"wayland-scanner",
"wayland-sys",
]
[[package]]
name = "wayland-commons"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902"
dependencies = [
"nix 0.24.3",
"once_cell",
"smallvec",
"wayland-sys",
]
[[package]]
name = "wayland-cursor"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661"
dependencies = [
"nix 0.24.3",
"wayland-client",
"xcursor",
]
[[package]]
name = "wayland-protocols"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6"
dependencies = [
"bitflags",
"wayland-client",
"wayland-commons",
"wayland-scanner",
]
[[package]]
name = "wayland-scanner"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53"
dependencies = [
"proc-macro2",
"quote",
"xml-rs",
]
[[package]]
name = "wayland-sys"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4"
dependencies = [
"dlib",
"lazy_static",
"pkg-config",
]
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.61" version = "0.3.61"
@ -2446,15 +2320,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "x11-clipboard"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "980b9aa9226c3b7de8e2adb11bf20124327c054e0e5812d2aac0b5b5a87e7464"
dependencies = [
"x11rb",
]
[[package]] [[package]]
name = "x11rb" name = "x11rb"
version = "0.10.1" version = "0.10.1"
@ -2476,18 +2341,3 @@ checksum = "56b245751c0ac9db0e006dc812031482784e434630205a93c73cfefcaabeac67"
dependencies = [ dependencies = [
"nix 0.24.3", "nix 0.24.3",
] ]
[[package]]
name = "xcursor"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7"
dependencies = [
"nom",
]
[[package]]
name = "xml-rs"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "374b609fb36c36ce3501094dc0548f7df5d8d102224b65bc59812e4a5425d571"

@ -38,7 +38,7 @@ base64 = "0.21.0"
rustc-hash = "1.1.0" rustc-hash = "1.1.0"
bstr = "1.3.0" bstr = "1.3.0"
nu-ansi-term = "0.47.0" nu-ansi-term = "0.47.0"
copypasta = "0.8.2" arboard = { version = "3.2.0", default-features = false }
[dependencies.reqwest] [dependencies.reqwest]
version = "0.11.14" version = "0.11.14"

@ -10,7 +10,6 @@ use crate::config::message::num_tokens_from_messages;
use crate::utils::{mask_text, now}; use crate::utils::{mask_text, now};
use anyhow::{anyhow, bail, Context, Result}; use anyhow::{anyhow, bail, Context, Result};
use copypasta::{ClipboardContext, ClipboardProvider};
use inquire::{Confirm, Text}; use inquire::{Confirm, Text};
use parking_lot::RwLock; use parking_lot::RwLock;
use serde::Deserialize; use serde::Deserialize;
@ -71,7 +70,7 @@ pub struct Config {
pub light_theme: bool, pub light_theme: bool,
/// Set a timeout in seconds for connect to gpt /// Set a timeout in seconds for connect to gpt
pub connect_timeout: usize, pub connect_timeout: usize,
/// Automatically copy the last message output to the clipboard /// Automatically copy the last output to the clipboard
pub auto_copy: bool, pub auto_copy: bool,
/// Predefined roles /// Predefined roles
#[serde(skip)] #[serde(skip)]
@ -173,20 +172,6 @@ impl Config {
Ok(path) Ok(path)
} }
pub fn copy_message(&self, output: &str) -> Result<()> {
if self.auto_copy {
match ClipboardContext::new() {
Ok(mut ctx) => {
ctx.set_contents(output.to_string()).map_err(|err| {
anyhow!("Error: Unable to the last message output to clipboard, {err}")
})?;
}
Err(_) => bail!("Error: Unable to access clipboard context."),
}
}
Ok(())
}
pub fn save_message(&self, input: &str, output: &str) -> Result<()> { pub fn save_message(&self, input: &str, output: &str) -> Result<()> {
if !self.save { if !self.save {
return Ok(()); return Ok(());

@ -2,6 +2,7 @@ use crate::client::ChatGptClient;
use crate::config::SharedConfig; use crate::config::SharedConfig;
use crate::print_now; use crate::print_now;
use crate::render::render_stream; use crate::render::render_stream;
use crate::utils::copy;
use super::abort::SharedAbortSignal; use super::abort::SharedAbortSignal;
@ -20,6 +21,7 @@ pub enum ReplCmd {
ViewInfo, ViewInfo,
StartConversation, StartConversation,
EndConversatoin, EndConversatoin,
Copy,
} }
pub struct ReplCmdHandler { pub struct ReplCmdHandler {
@ -64,7 +66,9 @@ impl ReplCmdHandler {
wg.wait(); wg.wait();
let buffer = ret?; let buffer = ret?;
self.config.read().save_message(&input, &buffer)?; self.config.read().save_message(&input, &buffer)?;
let _ = self.config.read().copy_message(&buffer); if self.config.read().auto_copy {
let _ = copy(&buffer);
}
self.config.write().save_conversation(&input, &buffer)?; self.config.write().save_conversation(&input, &buffer)?;
*self.reply.borrow_mut() = buffer; *self.reply.borrow_mut() = buffer;
} }
@ -100,6 +104,10 @@ impl ReplCmdHandler {
self.config.write().end_conversation(); self.config.write().end_conversation();
print_now!("\n"); print_now!("\n");
} }
ReplCmd::Copy => {
copy(&self.reply.borrow()).with_context(|| "Failed to copy the last output")?;
print_now!("\n");
}
} }
Ok(()) Ok(())
} }

@ -19,7 +19,7 @@ use reedline::Signal;
use std::borrow::Cow; use std::borrow::Cow;
use std::sync::Arc; use std::sync::Arc;
pub const REPL_COMMANDS: [(&str, &str); 12] = [ pub const REPL_COMMANDS: [(&str, &str); 13] = [
(".info", "Print system-wide information"), (".info", "Print system-wide information"),
(".set", "Modify the configuration temporarily"), (".set", "Modify the configuration temporarily"),
(".model", "Choose a model"), (".model", "Choose a model"),
@ -28,6 +28,7 @@ pub const REPL_COMMANDS: [(&str, &str); 12] = [
(".clear role", "Clear the currently selected role"), (".clear role", "Clear the currently selected role"),
(".conversation", "Start a conversation."), (".conversation", "Start a conversation."),
(".clear conversation", "End current conversation."), (".clear conversation", "End current conversation."),
(".copy", "Copy the last output to the clipboard"),
(".history", "Print the history"), (".history", "Print the history"),
(".clear history", "Clear the history"), (".clear history", "Clear the history"),
(".help", "Print this help message"), (".help", "Print this help message"),
@ -138,6 +139,9 @@ impl Repl {
".conversation" => { ".conversation" => {
handler.handle(ReplCmd::StartConversation)?; handler.handle(ReplCmd::StartConversation)?;
} }
".copy" => {
handler.handle(ReplCmd::Copy)?;
}
_ => dump_unknown_command(), _ => dump_unknown_command(),
}, },
None => { None => {

@ -2,6 +2,7 @@ mod tiktoken;
pub use self::tiktoken::{cl100k_base_singleton, count_tokens, text_to_tokens, tokens_to_text}; pub use self::tiktoken::{cl100k_base_singleton, count_tokens, text_to_tokens, tokens_to_text};
use arboard::Clipboard;
use chrono::prelude::*; use chrono::prelude::*;
use crossterm::style::{Color, Stylize}; use crossterm::style::{Color, Stylize};
use std::io::{stdout, Write}; use std::io::{stdout, Write};
@ -35,6 +36,11 @@ pub fn mask_text(text: &str, head: usize, tail: usize) -> String {
format!("{}...{}", &text[0..head], &text[text.len() - tail..]) format!("{}...{}", &text[0..head], &text[text.len() - tail..])
} }
pub fn copy(src: &str) -> Result<(), arboard::Error> {
let mut clipboard = Clipboard::new()?;
clipboard.set_text(src)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

Loading…
Cancel
Save