WIP hyperlink detection

This commit is contained in:
Mikayla Maki 2022-09-19 13:41:35 -07:00
parent 9f81f39f51
commit b8f362fd84
2 changed files with 80 additions and 26 deletions

View file

@ -83,6 +83,11 @@ const DEBUG_TERMINAL_HEIGHT: f32 = 30.;
const DEBUG_CELL_WIDTH: f32 = 5.;
const DEBUG_LINE_HEIGHT: f32 = 5.;
/// Copied from alacritty's ui_config.rs
const URL_REGEX: &str =
"(ipfs:|ipns:|magnet:|mailto:|gemini:|gopher:|https:|http:|news:|file:|git:|ssh:|ftp:)\
[^\u{0000}-\u{001F}\u{007F}-\u{009F}<>\"\\s{-}\\^⟨⟩`]+";
///Upward flowing events, for changing the title and such
#[derive(Clone, Copy, Debug)]
pub enum Event {
@ -105,6 +110,7 @@ enum InternalEvent {
ScrollToPoint(Point),
SetSelection(Option<(Selection, Point)>),
UpdateSelection(Vector2F),
HyperlinkHover(Vector2F),
Copy,
}
@ -643,6 +649,16 @@ impl Terminal {
}
}
InternalEvent::ScrollToPoint(point) => term.scroll_to_point(*point),
InternalEvent::HyperlinkHover(position) => {
let point = grid_point(
*position,
self.last_content.size,
term.grid().display_offset(),
);
let side = mouse_side(*position, self.last_content.size);
println!("Hyperlink hover")
}
}
}
@ -817,7 +833,6 @@ impl Terminal {
pub fn mouse_move(&mut self, e: &MouseMovedEvent, origin: Vector2F) {
self.last_hovered_hyperlink = None;
let position = e.position.sub(origin);
if self.mouse_mode(e.shift) {
let point = grid_point(
position,
@ -832,9 +847,39 @@ impl Terminal {
}
}
} else if e.cmd {
let hyperlink = cell_for_mouse(e.position, &self.last_content)
.cell
.hyperlink();
let content_index = content_index_for_mouse(position, &self.last_content);
let link = self.last_content.cells[content_index].hyperlink();
if link.is_some() {
let mut min_index = content_index;
loop {
if self.last_content.cells[min_index - 1].hyperlink() == link {
min_index = min_index - 1;
} else {
break;
}
}
let mut max_index = content_index;
loop {
if self.last_content.cells[max_index + 1].hyperlink() == link {
max_index = max_index + 1;
} else {
break;
}
}
self.last_hovered_hyperlink = link.map(|link| {
(
link,
self.last_content.cells[min_index].point
..self.last_content.cells[max_index].point,
)
});
} else {
self.events
.push_back(InternalEvent::HyperlinkHover(position));
}
}
}
@ -903,7 +948,12 @@ impl Terminal {
let position = e.position.sub(origin);
if !self.mouse_mode(e.shift) {
if e.cmd {
if let Some(link) = cell_for_mouse(position, &self.last_content).hyperlink() {
if let Some(link) = self.last_content.cells
[content_index_for_mouse(position, &self.last_content)]
.hyperlink()
{
dbg!(&link);
dbg!(&self.last_hovered_hyperlink);
open_uri(link.uri()).log_err();
}
} else {
@ -1073,7 +1123,7 @@ fn all_search_matches<'a, T>(
RegexIter::new(start, end, AlacDirection::Right, term, regex)
}
fn cell_for_mouse<'a>(pos: Vector2F, content: &'a TerminalContent) -> &'a IndexedCell {
fn content_index_for_mouse<'a>(pos: Vector2F, content: &'a TerminalContent) -> usize {
let col = min(
(pos.x() / content.size.cell_width()) as usize,
content.size.columns() - 1,
@ -1083,7 +1133,7 @@ fn cell_for_mouse<'a>(pos: Vector2F, content: &'a TerminalContent) -> &'a Indexe
content.size.screen_lines() - 1,
) as usize;
&content.cells[(line * content.size.columns() + col)]
line * content.size.columns() + col
}
fn open_uri(uri: &str) -> Result<(), std::io::Error> {
@ -1116,7 +1166,7 @@ mod tests {
use gpui::geometry::vector::vec2f;
use rand::{thread_rng, Rng};
use crate::cell_for_mouse;
use crate::content_index_for_mouse;
use self::terminal_test_context::TerminalTestContext;
@ -1153,7 +1203,10 @@ mod tests {
rng.gen_range(min_col..max_col),
);
assert_eq!(cell_for_mouse(mouse_pos, &content).c, cells[j][i]);
assert_eq!(
content.cells[content_index_for_mouse(mouse_pos, &content)].c,
cells[j][i]
);
}
}
}
@ -1172,7 +1225,13 @@ mod tests {
let (content, cells) = TerminalTestContext::create_terminal_content(size, &mut rng);
assert_eq!(cell_for_mouse(vec2f(-10., -10.), &content).c, cells[0][0]);
assert_eq!(cell_for_mouse(vec2f(1000., 1000.), &content).c, cells[9][9]);
assert_eq!(
content.cells[content_index_for_mouse(vec2f(-10., -10.), &content)].c,
cells[0][0]
);
assert_eq!(
content.cells[content_index_for_mouse(vec2f(1000., 1000.), &content)].c,
cells[9][9]
);
}
}

View file

@ -427,6 +427,16 @@ impl TerminalElement {
position: e.position,
});
}
})
.on_move(move |event, cx| {
if cx.is_parent_view_focused() {
if let Some(conn_handle) = connection.upgrade(cx.app) {
conn_handle.update(cx.app, |terminal, cx| {
terminal.mouse_move(&event, origin);
cx.notify();
})
}
}
});
// Mouse mode handlers:
@ -474,21 +484,6 @@ impl TerminalElement {
),
)
}
//Mouse move manages both dragging and motion events
if mode.intersects(TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION) {
region = region
//TODO: This does not fire on right-mouse-down-move events.
.on_move(move |event, cx| {
if cx.is_parent_view_focused() {
if let Some(conn_handle) = connection.upgrade(cx.app) {
conn_handle.update(cx.app, |terminal, cx| {
terminal.mouse_move(&event, origin);
cx.notify();
})
}
}
})
}
cx.scene.push_mouse_region(region);
}