Hyperlink clicking is working
This commit is contained in:
parent
ac390745a7
commit
1993a870e1
1 changed files with 86 additions and 75 deletions
|
@ -14,7 +14,7 @@ use alacritty_terminal::{
|
||||||
selection::{Selection, SelectionRange, SelectionType},
|
selection::{Selection, SelectionRange, SelectionType},
|
||||||
sync::FairMutex,
|
sync::FairMutex,
|
||||||
term::{
|
term::{
|
||||||
cell::Cell,
|
cell::{Cell, Hyperlink},
|
||||||
color::Rgb,
|
color::Rgb,
|
||||||
search::{Match, RegexIter, RegexSearch},
|
search::{Match, RegexIter, RegexSearch},
|
||||||
RenderableCursor, TermMode,
|
RenderableCursor, TermMode,
|
||||||
|
@ -36,13 +36,17 @@ use modal::deploy_modal;
|
||||||
|
|
||||||
use procinfo::LocalProcessInfo;
|
use procinfo::LocalProcessInfo;
|
||||||
use settings::{AlternateScroll, Settings, Shell, TerminalBlink};
|
use settings::{AlternateScroll, Settings, Shell, TerminalBlink};
|
||||||
|
use util::ResultExt;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
cmp::min,
|
||||||
collections::{HashMap, VecDeque},
|
collections::{HashMap, VecDeque},
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
|
io,
|
||||||
ops::{Deref, RangeInclusive, Sub},
|
ops::{Deref, RangeInclusive, Sub},
|
||||||
os::unix::prelude::AsRawFd,
|
os::unix::{prelude::AsRawFd, process::CommandExt},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
process::Command,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
@ -374,6 +378,7 @@ impl TerminalBuilder {
|
||||||
foreground_process_info: None,
|
foreground_process_info: None,
|
||||||
breadcrumb_text: String::new(),
|
breadcrumb_text: String::new(),
|
||||||
scroll_px: 0.,
|
scroll_px: 0.,
|
||||||
|
last_hovered_hyperlink: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(TerminalBuilder {
|
Ok(TerminalBuilder {
|
||||||
|
@ -488,6 +493,7 @@ pub struct Terminal {
|
||||||
pub matches: Vec<RangeInclusive<Point>>,
|
pub matches: Vec<RangeInclusive<Point>>,
|
||||||
last_content: TerminalContent,
|
last_content: TerminalContent,
|
||||||
last_synced: Instant,
|
last_synced: Instant,
|
||||||
|
last_hovered_hyperlink: Option<Hyperlink>,
|
||||||
sync_task: Option<Task<()>>,
|
sync_task: Option<Task<()>>,
|
||||||
selection_head: Option<Point>,
|
selection_head: Option<Point>,
|
||||||
breadcrumb_text: String,
|
breadcrumb_text: String,
|
||||||
|
@ -809,9 +815,10 @@ impl Terminal {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mouse_move(&mut self, e: &MouseMovedEvent, origin: Vector2F) {
|
pub fn mouse_move(&mut self, e: &MouseMovedEvent, origin: Vector2F) {
|
||||||
if self.mouse_mode(e.shift) {
|
self.last_hovered_hyperlink = None;
|
||||||
let position = e.position.sub(origin);
|
let position = e.position.sub(origin);
|
||||||
|
|
||||||
|
if self.mouse_mode(e.shift) {
|
||||||
let point = grid_point(
|
let point = grid_point(
|
||||||
position,
|
position,
|
||||||
self.last_content.size,
|
self.last_content.size,
|
||||||
|
@ -824,13 +831,10 @@ impl Terminal {
|
||||||
self.pty_tx.notify(bytes);
|
self.pty_tx.notify(bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if e.cmd {
|
||||||
if let Some(link) = cell_for_mouse(e.position, &self.last_content)
|
self.last_hovered_hyperlink = cell_for_mouse(e.position, &self.last_content)
|
||||||
.cell
|
.cell
|
||||||
.hyperlink()
|
.hyperlink();
|
||||||
{
|
|
||||||
link.uri()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -897,8 +901,12 @@ impl Terminal {
|
||||||
|
|
||||||
pub fn left_click(&mut self, e: &ClickRegionEvent, origin: Vector2F) {
|
pub fn left_click(&mut self, e: &ClickRegionEvent, origin: Vector2F) {
|
||||||
let position = e.position.sub(origin);
|
let position = e.position.sub(origin);
|
||||||
|
|
||||||
if !self.mouse_mode(e.shift) {
|
if !self.mouse_mode(e.shift) {
|
||||||
|
if e.cmd {
|
||||||
|
if let Some(link) = cell_for_mouse(position, &self.last_content).hyperlink() {
|
||||||
|
open_uri(link.uri()).log_err();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
let point = grid_point(
|
let point = grid_point(
|
||||||
position,
|
position,
|
||||||
self.last_content.size,
|
self.last_content.size,
|
||||||
|
@ -914,8 +922,8 @@ impl Terminal {
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let selection =
|
let selection = selection_type
|
||||||
selection_type.map(|selection_type| Selection::new(selection_type, point, side));
|
.map(|selection_type| Selection::new(selection_type, point, side));
|
||||||
|
|
||||||
if let Some(sel) = selection {
|
if let Some(sel) = selection {
|
||||||
self.events
|
self.events
|
||||||
|
@ -923,6 +931,7 @@ impl Terminal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mouse_up(&mut self, e: &UpRegionEvent, origin: Vector2F) {
|
pub fn mouse_up(&mut self, e: &UpRegionEvent, origin: Vector2F) {
|
||||||
let position = e.position.sub(origin);
|
let position = e.position.sub(origin);
|
||||||
|
@ -1065,36 +1074,22 @@ fn all_search_matches<'a, T>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cell_for_mouse<'a>(pos: Vector2F, content: &'a TerminalContent) -> &'a IndexedCell {
|
fn cell_for_mouse<'a>(pos: Vector2F, content: &'a TerminalContent) -> &'a IndexedCell {
|
||||||
let point = Point {
|
let col = min(
|
||||||
line: Line((pos.x() / content.size.cell_width()) as i32),
|
(pos.x() / content.size.cell_width()) as usize,
|
||||||
column: Column((pos.y() / content.size.line_height()) as usize),
|
content.size.columns() - 1,
|
||||||
};
|
) as usize;
|
||||||
|
let line = min(
|
||||||
|
(pos.y() / content.size.line_height()) as usize,
|
||||||
|
content.size.screen_lines() - 1,
|
||||||
|
) as usize;
|
||||||
|
|
||||||
debug_assert!(point.line.0.is_positive() || point.line.0 == 0);
|
&content.cells[(line * content.size.columns() + col)]
|
||||||
&content.cells[(point.line.0 as usize * content.size.columns() + point.column.0)]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_uri(uri: String) {
|
fn open_uri(uri: &str) -> Result<(), std::io::Error> {
|
||||||
// MacOS command is 'open'
|
let mut command = Command::new("open");
|
||||||
pub fn spawn_daemon<I, S>(
|
command.arg(uri);
|
||||||
program: &str,
|
|
||||||
args: I,
|
|
||||||
master_fd: RawFd,
|
|
||||||
shell_pid: u32,
|
|
||||||
) -> io::Result<()>
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S> + Copy,
|
|
||||||
S: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
let mut command = Command::new(program);
|
|
||||||
command
|
|
||||||
.args(args)
|
|
||||||
.stdin(Stdio::null())
|
|
||||||
.stdout(Stdio::null())
|
|
||||||
.stderr(Stdio::null());
|
|
||||||
if let Ok(cwd) = foreground_process_path(master_fd, shell_pid) {
|
|
||||||
command.current_dir(cwd);
|
|
||||||
}
|
|
||||||
unsafe {
|
unsafe {
|
||||||
command
|
command
|
||||||
.pre_exec(|| {
|
.pre_exec(|| {
|
||||||
|
@ -1115,7 +1110,6 @@ fn open_uri(uri: String) {
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -1145,9 +1139,9 @@ mod tests {
|
||||||
|
|
||||||
let (content, cells) = TerminalTestContext::create_terminal_content(size, &mut rng);
|
let (content, cells) = TerminalTestContext::create_terminal_content(size, &mut rng);
|
||||||
|
|
||||||
for i in 0..viewport_cells {
|
for i in 0..(viewport_cells - 1) {
|
||||||
let i = i as usize;
|
let i = i as usize;
|
||||||
for j in 0..viewport_cells {
|
for j in 0..(viewport_cells - 1) {
|
||||||
let j = j as usize;
|
let j = j as usize;
|
||||||
let min_row = i as f32 * cell_size;
|
let min_row = i as f32 * cell_size;
|
||||||
let max_row = (i + 1) as f32 * cell_size;
|
let max_row = (i + 1) as f32 * cell_size;
|
||||||
|
@ -1159,9 +1153,26 @@ mod tests {
|
||||||
rng.gen_range(min_col..max_col),
|
rng.gen_range(min_col..max_col),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(cell_for_mouse(mouse_pos, &content).c, cells[i][j]);
|
assert_eq!(cell_for_mouse(mouse_pos, &content).c, cells[j][i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mouse_to_cell_clamp() {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
|
let size = crate::TerminalSize {
|
||||||
|
cell_width: 10.,
|
||||||
|
line_height: 10.,
|
||||||
|
height: 100.,
|
||||||
|
width: 100.,
|
||||||
|
};
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue