1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-27 12:23:46 +03:00

add implicit hyperlink creation to termwiz

This commit is contained in:
Wez Furlong 2018-08-05 09:36:29 -07:00
parent 18f34545b3
commit 12db6e4629
3 changed files with 71 additions and 2 deletions

View File

@ -73,6 +73,7 @@ pub mod hyperlink;
pub mod input;
pub mod istty;
pub mod keymap;
mod range;
mod readbuf;
pub mod render;
pub mod surface;

6
termwiz/src/range.rs Normal file
View File

@ -0,0 +1,6 @@
use std::ops::Range;
/// range.contains(), but that is unstable
pub fn in_range<T: Ord + Copy>(value: T, range: &Range<T>) -> bool {
value >= range.start && value < range.end
}

View File

@ -1,4 +1,7 @@
use cell::{Cell, CellAttributes};
use hyperlink::Rule;
use range::in_range;
use std::rc::Rc;
use surface::Change;
bitflags! {
@ -51,10 +54,18 @@ impl Line {
/// If we have any cells with an implicit hyperlink, remove the hyperlink
/// from the cell attributes but leave the remainder of the attributes alone.
fn invalidate_implicit_hyperlinks(&mut self) {
pub fn invalidate_implicit_hyperlinks(&mut self) {
if (self.bits & (LineBits::SCANNED_IMPLICIT_HYPERLINKS | LineBits::HAS_IMPLICIT_HYPERLINKS))
== LineBits::NONE
{
return;
}
self.bits &= !LineBits::SCANNED_IMPLICIT_HYPERLINKS;
if (self.bits & LineBits::HAS_IMPLICIT_HYPERLINKS) == LineBits::NONE {
return;
}
for mut cell in &mut self.cells {
let replace = match cell.attrs().hyperlink {
Some(ref link) if link.is_implicit() => Some(Cell::new_grapheme(
@ -69,7 +80,58 @@ impl Line {
}
self.bits &= !LineBits::HAS_IMPLICIT_HYPERLINKS;
self.bits |= LineBits::SCANNED_IMPLICIT_HYPERLINKS | LineBits::DIRTY;
self.bits |= LineBits::DIRTY;
}
/// Scan through the line and look for sequences that match the provided
/// rules. Matching sequences are considered to be implicit hyperlinks
/// and will have a hyperlink attribute associated with them.
/// This function will only make changes if the line has been invalidated
/// since the last time this function was called.
/// This function does not remember the values of the `rules` slice, so it
/// is the responsibility of the caller to call `invalidate_implicit_hyperlinks`
/// if it wishes to call this function with different `rules`.
pub fn scan_and_create_hyperlinks(&mut self, rules: &[Rule]) {
if (self.bits & LineBits::SCANNED_IMPLICIT_HYPERLINKS)
== LineBits::SCANNED_IMPLICIT_HYPERLINKS
{
// Has not changed since last time we scanned
return;
}
let line = self.as_str();
self.bits |= LineBits::SCANNED_IMPLICIT_HYPERLINKS;
self.bits &= !LineBits::HAS_IMPLICIT_HYPERLINKS;
for m in Rule::match_hyperlinks(&line, rules) {
// The capture range is measured in bytes but we need to translate
// that to the char index of the column.
for (cell_idx, (byte_idx, _char)) in line.char_indices().enumerate() {
if self.cells[cell_idx].attrs().hyperlink.is_some() {
// Don't replace existing links
continue;
}
if in_range(byte_idx, &m.range) {
let attrs = self.cells[cell_idx]
.attrs()
.clone()
.set_hyperlink(Some(Rc::clone(&m.link)))
.clone();
let cell = Cell::new_grapheme(self.cells[cell_idx].str(), attrs);
self.cells[cell_idx] = cell;
self.bits |= LineBits::HAS_IMPLICIT_HYPERLINKS;
}
}
}
}
/// Recompose line into the corresponding utf8 string.
pub fn as_str(&self) -> String {
let mut s = String::new();
for (_, cell) in self.visible_cells() {
s.push_str(cell.str());
}
s
}
/// If we're about to modify a cell obscured by a double-width