diff options
Diffstat (limited to 'alacritty/src')
-rw-r--r-- | alacritty/src/clipboard.rs | 97 | ||||
-rw-r--r-- | alacritty/src/event.rs | 26 | ||||
-rw-r--r-- | alacritty/src/input.rs | 23 | ||||
-rw-r--r-- | alacritty/src/main.rs | 10 |
4 files changed, 138 insertions, 18 deletions
diff --git a/alacritty/src/clipboard.rs b/alacritty/src/clipboard.rs new file mode 100644 index 00000000..df0b1c78 --- /dev/null +++ b/alacritty/src/clipboard.rs @@ -0,0 +1,97 @@ +#[cfg(not(any(target_os = "macos", target_os = "windows")))] +use std::ffi::c_void; + +use log::{debug, warn}; + +use alacritty_terminal::term::ClipboardType; + +#[cfg(any(test, not(any(feature = "x11", target_os = "macos", windows))))] +use copypasta::nop_clipboard::NopClipboardContext; +#[cfg(all(not(any(target_os = "macos", windows)), feature = "wayland"))] +use copypasta::wayland_clipboard; +#[cfg(all(not(any(target_os = "macos", windows)), feature = "x11"))] +use copypasta::x11_clipboard::{Primary as X11SelectionClipboard, X11ClipboardContext}; +#[cfg(any(feature = "x11", target_os = "macos", windows))] +use copypasta::ClipboardContext; +use copypasta::ClipboardProvider; + +pub struct Clipboard { + clipboard: Box<dyn ClipboardProvider>, + selection: Option<Box<dyn ClipboardProvider>>, +} + +impl Clipboard { + #[cfg(any(target_os = "macos", windows))] + pub fn new() -> Self { + Self::default() + } + + #[cfg(not(any(target_os = "macos", windows)))] + pub fn new(_display: Option<*mut c_void>) -> Self { + #[cfg(feature = "wayland")] + { + if let Some(display) = _display { + let (selection, clipboard) = + unsafe { wayland_clipboard::create_clipboards_from_external(display) }; + return Self { + clipboard: Box::new(clipboard), + selection: Some(Box::new(selection)), + }; + } + } + + #[cfg(feature = "x11")] + return Self { + clipboard: Box::new(ClipboardContext::new().unwrap()), + selection: Some(Box::new(X11ClipboardContext::<X11SelectionClipboard>::new().unwrap())), + }; + + #[cfg(not(feature = "x11"))] + return Self::new_nop(); + } + + /// Used for tests and to handle missing clipboard provider when built without the `x11` + /// feature. + #[cfg(any(test, not(any(feature = "x11", target_os = "macos", windows))))] + pub fn new_nop() -> Self { + Self { clipboard: Box::new(NopClipboardContext::new().unwrap()), selection: None } + } +} + +impl Default for Clipboard { + fn default() -> Self { + #[cfg(any(feature = "x11", target_os = "macos", windows))] + return Self { clipboard: Box::new(ClipboardContext::new().unwrap()), selection: None }; + #[cfg(not(any(feature = "x11", target_os = "macos", windows)))] + return Self::new_nop(); + } +} + +impl Clipboard { + pub fn store(&mut self, ty: ClipboardType, text: impl Into<String>) { + let clipboard = match (ty, &mut self.selection) { + (ClipboardType::Selection, Some(provider)) => provider, + (ClipboardType::Selection, None) => return, + _ => &mut self.clipboard, + }; + + clipboard.set_contents(text.into()).unwrap_or_else(|err| { + warn!("Unable to store text in clipboard: {}", err); + }); + } + + pub fn load(&mut self, ty: ClipboardType) -> String { + let clipboard = match (ty, &mut self.selection) { + (ClipboardType::Selection, Some(provider)) => provider, + _ => &mut self.clipboard, + }; + + match clipboard.get_contents() { + Err(err) => { + debug!("Unable to load text from clipboard: {}", err); + String::new() + }, + Ok(text) => text, + } + } +} diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs index 21149ad0..4e2a0578 100644 --- a/alacritty/src/event.rs +++ b/alacritty/src/event.rs @@ -27,7 +27,6 @@ use serde_json as json; use font::set_font_smoothing; use font::{self, Size}; -use alacritty_terminal::clipboard::ClipboardType; use alacritty_terminal::config::Font; use alacritty_terminal::config::LOG_TARGET_CONFIG; use alacritty_terminal::event::OnResize; @@ -38,12 +37,13 @@ use alacritty_terminal::message_bar::{Message, MessageBuffer}; use alacritty_terminal::selection::{Selection, SelectionType}; use alacritty_terminal::sync::FairMutex; use alacritty_terminal::term::cell::Cell; -use alacritty_terminal::term::{SizeInfo, Term, TermMode}; +use alacritty_terminal::term::{ClipboardType, SizeInfo, Term, TermMode}; #[cfg(not(windows))] use alacritty_terminal::tty; use alacritty_terminal::util::{limit, start_daemon}; use crate::cli::Options; +use crate::clipboard::Clipboard; use crate::config; use crate::config::Config; use crate::display::Display; @@ -68,6 +68,7 @@ impl DisplayUpdate { pub struct ActionContext<'a, N, T> { pub notifier: &'a mut N, pub terminal: &'a mut Term<T>, + pub clipboard: &'a mut Clipboard, pub size_info: &'a mut SizeInfo, pub mouse: &'a mut Mouse, pub received_count: &'a mut usize, @@ -111,7 +112,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon fn copy_selection(&mut self, ty: ClipboardType) { if let Some(selected) = self.terminal.selection_to_string() { if !selected.is_empty() { - self.terminal.clipboard().store(ty, selected); + self.clipboard.store(ty, selected); } } } @@ -281,6 +282,10 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon self.urls } + fn clipboard(&mut self) -> &mut Clipboard { + self.clipboard + } + /// Spawn URL launcher when clicking on URLs. fn launch_url(&self, url: Url) { if self.mouse.block_url_launcher { @@ -358,6 +363,7 @@ pub struct Processor<N> { mouse: Mouse, received_count: usize, suppress_chars: bool, + clipboard: Clipboard, modifiers: ModifiersState, config: Config, message_buffer: MessageBuffer, @@ -376,6 +382,11 @@ impl<N: Notify + OnResize> Processor<N> { config: Config, display: Display, ) -> Processor<N> { + #[cfg(not(any(target_os = "macos", windows)))] + let clipboard = Clipboard::new(display.window.wayland_display()); + #[cfg(any(target_os = "macos", windows))] + let clipboard = Clipboard::new(); + Processor { notifier, mouse: Default::default(), @@ -387,6 +398,7 @@ impl<N: Notify + OnResize> Processor<N> { message_buffer, display, event_queue: Vec::new(), + clipboard, } } @@ -472,6 +484,7 @@ impl<N: Notify + OnResize> Processor<N> { terminal: &mut terminal, notifier: &mut self.notifier, mouse: &mut self.mouse, + clipboard: &mut self.clipboard, size_info: &mut self.display.size_info, received_count: &mut self.received_count, suppress_chars: &mut self.suppress_chars, @@ -569,6 +582,13 @@ impl<N: Notify + OnResize> Processor<N> { processor.ctx.display_update_pending.message_buffer = true; processor.ctx.terminal.dirty = true; }, + Event::ClipboardStore(clipboard_type, content) => { + processor.ctx.clipboard.store(clipboard_type, content); + }, + Event::ClipboardLoad(clipboard_type, format) => { + let text = format(processor.ctx.clipboard.load(clipboard_type).as_str()); + processor.ctx.write_to_pty(text.into_bytes()); + }, Event::MouseCursorDirty => processor.reset_mouse_cursor(), Event::Exit => (), }, diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs index 9109aa4f..2025f108 100644 --- a/alacritty/src/input.rs +++ b/alacritty/src/input.rs @@ -21,17 +21,17 @@ use glutin::platform::macos::EventLoopWindowTargetExtMacOS; use glutin::window::CursorIcon; use alacritty_terminal::ansi::{ClearMode, Handler}; -use alacritty_terminal::clipboard::ClipboardType; use alacritty_terminal::event::{Event, EventListener}; use alacritty_terminal::grid::Scroll; use alacritty_terminal::index::{Column, Line, Point, Side}; use alacritty_terminal::message_bar::{self, Message}; use alacritty_terminal::selection::SelectionType; use alacritty_terminal::term::mode::TermMode; -use alacritty_terminal::term::{SizeInfo, Term}; +use alacritty_terminal::term::{ClipboardType, SizeInfo, Term}; use alacritty_terminal::util::start_daemon; use alacritty_terminal::vi_mode::ViMotion; +use crate::clipboard::Clipboard; use crate::config::{Action, Binding, Config, Key, ViAction}; use crate::event::{ClickState, Mouse}; use crate::url::{Url, Urls}; @@ -77,6 +77,7 @@ pub trait ActionContext<T: EventListener> { fn message(&self) -> Option<&Message>; fn config(&self) -> &Config; fn event_loop(&self) -> &EventLoopWindowTarget<Event>; + fn clipboard(&mut self) -> &mut Clipboard; fn urls(&self) -> &Urls; fn launch_url(&self, url: Url); fn mouse_mode(&self) -> bool; @@ -127,11 +128,11 @@ impl<T: EventListener> Execute<T> for Action { #[cfg(not(any(target_os = "macos", windows)))] Action::CopySelection => ctx.copy_selection(ClipboardType::Selection), Action::Paste => { - let text = ctx.terminal_mut().clipboard().load(ClipboardType::Clipboard); + let text = ctx.clipboard().load(ClipboardType::Clipboard); paste(ctx, &text); }, Action::PasteSelection => { - let text = ctx.terminal_mut().clipboard().load(ClipboardType::Selection); + let text = ctx.clipboard().load(ClipboardType::Selection); paste(ctx, &text); }, Action::Command(ref program) => { @@ -881,14 +882,14 @@ mod tests { }; use glutin::event_loop::EventLoopWindowTarget; - use alacritty_terminal::clipboard::{Clipboard, ClipboardType}; use alacritty_terminal::event::{Event as TerminalEvent, EventListener}; use alacritty_terminal::grid::Scroll; use alacritty_terminal::index::{Point, Side}; use alacritty_terminal::message_bar::{Message, MessageBuffer}; use alacritty_terminal::selection::{Selection, SelectionType}; - use alacritty_terminal::term::{SizeInfo, Term, TermMode}; + use alacritty_terminal::term::{ClipboardType, SizeInfo, Term, TermMode}; + use crate::clipboard::Clipboard; use crate::config::{ClickHandler, Config}; use crate::event::{ClickState, Mouse}; use crate::url::{Url, Urls}; @@ -909,6 +910,7 @@ mod tests { pub selection: &'a mut Option<Selection>, pub size_info: &'a SizeInfo, pub mouse: &'a mut Mouse, + pub clipboard: &'a mut Clipboard, pub message_buffer: &'a mut MessageBuffer, pub received_count: usize, pub suppress_chars: bool, @@ -1020,6 +1022,10 @@ mod tests { unimplemented!(); } + fn clipboard(&mut self) -> &mut Clipboard { + self.clipboard + } + fn launch_url(&self, _: Url) { unimplemented!(); } @@ -1057,7 +1063,9 @@ mod tests { dpr: 1.0, }; - let mut terminal = Term::new(&cfg, &size, Clipboard::new_nop(), MockEventProxy); + let mut clipboard = Clipboard::new_nop(); + + let mut terminal = Term::new(&cfg, &size, MockEventProxy); let mut mouse = Mouse::default(); mouse.click_state = $initial_state; @@ -1071,6 +1079,7 @@ mod tests { selection: &mut selection, mouse: &mut mouse, size_info: &size, + clipboard: &mut clipboard, received_count: 0, suppress_chars: false, modifiers: Default::default(), diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs index a7f53c2a..9587aec3 100644 --- a/alacritty/src/main.rs +++ b/alacritty/src/main.rs @@ -23,7 +23,6 @@ use log::{error, info}; #[cfg(windows)] use winapi::um::wincon::{AttachConsole, FreeConsole, ATTACH_PARENT_PROCESS}; -use alacritty_terminal::clipboard::Clipboard; use alacritty_terminal::event::Event; use alacritty_terminal::event_loop::{self, EventLoop, Msg}; #[cfg(target_os = "macos")] @@ -35,6 +34,7 @@ use alacritty_terminal::term::Term; use alacritty_terminal::tty; mod cli; +mod clipboard; mod config; mod cursor; mod display; @@ -136,18 +136,12 @@ fn run(window_event_loop: GlutinEventLoop<Event>, config: Config) -> Result<(), info!("PTY dimensions: {:?} x {:?}", display.size_info.lines(), display.size_info.cols()); - // Create new native clipboard. - #[cfg(not(any(target_os = "macos", windows)))] - let clipboard = Clipboard::new(display.window.wayland_display()); - #[cfg(any(target_os = "macos", windows))] - let clipboard = Clipboard::new(); - // Create the terminal. // // This object contains all of the state about what's being displayed. It's // wrapped in a clonable mutex since both the I/O loop and display need to // access it. - let terminal = Term::new(&config, &display.size_info, clipboard, event_proxy.clone()); + let terminal = Term::new(&config, &display.size_info, event_proxy.clone()); let terminal = Arc::new(FairMutex::new(terminal)); // Create the PTY. |