aboutsummaryrefslogtreecommitdiff
path: root/alacritty
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2021-03-30 23:25:38 +0000
committerGitHub <noreply@github.com>2021-03-30 23:25:38 +0000
commit3bd5ac221ab3b122962063edd1f4c10f9f2d117f (patch)
treeb0a367b91611e911344aec9ff35354e5a473b6aa /alacritty
parent974392cdc6fdf1ba0d213145ae578a9316e9d404 (diff)
downloadr-alacritty-3bd5ac221ab3b122962063edd1f4c10f9f2d117f.tar.gz
r-alacritty-3bd5ac221ab3b122962063edd1f4c10f9f2d117f.tar.bz2
r-alacritty-3bd5ac221ab3b122962063edd1f4c10f9f2d117f.zip
Unify the grid line indexing types
Previously Alacritty was using two different ways to reference lines in the terminal. Either a `usize`, or a `Line(usize)`. These indexing systems both served different purposes, but made it difficult to reason about logic involving these systems because of its inconsistency. To resolve this issue, a single new `Line(i32)` type has been introduced. All existing references to lines and points now rely on this definition of a line. The indexing starts at the top of the terminal region with the line 0, which matches the line 1 used by escape sequences. Each line in the history becomes increasingly negative and the bottommost line is equal to the number of visible lines minus one. Having a system which goes into the negatives allows following the escape sequence's indexing system closely, while at the same time making it trivial to implement `Ord` for points. The Alacritty UI crate is the only place which has a different indexing system, since rendering and input puts the zero line at the top of the viewport, rather than the top of the terminal region. All instances which refer to a number of lines/columns instead of just a single Line/Column have also been changed to use a `usize` instead. This way a Line/Column will always refer to a specific place in the grid and no confusion is created by having a count of lines as a possible index into the grid storage.
Diffstat (limited to 'alacritty')
-rw-r--r--alacritty/src/config/window.rs6
-rw-r--r--alacritty/src/display/content.rs63
-rw-r--r--alacritty/src/display/cursor.rs2
-rw-r--r--alacritty/src/display/hint.rs4
-rw-r--r--alacritty/src/display/mod.rs58
-rw-r--r--alacritty/src/event.rs161
-rw-r--r--alacritty/src/input.rs163
-rw-r--r--alacritty/src/main.rs3
-rw-r--r--alacritty/src/message_bar.rs6
-rw-r--r--alacritty/src/renderer/mod.rs5
-rw-r--r--alacritty/src/renderer/rects.rs17
-rw-r--r--alacritty/src/url.rs65
12 files changed, 229 insertions, 324 deletions
diff --git a/alacritty/src/config/window.rs b/alacritty/src/config/window.rs
index 2d501b91..d74390d8 100644
--- a/alacritty/src/config/window.rs
+++ b/alacritty/src/config/window.rs
@@ -8,7 +8,7 @@ use serde::{Deserialize, Deserializer};
use alacritty_config_derive::ConfigDeserialize;
use alacritty_terminal::config::LOG_TARGET_CONFIG;
-use alacritty_terminal::index::{Column, Line};
+use alacritty_terminal::index::Column;
use crate::config::ui_config::Delta;
@@ -74,7 +74,7 @@ impl WindowConfig {
#[inline]
pub fn dimensions(&self) -> Option<Dimensions> {
if self.dimensions.columns.0 != 0
- && self.dimensions.lines.0 != 0
+ && self.dimensions.lines != 0
&& self.startup_mode != StartupMode::Maximized
{
Some(self.dimensions)
@@ -145,7 +145,7 @@ pub struct Dimensions {
pub columns: Column,
/// Window Height in character lines.
- pub lines: Line,
+ pub lines: usize,
}
/// Window class hint.
diff --git a/alacritty/src/display/content.rs b/alacritty/src/display/content.rs
index a25ddce8..a793f443 100644
--- a/alacritty/src/display/content.rs
+++ b/alacritty/src/display/content.rs
@@ -1,5 +1,5 @@
use std::borrow::Cow;
-use std::cmp::max;
+use std::cmp::{max, min};
use std::mem;
use std::ops::{Deref, DerefMut, RangeInclusive};
@@ -126,12 +126,17 @@ impl<'a> RenderableContent<'a> {
let text_color = text_color.color(cell.fg, cell.bg);
let cursor_color = cursor_color.color(cell.fg, cell.bg);
+ // Convert cursor point to viewport position.
+ let cursor_point = self.terminal_cursor.point;
+ let line = (cursor_point.line + self.terminal_content.display_offset as i32).0 as usize;
+ let point = Point::new(line, cursor_point.column);
+
Some(RenderableCursor {
- point: self.terminal_cursor.point,
shape: self.terminal_cursor.shape,
cursor_color,
text_color,
is_wide,
+ point,
})
}
}
@@ -147,9 +152,10 @@ impl<'a> Iterator for RenderableContent<'a> {
fn next(&mut self) -> Option<Self::Item> {
loop {
let cell = self.terminal_content.display_iter.next()?;
+ let cell_point = cell.point;
let mut cell = RenderableCell::new(self, cell);
- if self.terminal_cursor.point == cell.point {
+ if self.terminal_cursor.point == cell_point {
// Store the cursor which should be rendered.
self.cursor = self.renderable_cursor(&cell).map(|cursor| {
if cursor.shape == CursorShape::Block {
@@ -178,16 +184,15 @@ impl<'a> Iterator for RenderableContent<'a> {
pub struct RenderableCell {
pub character: char,
pub zerowidth: Option<Vec<char>>,
- pub point: Point,
+ pub point: Point<usize>,
pub fg: Rgb,
pub bg: Rgb,
pub bg_alpha: f32,
pub flags: Flags,
- pub is_match: bool,
}
impl RenderableCell {
- fn new<'a>(content: &mut RenderableContent<'a>, cell: Indexed<&Cell, Line>) -> Self {
+ fn new<'a>(content: &mut RenderableContent<'a>, cell: Indexed<&Cell>) -> Self {
// Lookup RGB values.
let mut fg_rgb = Self::compute_fg_rgb(content, cell.fg, cell.flags);
let mut bg_rgb = Self::compute_bg_rgb(content, cell.bg);
@@ -203,7 +208,6 @@ impl RenderableCell {
.terminal_content
.selection
.map_or(false, |selection| selection.contains_cell(&cell, content.terminal_cursor));
- let mut is_match = false;
let mut character = cell.c;
@@ -233,19 +237,21 @@ impl RenderableCell {
let config_fg = colors.search.matches.foreground;
let config_bg = colors.search.matches.background;
Self::compute_cell_rgb(&mut fg_rgb, &mut bg_rgb, &mut bg_alpha, config_fg, config_bg);
-
- is_match = true;
}
+ // Convert cell point to viewport position.
+ let cell_point = cell.point;
+ let line = (cell_point.line + content.terminal_content.display_offset as i32).0 as usize;
+ let point = Point::new(line, cell_point.column);
+
RenderableCell {
- character,
zerowidth: cell.zerowidth().map(|zerowidth| zerowidth.to_vec()),
- point: cell.point,
+ flags: cell.flags,
fg: fg_rgb,
bg: bg_rgb,
+ character,
bg_alpha,
- flags: cell.flags,
- is_match,
+ point,
}
}
@@ -349,7 +355,7 @@ pub struct RenderableCursor {
cursor_color: Rgb,
text_color: Rgb,
is_wide: bool,
- point: Point,
+ point: Point<usize>,
}
impl RenderableCursor {
@@ -365,7 +371,7 @@ impl RenderableCursor {
self.is_wide
}
- pub fn point(&self) -> Point {
+ pub fn point(&self) -> Point<usize> {
self.point
}
}
@@ -423,36 +429,23 @@ pub struct RegexMatches(Vec<RangeInclusive<Point>>);
impl RegexMatches {
/// Find all visible matches.
pub fn new<T>(term: &Term<T>, dfas: &RegexSearch) -> Self {
- let viewport_end = term.grid().display_offset();
- let viewport_start = viewport_end + term.screen_lines().0 - 1;
+ let viewport_start = Line(-(term.grid().display_offset() as i32));
+ let viewport_end = viewport_start + term.bottommost_line();
// Compute start of the first and end of the last line.
let start_point = Point::new(viewport_start, Column(0));
let mut start = term.line_search_left(start_point);
- let end_point = Point::new(viewport_end, term.cols() - 1);
+ let end_point = Point::new(viewport_end, term.last_column());
let mut end = term.line_search_right(end_point);
// Set upper bound on search before/after the viewport to prevent excessive blocking.
- if start.line > viewport_start + MAX_SEARCH_LINES {
- if start.line == 0 {
- // Do not highlight anything if this line is the last.
- return Self::default();
- } else {
- // Start at next line if this one is too long.
- start.line -= 1;
- }
- }
- end.line = max(end.line, viewport_end.saturating_sub(MAX_SEARCH_LINES));
+ start.line = max(start.line, viewport_start - MAX_SEARCH_LINES);
+ end.line = min(end.line, viewport_end + MAX_SEARCH_LINES);
// Create an iterater for the current regex search for all visible matches.
let iter = RegexIter::new(start, end, Direction::Right, term, dfas)
- .skip_while(move |rm| rm.end().line > viewport_start)
- .take_while(move |rm| rm.start().line >= viewport_end)
- .map(|rm| {
- let viewport_start = term.grid().clamp_buffer_to_visible(*rm.start());
- let viewport_end = term.grid().clamp_buffer_to_visible(*rm.end());
- viewport_start..=viewport_end
- });
+ .skip_while(move |rm| rm.end().line < viewport_start)
+ .take_while(move |rm| rm.start().line <= viewport_end);
Self(iter.collect())
}
diff --git a/alacritty/src/display/cursor.rs b/alacritty/src/display/cursor.rs
index 7cd631e3..f3a782cc 100644
--- a/alacritty/src/display/cursor.rs
+++ b/alacritty/src/display/cursor.rs
@@ -17,7 +17,7 @@ impl IntoRects for RenderableCursor {
fn rects(self, size_info: &SizeInfo, thickness: f32) -> CursorRects {
let point = self.point();
let x = point.column.0 as f32 * size_info.cell_width() + size_info.padding_x();
- let y = point.line.0 as f32 * size_info.cell_height() + size_info.padding_y();
+ let y = point.line as f32 * size_info.cell_height() + size_info.padding_y();
let mut width = size_info.cell_width();
let height = size_info.cell_height();
diff --git a/alacritty/src/display/hint.rs b/alacritty/src/display/hint.rs
index 6499a959..fe107139 100644
--- a/alacritty/src/display/hint.rs
+++ b/alacritty/src/display/hint.rs
@@ -118,9 +118,7 @@ impl HintState {
if label.len() == 1 {
// Get text for the hint's regex match.
let hint_match = &self.matches[index];
- let start = term.visible_to_buffer(*hint_match.start());
- let end = term.visible_to_buffer(*hint_match.end());
- let text = term.bounds_to_string(start, end);
+ let text = term.bounds_to_string(*hint_match.start(), *hint_match.end());
// Append text as last argument and launch command.
let program = hint.command.program();
diff --git a/alacritty/src/display/mod.rs b/alacritty/src/display/mod.rs
index cbf2930a..0f20e45f 100644
--- a/alacritty/src/display/mod.rs
+++ b/alacritty/src/display/mod.rs
@@ -27,7 +27,7 @@ use alacritty_terminal::event::{EventListener, OnResize};
use alacritty_terminal::grid::Dimensions as _;
use alacritty_terminal::index::{Column, Direction, Line, Point};
use alacritty_terminal::selection::Selection;
-use alacritty_terminal::term::{SizeInfo, Term, TermMode, MIN_COLS, MIN_SCREEN_LINES};
+use alacritty_terminal::term::{SizeInfo, Term, TermMode, MIN_COLUMNS, MIN_SCREEN_LINES};
use crate::config::font::Font;
use crate::config::window::Dimensions;
@@ -477,12 +477,6 @@ impl Display {
mods: ModifiersState,
search_state: &SearchState,
) {
- // Convert search match from viewport to absolute indexing.
- let search_active = search_state.regex().is_some();
- let viewport_match = search_state
- .focused_match()
- .and_then(|focused_match| terminal.grid().clamp_buffer_range_to_visible(focused_match));
-
// Collect renderable content before the terminal is dropped.
let mut content = RenderableContent::new(config, self, &terminal, search_state);
let mut grid_cells = Vec::new();
@@ -522,13 +516,15 @@ impl Display {
let glyph_cache = &mut self.glyph_cache;
self.renderer.with_api(&config.ui_config, &size_info, |mut api| {
// Iterate over all non-empty cells in the grid.
+ let focused_match = search_state.focused_match();
for mut cell in grid_cells {
- // Invert the active match during search.
- if cell.is_match
- && viewport_match
- .as_ref()
- .map_or(false, |viewport_match| viewport_match.contains(&cell.point))
- {
+ let focused = focused_match.as_ref().map_or(false, |focused_match| {
+ let line = Line(cell.point.line as i32) - display_offset;
+ focused_match.contains(&Point::new(line, cell.point.column))
+ });
+
+ // Invert the focused match during search.
+ if focused {
let colors = config.ui_config.colors.search.focused_match;
let match_fg = colors.foreground.color(cell.fg, cell.bg);
cell.bg = colors.background.color(cell.fg, cell.bg);
@@ -537,7 +533,7 @@ impl Display {
}
// Update URL underlines.
- urls.update(size_info.cols(), &cell);
+ urls.update(&size_info, &cell);
// Update underline/strikeout.
lines.update(&cell);
@@ -570,15 +566,16 @@ impl Display {
if let Some(vi_mode_cursor) = vi_mode_cursor {
// Highlight URLs at the vi mode cursor position.
- let vi_mode_point = vi_mode_cursor.point;
- if let Some(url) = self.urls.find_at(vi_mode_point) {
+ let vi_point = vi_mode_cursor.point;
+ let line = (vi_point.line + display_offset).0 as usize;
+ if let Some(url) = self.urls.find_at(Point::new(line, vi_point.column)) {
rects.append(&mut url.rects(&metrics, &size_info));
}
// Indicate vi mode by showing the cursor's position in the top right corner.
- let line = size_info.screen_lines() + display_offset - vi_mode_point.line - 1;
- self.draw_line_indicator(config, &size_info, total_lines, Some(vi_mode_point), line.0);
- } else if search_active {
+ let line = (-vi_point.line.0 + size_info.bottommost_line().0) as usize;
+ self.draw_line_indicator(config, &size_info, total_lines, Some(vi_point), line);
+ } else if search_state.regex().is_some() {
// Show current display offset in vi-less search to indicate match position.
self.draw_line_indicator(config, &size_info, total_lines, None, display_offset);
}
@@ -605,12 +602,12 @@ impl Display {
}
if let Some(message) = message_buffer.message() {
- let search_offset = if search_active { 1 } else { 0 };
+ let search_offset = if search_state.regex().is_some() { 1 } else { 0 };
let text = message.text(&size_info);
// Create a new rectangle for the background.
let start_line = size_info.screen_lines() + search_offset;
- let y = size_info.cell_height().mul_add(start_line.0 as f32, size_info.padding_y());
+ let y = size_info.cell_height().mul_add(start_line as f32, size_info.padding_y());
let bg = match message.ty() {
MessageType::Error => config.ui_config.colors.normal.red,
@@ -656,7 +653,8 @@ impl Display {
self.draw_search(config, &size_info, &search_text);
// Compute IME position.
- Point::new(size_info.screen_lines() + 1, Column(search_text.chars().count() - 1))
+ let line = Line(size_info.screen_lines() as i32 + 1);
+ Point::new(line, Column(search_text.chars().count() - 1))
},
None => cursor_point,
};
@@ -703,7 +701,7 @@ impl Display {
formatted_regex.push('_');
// Truncate beginning of the search regex if it exceeds the viewport width.
- let num_cols = size_info.cols().0;
+ let num_cols = size_info.columns();
let label_len = search_label.chars().count();
let regex_len = formatted_regex.chars().count();
let truncate_len = min((regex_len + label_len).saturating_sub(num_cols), regex_len);
@@ -722,7 +720,7 @@ impl Display {
/// Draw current search regex.
fn draw_search(&mut self, config: &Config, size_info: &SizeInfo, text: &str) {
let glyph_cache = &mut self.glyph_cache;
- let num_cols = size_info.cols().0;
+ let num_cols = size_info.columns();
// Assure text length is at least num_cols.
let text = format!("{:<1$}", text, num_cols);
@@ -745,7 +743,7 @@ impl Display {
let glyph_cache = &mut self.glyph_cache;
let timing = format!("{:.3} usec", self.meter.average());
- let point = Point::new(size_info.screen_lines() - 2, Column(0));
+ let point = Point::new(size_info.screen_lines().saturating_sub(2), Column(0));
let fg = config.ui_config.colors.primary.background;
let bg = config.ui_config.colors.normal.red;
@@ -764,16 +762,16 @@ impl Display {
line: usize,
) {
let text = format!("[{}/{}]", line, total_lines - 1);
- let column = Column(size_info.cols().0.saturating_sub(text.len()));
+ let column = Column(size_info.columns().saturating_sub(text.len()));
let colors = &config.ui_config.colors;
let fg = colors.line_indicator.foreground.unwrap_or(colors.primary.background);
let bg = colors.line_indicator.background.unwrap_or(colors.primary.foreground);
// Do not render anything if it would obscure the vi mode cursor.
- if vi_mode_point.map_or(true, |point| point.line.0 != 0 || point.column < column) {
+ if vi_mode_point.map_or(true, |point| point.line != 0 || point.column < column) {
let glyph_cache = &mut self.glyph_cache;
self.renderer.with_api(&config.ui_config, &size_info, |mut api| {
- api.render_string(glyph_cache, Point::new(Line(0), column), fg, bg, &text);
+ api.render_string(glyph_cache, Point::new(0, column), fg, bg, &text);
});
}
}
@@ -822,8 +820,8 @@ fn window_size(
) -> PhysicalSize<u32> {
let padding = config.ui_config.window.padding(dpr);
- let grid_width = cell_width * dimensions.columns.0.max(MIN_COLS) as f32;
- let grid_height = cell_height * dimensions.lines.0.max(MIN_SCREEN_LINES) as f32;
+ let grid_width = cell_width * dimensions.columns.0.max(MIN_COLUMNS) as f32;
+ let grid_height = cell_height * dimensions.lines.max(MIN_SCREEN_LINES) as f32;
let width = (padding.0).mul_add(2., grid_width).floor();
let height = (padding.1).mul_add(2., grid_height).floor();
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
index 7faf380e..94c40a39 100644
--- a/alacritty/src/event.rs
+++ b/alacritty/src/event.rs
@@ -11,7 +11,6 @@ use std::fs;
use std::fs::File;
use std::io::Write;
use std::mem;
-use std::ops::RangeInclusive;
use std::path::{Path, PathBuf};
#[cfg(not(any(target_os = "macos", windows)))]
use std::sync::atomic::Ordering;
@@ -93,13 +92,13 @@ pub struct SearchState {
direction: Direction,
/// Change in display offset since the beginning of the search.
- display_offset_delta: isize,
+ display_offset_delta: i32,
/// Search origin in viewport coordinates relative to original display offset.
origin: Point,
/// Focused match during active search.
- focused_match: Option<RangeInclusive<Point<usize>>>,
+ focused_match: Option<Match>,
/// Search regex and history.
///
@@ -128,7 +127,7 @@ impl SearchState {
}
/// Focused match during vi-less search.
- pub fn focused_match(&self) -> Option<&RangeInclusive<Point<usize>>> {
+ pub fn focused_match(&self) -> Option<&Match> {
self.focused_match.as_ref()
}
@@ -195,14 +194,14 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
}
fn scroll(&mut self, scroll: Scroll) {
- let old_offset = self.terminal.grid().display_offset() as isize;
+ let old_offset = self.terminal.grid().display_offset() as i32;
self.terminal.scroll_display(scroll);
// Keep track of manual display offset changes during search.
if self.search_active() {
let display_offset = self.terminal.grid().display_offset();
- self.search_state.display_offset_delta += old_offset - display_offset as isize;
+ self.search_state.display_offset_delta += old_offset - display_offset as i32;
}
// Update selection.
@@ -213,9 +212,10 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
} else if self.mouse().left_button_state == ElementState::Pressed
|| self.mouse().right_button_state == ElementState::Pressed
{
- let point = self.size_info().pixels_to_coords(self.mouse().x, self.mouse().y);
- let cell_side = self.mouse().cell_side;
- self.update_selection(point, cell_side);
+ let point = self.mouse().point;
+ let line = Line(point.line as i32) - self.terminal.grid().display_offset();
+ let point = Point::new(line, point.column);
+ self.update_selection(point, self.mouse().cell_side);
}
*self.dirty = true;
@@ -245,11 +245,10 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
};
// Treat motion over message bar like motion over the last line.
- point.line = min(point.line, self.terminal.screen_lines() - 1);
+ point.line = min(point.line, self.terminal.bottommost_line());
// Update selection.
- let absolute_point = self.terminal.visible_to_buffer(point);
- selection.update(absolute_point, side);
+ selection.update(point, side);
// Move vi cursor and expand selection.
if self.terminal.mode().contains(TermMode::VI) && !self.search_active() {
@@ -262,7 +261,6 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
}
fn start_selection(&mut self, ty: SelectionType, point: Point, side: Side) {
- let point = self.terminal.visible_to_buffer(point);
self.terminal.selection = Some(Selection::new(ty, point, side));
*self.dirty = true;
}
@@ -280,17 +278,6 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
}
}
- fn mouse_coords(&self) -> Option<Point> {
- let x = self.mouse.x as usize;
- let y = self.mouse.y as usize;
-
- if self.display.size_info.contains_point(x, y) {
- Some(self.display.size_info.pixels_to_coords(x, y))
- } else {
- None
- }
- }
-
#[inline]
fn mouse_mode(&self) -> bool {
self.terminal.mode().intersects(TermMode::MOUSE_MODE)
@@ -393,9 +380,13 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
}
if let Some(ref launcher) = self.config.ui_config.mouse.url.launcher {
+ let display_offset = self.terminal.grid().display_offset();
+ let start = url.start();
+ let start = Point::new(Line(start.line as i32 - display_offset as i32), start.column);
+ let end = url.end();
+ let end = Point::new(Line(end.line as i32 - display_offset as i32), end.column);
+
let mut args = launcher.args().to_vec();
- let start = self.terminal.visible_to_buffer(url.start());
- let end = self.terminal.visible_to_buffer(url.end());
args.push(self.terminal.bounds_to_string(start, end));
start_daemon(launcher.program(), &args);
@@ -430,9 +421,6 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
#[inline]
fn start_search(&mut self, direction: Direction) {
- let num_lines = self.terminal.screen_lines();
- let num_cols = self.terminal.cols();
-
// Only create new history entry if the previous regex wasn't empty.
if self.search_state.history.get(0).map_or(true, |regex| !regex.is_empty()) {
self.search_state.history.push_front(String::new());
@@ -448,12 +436,12 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
self.search_state.origin = self.terminal.vi_mode_cursor.point;
self.search_state.display_offset_delta = 0;
} else {
- match direction {
- Direction::Right => self.search_state.origin = Point::new(Line(0), Column(0)),
- Direction::Left => {
- self.search_state.origin = Point::new(num_lines - 2, num_cols - 1);
- },
- }
+ let screen_lines = self.terminal.screen_lines();
+ let last_column = self.terminal.last_column();
+ self.search_state.origin = match direction {
+ Direction::Right => Point::new(Line(0), Column(0)),
+ Direction::Left => Point::new(Line(screen_lines as i32 - 2), last_column),
+ };
}
self.display_update_pending.dirty = true;
@@ -483,8 +471,8 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
self.search_reset_state();
} else if let Some(focused_match) = &self.search_state.focused_match {
// Create a selection for the focused match.
- let start = self.terminal.grid().clamp_buffer_to_visible(*focused_match.start());
- let end = self.terminal.grid().clamp_buffer_to_visible(*focused_match.end());
+ let start = *focused_match.start();
+ let end = *focused_match.end();
self.start_selection(SelectionType::Simple, start, Side::Left);
self.update_selection(end, Side::Right);
}
@@ -565,19 +553,14 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
// Use focused match as new search origin if available.
if let Some(focused_match) = &self.search_state.focused_match {
let new_origin = match direction {
- Direction::Right => {
- focused_match.end().add_absolute(self.terminal, Boundary::Wrap, 1)
- },
- Direction::Left => {
- focused_match.start().sub_absolute(self.terminal, Boundary::Wrap, 1)
- },
+ Direction::Right => focused_match.end().add(self.terminal, Boundary::None, 1),
+ Direction::Left => focused_match.start().sub(self.terminal, Boundary::None, 1),
};
self.terminal.scroll_to_point(new_origin);
- let origin_relative = self.terminal.grid().clamp_buffer_to_visible(new_origin);
- self.search_state.origin = origin_relative;
self.search_state.display_offset_delta = 0;
+ self.search_state.origin = new_origin;
}
// Search for the next match using the supplied direction.
@@ -600,24 +583,18 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
};
// Store the search origin with display offset by checking how far we need to scroll to it.
- let old_display_offset = self.terminal.grid().display_offset() as isize;
+ let old_display_offset = self.terminal.grid().display_offset() as i32;
self.terminal.scroll_to_point(new_origin);
- let new_display_offset = self.terminal.grid().display_offset() as isize;
+ let new_display_offset = self.terminal.grid().display_offset() as i32;
self.search_state.display_offset_delta = new_display_offset - old_display_offset;
// Store origin and scroll back to the match.
- let origin_relative = self.terminal.grid().clamp_buffer_to_visible(new_origin);
self.terminal.scroll_display(Scroll::Delta(-self.search_state.display_offset_delta));
- self.search_state.origin = origin_relative;
+ self.search_state.origin = new_origin;
}
/// Find the next search match.
- fn search_next(
- &mut self,
- origin: Point<usize>,
- direction: Direction,
- side: Side,
- ) -> Option<Match> {
+ fn search_next(&mut self, origin: Point, direction: Direction, side: Side) -> Option<Match> {
self.search_state
.dfas
.as_ref()
@@ -746,15 +723,10 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> {
return;
}
- // Reset display offset.
+ // Reset display offset and cursor position.
self.terminal.scroll_display(Scroll::Delta(self.search_state.display_offset_delta));
self.search_state.display_offset_delta = 0;
-
- // Reset vi mode cursor.
- let mut origin = self.search_state.origin;
- origin.line = min(origin.line, self.terminal.screen_lines() - 1);
- origin.column = min(origin.column, self.terminal.cols() - 1);
- self.terminal.vi_mode_cursor.point = origin;
+ self.terminal.vi_mode_cursor.point = self.search_state.origin;
*self.dirty = true;
}
@@ -771,10 +743,10 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> {
// Jump to the next match.
let direction = self.search_state.direction;
- let origin = self.absolute_origin();
- match self.terminal.search_next(dfas, origin, direction, Side::Left, limit) {
+ let clamped_origin = self.search_state.origin.grid_clamp(self.terminal, Boundary::Grid);
+ match self.terminal.search_next(dfas, clamped_origin, direction, Side::Left, limit) {
Some(regex_match) => {
- let old_offset = self.terminal.grid().display_offset() as isize;
+ let old_offset = self.terminal.grid().display_offset() as i32;
if self.terminal.mode().contains(TermMode::VI) {
// Move vi cursor to the start of the match.
@@ -789,7 +761,7 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> {
// Store number of lines the viewport had to be moved.
let display_offset = self.terminal.grid().display_offset();
- self.search_state.display_offset_delta += old_offset - display_offset as isize;
+ self.search_state.display_offset_delta = old_offset - display_offset as i32;
// Since we found a result, we require no delayed re-search.
self.scheduler.unschedule(TimerId::DelayedSearch);
@@ -817,14 +789,6 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> {
/// Cleanup the search state.
fn exit_search(&mut self) {
- // Move vi cursor down if resize will pull content from history.
- if self.terminal.history_size() != 0
- && self.terminal.grid().display_offset() == 0
- && self.terminal.screen_lines() > self.terminal.vi_mode_cursor.point.line + 1
- {
- self.terminal.vi_mode_cursor.point.line += 1;
- }
-
self.display_update_pending.dirty = true;
self.search_state.history_index = None;
*self.dirty = true;
@@ -833,20 +797,6 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> {
self.search_state.focused_match = None;
}
- /// Get the absolute position of the search origin.
- ///
- /// This takes the relative motion of the viewport since the start of the search into account.
- /// So while the absolute point of the origin might have changed since new content was printed,
- /// this will still return the correct absolute position.
- fn absolute_origin(&self) -> Point<usize> {
- let mut relative_origin = self.search_state.origin;
- relative_origin.line = min(relative_origin.line, self.terminal.screen_lines() - 1);
- relative_origin.column = min(relative_origin.column, self.terminal.cols() - 1);
- let mut origin = self.terminal.visible_to_buffer(relative_origin);
- origin.line = (origin.line as isize + self.search_state.display_offset_delta) as usize;
- origin
- }
-
/// Update the cursor blinking state.
fn update_cursor_blinking(&mut self) {
// Get config cursor style.
@@ -886,8 +836,6 @@ pub enum ClickState {
/// State of the mouse.
#[derive(Debug)]
pub struct Mouse {
- pub x: usize,
- pub y: usize,
pub left_button_state: ElementState,
pub middle_button_state: ElementState,
pub right_button_state: ElementState,
@@ -895,32 +843,32 @@ pub struct Mouse {
pub last_click_button: MouseButton,
pub click_state: ClickState,
pub scroll_px: f64,
- pub line: Line,
- pub column: Column,
pub cell_side: Side,
pub lines_scrolled: f32,
pub block_url_launcher: bool,
pub inside_text_area: bool,
+ pub point: Point<usize>,
+ pub x: usize,
+ pub y: usize,
}
impl Default for Mouse {
fn default() -> Mouse {
Mouse {
- x: 0,
- y: 0,
last_click_timestamp: Instant::now(),
last_click_button: MouseButton::Left,
left_button_state: ElementState::Released,
middle_button_state: ElementState::Released,
right_button_state: ElementState::Released,
click_state: ClickState::None,
- scroll_px: 0.,
- line: Line(0),
- column: Column(0),
cell_side: Side::Left,
- lines_scrolled: 0.,
- block_url_launcher: false,
- inside_text_area: false,
+ block_url_launcher: Default::default(),
+ inside_text_area: Default::default(),
+ lines_scrolled: Default::default(),
+ scroll_px: Default::default(),
+ point: Default::default(),
+ x: Default::default(),
+ y: Default::default(),
}
}
}
@@ -1409,14 +1357,12 @@ impl<N: Notify + OnResize> Processor<N> {
{
// Compute cursor positions before resize.
let num_lines = terminal.screen_lines();
- let vi_mode = terminal.mode().contains(TermMode::VI);
let cursor_at_bottom = terminal.grid().cursor.point.line + 1 == num_lines;
- let origin_at_bottom = if vi_mode {
+ let origin_at_bottom = if terminal.mode().contains(TermMode::VI) {
terminal.vi_mode_cursor.point.line == num_lines - 1
} else {
self.search_state.direction == Direction::Left
};
- let old_display_offset = terminal.grid().display_offset();
self.display.handle_update(
terminal,
@@ -1436,15 +1382,6 @@ impl<N: Notify + OnResize> Processor<N> {
} else if display_offset != 0 && origin_at_bottom {
terminal.scroll_display(Scroll::Delta(-1));
}
- } else if old_is_searching
- && !new_is_searching
- && old_display_offset == 0
- && cursor_at_bottom
- && origin_at_bottom
- && vi_mode
- {
- // Pull down the vi cursor if it was moved up when the search was started.
- terminal.vi_mode_cursor.point.line += 1;
}
}
diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs
index 0d6a066d..c5f41b6e 100644
--- a/alacritty/src/input.rs
+++ b/alacritty/src/input.rs
@@ -71,7 +71,6 @@ pub trait ActionContext<T: EventListener> {
fn selection_is_empty(&self) -> bool;
fn mouse_mut(&mut self) -> &mut Mouse;
fn mouse(&self) -> &Mouse;
- fn mouse_coords(&self) -> Option<Point>;
fn received_count(&mut self) -> &mut usize;
fn suppress_chars(&mut self) -> &mut bool;
fn modifiers(&mut self) -> &mut ModifiersState;
@@ -100,12 +99,7 @@ pub trait ActionContext<T: EventListener> {
fn search_pop_word(&mut self) {}
fn search_history_previous(&mut self) {}
fn search_history_next(&mut self) {}
- fn search_next(
- &mut self,
- origin: Point<usize>,
- direction: Direction,
- side: Side,
- ) -> Option<Match>;
+ fn search_next(&mut self, origin: Point, direction: Direction, side: Side) -> Option<Match>;
fn advance_search_origin(&mut self, _direction: Direction) {}
fn search_direction(&self) -> Direction;
fn search_active(&self) -> bool;
@@ -121,8 +115,7 @@ impl Action {
A: ActionContext<T>,
T: EventListener,
{
- let cursor_point = ctx.terminal().vi_mode_cursor.point;
- ctx.toggle_selection(ty, cursor_point, Side::Left);
+ ctx.toggle_selection(ty, ctx.terminal().vi_mode_cursor.point, Side::Left);
// Make sure initial selection is not empty.
if let Some(selection) = &mut ctx.terminal_mut().selection {
@@ -171,17 +164,19 @@ impl<T: EventListener> Execute<T> for Action {
},
Action::ViAction(ViAction::Open) => {
ctx.mouse_mut().block_url_launcher = false;
- if let Some(url) = ctx.urls().find_at(ctx.terminal().vi_mode_cursor.point) {
+ let vi_point = ctx.terminal().vi_mode_cursor.point;
+ let line = (vi_point.line + ctx.terminal().grid().display_offset()).0 as usize;
+ if let Some(url) = ctx.urls().find_at(Point::new(line, vi_point.column)) {
ctx.launch_url(url);
}
},
Action::ViAction(ViAction::SearchNext) => {
let terminal = ctx.terminal();
let direction = ctx.search_direction();
- let vi_point = terminal.visible_to_buffer(terminal.vi_mode_cursor.point);
+ let vi_point = terminal.vi_mode_cursor.point;
let origin = match direction {
- Direction::Right => vi_point.add_absolute(terminal, Boundary::Wrap, 1),
- Direction::Left => vi_point.sub_absolute(terminal, Boundary::Wrap, 1),
+ Direction::Right => vi_point.add(terminal, Boundary::None, 1),
+ Direction::Left => vi_point.sub(terminal, Boundary::None, 1),
};
if let Some(regex_match) = ctx.search_next(origin, direction, Side::Left) {
@@ -192,10 +187,10 @@ impl<T: EventListener> Execute<T> for Action {
Action::ViAction(ViAction::SearchPrevious) => {
let terminal = ctx.terminal();
let direction = ctx.search_direction().opposite();
- let vi_point = terminal.visible_to_buffer(terminal.vi_mode_cursor.point);
+ let vi_point = terminal.vi_mode_cursor.point;
let origin = match direction {
- Direction::Right => vi_point.add_absolute(terminal, Boundary::Wrap, 1),
- Direction::Left => vi_point.sub_absolute(terminal, Boundary::Wrap, 1),
+ Direction::Right => vi_point.add(terminal, Boundary::None, 1),
+ Direction::Left => vi_point.sub(terminal, Boundary::None, 1),
};
if let Some(regex_match) = ctx.search_next(origin, direction, Side::Left) {
@@ -205,9 +200,7 @@ impl<T: EventListener> Execute<T> for Action {
},
Action::ViAction(ViAction::SearchStart) => {
let terminal = ctx.terminal();
- let origin = terminal
- .visible_to_buffer(terminal.vi_mode_cursor.point)
- .sub_absolute(terminal, Boundary::Wrap, 1);
+ let origin = terminal.vi_mode_cursor.point.sub(terminal, Boundary::None, 1);
if let Some(regex_match) = ctx.search_next(origin, Direction::Left, Side::Left) {
ctx.terminal_mut().vi_goto_point(*regex_match.start());
@@ -216,9 +209,7 @@ impl<T: EventListener> Execute<T> for Action {
},
Action::ViAction(ViAction::SearchEnd) => {
let terminal = ctx.terminal();
- let origin = terminal
- .visible_to_buffer(terminal.vi_mode_cursor.point)
- .add_absolute(terminal, Boundary::Wrap, 1);
+ let origin = terminal.vi_mode_cursor.point.add(terminal, Boundary::None, 1);
if let Some(regex_match) = ctx.search_next(origin, Direction::Right, Side::Right) {
ctx.terminal_mut().vi_goto_point(*regex_match.end());
@@ -273,7 +264,7 @@ impl<T: EventListener> Execute<T> for Action {
Action::ScrollPageUp => {
// Move vi mode cursor.
let term = ctx.terminal_mut();
- let scroll_lines = term.screen_lines().0 as isize;
+ let scroll_lines = term.screen_lines() as i32;
term.vi_mode_cursor = term.vi_mode_cursor.scroll(term, scroll_lines);
ctx.scroll(Scroll::PageUp);
@@ -281,7 +272,7 @@ impl<T: EventListener> Execute<T> for Action {
Action::ScrollPageDown => {
// Move vi mode cursor.
let term = ctx.terminal_mut();
- let scroll_lines = -(term.screen_lines().0 as isize);
+ let scroll_lines = -(term.screen_lines() as i32);
term.vi_mode_cursor = term.vi_mode_cursor.scroll(term, scroll_lines);
ctx.scroll(Scroll::PageDown);
@@ -289,7 +280,7 @@ impl<T: EventListener> Execute<T> for Action {
Action::ScrollHalfPageUp => {
// Move vi mode cursor.
let term = ctx.terminal_mut();
- let scroll_lines = term.screen_lines().0 as isize / 2;
+ let scroll_lines = term.screen_lines() as i32 / 2;
term.vi_mode_cursor = term.vi_mode_cursor.scroll(term, scroll_lines);
ctx.scroll(Scroll::Delta(scroll_lines));
@@ -297,37 +288,19 @@ impl<T: EventListener> Execute<T> for Action {
Action::ScrollHalfPageDown => {
// Move vi mode cursor.
let term = ctx.terminal_mut();
- let scroll_lines = -(term.screen_lines().0 as isize / 2);
+ let scroll_lines = -(term.screen_lines() as i32 / 2);
term.vi_mode_cursor = term.vi_mode_cursor.scroll(term, scroll_lines);
ctx.scroll(Scroll::Delta(scroll_lines));
},
- Action::ScrollLineUp => {
- // Move vi mode cursor.
- let term = ctx.terminal();
- if term.grid().display_offset() != term.history_size()
- && term.vi_mode_cursor.point.line + 1 != term.screen_lines()
- {
- ctx.terminal_mut().vi_mode_cursor.point.line += 1;
- }
-
- ctx.scroll(Scroll::Delta(1));
- },
- Action::ScrollLineDown => {
- // Move vi mode cursor.
- if ctx.terminal().grid().display_offset() != 0
- && ctx.terminal().vi_mode_cursor.point.line.0 != 0
- {
- ctx.terminal_mut().vi_mode_cursor.point.line -= 1;
- }
-
- ctx.scroll(Scroll::Delta(-1));
- },
+ Action::ScrollLineUp => ctx.scroll(Scroll::Delta(1)),
+ Action::ScrollLineDown => ctx.scroll(Scroll::Delta(-1)),
Action::ScrollToTop => {
ctx.scroll(Scroll::Top);
// Move vi mode cursor.
- ctx.terminal_mut().vi_mode_cursor.point.line = Line(0);
+ let topmost_line = ctx.terminal().topmost_line();
+ ctx.terminal_mut().vi_mode_cursor.point.line = topmost_line;
ctx.terminal_mut().vi_motion(ViMotion::FirstOccupied);
ctx.mark_dirty();
},
@@ -336,7 +309,7 @@ impl<T: EventListener> Execute<T> for Action {
// Move vi mode cursor.
let term = ctx.terminal_mut();
- term.vi_mode_cursor.point.line = term.screen_lines() - 1;
+ term.vi_mode_cursor.point.line = term.bottommost_line();
// Move to beginning twice, to always jump across linewraps.
term.vi_motion(ViMotion::FirstOccupied);
@@ -414,11 +387,10 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
self.ctx.mouse_mut().y = y;
let inside_text_area = size_info.contains_point(x, y);
- let point = size_info.pixels_to_coords(x, y);
- let cell_side = self.get_mouse_side();
+ let point = self.coords_to_point(x, y);
+ let cell_side = self.cell_side(x);
- let cell_changed =
- point.line != self.ctx.mouse().line || point.column != self.ctx.mouse().column;
+ let cell_changed = point != self.ctx.mouse().point;
// Update mouse state and check for URL change.
let mouse_state = self.mouse_state();
@@ -435,14 +407,15 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
self.ctx.mouse_mut().inside_text_area = inside_text_area;
self.ctx.mouse_mut().cell_side = cell_side;
- self.ctx.mouse_mut().line = point.line;
- self.ctx.mouse_mut().column = point.column;
+ self.ctx.mouse_mut().point = point;
// Don't launch URLs if mouse has moved.
self.ctx.mouse_mut().block_url_launcher = true;
if (lmb_pressed || rmb_pressed) && (self.ctx.modifiers().shift() || !self.ctx.mouse_mode())
{
+ let line = Line(point.line as i32) - self.ctx.terminal().grid().display_offset();
+ let point = Point::new(line, point.column);
self.ctx.update_selection(point, cell_side);
} else if cell_changed
&& point.line < self.ctx.terminal().screen_lines()
@@ -460,9 +433,26 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
}
}
- fn get_mouse_side(&self) -> Side {
+ /// Convert window space pixels to terminal grid coordinates.
+ ///
+ /// If the coordinates are outside of the terminal grid, like positions inside the padding, the
+ /// coordinates will be clamped to the closest grid coordinates.
+ #[inline]
+ fn coords_to_point(&self, x: usize, y: usize) -> Point<usize> {
+ let size = self.ctx.size_info();
+
+ let column = x.saturating_sub(size.padding_x() as usize) / (size.cell_width() as usize);
+ let column = min(Column(column), size.last_column());
+
+ let line = y.saturating_sub(size.padding_y() as usize) / (size.cell_height() as usize);
+ let line = min(line, size.bottommost_line().0 as usize);
+
+ Point::new(line, column)
+ }
+
+ /// Check which side of a cell an X coordinate lies on.
+ fn cell_side(&self, x: usize) -> Side {
let size_info = self.ctx.size_info();
- let x = self.ctx.mouse().x;
let cell_x =
x.saturating_sub(size_info.padding_x() as usize) % size_info.cell_width() as usize;
@@ -483,12 +473,12 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
}
fn normal_mouse_report(&mut self, button: u8) {
- let (line, column) = (self.ctx.mouse().line, self.ctx.mouse().column);
+ let Point { line, column } = self.ctx.mouse().point;
let utf8 = self.ctx.terminal().mode().contains(TermMode::UTF8_MOUSE);
let max_point = if utf8 { 2015 } else { 223 };
- if line >= Line(max_point) || column >= Column(max_point) {
+ if line >= max_point || column >= Column(max_point) {
return;
}
@@ -507,17 +497,17 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
msg.push(32 + 1 + column.0 as u8);
}
- if utf8 && line >= Line(95) {
- msg.append(&mut mouse_pos_encode(line.0));
+ if utf8 && line >= 95 {
+ msg.append(&mut mouse_pos_encode(line));
} else {
- msg.push(32 + 1 + line.0 as u8);
+ msg.push(32 + 1 + line as u8);
}
self.ctx.write_to_pty(msg);
}
fn sgr_mouse_report(&mut self, button: u8, state: ElementState) {
- let (line, column) = (self.ctx.mouse().line, self.ctx.mouse().column);
+ let Point { line, column } = self.ctx.mouse().point;
let c = match state {
ElementState::Pressed => 'M',
ElementState::Released => 'm',
@@ -589,9 +579,10 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
};
// Load mouse point, treating message bar and padding as the closest cell.
- let mouse = self.ctx.mouse();
- let mut point = self.ctx.size_info().pixels_to_coords(mouse.x, mouse.y);
- point.line = min(point.line, self.ctx.terminal().screen_lines() - 1);
+ let point = self.ctx.mouse().point;
+ let display_offset = self.ctx.terminal().grid().display_offset();
+ let absolute_line = Line(point.line as i32) - display_offset;
+ let point = Point::new(absolute_line, point.column);
match button {
MouseButton::Left => self.on_left_click(point),
@@ -751,24 +742,7 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
let lines = self.ctx.mouse().scroll_px / height;
- // Store absolute position of vi mode cursor.
- let term = self.ctx.terminal();
- let absolute = term.visible_to_buffer(term.vi_mode_cursor.point);
-
- self.ctx.scroll(Scroll::Delta(lines as isize));
-
- // Try to restore vi mode cursor position, to keep it above its previous content.
- let term = self.ctx.terminal_mut();
- term.vi_mode_cursor.point = term.grid().clamp_buffer_to_visible(absolute);
- term.vi_mode_cursor.point.column = absolute.column;
-
- // Update selection.
- if term.mode().contains(TermMode::VI) {
- let point = term.vi_mode_cursor.point;
- if !self.ctx.selection_is_empty() {
- self.ctx.update_selection(point, Side::Right);
- }
- }
+ self.ctx.scroll(Scroll::Delta(lines as i32));
}
self.ctx.mouse_mut().scroll_px %= height;
@@ -977,13 +951,13 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
// Calculate Y position of the end of the last terminal line.
let size = self.ctx.size_info();
let terminal_end = size.padding_y() as usize
- + size.cell_height() as usize * (size.screen_lines().0 + search_height);
+ + size.cell_height() as usize * (size.screen_lines() + search_height);
let mouse = self.ctx.mouse();
if self.ctx.message().is_none() || (mouse.y <= terminal_end) {
None
} else if mouse.y <= terminal_end + size.cell_height() as usize
- && mouse.column + message_bar::CLOSE_BUTTON_TEXT.len() >= size.cols()
+ && mouse.point.column + message_bar::CLOSE_BUTTON_TEXT.len() >= size.columns()
{
Some(MouseState::MessageBarButton)
} else {
@@ -1055,7 +1029,7 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
// Compute the height of the scrolling areas.
let end_top = max(min_height, size.padding_y() as i32);
- let text_area_bottom = size.padding_y() + size.screen_lines().0 as f32 * size.cell_height();
+ let text_area_bottom = size.padding_y() + size.screen_lines() as f32 * size.cell_height();
let start_bottom = min(size.height() as i32 - min_height, text_area_bottom as i32);
// Get distance from closest window boundary.
@@ -1069,7 +1043,7 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
};
// Scale number of lines scrolled based on distance to boundary.
- let delta = delta as isize / step as isize;
+ let delta = delta as i32 / step as i32;
let event = Event::Scroll(Scroll::Delta(delta));
// Schedule event.
@@ -1120,7 +1094,7 @@ mod tests {
impl<'a, T: EventListener> super::ActionContext<T> for ActionContext<'a, T> {
fn search_next(
&mut self,
- _origin: Point<usize>,
+ _origin: Point,
_direction: Direction,
_side: Side,
) -> Option<Match> {
@@ -1155,17 +1129,6 @@ mod tests {
self.terminal.scroll_display(scroll);
}
- fn mouse_coords(&self) -> Option<Point> {
- let x = self.mouse.x as usize;
- let y = self.mouse.y as usize;
-
- if self.size_info.contains_point(x, y) {
- Some(self.size_info.pixels_to_coords(x, y))
- } else {
- None
- }
- }
-
fn mouse_mode(&self) -> bool {
false
}
diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs
index 30eff73d..0914aee4 100644
--- a/alacritty/src/main.rs
+++ b/alacritty/src/main.rs
@@ -25,6 +25,7 @@ use log::{error, info};
use winapi::um::wincon::{AttachConsole, FreeConsole, ATTACH_PARENT_PROCESS};
use alacritty_terminal::event_loop::{self, EventLoop, Msg};
+use alacritty_terminal::grid::Dimensions;
use alacritty_terminal::sync::FairMutex;
use alacritty_terminal::term::Term;
use alacritty_terminal::tty;
@@ -139,7 +140,7 @@ fn run(
info!(
"PTY dimensions: {:?} x {:?}",
display.size_info.screen_lines(),
- display.size_info.cols()
+ display.size_info.columns()
);
// Create the terminal.
diff --git a/alacritty/src/message_bar.rs b/alacritty/src/message_bar.rs
index 609af55d..72e6f354 100644
--- a/alacritty/src/message_bar.rs
+++ b/alacritty/src/message_bar.rs
@@ -1,8 +1,10 @@
use std::collections::VecDeque;
-use alacritty_terminal::term::SizeInfo;
use unicode_width::UnicodeWidthChar;
+use alacritty_terminal::grid::Dimensions;
+use alacritty_terminal::term::SizeInfo;
+
pub const CLOSE_BUTTON_TEXT: &str = "[X]";
const CLOSE_BUTTON_PADDING: usize = 1;
const MIN_FREE_LINES: usize = 3;
@@ -34,7 +36,7 @@ impl Message {
/// Formatted message text lines.
pub fn text(&self, size_info: &SizeInfo) -> Vec<String> {
- let num_cols = size_info.cols().0;
+ let num_cols = size_info.columns();
let total_lines =
(size_info.height() - 2. * size_info.padding_y()) / size_info.cell_height();
let max_lines = (total_lines as usize).saturating_sub(MIN_FREE_LINES);
diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs
index 4d752463..414d9bd5 100644
--- a/alacritty/src/renderer/mod.rs
+++ b/alacritty/src/renderer/mod.rs
@@ -481,7 +481,7 @@ impl Batch {
self.instances.push(InstanceData {
col: cell.point.column.0 as u16,
- row: cell.point.line.0 as u16,
+ row: cell.point.line as u16,
top: glyph.top,
left: glyph.left,
@@ -830,7 +830,7 @@ impl<'a> RenderApi<'a> {
pub fn render_string(
&mut self,
glyph_cache: &mut GlyphCache,
- point: Point,
+ point: Point<usize>,
fg: Rgb,
bg: Rgb,
string: &str,
@@ -846,7 +846,6 @@ impl<'a> RenderApi<'a> {
bg_alpha: 1.0,
fg,
bg,
- is_match: false,
})
.collect::<Vec<_>>();
diff --git a/alacritty/src/renderer/rects.rs b/alacritty/src/renderer/rects.rs
index fd966d27..591c9f46 100644
--- a/alacritty/src/renderer/rects.rs
+++ b/alacritty/src/renderer/rects.rs
@@ -3,6 +3,7 @@ use std::mem;
use crossfont::Metrics;
+use alacritty_terminal::grid::Dimensions;
use alacritty_terminal::index::{Column, Point};
use alacritty_terminal::term::cell::Flags;
use alacritty_terminal::term::color::Rgb;
@@ -31,8 +32,8 @@ impl RenderRect {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct RenderLine {
- pub start: Point,
- pub end: Point,
+ pub start: Point<usize>,
+ pub end: Point<usize>,
pub color: Rgb,
}
@@ -42,7 +43,7 @@ impl RenderLine {
let mut start = self.start;
while start.line < self.end.line {
- let end = Point::new(start.line, size.cols() - 1);
+ let end = Point::new(start.line, size.last_column());
Self::push_rects(&mut rects, metrics, size, flag, start, end, self.color);
start = Point::new(start.line + 1, Column(0));
}
@@ -57,8 +58,8 @@ impl RenderLine {
metrics: &Metrics,
size: &SizeInfo,
flag: Flags,
- start: Point,
- end: Point,
+ start: Point<usize>,
+ end: Point<usize>,
color: Rgb,
) {
let (position, thickness) = match flag {
@@ -99,8 +100,8 @@ impl RenderLine {
fn create_rect(
size: &SizeInfo,
descent: f32,
- start: Point,
- end: Point,
+ start: Point<usize>,
+ end: Point<usize>,
position: f32,
mut thickness: f32,
color: Rgb,
@@ -112,7 +113,7 @@ impl RenderLine {
// Make sure lines are always visible.
thickness = thickness.max(1.);
- let line_bottom = (start.line.0 as f32 + 1.) * size.cell_height();
+ let line_bottom = (start.line as f32 + 1.) * size.cell_height();
let baseline = line_bottom + descent;
let mut y = (baseline - position - thickness / 2.).ceil();
diff --git a/alacritty/src/url.rs b/alacritty/src/url.rs
index e4a29512..add4a1aa 100644
--- a/alacritty/src/url.rs
+++ b/alacritty/src/url.rs
@@ -5,7 +5,8 @@ use crossfont::Metrics;
use glutin::event::{ElementState, ModifiersState};
use urlocator::{UrlLocation, UrlLocator};
-use alacritty_terminal::index::{Column, Point};
+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;
@@ -15,14 +16,15 @@ use crate::display::content::RenderableCell;
use crate::event::Mouse;
use crate::renderer::rects::{RenderLine, RenderRect};
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq)]
pub struct Url {
lines: Vec<RenderLine>,
end_offset: u16,
- num_cols: Column,
+ 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
@@ -37,20 +39,28 @@ impl Url {
.collect()
}
- pub fn start(&self) -> Point {
+ /// Viewport start point of the URL.
+ pub fn start(&self) -> Point<usize> {
self.lines[0].start
}
- pub fn end(&self) -> Point {
- self.lines[self.lines.len() - 1].end.sub(self.num_cols, self.end_offset as usize)
+ /// 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, Rgb)>,
- last_point: Option<Point>,
+ scheme_buffer: Vec<(Point<usize>, Rgb)>,
+ next_point: Point<usize>,
state: UrlLocation,
}
@@ -61,7 +71,7 @@ impl Default for Urls {
scheme_buffer: Vec::new(),
urls: Vec::new(),
state: UrlLocation::Reset,
- last_point: None,
+ next_point: Point::new(0, Column(0)),
}
}
}
@@ -72,7 +82,7 @@ impl Urls {
}
// Update tracked URLs.
- pub fn update(&mut self, num_cols: Column, cell: &RenderableCell) {
+ pub fn update(&mut self, size: &SizeInfo, cell: &RenderableCell) {
let point = cell.point;
let mut end = point;
@@ -82,11 +92,15 @@ impl Urls {
}
// Reset URL when empty cells have been skipped.
- if point != Point::default() && Some(point.sub(num_cols, 1)) != self.last_point {
+ if point != Point::new(0, Column(0)) && point != self.next_point {
self.reset();
}
- self.last_point = Some(end);
+ 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) {
@@ -106,7 +120,7 @@ impl Urls {
match (self.state, last_state) {
(UrlLocation::Url(_length, end_offset), UrlLocation::Scheme) => {
// Create empty URL.
- self.urls.push(Url { lines: Vec::new(), end_offset, num_cols });
+ 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) {
@@ -125,13 +139,13 @@ impl Urls {
}
// Reset at un-wrapped linebreak.
- if cell.point.column + 1 == num_cols && !cell.flags.contains(Flags::WRAPLINE) {
+ 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, end: Point, color: Rgb, end_offset: u16) {
+ 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.
@@ -170,11 +184,11 @@ impl Urls {
return None;
}
- self.find_at(Point::new(mouse.line, mouse.column))
+ self.find_at(mouse.point)
}
/// Find URL at location.
- pub fn find_at(&self, point: Point) -> Option<Url> {
+ 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());
@@ -194,7 +208,7 @@ impl Urls {
mod tests {
use super::*;
- use alacritty_terminal::index::{Column, Line};
+ use alacritty_terminal::index::Column;
fn text_to_cells(text: &str) -> Vec<RenderableCell> {
text.chars()
@@ -202,12 +216,11 @@ mod tests {
.map(|(i, character)| RenderableCell {
character,
zerowidth: None,
- point: Point::new(Line(0), Column(i)),
+ point: Point::new(0, Column(i)),
fg: Default::default(),
bg: Default::default(),
bg_alpha: 0.,
flags: Flags::empty(),
- is_match: false,
})
.collect()
}
@@ -215,14 +228,14 @@ mod tests {
#[test]
fn multi_color_url() {
let mut input = text_to_cells("test https://example.org ing");
- let num_cols = input.len();
+ 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(Column(num_cols), &cell);
+ urls.update(&size, &cell);
}
let url = urls.urls.first().unwrap();
@@ -233,12 +246,12 @@ mod tests {
#[test]
fn multiple_urls() {
let input = text_to_cells("test git:a git:b git:c ing");
- let num_cols = input.len();
+ 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(Column(num_cols), &cell);
+ urls.update(&size, &cell);
}
assert_eq!(urls.urls.len(), 3);
@@ -256,12 +269,12 @@ mod tests {
#[test]
fn wide_urls() {
let input = text_to_cells("test https://こんにちは (http:여보세요) ing");
- let num_cols = input.len() + 9;
+ 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(Column(num_cols), &cell);
+ urls.update(&size, &cell);
}
assert_eq!(urls.urls.len(), 2);