Hyperlink clicking is working

This commit is contained in:
Mikayla Maki 2022-09-18 23:33:06 -07:00
parent ac390745a7
commit 1993a870e1

View file

@ -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,29 +901,34 @@ 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) {
let point = grid_point( if e.cmd {
position, if let Some(link) = cell_for_mouse(position, &self.last_content).hyperlink() {
self.last_content.size, open_uri(link.uri()).log_err();
self.last_content.display_offset, }
); } else {
let side = mouse_side(position, self.last_content.size); let point = grid_point(
position,
self.last_content.size,
self.last_content.display_offset,
);
let side = mouse_side(position, self.last_content.size);
let selection_type = match e.click_count { let selection_type = match e.click_count {
0 => return, //This is a release 0 => return, //This is a release
1 => Some(SelectionType::Simple), 1 => Some(SelectionType::Simple),
2 => Some(SelectionType::Semantic), 2 => Some(SelectionType::Semantic),
3 => Some(SelectionType::Lines), 3 => Some(SelectionType::Lines),
_ => 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
.push_back(InternalEvent::SetSelection(Some((sel, point)))); .push_back(InternalEvent::SetSelection(Some((sel, point))));
}
} }
} }
} }
@ -1065,55 +1074,40 @@ 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, unsafe {
master_fd: RawFd,
shell_pid: u32,
) -> io::Result<()>
where
I: IntoIterator<Item = S> + Copy,
S: AsRef<OsStr>,
{
let mut command = Command::new(program);
command command
.args(args) .pre_exec(|| {
.stdin(Stdio::null()) match libc::fork() {
.stdout(Stdio::null()) -1 => return Err(io::Error::last_os_error()),
.stderr(Stdio::null()); 0 => (),
if let Ok(cwd) = foreground_process_path(master_fd, shell_pid) { _ => libc::_exit(0),
command.current_dir(cwd); }
}
unsafe {
command
.pre_exec(|| {
match libc::fork() {
-1 => return Err(io::Error::last_os_error()),
0 => (),
_ => libc::_exit(0),
}
if libc::setsid() == -1 { if libc::setsid() == -1 {
return Err(io::Error::last_os_error()); return Err(io::Error::last_os_error());
} }
Ok(()) Ok(())
}) })
.spawn()? .spawn()?
.wait() .wait()
.map(|_| ()) .map(|_| ())
}
} }
} }
@ -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]);
}
} }