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:
parent
b58d329b07
commit
302db2c976
@ -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 {
|
||||||
|
@ -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);
|
||||||
|
@ -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)]
|
||||||
|
@ -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) => {
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user