1
1
mirror of https://github.com/wez/wezterm.git synced 2024-09-20 03:09:06 +03:00

hyperlinks, selection by word and line deal with wrapping better

These now operate in terms of logical lines so they deal with
lines that have wrapped outside the viewport better than in
previous releases.

closes: https://github.com/wez/wezterm/issues/408
This commit is contained in:
Wez Furlong 2021-03-26 14:52:00 -07:00
parent 0f23c140d1
commit c6308202cb
6 changed files with 63 additions and 73 deletions

View File

@ -27,6 +27,7 @@ brief notes about them may accumulate here.
* Fixed: X10 mouse coordinate reporting encoding could produce invalid outputs for large windows. Capped coordinate values to the maximum value that is representable in UTF-8 encoding
* Fixed: font fallback now happens asynchronously from painting [#508](https://github.com/wez/wezterm/issues/508)
* New: added [window:get_selection_text_for_pane](config/lua/window/get_selection_text_for_pane.md) method [#575](https://github.com/wez/wezterm/issues/575)
* Fixed: implicit hyperlink rules, word and line selection now operate on logical lines which means that they deal with wrapped lines outside of the viewport. [#408](https://github.com/wez/wezterm/issues/408)
### 20210314-114017-04b7cedd

View File

@ -78,6 +78,24 @@ pub struct LogicalLine {
}
impl LogicalLine {
pub fn xy_to_logical_x(&self, x: usize, y: StableRowIndex) -> usize {
let mut offset = 0;
for (idx, line) in self.physical_lines.iter().enumerate() {
let phys_y = self.first_row + idx as StableRowIndex;
if phys_y == y {
return offset + x;
}
offset += line.cells().len();
}
panic!(
"x={} y={} is outside of this logical line starting at {} comprised of {} physical lines",
x, y,
self.first_row,
self.physical_lines.len()
);
}
pub fn logical_x_to_physical_coord(&self, x: usize) -> (StableRowIndex, usize) {
let mut y = self.first_row;
let mut idx = 0;
@ -109,8 +127,11 @@ impl LogicalLine {
let num_phys = self.physical_lines.len();
for (idx, phys) in self.physical_lines.iter_mut().enumerate() {
let len = phys.cells().len();
*phys = line.split_off(len);
phys.set_last_cell_was_wrapped(idx == num_phys - 1);
let remainder = line.split_off(len);
*phys = line;
line = remainder;
let wrapped = idx == num_phys - 1;
phys.set_last_cell_was_wrapped(wrapped);
}
}
}
@ -230,7 +251,11 @@ pub trait Pane: Downcast {
}
}
(first.unwrap(), phys_lines)
if first.is_none() {
assert_eq!(phys_lines.len(), 0);
}
(first.unwrap_or(0), phys_lines)
}
/// Returns render related dimensions

View File

@ -68,21 +68,17 @@ impl SelectionRange {
/// Computes the selection range for the line around the specified coords
pub fn line_around(start: SelectionCoordinate, pane: &dyn Pane) -> Self {
let mut end_y = start.y;
loop {
let next_y = end_y + 1;
let (_, lines) = pane.get_lines(end_y..next_y);
if !lines[0].last_cell_was_wrapped() {
break;
}
end_y = next_y;
}
let logical = pane.get_logical_lines(start.y..start.y + 1);
let logical = &logical[0];
Self {
start: SelectionCoordinate { x: 0, y: start.y },
start: SelectionCoordinate {
x: 0,
y: logical.first_row,
},
end: SelectionCoordinate {
x: usize::max_value(),
y: end_y,
y: logical.first_row + (logical.physical_lines.len() - 1) as StableRowIndex,
},
}
}
@ -135,62 +131,30 @@ impl SelectionRange {
/// Computes the selection range for the word around the specified coords
pub fn word_around(start: SelectionCoordinate, pane: &dyn Pane) -> Self {
let (first, lines) = pane.get_lines(start.y..start.y + 1);
// TODO: if selection_range.start.x == 0, search backwards for wrapping
// lines too.
match lines[0].compute_double_click_range(start.x, is_double_click_word) {
DoubleClickRange::Range(click_range) => Self {
start: SelectionCoordinate {
x: click_range.start,
y: first,
},
end: SelectionCoordinate {
x: click_range.end - 1,
y: first,
},
},
DoubleClickRange::RangeWithWrap(range_start) => {
let start_coord = SelectionCoordinate {
x: range_start.start,
y: first,
};
let mut end_coord = SelectionCoordinate {
x: range_start.end - 1,
y: first,
};
for y_cont in start.y + 1.. {
let (first, lines) = pane.get_lines(y_cont..y_cont + 1);
if first != y_cont {
break;
}
match lines[0].compute_double_click_range(0, is_double_click_word) {
DoubleClickRange::Range(range_end) => {
if range_end.end > range_end.start {
end_coord = SelectionCoordinate {
x: range_end.end - 1,
y: y_cont,
};
}
break;
}
DoubleClickRange::RangeWithWrap(range_end) => {
end_coord = SelectionCoordinate {
x: range_end.end - 1,
y: y_cont,
};
}
}
}
let logical = pane.get_logical_lines(start.y..start.y + 1);
let logical = &logical[0];
let start_idx = logical.xy_to_logical_x(start.x, start.y);
match logical
.logical
.compute_double_click_range(start_idx, is_double_click_word)
{
DoubleClickRange::Range(click_range) => {
let (start_y, start_x) = logical.logical_x_to_physical_coord(click_range.start);
let (end_y, end_x) = logical.logical_x_to_physical_coord(click_range.end - 1);
Self {
start: start_coord,
end: end_coord,
start: SelectionCoordinate {
x: start_x,
y: start_y,
},
end: SelectionCoordinate { x: end_x, y: end_y },
}
}
DoubleClickRange::RangeWithWrap(_) => {
// We're using logical lines to match against, so we should never get
// a RangeWithWrap result here
unreachable!()
}
}
}

View File

@ -358,7 +358,10 @@ impl super::TermWindow {
self.last_mouse_terminal_coords = (x, stable_row); // FIXME: per-pane
let (top, mut lines) = pane.get_lines(stable_row..stable_row + 1);
let (top, mut lines) = pane.get_lines_with_hyperlinks_applied(
stable_row..stable_row + 1,
&self.config.hyperlink_rules,
);
let new_highlight = if top == stable_row {
if let Some(line) = lines.get_mut(0) {
if let Some(cell) = line.cells().get(x) {

View File

@ -18,7 +18,6 @@ use mux::renderable::{RenderableDimensions, StableCursorPosition};
use mux::tab::{PositionedPane, PositionedSplit, SplitDirection};
use std::ops::Range;
use std::rc::Rc;
use std::sync::Arc;
use std::time::Instant;
use termwiz::cellcluster::CellCluster;
use termwiz::surface::{CursorShape, CursorVisibility};
@ -172,12 +171,9 @@ impl super::TermWindow {
None => dims.physical_top..dims.physical_top + dims.viewport_rows as StableRowIndex,
};
/*
let (top, vp_lines) = pos
.pane
.get_lines_with_hyperlinks_applied(stable_range, &self.config.hyperlink_rules);
*/
let (top, vp_lines) = pos.pane.get_lines(stable_range);
stable_top = top;
lines = vp_lines;
}
@ -695,7 +691,7 @@ impl super::TermWindow {
let attrs = &cluster.attrs;
let is_highlited_hyperlink = match (attrs.hyperlink(), &self.current_highlight) {
(Some(ref this), &Some(ref highlight)) => Arc::ptr_eq(this, highlight),
(Some(ref this), &Some(ref highlight)) => **this == *highlight,
_ => false,
};
let style = self.fonts.match_style(params.config, attrs);

View File

@ -14,7 +14,8 @@ impl super::TermWindow {
.map(|r| r.normalize())
{
let mut last_was_wrapped = false;
let (first_row, lines) = pane.get_lines(sel.rows());
let (first_row, lines) =
pane.get_lines_with_hyperlinks_applied(sel.rows(), &self.config.hyperlink_rules);
for (idx, line) in lines.iter().enumerate() {
let cols = sel.cols_for_row(first_row + idx as StableRowIndex);
let last_col_idx = cols.end.min(line.cells().len()).saturating_sub(1);