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 all 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
21 changes: 21 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::{borrow::Borrow, fmt::format, sync::Arc};

#[cfg(not(feature = "termux"))]
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 +162,10 @@ where
let mut tui = tui::Tui::new()?.mouse(self.mouse_mode_override.or(self.config.settings.mouse_mode));
tui.enter()?;

#[allow(unused_mut)]
#[cfg(not(feature = "termux"))]
let mut clipboard = Clipboard::new();
achristmascarl marked this conversation as resolved.
Show resolved Hide resolved

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 +456,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
4 changes: 2 additions & 2 deletions src/components/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ pub struct Data<'a> {
explain_max_y_offset: u16,
}

impl<'a> Data<'a> {
impl Data<'_> {
pub fn new() -> Self {
Data {
command_tx: None,
Expand Down Expand Up @@ -232,7 +232,7 @@ impl<'a> SettableDataTable<'a> for Data<'a> {
}
}

impl<'a, DB: Database> Component<DB> for Data<'a> {
impl<DB: Database> Component<DB> for Data<'_> {
fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> Result<()> {
self.command_tx = Some(tx);
Ok(())
Expand Down
31 changes: 8 additions & 23 deletions src/components/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub struct Editor<'a> {
last_query_duration: Option<chrono::Duration>,
}

impl<'a> Editor<'a> {
impl Editor<'_> {
pub fn new() -> Self {
let mut textarea = TextArea::default();
textarea.set_search_pattern(keyword_regex()).unwrap();
Expand All @@ -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,14 +108,16 @@ 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(())
}
}

impl<'a, DB: Database + DatabaseQueries> Component<DB> for Editor<'a> {
impl<DB: Database + DatabaseQueries> Component<DB> for Editor<'_> {
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,31 +191,13 @@ 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();
},
Action::CopyData(data) => {
self.textarea.set_yank_text(data);
},
_ => {},
}
Ok(None)
Expand Down
2 changes: 1 addition & 1 deletion src/components/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ impl Menu {
}
}

impl<'a> SettableTableList<'a> for Menu {
impl SettableTableList<'_> for Menu {
fn set_table_list(&mut self, data: Option<Result<Rows, DbError>>) {
log::info!("setting menu table list");
self.table_map = IndexMap::new();
Expand Down
4 changes: 2 additions & 2 deletions src/components/scroll_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ impl<'a> ScrollTable<'a> {
}
}

impl<'a, DB: Database> Component<DB> for ScrollTable<'a> {
impl<DB: Database> Component<DB> for ScrollTable<'_> {
fn draw(&mut self, f: &mut Frame<'_>, area: Rect, app_state: &AppState<'_, DB>) -> Result<()> {
self.parent_area = area;
let render_area = self.block.inner_if_some(area);
Expand Down Expand Up @@ -252,7 +252,7 @@ impl<'a> Renderer<'a> {
}
}

impl<'a> Widget for Renderer<'a> {
impl Widget for Renderer<'_> {
fn render(self, area: Rect, buf: &mut Buffer) {
let scrollable = self.0;
let table = &scrollable.table;
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
}