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 std::cell::{RefCell, RefMut};
use term::color::ColorPalette;
use term::selection::SelectionRange;
use term::{KeyCode, KeyModifiers, MouseEvent, Terminal, TerminalHost};
pub struct LocalTab {
@ -81,6 +82,14 @@ impl Tab for LocalTab {
fn domain_id(&self) -> DomainId {
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 {

View File

@ -5,6 +5,7 @@ use failure::Fallible;
use portable_pty::PtySize;
use std::cell::RefMut;
use term::color::ColorPalette;
use term::selection::SelectionRange;
use term::{KeyCode, KeyModifiers, MouseEvent, TerminalHost};
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 palette(&self) -> ColorPalette;
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);

View File

@ -19,6 +19,7 @@ use log::debug;
use portable_pty::{CommandBuilder, PtySize};
use serde_derive::*;
use std::sync::Arc;
use term::selection::SelectionRange;
use term::{CursorPosition, Line};
use termwiz::hyperlink::Hyperlink;
use termwiz::surface::{Change, SequenceNo};
@ -330,6 +331,7 @@ pub struct SendMouseEvent {
#[derive(Deserialize, Serialize, PartialEq, Debug)]
pub struct SendMouseEventResponse {
pub clipboard: Option<String>,
pub selection_range: Option<SelectionRange>,
}
#[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::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 tab = mux
.get_tab(tab_id)
@ -394,10 +394,12 @@ impl<S: std::io::Read + std::io::Write> ClientSession<S> {
title: None,
};
tab.mouse_event(event, &mut host)?;
Ok(host.clipboard)
Ok(Pdu::SendMouseEventResponse(SendMouseEventResponse {
clipboard: host.clipboard,
selection_range: tab.selection_range(),
}))
})
.wait()?;
Pdu::SendMouseEventResponse(SendMouseEventResponse { clipboard })
.wait()?
}
Pdu::Spawn(spawn) => {

View File

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

View File

@ -1,11 +1,12 @@
// The range_plus_one lint can't see when the LHS is not compatible with
// and inclusive range
#![cfg_attr(feature = "cargo-clippy", allow(clippy::range_plus_one))]
use super::ScrollbackOrVisibleRowIndex;
use super::{ScrollbackOrVisibleRowIndex, VisibleRowIndex};
use serde_derive::*;
use std::ops::Range;
/// 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 x: usize,
pub y: ScrollbackOrVisibleRowIndex,
@ -13,7 +14,7 @@ pub struct SelectionCoordinate {
/// Represents the selected text range.
/// 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 start: SelectionCoordinate,
pub end: SelectionCoordinate,
@ -26,6 +27,33 @@ impl SelectionRange {
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
pub fn extend(&self, end: SelectionCoordinate) -> 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> {
// dragging out the selection region
// TODO: may drag and change the viewport