From ead3d4a188d68a24d59a356c9cea28e4e7b526c6 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Fri, 3 Jun 2022 08:38:24 -0700 Subject: [PATCH] avoid invalidating line seqno when applying hyperlinks Return the the appropriate seqno from the original line --- mux/src/pane.rs | 47 ++++++++++++++++++++++++++++++---------- termwiz/src/hyperlink.rs | 4 ++-- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/mux/src/pane.rs b/mux/src/pane.rs index 4dffc18a9..92ef3957d 100644 --- a/mux/src/pane.rs +++ b/mux/src/pane.rs @@ -13,7 +13,7 @@ use std::ops::Range; use std::sync::{Arc, Mutex}; use termwiz::hyperlink::Rule; 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::{ @@ -175,7 +175,8 @@ impl LogicalLine { } pub fn apply_hyperlink_rules(&mut self, rules: &[Rule]) { - self.logical.invalidate_implicit_hyperlinks(SEQ_ZERO); + let seq = self.logical.current_seqno(); + self.logical.invalidate_implicit_hyperlinks(seq); self.logical.scan_and_create_hyperlinks(rules); if !self.logical.has_hyperlink() { return; @@ -186,11 +187,12 @@ impl LogicalLine { let num_phys = self.physical_lines.len(); for (idx, phys) in self.physical_lines.iter_mut().enumerate() { let len = phys.cells().len(); - let remainder = line.split_off(len, SEQ_ZERO); + let seq = seq.max(phys.current_seqno()); + let remainder = line.split_off(len, seq); *phys = line; line = remainder; let wrapped = idx == num_phys - 1; - phys.set_last_cell_was_wrapped(wrapped, SEQ_ZERO); + phys.set_last_cell_was_wrapped(wrapped, seq); } } } @@ -293,8 +295,9 @@ pub trait Pane: Downcast { if prior.logical.last_cell_was_wrapped() && prior.logical.cells().len() <= MAX_LOGICAL_LINE_LEN { - prior.logical.set_last_cell_was_wrapped(false, SEQ_ZERO); - prior.logical.append_line(line.clone(), SEQ_ZERO); + 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(); @@ -448,6 +451,7 @@ impl_downcast!(Pane); mod test { use super::*; use k9::snapshot; + use termwiz::surface::SEQ_ZERO; struct FakePane { lines: Vec, @@ -535,10 +539,23 @@ mod test { } #[test] - fn logical_lines() { - let text = "Hello there this is a long line.\nlogical line two\nanother long line here\nlogical line four\nlogical line five\ncap it off with another long line"; + fn hyperlink_rule_apply_preserves_seqno() { + let text = "Hello https://example.com\nwoot"; + let lines = physical_lines_from_text(text, 5); + let pane = FakePane { lines }; + let (_first, lines) = pane.get_lines_with_hyperlinks_applied( + 0..2, + &[Rule { + regex: regex::Regex::new("example").unwrap(), + format: "$0".to_string(), + }], + ); + let seqs: Vec<_> = lines.iter().map(|line| line.current_seqno()).collect(); + k9::assert_equal!(seqs, vec![1, 1]); + } + + fn physical_lines_from_text(text: &str, width: usize) -> Vec { let mut physical_lines = vec![]; - let width = 20; for logical in text.split('\n') { let chunks = logical .chars() @@ -548,13 +565,21 @@ mod test { .collect::>(); let n_chunks = chunks.len(); for (idx, chunk) in chunks.into_iter().enumerate() { - let mut line = Line::from_text(&chunk, &Default::default(), SEQ_ZERO, None); + let mut line = Line::from_text(&chunk, &Default::default(), 1, None); if idx < n_chunks - 1 { - line.set_last_cell_was_wrapped(true, SEQ_ZERO); + line.set_last_cell_was_wrapped(true, 1); } physical_lines.push(line); } } + physical_lines + } + + #[test] + fn logical_lines() { + let text = "Hello there this is a long line.\nlogical line two\nanother long line here\nlogical line four\nlogical line five\ncap it off with another long line"; + let width = 20; + let physical_lines = physical_lines_from_text(text, width); fn text_from_lines(lines: &[Line]) -> Vec { lines.iter().map(|l| l.as_str()).collect::>() diff --git a/termwiz/src/hyperlink.rs b/termwiz/src/hyperlink.rs index 60477b846..6feb4c024 100644 --- a/termwiz/src/hyperlink.rs +++ b/termwiz/src/hyperlink.rs @@ -138,7 +138,7 @@ pub struct Rule { ) )] #[dynamic(into = "RegexWrap", try_from = "RegexWrap")] - regex: Regex, + pub regex: Regex, /// The format string that defines how to transform the matched /// text into a URL. For example, a format string of `$0` expands /// to the entire matched text, whereas `mailto:$0` expands to @@ -149,7 +149,7 @@ pub struct Rule { /// with the highest numbered capture first. This avoids issues /// with ambiguous replacement of `$11` vs `$1` in the case of /// more complex regexes. - format: String, + pub format: String, } struct RegexWrap(Regex);