diff options
Diffstat (limited to 'alacritty/src/url.rs')
-rw-r--r-- | alacritty/src/url.rs | 288 |
1 files changed, 0 insertions, 288 deletions
diff --git a/alacritty/src/url.rs b/alacritty/src/url.rs deleted file mode 100644 index add4a1aa..00000000 --- a/alacritty/src/url.rs +++ /dev/null @@ -1,288 +0,0 @@ -use std::cmp::min; -use std::mem; - -use crossfont::Metrics; -use glutin::event::{ElementState, ModifiersState}; -use urlocator::{UrlLocation, UrlLocator}; - -use alacritty_terminal::grid::Dimensions; -use alacritty_terminal::index::{Boundary, Column, Line, Point}; -use alacritty_terminal::term::cell::Flags; -use alacritty_terminal::term::color::Rgb; -use alacritty_terminal::term::SizeInfo; - -use crate::config::Config; -use crate::display::content::RenderableCell; -use crate::event::Mouse; -use crate::renderer::rects::{RenderLine, RenderRect}; - -#[derive(Clone, Debug, PartialEq)] -pub struct Url { - lines: Vec<RenderLine>, - end_offset: u16, - size: SizeInfo, -} - -impl Url { - /// Rectangles required for underlining the URL. - pub fn rects(&self, metrics: &Metrics, size: &SizeInfo) -> Vec<RenderRect> { - let end = self.end(); - self.lines - .iter() - .filter(|line| line.start <= end) - .map(|line| { - let mut rect_line = *line; - rect_line.end = min(line.end, end); - rect_line.rects(Flags::UNDERLINE, metrics, size) - }) - .flatten() - .collect() - } - - /// Viewport start point of the URL. - pub fn start(&self) -> Point<usize> { - self.lines[0].start - } - - /// Viewport end point of the URL. - pub fn end(&self) -> Point<usize> { - let end = self.lines[self.lines.len() - 1].end; - - // Convert to Point<Line> to make use of the grid clamping logic. - let mut end = Point::new(Line(end.line as i32), end.column); - end = end.sub(&self.size, Boundary::Cursor, self.end_offset as usize); - - Point::new(end.line.0 as usize, end.column) - } -} - -pub struct Urls { - locator: UrlLocator, - urls: Vec<Url>, - scheme_buffer: Vec<(Point<usize>, Rgb)>, - next_point: Point<usize>, - state: UrlLocation, -} - -impl Default for Urls { - fn default() -> Self { - Self { - locator: UrlLocator::new(), - scheme_buffer: Vec::new(), - urls: Vec::new(), - state: UrlLocation::Reset, - next_point: Point::new(0, Column(0)), - } - } -} - -impl Urls { - pub fn new() -> Self { - Self::default() - } - - // Update tracked URLs. - pub fn update(&mut self, size: &SizeInfo, cell: &RenderableCell) { - let point = cell.point; - let mut end = point; - - // Include the following wide char spacer. - if cell.flags.contains(Flags::WIDE_CHAR) { - end.column += 1; - } - - // Reset URL when empty cells have been skipped. - if point != Point::new(0, Column(0)) && point != self.next_point { - self.reset(); - } - - self.next_point = if end.column.0 + 1 == size.columns() { - Point::new(end.line + 1, Column(0)) - } else { - Point::new(end.line, end.column + 1) - }; - - // Extend current state if a leading wide char spacer is encountered. - if cell.flags.intersects(Flags::LEADING_WIDE_CHAR_SPACER) { - if let UrlLocation::Url(_, mut end_offset) = self.state { - if end_offset != 0 { - end_offset += 1; - } - - self.extend_url(point, end, cell.fg, end_offset); - } - - return; - } - - // Advance parser. - let last_state = mem::replace(&mut self.state, self.locator.advance(cell.character)); - match (self.state, last_state) { - (UrlLocation::Url(_length, end_offset), UrlLocation::Scheme) => { - // Create empty URL. - self.urls.push(Url { lines: Vec::new(), end_offset, size: *size }); - - // Push schemes into URL. - for (scheme_point, scheme_fg) in self.scheme_buffer.split_off(0) { - self.extend_url(scheme_point, scheme_point, scheme_fg, end_offset); - } - - // Push the new cell into URL. - self.extend_url(point, end, cell.fg, end_offset); - }, - (UrlLocation::Url(_length, end_offset), UrlLocation::Url(..)) => { - self.extend_url(point, end, cell.fg, end_offset); - }, - (UrlLocation::Scheme, _) => self.scheme_buffer.push((cell.point, cell.fg)), - (UrlLocation::Reset, _) => self.reset(), - _ => (), - } - - // Reset at un-wrapped linebreak. - if cell.point.column.0 + 1 == size.columns() && !cell.flags.contains(Flags::WRAPLINE) { - self.reset(); - } - } - - /// Extend the last URL. - fn extend_url(&mut self, start: Point<usize>, end: Point<usize>, color: Rgb, end_offset: u16) { - let url = self.urls.last_mut().unwrap(); - - // If color changed, we need to insert a new line. - if url.lines.last().map(|last| last.color) == Some(color) { - url.lines.last_mut().unwrap().end = end; - } else { - url.lines.push(RenderLine { start, end, color }); - } - - // Update excluded cells at the end of the URL. - url.end_offset = end_offset; - } - - /// Find URL below the mouse cursor. - pub fn highlighted( - &self, - config: &Config, - mouse: &Mouse, - mods: ModifiersState, - mouse_mode: bool, - selection: bool, - ) -> Option<Url> { - // Require additional shift in mouse mode. - let mut required_mods = config.ui_config.mouse.url.mods(); - if mouse_mode { - required_mods |= ModifiersState::SHIFT; - } - - // Make sure all prerequisites for highlighting are met. - if selection - || !mouse.inside_text_area - || config.ui_config.mouse.url.launcher.is_none() - || required_mods != mods - || mouse.left_button_state == ElementState::Pressed - { - return None; - } - - self.find_at(mouse.point) - } - - /// Find URL at location. - pub fn find_at(&self, point: Point<usize>) -> Option<Url> { - for url in &self.urls { - if (url.start()..=url.end()).contains(&point) { - return Some(url.clone()); - } - } - None - } - - fn reset(&mut self) { - self.locator = UrlLocator::new(); - self.state = UrlLocation::Reset; - self.scheme_buffer.clear(); - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use alacritty_terminal::index::Column; - - fn text_to_cells(text: &str) -> Vec<RenderableCell> { - text.chars() - .enumerate() - .map(|(i, character)| RenderableCell { - character, - zerowidth: None, - point: Point::new(0, Column(i)), - fg: Default::default(), - bg: Default::default(), - bg_alpha: 0., - flags: Flags::empty(), - }) - .collect() - } - - #[test] - fn multi_color_url() { - let mut input = text_to_cells("test https://example.org ing"); - let size = SizeInfo::new(input.len() as f32, 1., 1.0, 1.0, 0.0, 0.0, false); - - input[10].fg = Rgb { r: 0xff, g: 0x00, b: 0xff }; - - let mut urls = Urls::new(); - - for cell in input { - urls.update(&size, &cell); - } - - let url = urls.urls.first().unwrap(); - assert_eq!(url.start().column, Column(5)); - assert_eq!(url.end().column, Column(23)); - } - - #[test] - fn multiple_urls() { - let input = text_to_cells("test git:a git:b git:c ing"); - let size = SizeInfo::new(input.len() as f32, 1., 1.0, 1.0, 0.0, 0.0, false); - - let mut urls = Urls::new(); - - for cell in input { - urls.update(&size, &cell); - } - - assert_eq!(urls.urls.len(), 3); - - assert_eq!(urls.urls[0].start().column, Column(5)); - assert_eq!(urls.urls[0].end().column, Column(9)); - - assert_eq!(urls.urls[1].start().column, Column(11)); - assert_eq!(urls.urls[1].end().column, Column(15)); - - assert_eq!(urls.urls[2].start().column, Column(17)); - assert_eq!(urls.urls[2].end().column, Column(21)); - } - - #[test] - fn wide_urls() { - let input = text_to_cells("test https://こんにちは (http:여보세요) ing"); - let size = SizeInfo::new(input.len() as f32 + 9., 1., 1.0, 1.0, 0.0, 0.0, false); - - let mut urls = Urls::new(); - - for cell in input { - urls.update(&size, &cell); - } - - assert_eq!(urls.urls.len(), 2); - - assert_eq!(urls.urls[0].start().column, Column(5)); - assert_eq!(urls.urls[0].end().column, Column(17)); - - assert_eq!(urls.urls[1].start().column, Column(20)); - assert_eq!(urls.urls[1].end().column, Column(28)); - } -} |