Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix copy to the linux system clipboard #120

Merged
merged 6 commits into from
Oct 20, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{borrow::Borrow, fmt::format, sync::Arc};

use arboard::Clipboard;
use color_eyre::eyre::Result;
use crossterm::event::{Event, KeyCode, KeyEvent, MouseButton, MouseEvent, MouseEventKind};
use futures::{task::Poll, FutureExt};
Expand Down Expand Up @@ -160,6 +161,9 @@ where
let mut tui = tui::Tui::new()?.mouse(self.mouse_mode_override.or(self.config.settings.mouse_mode));
tui.enter()?;

#[allow(unused_mut)]
let mut clipboard = Clipboard::new();

self.components.menu.register_action_handler(action_tx.clone())?;
self.components.editor.register_action_handler(action_tx.clone())?;
self.components.history.register_action_handler(action_tx.clone())?;
Expand Down Expand Up @@ -450,6 +454,21 @@ where
Action::ClearHistory => {
self.clear_history();
},
Action::CopyData(data) => {
#[cfg(not(feature = "termux"))]
{
clipboard.as_mut().map_or_else(
|e| {
log::error!("{e:?}");
},
|clipboard| {
clipboard.set_text(data).unwrap_or_else(|e| {
log::error!("{e:?}");
})
},
);
}
},
achristmascarl marked this conversation as resolved.
Show resolved Hide resolved
_ => {},
}
if !action_consumed {
Expand Down
24 changes: 3 additions & 21 deletions src/components/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ impl<'a> Editor<'a> {
if let Some(sender) = &self.command_tx {
sender.send(Action::Query(self.textarea.lines().to_vec(), false))?;
self.vim_state = Vim::new(Mode::Normal);
self.vim_state.register_action_handler(self.command_tx.clone())?;
achristmascarl marked this conversation as resolved.
Show resolved Hide resolved
self.cursor_style = Mode::Normal.cursor_style();
}
}
Expand Down Expand Up @@ -107,6 +108,7 @@ impl<'a> Editor<'a> {
Transition::Nop | Transition::Mode(_) => new_vim_state,
Transition::Pending(input) => new_vim_state.with_pending(input),
};
self.vim_state.register_action_handler(self.command_tx.clone())?;
achristmascarl marked this conversation as resolved.
Show resolved Hide resolved
},
};
Ok(())
Expand All @@ -115,6 +117,7 @@ impl<'a> Editor<'a> {

impl<'a, DB: Database + DatabaseQueries> Component<DB> for Editor<'a> {
fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> Result<()> {
self.vim_state.register_action_handler(self.command_tx.clone())?;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: self.command_tx is None here, so this call will always fail

self.command_tx = Some(tx);
Ok(())
}
Expand Down Expand Up @@ -188,27 +191,6 @@ impl<'a, DB: Database + DatabaseQueries> Component<DB> for Editor<'a> {
sender.send(Action::Query(self.textarea.lines().to_vec(), false))?;
}
},
Action::CopyData(data) => {
#[cfg(not(feature = "termux"))]
{
Clipboard::new().map_or_else(
|e| {
log::error!("{e:?}");
},
|mut clipboard| {
clipboard.set_text(data.clone()).unwrap_or_else(|e| {
log::error!("{e:?}");
})
},
);
// also set textarea buffer as a fallback
achristmascarl marked this conversation as resolved.
Show resolved Hide resolved
self.textarea.set_yank_text(data.clone());
}
#[cfg(feature = "termux")]
{
self.textarea.set_yank_text(data);
}
},
Action::HistoryToEditor(lines) => {
self.textarea = TextArea::from(lines.clone());
self.textarea.set_search_pattern(keyword_regex()).unwrap();
Expand Down
94 changes: 22 additions & 72 deletions src/vim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ use ratatui::{
widgets::{Block, Borders},
Terminal,
};
use tokio::sync::mpsc::UnboundedSender;
use tui_textarea::{CursorMove, Input, Key, Scrolling, TextArea};

use crate::action::Action;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Mode {
#[default]
Expand Down Expand Up @@ -93,15 +96,21 @@ pub enum Transition {
pub struct Vim {
pub mode: Mode,
pub pending: Input, // Pending input to handle a sequence with two keys like gg
command_tx: Option<UnboundedSender<Action>>,
achristmascarl marked this conversation as resolved.
Show resolved Hide resolved
}

impl Vim {
pub fn new(mode: Mode) -> Self {
Self { mode, pending: Input::default() }
Self { mode, pending: Input::default(), command_tx: None }
}

pub fn with_pending(self, pending: Input) -> Self {
Self { mode: self.mode, pending }
Self { mode: self.mode, pending, command_tx: None }
}
Comment on lines 107 to +109
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: command_tx is set to None here, potentially losing the original transmitter


pub fn register_action_handler(&mut self, tx: Option<UnboundedSender<Action>>) -> Result<()> {
self.command_tx = tx;
Ok(())
}

pub fn transition(&self, input: Input, textarea: &mut TextArea<'_>) -> Transition {
Expand Down Expand Up @@ -174,20 +183,7 @@ impl Vim {
}
}
textarea.cut();
let text = textarea.yank_text();
#[cfg(not(feature = "termux"))]
{
Clipboard::new().map_or_else(
|e| {
log::error!("{e:?}");
},
|mut clipboard| {
clipboard.set_text(text).unwrap_or_else(|e| {
log::error!("{e:?}");
})
},
);
}
self.send_copy_action_with_text(textarea.yank_text());
return Transition::Mode(Mode::Normal);
},
Input { key: Key::Char('i'), .. } => {
Expand Down Expand Up @@ -288,20 +284,7 @@ impl Vim {
}
}
textarea.copy();
let text = textarea.yank_text();
#[cfg(not(feature = "termux"))]
{
Clipboard::new().map_or_else(
|e| {
log::error!("{e:?}");
},
|mut clipboard| {
clipboard.set_text(text).unwrap_or_else(|e| {
log::error!("{e:?}");
})
},
);
}
self.send_copy_action_with_text(textarea.yank_text());
return Transition::Mode(Mode::Normal);
},
Input { key: Key::Char('d'), ctrl: false, .. } if self.mode == Mode::Visual => {
Expand All @@ -328,20 +311,7 @@ impl Vim {
}
}
textarea.cut();
let text = textarea.yank_text();
#[cfg(not(feature = "termux"))]
{
Clipboard::new().map_or_else(
|e| {
log::error!("{e:?}");
},
|mut clipboard| {
clipboard.set_text(text).unwrap_or_else(|e| {
log::error!("{e:?}");
})
},
);
}
self.send_copy_action_with_text(textarea.yank_text());
return Transition::Mode(Mode::Insert);
},
Input { key: Key::Esc, .. } => {
Expand All @@ -355,20 +325,7 @@ impl Vim {
match self.mode {
Mode::Operator('y') => {
textarea.copy();
let text = textarea.yank_text();
#[cfg(not(feature = "termux"))]
{
Clipboard::new().map_or_else(
|e| {
log::error!("{e:?}");
},
|mut clipboard| {
clipboard.set_text(text).unwrap_or_else(|e| {
log::error!("{e:?}");
})
},
);
}
self.send_copy_action_with_text(textarea.yank_text());
Transition::Mode(Mode::Normal)
},
Mode::Operator('d') => {
Expand All @@ -377,20 +334,7 @@ impl Vim {
},
Mode::Operator('c') => {
textarea.cut();
let text = textarea.yank_text();
#[cfg(not(feature = "termux"))]
{
Clipboard::new().map_or_else(
|e| {
log::error!("{e:?}");
},
|mut clipboard| {
clipboard.set_text(text).unwrap_or_else(|e| {
log::error!("{e:?}");
})
},
);
}
self.send_copy_action_with_text(textarea.yank_text());
Transition::Mode(Mode::Insert)
},
_ => Transition::Nop,
Expand All @@ -417,4 +361,10 @@ impl Vim {
},
}
}

fn send_copy_action_with_text(&self, text: String) {
if let Some(sender) = &self.command_tx {
sender.send(Action::CopyData(text)).map_or_else(|e| log::error!("{e:?}"), |_| {});
}
}
achristmascarl marked this conversation as resolved.
Show resolved Hide resolved
}
Loading