1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-27 12:23:46 +03:00

a lighter way to pass selection ranges for client tabs

This commit is contained in:
Wez Furlong 2019-06-15 13:48:28 -07:00
parent b58d329b07
commit 302db2c976
7 changed files with 74 additions and 8 deletions

View File

@ -5,6 +5,7 @@ use failure::Error;
use portable_pty::{Child, MasterPty, PtySize}; use portable_pty::{Child, MasterPty, PtySize};
use std::cell::{RefCell, RefMut}; use std::cell::{RefCell, RefMut};
use term::color::ColorPalette; use term::color::ColorPalette;
use term::selection::SelectionRange;
use term::{KeyCode, KeyModifiers, MouseEvent, Terminal, TerminalHost}; use term::{KeyCode, KeyModifiers, MouseEvent, Terminal, TerminalHost};
pub struct LocalTab { pub struct LocalTab {
@ -81,6 +82,14 @@ impl Tab for LocalTab {
fn domain_id(&self) -> DomainId { fn domain_id(&self) -> DomainId {
self.domain_id self.domain_id
} }
fn selection_range(&self) -> Option<SelectionRange> {
let terminal = self.terminal.borrow();
let rows = terminal.screen().physical_rows;
terminal
.selection_range()
.map(|r| r.clip_to_viewport(terminal.get_viewport_offset(), rows))
}
} }
impl LocalTab { impl LocalTab {

View File

@ -5,6 +5,7 @@ use failure::Fallible;
use portable_pty::PtySize; use portable_pty::PtySize;
use std::cell::RefMut; use std::cell::RefMut;
use term::color::ColorPalette; use term::color::ColorPalette;
use term::selection::SelectionRange;
use term::{KeyCode, KeyModifiers, MouseEvent, TerminalHost}; use term::{KeyCode, KeyModifiers, MouseEvent, TerminalHost};
static TAB_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::AtomicUsize::new(0); static TAB_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::AtomicUsize::new(0);
@ -28,5 +29,10 @@ pub trait Tab: Downcast {
fn is_dead(&self) -> bool; fn is_dead(&self) -> bool;
fn palette(&self) -> ColorPalette; fn palette(&self) -> ColorPalette;
fn domain_id(&self) -> DomainId; fn domain_id(&self) -> DomainId;
/// Returns the selection range adjusted to the viewport
/// (eg: it has been normalized and had clip_to_viewport called
/// on it prior to being returned)
fn selection_range(&self) -> Option<SelectionRange>;
} }
impl_downcast!(Tab); impl_downcast!(Tab);

View File

@ -19,6 +19,7 @@ use log::debug;
use portable_pty::{CommandBuilder, PtySize}; use portable_pty::{CommandBuilder, PtySize};
use serde_derive::*; use serde_derive::*;
use std::sync::Arc; use std::sync::Arc;
use term::selection::SelectionRange;
use term::{CursorPosition, Line}; use term::{CursorPosition, Line};
use termwiz::hyperlink::Hyperlink; use termwiz::hyperlink::Hyperlink;
use termwiz::surface::{Change, SequenceNo}; use termwiz::surface::{Change, SequenceNo};
@ -330,6 +331,7 @@ pub struct SendMouseEvent {
#[derive(Deserialize, Serialize, PartialEq, Debug)] #[derive(Deserialize, Serialize, PartialEq, Debug)]
pub struct SendMouseEventResponse { pub struct SendMouseEventResponse {
pub clipboard: Option<String>, pub clipboard: Option<String>,
pub selection_range: Option<SelectionRange>,
} }
#[derive(Deserialize, Serialize, PartialEq, Debug)] #[derive(Deserialize, Serialize, PartialEq, Debug)]

View File

@ -383,7 +383,7 @@ impl<S: std::io::Read + std::io::Write> ClientSession<S> {
Pdu::UnitResponse(UnitResponse {}) Pdu::UnitResponse(UnitResponse {})
} }
Pdu::SendMouseEvent(SendMouseEvent { tab_id, event }) => { Pdu::SendMouseEvent(SendMouseEvent { tab_id, event }) => {
let clipboard = Future::with_executor(self.executor.clone_executor(), move || { Future::with_executor(self.executor.clone_executor(), move || {
let mux = Mux::get().unwrap(); let mux = Mux::get().unwrap();
let tab = mux let tab = mux
.get_tab(tab_id) .get_tab(tab_id)
@ -394,10 +394,12 @@ impl<S: std::io::Read + std::io::Write> ClientSession<S> {
title: None, title: None,
}; };
tab.mouse_event(event, &mut host)?; tab.mouse_event(event, &mut host)?;
Ok(host.clipboard) Ok(Pdu::SendMouseEventResponse(SendMouseEventResponse {
clipboard: host.clipboard,
selection_range: tab.selection_range(),
}))
}) })
.wait()?; .wait()?
Pdu::SendMouseEventResponse(SendMouseEventResponse { clipboard })
} }
Pdu::Spawn(spawn) => { Pdu::Spawn(spawn) => {

View File

@ -14,6 +14,7 @@ use std::ops::Range;
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use term::color::ColorPalette; use term::color::ColorPalette;
use term::selection::SelectionRange;
use term::{CursorPosition, Line}; use term::{CursorPosition, Line};
use term::{KeyCode, KeyModifiers, MouseEvent, TerminalHost}; use term::{KeyCode, KeyModifiers, MouseEvent, TerminalHost};
use termwiz::hyperlink::Hyperlink; use termwiz::hyperlink::Hyperlink;
@ -45,6 +46,7 @@ impl ClientTab {
surface: RefCell::new(Surface::new(80, 24)), surface: RefCell::new(Surface::new(80, 24)),
remote_sequence: RefCell::new(0), remote_sequence: RefCell::new(0),
local_sequence: RefCell::new(0), local_sequence: RefCell::new(0),
selection_range: RefCell::new(None),
}; };
let reader = Pipe::new().expect("Pipe::new failed"); let reader = Pipe::new().expect("Pipe::new failed");
@ -130,6 +132,7 @@ impl Tab for ClientTab {
if resp.clipboard.is_some() { if resp.clipboard.is_some() {
host.set_clipboard(resp.clipboard)?; host.set_clipboard(resp.clipboard)?;
} }
*self.renderable.borrow().selection_range.borrow_mut() = resp.selection_range;
Ok(()) Ok(())
} }
@ -153,6 +156,10 @@ impl Tab for ClientTab {
fn domain_id(&self) -> DomainId { fn domain_id(&self) -> DomainId {
self.client.local_domain_id self.client.local_domain_id
} }
fn selection_range(&self) -> Option<SelectionRange> {
self.renderable.borrow().selection_range.borrow().clone()
}
} }
struct RenderableState { struct RenderableState {
@ -164,6 +171,7 @@ struct RenderableState {
surface: RefCell<Surface>, surface: RefCell<Surface>,
remote_sequence: RefCell<SequenceNo>, remote_sequence: RefCell<SequenceNo>,
local_sequence: RefCell<SequenceNo>, local_sequence: RefCell<SequenceNo>,
selection_range: RefCell<Option<SelectionRange>>,
} }
const POLL_INTERVAL: Duration = Duration::from_millis(50); const POLL_INTERVAL: Duration = Duration::from_millis(50);
@ -228,11 +236,18 @@ impl Renderable for RenderableState {
let mut surface = self.surface.borrow_mut(); let mut surface = self.surface.borrow_mut();
let seq = surface.current_seqno(); let seq = surface.current_seqno();
surface.flush_changes_older_than(seq); surface.flush_changes_older_than(seq);
let selection = *self.selection_range.borrow();
surface surface
.screen_lines() .screen_lines()
.into_iter() .into_iter()
.enumerate() .enumerate()
.map(|(idx, line)| (idx, line, 0..0)) .map(|(idx, line)| {
let r = match selection {
None => 0..0,
Some(sel) => sel.cols_for_row(idx as i32),
};
(idx, line, r)
})
.collect() .collect()
} }

View File

@ -1,11 +1,12 @@
// The range_plus_one lint can't see when the LHS is not compatible with // The range_plus_one lint can't see when the LHS is not compatible with
// and inclusive range // and inclusive range
#![cfg_attr(feature = "cargo-clippy", allow(clippy::range_plus_one))] #![cfg_attr(feature = "cargo-clippy", allow(clippy::range_plus_one))]
use super::ScrollbackOrVisibleRowIndex; use super::{ScrollbackOrVisibleRowIndex, VisibleRowIndex};
use serde_derive::*;
use std::ops::Range; use std::ops::Range;
/// The x,y coordinates of either the start or end of a selection region /// The x,y coordinates of either the start or end of a selection region
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct SelectionCoordinate { pub struct SelectionCoordinate {
pub x: usize, pub x: usize,
pub y: ScrollbackOrVisibleRowIndex, pub y: ScrollbackOrVisibleRowIndex,
@ -13,7 +14,7 @@ pub struct SelectionCoordinate {
/// Represents the selected text range. /// Represents the selected text range.
/// The end coordinates are inclusive. /// The end coordinates are inclusive.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct SelectionRange { pub struct SelectionRange {
pub start: SelectionCoordinate, pub start: SelectionCoordinate,
pub end: SelectionCoordinate, pub end: SelectionCoordinate,
@ -26,6 +27,33 @@ impl SelectionRange {
Self { start, end } Self { start, end }
} }
/// Returns a modified version of the selection that is adjusted
/// for a Surface that holds only the visible viewport.
/// The y values are adjusted such that 0 indicates the top of
/// the viewport.
pub fn clip_to_viewport(
&self,
viewport_offset: VisibleRowIndex,
height: usize,
) -> SelectionRange {
let offset = -viewport_offset as ScrollbackOrVisibleRowIndex;
let res = SelectionRange {
start: SelectionCoordinate {
x: self.start.x,
y: self.start.y.max(offset) - offset,
},
end: SelectionCoordinate {
x: self.end.x,
y: self
.end
.y
.min(offset + height as ScrollbackOrVisibleRowIndex)
- offset,
},
};
res
}
/// Returns an extended selection that it ends at the specified location /// Returns an extended selection that it ends at the specified location
pub fn extend(&self, end: SelectionCoordinate) -> Self { pub fn extend(&self, end: SelectionCoordinate) -> Self {
Self { Self {

View File

@ -590,6 +590,10 @@ impl TerminalState {
} }
} }
pub fn selection_range(&self) -> Option<SelectionRange> {
self.selection_range.clone().map(|r| r.normalize())
}
fn mouse_drag_left(&mut self, event: MouseEvent) -> Result<(), Error> { fn mouse_drag_left(&mut self, event: MouseEvent) -> Result<(), Error> {
// dragging out the selection region // dragging out the selection region
// TODO: may drag and change the viewport // TODO: may drag and change the viewport