1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +03:00

flesh out some todos with new pane trait methods

Tidy some things up to avoid some dead code and redundant impls.
Make it easier to select whether you want to implement the new
methods in terms of the old, or the old methods in terms of
the new in a given pane impl.
This commit is contained in:
Wez Furlong 2022-08-27 07:58:17 -07:00
parent d492eef700
commit cb9fe1a676
10 changed files with 222 additions and 255 deletions

View File

@ -22,14 +22,15 @@ use std::io::{Result as IoResult, Write};
use std::ops::Range;
use std::sync::Arc;
use std::time::{Duration, Instant};
use termwiz::escape::DeviceControlMode;
use termwiz::escape::csi::{Sgr, CSI};
use termwiz::escape::{Action, ControlCode, DeviceControlMode};
use termwiz::input::KeyboardEncoding;
use termwiz::surface::{Line, SequenceNo, SEQ_ZERO};
use termwiz::surface::{Line, SequenceNo};
use url::Url;
use wezterm_term::color::ColorPalette;
use wezterm_term::{
Alert, AlertHandler, CellAttributes, Clipboard, DownloadHandler, KeyCode, KeyModifiers,
MouseEvent, SemanticZone, StableRowIndex, Terminal, TerminalConfiguration, TerminalSize,
Alert, AlertHandler, Clipboard, DownloadHandler, KeyCode, KeyModifiers, MouseEvent,
SemanticZone, StableRowIndex, Terminal, TerminalConfiguration, TerminalSize,
};
#[derive(Debug)]
@ -112,28 +113,11 @@ impl Pane for LocalPane {
}
fn get_lines(&self, lines: Range<StableRowIndex>) -> (StableRowIndex, Vec<Line>) {
let (first, mut lines) = terminal_get_lines(&mut self.terminal.borrow_mut(), lines);
if self.tmux_domain.borrow().is_some() {
let cursor = terminal_get_cursor_position(&mut self.terminal.borrow_mut());
let idx = cursor.y as isize - first as isize;
if idx > 0 {
if let Some(line) = lines.get_mut(idx as usize) {
line.overlay_text_with_attribute(
0,
"This pane is running tmux control mode. Press q to detach.",
CellAttributes::default(),
SEQ_ZERO,
);
}
}
}
(first, lines)
crate::pane::impl_get_lines_via_with_lines(self, lines)
}
fn get_logical_lines(&self, lines: Range<StableRowIndex>) -> Vec<LogicalLine> {
terminal_get_logical_lines(&mut self.terminal.borrow_mut(), lines)
crate::pane::impl_get_logical_lines_via_get_lines(self, lines)
}
fn get_dimensions(&self) -> RenderableDimensions {
@ -681,6 +665,27 @@ struct LocalPaneDCSHandler {
tmux_domain: Option<Arc<TmuxDomainState>>,
}
fn emit_output_for_pane(pane_id: PaneId, message: &str) {
let mut actions = vec![
Action::CSI(CSI::Sgr(Sgr::Reset)),
Action::Control(ControlCode::CarriageReturn),
Action::Control(ControlCode::LineFeed),
];
for c in message.chars() {
actions.push(Action::Print(c));
}
actions.push(Action::Control(ControlCode::CarriageReturn));
actions.push(Action::Control(ControlCode::LineFeed));
promise::spawn::spawn_into_main_thread(async move {
let mux = Mux::get().unwrap();
if let Some(pane) = mux.get_pane(pane_id) {
pane.perform_actions(actions);
}
})
.detach();
}
impl wezterm_term::DeviceControlHandler for LocalPaneDCSHandler {
fn handle_device_control(&mut self, control: termwiz::escape::DeviceControlMode) {
match control {
@ -705,6 +710,11 @@ impl wezterm_term::DeviceControlHandler for LocalPaneDCSHandler {
pane.tmux_domain
.borrow_mut()
.replace(Arc::clone(&tmux_domain));
emit_output_for_pane(
self.pane_id,
"[This pane is running tmux control mode. Press q to detach]",
);
}
self.tmux_domain.replace(tmux_domain);

View File

@ -224,6 +224,7 @@ pub trait Pane: Downcast {
/// Because of this, we also return the adjusted StableRowIndex for
/// the first row in the range.
fn get_lines(&self, lines: Range<StableRowIndex>) -> (StableRowIndex, Vec<Line>);
fn with_lines_mut(&self, lines: Range<StableRowIndex>, with_lines: &mut dyn WithPaneLines);
fn for_each_logical_line_in_stable_range_mut(
@ -232,88 +233,7 @@ pub trait Pane: Downcast {
for_line: &mut dyn ForEachPaneLogicalLine,
);
fn get_logical_lines(&self, lines: Range<StableRowIndex>) -> Vec<LogicalLine> {
// NOTE: see terminal_get_logical_lines() for the implementation that is
// actually used by most panes; this particular method is the fallback
// implementation for other Panes.
let (mut first, mut phys) = self.get_lines(lines);
// Avoid pathological cases where we have eg: a really long logical line
// (such as 1.5MB of json) that we previously wrapped. We don't want to
// un-wrap, scan, and re-wrap that thing.
// This is an imperfect length constraint to partially manage the cost.
const MAX_LOGICAL_LINE_LEN: usize = 1024;
let mut back_len = 0;
// Look backwards to find the start of the first logical line
while first > 0 {
let (prior, back) = self.get_lines(first - 1..first);
if prior == first {
break;
}
if !back[0].last_cell_was_wrapped() {
break;
}
if back[0].len() + back_len > MAX_LOGICAL_LINE_LEN {
break;
}
back_len += back[0].len();
first = prior;
for (idx, line) in back.into_iter().enumerate() {
phys.insert(idx, line);
}
}
// Look forwards to find the end of the last logical line
while let Some(last) = phys.last() {
if !last.last_cell_was_wrapped() {
break;
}
if last.len() > MAX_LOGICAL_LINE_LEN {
break;
}
let next_row = first + phys.len() as StableRowIndex;
let (last_row, mut ahead) = self.get_lines(next_row..next_row + 1);
if last_row != next_row {
break;
}
phys.append(&mut ahead);
}
// Now process this stuff into logical lines
let mut lines = vec![];
for (idx, line) in phys.into_iter().enumerate() {
match lines.last_mut() {
None => {
let logical = line.clone();
lines.push(LogicalLine {
physical_lines: vec![line],
logical,
first_row: first + idx as StableRowIndex,
});
}
Some(prior) => {
if prior.logical.last_cell_was_wrapped()
&& prior.logical.len() <= MAX_LOGICAL_LINE_LEN
{
let seqno = prior.logical.current_seqno().max(line.current_seqno());
prior.logical.set_last_cell_was_wrapped(false, seqno);
prior.logical.append_line(line.clone(), seqno);
prior.physical_lines.push(line);
} else {
let logical = line.clone();
lines.push(LogicalLine {
physical_lines: vec![line],
logical,
first_row: first + idx as StableRowIndex,
});
}
}
}
}
lines
}
fn get_logical_lines(&self, lines: Range<StableRowIndex>) -> Vec<LogicalLine>;
fn apply_hyperlinks(&self, lines: Range<StableRowIndex>, rules: &[Rule]) {
struct ApplyHyperLinks<'a> {
@ -495,6 +415,150 @@ pub trait ForEachPaneLogicalLine {
) -> bool;
}
pub fn impl_with_lines_via_get_lines<P: Pane + ?Sized>(
pane: &P,
lines: Range<StableRowIndex>,
with_lines: &mut dyn WithPaneLines,
) {
let (first, mut lines) = pane.get_lines(lines);
let mut line_refs = vec![];
for line in lines.iter_mut() {
line_refs.push(line);
}
with_lines.with_lines_mut(first, &mut line_refs);
}
pub fn impl_for_each_logical_line_via_get_logical_lines<P: Pane + ?Sized>(
pane: &P,
lines: Range<StableRowIndex>,
for_line: &mut dyn ForEachPaneLogicalLine,
) {
let mut logical = pane.get_logical_lines(lines);
for line in &mut logical {
let num_lines = line.physical_lines.len() as StableRowIndex;
let mut line_refs = vec![];
for phys in line.physical_lines.iter_mut() {
line_refs.push(phys);
}
let should_continue = for_line
.with_logical_line_mut(line.first_row..line.first_row + num_lines, &mut line_refs);
if !should_continue {
break;
}
}
}
pub fn impl_get_logical_lines_via_get_lines<P: Pane + ?Sized>(
pane: &P,
lines: Range<StableRowIndex>,
) -> Vec<LogicalLine> {
let (mut first, mut phys) = pane.get_lines(lines);
// Avoid pathological cases where we have eg: a really long logical line
// (such as 1.5MB of json) that we previously wrapped. We don't want to
// un-wrap, scan, and re-wrap that thing.
// This is an imperfect length constraint to partially manage the cost.
const MAX_LOGICAL_LINE_LEN: usize = 1024;
let mut back_len = 0;
// Look backwards to find the start of the first logical line
while first > 0 {
let (prior, back) = pane.get_lines(first - 1..first);
if prior == first {
break;
}
if !back[0].last_cell_was_wrapped() {
break;
}
if back[0].len() + back_len > MAX_LOGICAL_LINE_LEN {
break;
}
back_len += back[0].len();
first = prior;
for (idx, line) in back.into_iter().enumerate() {
phys.insert(idx, line);
}
}
// Look forwards to find the end of the last logical line
while let Some(last) = phys.last() {
if !last.last_cell_was_wrapped() {
break;
}
if last.len() > MAX_LOGICAL_LINE_LEN {
break;
}
let next_row = first + phys.len() as StableRowIndex;
let (last_row, mut ahead) = pane.get_lines(next_row..next_row + 1);
if last_row != next_row {
break;
}
phys.append(&mut ahead);
}
// Now process this stuff into logical lines
let mut lines = vec![];
for (idx, line) in phys.into_iter().enumerate() {
match lines.last_mut() {
None => {
let logical = line.clone();
lines.push(LogicalLine {
physical_lines: vec![line],
logical,
first_row: first + idx as StableRowIndex,
});
}
Some(prior) => {
if prior.logical.last_cell_was_wrapped()
&& prior.logical.len() <= MAX_LOGICAL_LINE_LEN
{
let seqno = prior.logical.current_seqno().max(line.current_seqno());
prior.logical.set_last_cell_was_wrapped(false, seqno);
prior.logical.append_line(line.clone(), seqno);
prior.physical_lines.push(line);
} else {
let logical = line.clone();
lines.push(LogicalLine {
physical_lines: vec![line],
logical,
first_row: first + idx as StableRowIndex,
});
}
}
}
}
lines
}
pub fn impl_get_lines_via_with_lines<P: Pane + ?Sized>(
pane: &P,
lines: Range<StableRowIndex>,
) -> (StableRowIndex, Vec<Line>) {
struct LineCollector {
first: StableRowIndex,
lines: Vec<Line>,
}
let mut collector = LineCollector {
first: 0,
lines: vec![],
};
impl WithPaneLines for LineCollector {
fn with_lines_mut(&mut self, first_row: StableRowIndex, lines: &mut [&mut Line]) {
self.first = first_row;
for line in lines.iter_mut() {
self.lines.push(line.clone());
}
}
}
pane.with_lines_mut(lines, &mut collector);
(collector.first, collector.lines)
}
#[cfg(test)]
mod test {
use super::*;
@ -549,7 +613,11 @@ mod test {
lines: Range<StableRowIndex>,
for_line: &mut dyn ForEachPaneLogicalLine,
) {
unimplemented!();
crate::pane::impl_for_each_logical_line_via_get_logical_lines(self, lines, for_line)
}
fn get_logical_lines(&self, lines: Range<StableRowIndex>) -> Vec<LogicalLine> {
crate::pane::impl_get_logical_lines_via_get_lines(self, lines)
}
fn get_lines(&self, lines: Range<StableRowIndex>) -> (StableRowIndex, Vec<Line>) {
@ -654,88 +722,6 @@ mod test {
physical_lines
}
#[test]
fn logical_lines_terminal() {
use wezterm_term::{Terminal, TerminalConfiguration};
#[derive(Debug)]
struct TermConfig {}
impl TerminalConfiguration for TermConfig {
fn color_palette(&self) -> ColorPalette {
ColorPalette::default()
}
}
let mut terminal = Terminal::new(
TerminalSize {
rows: 24,
cols: 20,
pixel_width: 0,
pixel_height: 0,
dpi: 0,
},
Arc::new(TermConfig {}),
"WezTerm",
"o_O",
Box::new(Vec::new()),
);
let text = "Hello there this is a long line.\r\nlogical line two\r\nanother long line here\r\nlogical line four\r\nlogical line five\r\ncap it off with another long line";
terminal.advance_bytes(text.as_bytes());
let logical = terminal_get_logical_lines(&mut terminal, 0..9);
snapshot!(
summarize_logical_lines(&logical),
r#"
[
(
0,
"Hello there this is a long line.",
),
(
2,
"logical line two",
),
(
3,
"another long line here",
),
(
5,
"logical line four",
),
(
6,
"logical line five",
),
(
7,
"cap it off with another long line",
),
]
"#
);
// Now try with offset bounds
let offset = terminal_get_logical_lines(&mut terminal, 1..3);
snapshot!(
summarize_logical_lines(&offset),
r#"
[
(
0,
"Hello there this is a long line.",
),
(
2,
"logical line two",
),
]
"#
);
}
fn summarize_logical_lines(lines: &[LogicalLine]) -> Vec<(StableRowIndex, Cow<str>)> {
lines
.iter()

View File

@ -1,4 +1,4 @@
use crate::pane::{ForEachPaneLogicalLine, LogicalLine, WithPaneLines};
use crate::pane::{ForEachPaneLogicalLine, WithPaneLines};
use luahelper::impl_lua_conversion_dynamic;
use rangeset::RangeSet;
use serde::{Deserialize, Serialize};
@ -85,39 +85,6 @@ pub fn terminal_for_each_logical_line_in_stable_range_mut(
});
}
pub fn terminal_get_logical_lines(
term: &mut Terminal,
lines: Range<StableRowIndex>,
) -> Vec<LogicalLine> {
let screen = term.screen();
let mut result = vec![];
screen.for_each_logical_line_in_stable_range(lines.clone(), |sr, lines| {
let mut physical_lines: Vec<Line> = lines
.iter()
.map(|line| {
let line = (*line).clone();
line
})
.collect();
let mut logical = physical_lines[0].clone();
for line in &mut physical_lines[1..] {
let seqno = line.current_seqno();
logical.set_last_cell_was_wrapped(false, seqno);
logical.append_line((*line).clone(), seqno);
}
result.push(LogicalLine {
physical_lines,
logical,
first_row: sr.start,
});
true
});
result
}
/// Implements Pane::with_lines for Terminal
pub fn terminal_with_lines<F>(term: &mut Terminal, lines: Range<StableRowIndex>, mut func: F)
where

View File

@ -2009,16 +2009,16 @@ mod test {
fn with_lines_mut(
&self,
stable_range: Range<StableRowIndex>,
with_lines: &mut dyn WithPaneLines,
_stable_range: Range<StableRowIndex>,
_with_lines: &mut dyn WithPaneLines,
) {
unimplemented!();
}
fn for_each_logical_line_in_stable_range_mut(
&self,
lines: Range<StableRowIndex>,
for_line: &mut dyn ForEachPaneLogicalLine,
_lines: Range<StableRowIndex>,
_for_line: &mut dyn ForEachPaneLogicalLine,
) {
unimplemented!();
}
@ -2027,6 +2027,10 @@ mod test {
unimplemented!();
}
fn get_logical_lines(&self, _lines: Range<StableRowIndex>) -> Vec<LogicalLine> {
unimplemented!();
}
fn get_dimensions(&self) -> RenderableDimensions {
unimplemented!();
}

View File

@ -5,7 +5,7 @@
use crate::domain::{alloc_domain_id, Domain, DomainId, DomainState};
use crate::pane::{
alloc_pane_id, CloseReason, ForEachPaneLogicalLine, Pane, PaneId, WithPaneLines,
alloc_pane_id, CloseReason, ForEachPaneLogicalLine, LogicalLine, Pane, PaneId, WithPaneLines,
};
use crate::renderable::*;
use crate::tab::Tab;
@ -153,6 +153,10 @@ impl Pane for TermWizTerminalPane {
);
}
fn get_logical_lines(&self, lines: Range<StableRowIndex>) -> Vec<LogicalLine> {
crate::pane::impl_get_logical_lines_via_get_lines(self, lines)
}
fn with_lines_mut(&self, lines: Range<StableRowIndex>, with_lines: &mut dyn WithPaneLines) {
terminal_with_lines_mut(&mut self.terminal.borrow_mut(), lines, with_lines)
}

View File

@ -7,8 +7,8 @@ use codec::*;
use config::configuration;
use mux::domain::DomainId;
use mux::pane::{
alloc_pane_id, CloseReason, ForEachPaneLogicalLine, Pane, PaneId, Pattern, SearchResult,
WithPaneLines,
alloc_pane_id, CloseReason, ForEachPaneLogicalLine, LogicalLine, Pane, PaneId, Pattern,
SearchResult, WithPaneLines,
};
use mux::renderable::{RenderableDimensions, StableCursorPosition};
use mux::tab::TabId;
@ -204,7 +204,7 @@ impl Pane for ClientPane {
}
fn with_lines_mut(&self, lines: Range<StableRowIndex>, with_lines: &mut dyn WithPaneLines) {
todo!();
mux::pane::impl_with_lines_via_get_lines(self, lines, with_lines);
}
fn for_each_logical_line_in_stable_range_mut(
@ -212,13 +212,17 @@ impl Pane for ClientPane {
lines: Range<StableRowIndex>,
for_line: &mut dyn ForEachPaneLogicalLine,
) {
todo!();
mux::pane::impl_for_each_logical_line_via_get_logical_lines(self, lines, for_line);
}
fn get_lines(&self, lines: Range<StableRowIndex>) -> (StableRowIndex, Vec<Line>) {
self.renderable.borrow().get_lines(lines)
}
fn get_logical_lines(&self, lines: Range<StableRowIndex>) -> Vec<LogicalLine> {
mux::pane::impl_get_logical_lines_via_get_lines(self, lines)
}
fn get_current_seqno(&self) -> SequenceNo {
self.renderable.borrow().get_current_seqno()
}

View File

@ -716,13 +716,6 @@ impl RenderableState {
self.inner.borrow().cursor_position
}
pub fn with_lines<F>(&self, lines: Range<StableRowIndex>, func: F)
where
F: FnMut(StableRowIndex, &[&Line]),
{
todo!();
}
pub fn get_lines(&self, lines: Range<StableRowIndex>) -> (StableRowIndex, Vec<Line>) {
let mut inner = self.inner.borrow_mut();
let mut result = vec![];

View File

@ -5,7 +5,9 @@ use config::keyassignment::{
ScrollbackEraseMode, SelectionMode,
};
use mux::domain::DomainId;
use mux::pane::{ForEachPaneLogicalLine, Pane, PaneId, Pattern, SearchResult, WithPaneLines};
use mux::pane::{
ForEachPaneLogicalLine, LogicalLine, Pane, PaneId, Pattern, SearchResult, WithPaneLines,
};
use mux::renderable::*;
use mux::tab::TabId;
use rangeset::RangeSet;
@ -1023,6 +1025,10 @@ impl Pane for CopyOverlay {
self.delegate.get_changed_since(lines, seqno)
}
fn get_logical_lines(&self, lines: Range<StableRowIndex>) -> Vec<LogicalLine> {
self.delegate.get_logical_lines(lines)
}
fn for_each_logical_line_in_stable_range_mut(
&self,
lines: Range<StableRowIndex>,

View File

@ -3,7 +3,9 @@ use crate::termwindow::{TermWindow, TermWindowNotif};
use config::keyassignment::{ClipboardCopyDestination, QuickSelectArguments, ScrollbackEraseMode};
use config::ConfigHandle;
use mux::domain::DomainId;
use mux::pane::{ForEachPaneLogicalLine, Pane, PaneId, Pattern, SearchResult, WithPaneLines};
use mux::pane::{
ForEachPaneLogicalLine, LogicalLine, Pane, PaneId, Pattern, SearchResult, WithPaneLines,
};
use mux::renderable::*;
use rangeset::RangeSet;
use std::cell::{RefCell, RefMut};
@ -461,6 +463,10 @@ impl Pane for QuickSelectOverlay {
.for_each_logical_line_in_stable_range_mut(lines, for_line);
}
fn get_logical_lines(&self, lines: Range<StableRowIndex>) -> Vec<LogicalLine> {
self.delegate.get_logical_lines(lines)
}
fn with_lines_mut(&self, lines: Range<StableRowIndex>, with_lines: &mut dyn WithPaneLines) {
let mut renderer = self.renderer.borrow_mut();
// Take care to access self.delegate methods here before we get into

View File

@ -48,13 +48,13 @@ use smol::Timer;
use std::any::Any;
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
use std::ops::{Add, Range};
use std::ops::Add;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use termwiz::hyperlink::Hyperlink;
use termwiz::surface::{Line, SequenceNo};
use termwiz::surface::SequenceNo;
use wezterm_dynamic::Value;
use wezterm_font::FontConfiguration;
use wezterm_gui_subcommands::GuiPosition;
@ -190,19 +190,6 @@ pub struct PaneState {
bell_start: Option<Instant>,
pub mouse_terminal_coords: Option<(ClickPosition, StableRowIndex)>,
/// Cache to avoid calling pane.get_lines_with_hyperlinks_applied
/// if the pane hasn't changed since the last render
pub logical_line_cache: Option<CachedLogicalLines>,
}
pub struct CachedLogicalLines {
// Key fields
pub seqno: SequenceNo,
pub stable_range: Range<StableRowIndex>,
// Value fields
pub top: StableRowIndex,
pub lines: Rc<Vec<Line>>,
}
/// Data used when synchronously formatting pane and window titles