diff --git a/Cargo.toml b/Cargo.toml index 0ca31bd01c..3cbdc93ba9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ keywords = ["git", "gui", "cli", "terminal", "ui"] [dependencies] anyhow = "1.0" +arboard = "3.3.1" asyncgit = { path = "./asyncgit", version = "0.24", default-features = false } backtrace = "0.3" bitflags = "2.4" diff --git a/src/app.rs b/src/app.rs index 76c5b3c21b..15dc31a702 100644 --- a/src/app.rs +++ b/src/app.rs @@ -54,9 +54,10 @@ use std::{ cell::{Cell, RefCell}, path::{Path, PathBuf}, rc::Rc, + sync::atomic::AtomicBool, }; use unicode_width::UnicodeWidthStr; - +pub static ENABLE_HARD_EXIT: AtomicBool = AtomicBool::new(true); #[derive(Clone)] pub enum QuitState { None, @@ -546,7 +547,10 @@ impl App { fn check_hard_exit(&mut self, ev: &Event) -> bool { if let Event::Key(e) = ev { - if key_match(e, self.key_config.keys.exit) { + if ENABLE_HARD_EXIT + .load(std::sync::atomic::Ordering::Relaxed) + && key_match(e, self.key_config.keys.exit) + { self.do_quit = QuitState::Close; return true; } diff --git a/src/components/textinput.rs b/src/components/textinput.rs index e5fe3f4f37..ab00b6b16b 100644 --- a/src/components/textinput.rs +++ b/src/components/textinput.rs @@ -1,4 +1,4 @@ -use crate::app::Environment; +use crate::app::{self, Environment}; use crate::keys::key_match; use crate::ui::Size; use crate::{ @@ -11,6 +11,7 @@ use crate::{ ui::{self, style::SharedTheme}, }; use anyhow::Result; +use arboard::Clipboard; use crossterm::event::Event; use ratatui::widgets::{Block, Borders}; use ratatui::{ @@ -19,9 +20,11 @@ use ratatui::{ widgets::{Clear, Paragraph}, Frame, }; + use std::cell::Cell; use std::cell::OnceCell; use std::convert::From; + use tui_textarea::{CursorMove, Input, Key, Scrolling, TextArea}; /// @@ -173,6 +176,9 @@ impl TextInputComponent { .title(self.title.clone()), ); }; + app::ENABLE_HARD_EXIT + .store(false, std::sync::atomic::Ordering::Relaxed); + text_area }); } @@ -267,6 +273,7 @@ impl TextInputComponent { ta.insert_char(*c); true } + Input { key: Key::Tab, ctrl: false, @@ -686,6 +693,33 @@ impl Component for TextInputComponent { { ta.insert_newline(); true + } else if key_match(e, self.key_config.keys.edit_copy) + { + ta.copy(); + let text = ta.yank_text(); + if let Ok(mut clip) = Clipboard::new() { + let _ = clip.set_text(text); + } + false + } else if key_match(e, self.key_config.keys.edit_cut) + { + ta.cut(); + let text = ta.yank_text(); + if let Ok(mut clip) = Clipboard::new() { + let _ = clip.set_text(text); + } + true + } else if key_match( + e, + self.key_config.keys.edit_paste, + ) { + if let Ok(mut clip) = Clipboard::new() { + if let Ok(text) = clip.get_text() { + ta.set_yank_text(text); + ta.paste(); + } + } + true } else { Self::process_inputs(ta, &input) } @@ -719,6 +753,8 @@ impl Component for TextInputComponent { } fn hide(&mut self) { + app::ENABLE_HARD_EXIT + .store(true, std::sync::atomic::Ordering::Relaxed); self.textarea = None; } diff --git a/src/keys/key_list.rs b/src/keys/key_list.rs index b6e9c32839..4a18cb105a 100644 --- a/src/keys/key_list.rs +++ b/src/keys/key_list.rs @@ -122,6 +122,9 @@ pub struct KeysList { pub commit_history_next: GituiKeyEvent, pub commit: GituiKeyEvent, pub newline: GituiKeyEvent, + pub edit_cut: GituiKeyEvent, + pub edit_copy: GituiKeyEvent, + pub edit_paste: GituiKeyEvent, } #[rustfmt::skip] @@ -213,6 +216,9 @@ impl Default for KeysList { commit_history_next: GituiKeyEvent::new(KeyCode::Char('n'), KeyModifiers::CONTROL), commit: GituiKeyEvent::new(KeyCode::Char('d'), KeyModifiers::CONTROL), newline: GituiKeyEvent::new(KeyCode::Enter, KeyModifiers::empty()), + edit_cut: GituiKeyEvent::new(KeyCode::Char('x'), KeyModifiers::CONTROL), + edit_copy: GituiKeyEvent::new(KeyCode::Char('c'), KeyModifiers::CONTROL), + edit_paste: GituiKeyEvent::new(KeyCode::Char('v'), KeyModifiers::CONTROL), } } }