summaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/term/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty_terminal/src/term/mod.rs')
-rw-r--r--alacritty_terminal/src/term/mod.rs279
1 files changed, 135 insertions, 144 deletions
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs
index 00726dad..a33ac919 100644
--- a/alacritty_terminal/src/term/mod.rs
+++ b/alacritty_terminal/src/term/mod.rs
@@ -40,8 +40,13 @@ const MAX_SEARCH_LINES: usize = 100;
/// Default tab interval, corresponding to terminfo `it` value.
const INITIAL_TABSTOPS: usize = 8;
-/// Minimum number of columns and lines.
-const MIN_SIZE: usize = 2;
+/// Minimum number of columns.
+///
+/// A minimum of 2 is necessary to hold fullwidth unicode characters.
+pub const MIN_COLS: usize = 2;
+
+/// Minimum number of visible lines.
+pub const MIN_SCREEN_LINES: usize = 1;
/// Cursor storing all information relevant for rendering.
#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize)]
@@ -612,69 +617,139 @@ impl From<&BellConfig> for VisualBell {
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
pub struct SizeInfo {
/// Terminal window width.
- pub width: f32,
+ width: f32,
/// Terminal window height.
- pub height: f32,
+ height: f32,
/// Width of individual cell.
- pub cell_width: f32,
+ cell_width: f32,
/// Height of individual cell.
- pub cell_height: f32,
+ cell_height: f32,
/// Horizontal window padding.
- pub padding_x: f32,
+ padding_x: f32,
/// Horizontal window padding.
- pub padding_y: f32,
+ padding_y: f32,
- /// DPR of the current window.
- #[serde(default)]
- pub dpr: f64,
+ /// Number of lines in the viewport.
+ screen_lines: Line,
+
+ /// Number of columns in the viewport.
+ cols: Column,
}
impl SizeInfo {
- #[inline]
- pub fn lines(&self) -> Line {
- Line(((self.height - 2. * self.padding_y) / self.cell_height) as usize)
- }
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ width: f32,
+ height: f32,
+ cell_width: f32,
+ cell_height: f32,
+ mut padding_x: f32,
+ mut padding_y: f32,
+ dynamic_padding: bool,
+ ) -> SizeInfo {
+ if dynamic_padding {
+ padding_x = Self::dynamic_padding(padding_x.floor(), width, cell_width);
+ padding_y = Self::dynamic_padding(padding_y.floor(), height, cell_height);
+ }
- #[inline]
- pub fn cols(&self) -> Column {
- Column(((self.width - 2. * self.padding_x) / self.cell_width) as usize)
- }
+ let lines = (height - 2. * padding_y) / cell_height;
+ let screen_lines = Line(max(lines as usize, MIN_SCREEN_LINES));
- #[inline]
- pub fn padding_right(&self) -> usize {
- (self.padding_x + (self.width - 2. * self.padding_x) % self.cell_width) as usize
+ let cols = (width - 2. * padding_x) / cell_width;
+ let cols = Column(max(cols as usize, MIN_COLS));
+
+ SizeInfo {
+ width,
+ height,
+ cell_width,
+ cell_height,
+ padding_x: padding_x.floor(),
+ padding_y: padding_y.floor(),
+ screen_lines,
+ cols,
+ }
}
#[inline]
- pub fn padding_bottom(&self) -> usize {
- (self.padding_y + (self.height - 2. * self.padding_y) % self.cell_height) as usize
+ pub fn reserve_lines(&mut self, count: usize) {
+ self.screen_lines = Line(max(self.screen_lines.saturating_sub(count), MIN_SCREEN_LINES));
}
/// Check if coordinates are inside the terminal grid.
///
- /// The padding is not counted as part of the grid.
+ /// The padding, message bar or search are not counted as part of the grid.
#[inline]
pub fn contains_point(&self, x: usize, y: usize) -> bool {
- x < (self.width as usize - self.padding_right())
- && x >= self.padding_x as usize
- && y < (self.height as usize - self.padding_bottom())
- && y >= self.padding_y as usize
+ x <= (self.padding_x + self.cols.0 as f32 * self.cell_width) as usize
+ && x > self.padding_x as usize
+ && y <= (self.padding_y + self.screen_lines.0 as f32 * self.cell_height) as usize
+ && y > self.padding_y as usize
}
+ /// 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.
pub fn pixels_to_coords(&self, x: usize, y: usize) -> Point {
let col = Column(x.saturating_sub(self.padding_x as usize) / (self.cell_width as usize));
let line = Line(y.saturating_sub(self.padding_y as usize) / (self.cell_height as usize));
Point {
- line: min(line, Line(self.lines().saturating_sub(1))),
- col: min(col, Column(self.cols().saturating_sub(1))),
+ line: min(line, Line(self.screen_lines.saturating_sub(1))),
+ col: min(col, Column(self.cols.saturating_sub(1))),
}
}
+
+ #[inline]
+ pub fn width(&self) -> f32 {
+ self.width
+ }
+
+ #[inline]
+ pub fn height(&self) -> f32 {
+ self.height
+ }
+
+ #[inline]
+ pub fn cell_width(&self) -> f32 {
+ self.cell_width
+ }
+
+ #[inline]
+ pub fn cell_height(&self) -> f32 {
+ self.cell_height
+ }
+
+ #[inline]
+ pub fn padding_x(&self) -> f32 {
+ self.padding_x
+ }
+
+ #[inline]
+ pub fn padding_y(&self) -> f32 {
+ self.padding_y
+ }
+
+ #[inline]
+ pub fn screen_lines(&self) -> Line {
+ self.screen_lines
+ }
+
+ #[inline]
+ pub fn cols(&self) -> Column {
+ self.cols
+ }
+
+ /// Calculate padding to spread it evenly around the terminal content.
+ #[inline]
+ fn dynamic_padding(padding: f32, dimension: f32, cell_dimension: f32) -> f32 {
+ padding + ((dimension - 2. * padding) % cell_dimension) / 2.
+ }
}
pub struct Term<T> {
@@ -751,8 +826,9 @@ pub struct Term<T> {
/// Current forward and backward buffer search regexes.
regex_search: Option<RegexSearch>,
- /// Information about window dimensions.
- size: SizeInfo,
+ /// Information about cell dimensions.
+ cell_width: usize,
+ cell_height: usize,
}
impl<T> Term<T> {
@@ -767,8 +843,8 @@ impl<T> Term<T> {
}
pub fn new<C>(config: &Config<C>, size: SizeInfo, event_proxy: T) -> Term<T> {
- let num_cols = size.cols();
- let num_lines = size.lines();
+ let num_cols = size.cols;
+ let num_lines = size.screen_lines;
let history_size = config.scrolling.history() as usize;
let grid = Grid::new(num_lines, num_cols, history_size, Cell::default());
@@ -803,7 +879,8 @@ impl<T> Term<T> {
title_stack: Vec::new(),
selection: None,
regex_search: None,
- size,
+ cell_width: size.cell_width as usize,
+ cell_height: size.cell_height as usize,
}
}
@@ -974,12 +1051,14 @@ impl<T> Term<T> {
/// Resize terminal to new dimensions.
pub fn resize(&mut self, size: SizeInfo) {
- self.size = size;
+ self.cell_width = size.cell_width as usize;
+ self.cell_height = size.cell_height as usize;
let old_cols = self.cols();
let old_lines = self.screen_lines();
- let num_cols = max(size.cols(), Column(MIN_SIZE));
- let num_lines = max(size.lines(), Line(MIN_SIZE));
+
+ let num_cols = size.cols;
+ let num_lines = size.screen_lines;
if old_cols == num_cols && old_lines == num_lines {
debug!("Term::resize dimensions unchanged");
@@ -2233,8 +2312,8 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn text_area_size_pixels<W: io::Write>(&mut self, writer: &mut W) {
- let width = self.size.cell_width as usize * self.cols().0;
- let height = self.size.cell_height as usize * self.screen_lines().0;
+ let width = self.cell_width * self.cols().0;
+ let height = self.cell_height * self.screen_lines().0;
let _ = write!(writer, "\x1b[4;{};{}t", height, width);
}
@@ -2356,15 +2435,7 @@ pub mod test {
.unwrap_or(0);
// Create terminal with the appropriate dimensions.
- let size = SizeInfo {
- width: num_cols as f32,
- height: lines.len() as f32,
- cell_width: 1.,
- cell_height: 1.,
- padding_x: 0.,
- padding_y: 0.,
- dpr: 1.,
- };
+ let size = SizeInfo::new(num_cols as f32, lines.len() as f32, 1., 1., 0., 0., false);
let mut term = Term::new(&Config::<()>::default(), size, ());
// Fill terminal with content.
@@ -2413,15 +2484,7 @@ mod tests {
#[test]
fn semantic_selection_works() {
- let size = SizeInfo {
- width: 21.0,
- height: 51.0,
- cell_width: 3.0,
- cell_height: 3.0,
- padding_x: 0.0,
- padding_y: 0.0,
- dpr: 1.0,
- };
+ let size = SizeInfo::new(21.0, 51.0, 3.0, 3.0, 0.0, 0.0, false);
let mut term = Term::new(&MockConfig::default(), size, Mock);
let mut grid: Grid<Cell> = Grid::new(Line(3), Column(5), 0, Cell::default());
for i in 0..5 {
@@ -2469,15 +2532,7 @@ mod tests {
#[test]
fn line_selection_works() {
- let size = SizeInfo {
- width: 21.0,
- height: 51.0,
- cell_width: 3.0,
- cell_height: 3.0,
- padding_x: 0.0,
- padding_y: 0.0,
- dpr: 1.0,
- };
+ let size = SizeInfo::new(21.0, 51.0, 3.0, 3.0, 0.0, 0.0, false);
let mut term = Term::new(&MockConfig::default(), size, Mock);
let mut grid: Grid<Cell> = Grid::new(Line(1), Column(5), 0, Cell::default());
for i in 0..5 {
@@ -2498,15 +2553,7 @@ mod tests {
#[test]
fn selecting_empty_line() {
- let size = SizeInfo {
- width: 21.0,
- height: 51.0,
- cell_width: 3.0,
- cell_height: 3.0,
- padding_x: 0.0,
- padding_y: 0.0,
- dpr: 1.0,
- };
+ let size = SizeInfo::new(21.0, 51.0, 3.0, 3.0, 0.0, 0.0, false);
let mut term = Term::new(&MockConfig::default(), size, Mock);
let mut grid: Grid<Cell> = Grid::new(Line(3), Column(3), 0, Cell::default());
for l in 0..3 {
@@ -2543,15 +2590,7 @@ mod tests {
#[test]
fn input_line_drawing_character() {
- let size = SizeInfo {
- width: 21.0,
- height: 51.0,
- cell_width: 3.0,
- cell_height: 3.0,
- padding_x: 0.0,
- padding_y: 0.0,
- dpr: 1.0,
- };
+ let size = SizeInfo::new(21.0, 51.0, 3.0, 3.0, 0.0, 0.0, false);
let mut term = Term::new(&MockConfig::default(), size, Mock);
let cursor = Point::new(Line(0), Column(0));
term.configure_charset(CharsetIndex::G0, StandardCharset::SpecialCharacterAndLineDrawing);
@@ -2562,15 +2601,7 @@ mod tests {
#[test]
fn clear_saved_lines() {
- let size = SizeInfo {
- width: 21.0,
- height: 51.0,
- cell_width: 3.0,
- cell_height: 3.0,
- padding_x: 0.0,
- padding_y: 0.0,
- dpr: 1.0,
- };
+ let size = SizeInfo::new(21.0, 51.0, 3.0, 3.0, 0.0, 0.0, false);
let mut term = Term::new(&MockConfig::default(), size, Mock);
// Add one line of scrollback.
@@ -2592,15 +2623,7 @@ mod tests {
#[test]
fn grow_lines_updates_active_cursor_pos() {
- let mut size = SizeInfo {
- width: 100.0,
- height: 10.0,
- cell_width: 1.0,
- cell_height: 1.0,
- padding_x: 0.0,
- padding_y: 0.0,
- dpr: 1.0,
- };
+ let mut size = SizeInfo::new(100.0, 10.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&MockConfig::default(), size, Mock);
// Create 10 lines of scrollback.
@@ -2611,7 +2634,7 @@ mod tests {
assert_eq!(term.grid.cursor.point, Point::new(Line(9), Column(0)));
// Increase visible lines.
- size.height = 30.;
+ size.screen_lines.0 = 30;
term.resize(size);
assert_eq!(term.history_size(), 0);
@@ -2620,15 +2643,7 @@ mod tests {
#[test]
fn grow_lines_updates_inactive_cursor_pos() {
- let mut size = SizeInfo {
- width: 100.0,
- height: 10.0,
- cell_width: 1.0,
- cell_height: 1.0,
- padding_x: 0.0,
- padding_y: 0.0,
- dpr: 1.0,
- };
+ let mut size = SizeInfo::new(100.0, 10.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&MockConfig::default(), size, Mock);
// Create 10 lines of scrollback.
@@ -2642,7 +2657,7 @@ mod tests {
term.set_mode(ansi::Mode::SwapScreenAndSetRestoreCursor);
// Increase visible lines.
- size.height = 30.;
+ size.screen_lines.0 = 30;
term.resize(size);
// Leave alt screen.
@@ -2654,15 +2669,7 @@ mod tests {
#[test]
fn shrink_lines_updates_active_cursor_pos() {
- let mut size = SizeInfo {
- width: 100.0,
- height: 10.0,
- cell_width: 1.0,
- cell_height: 1.0,
- padding_x: 0.0,
- padding_y: 0.0,
- dpr: 1.0,
- };
+ let mut size = SizeInfo::new(100.0, 10.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&MockConfig::default(), size, Mock);
// Create 10 lines of scrollback.
@@ -2673,7 +2680,7 @@ mod tests {
assert_eq!(term.grid.cursor.point, Point::new(Line(9), Column(0)));
// Increase visible lines.
- size.height = 5.;
+ size.screen_lines.0 = 5;
term.resize(size);
assert_eq!(term.history_size(), 15);
@@ -2682,15 +2689,7 @@ mod tests {
#[test]
fn shrink_lines_updates_inactive_cursor_pos() {
- let mut size = SizeInfo {
- width: 100.0,
- height: 10.0,
- cell_width: 1.0,
- cell_height: 1.0,
- padding_x: 0.0,
- padding_y: 0.0,
- dpr: 1.0,
- };
+ let mut size = SizeInfo::new(100.0, 10.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&MockConfig::default(), size, Mock);
// Create 10 lines of scrollback.
@@ -2704,7 +2703,7 @@ mod tests {
term.set_mode(ansi::Mode::SwapScreenAndSetRestoreCursor);
// Increase visible lines.
- size.height = 5.;
+ size.screen_lines.0 = 5;
term.resize(size);
// Leave alt screen.
@@ -2716,15 +2715,7 @@ mod tests {
#[test]
fn window_title() {
- let size = SizeInfo {
- width: 21.0,
- height: 51.0,
- cell_width: 3.0,
- cell_height: 3.0,
- padding_x: 0.0,
- padding_y: 0.0,
- dpr: 1.0,
- };
+ let size = SizeInfo::new(21.0, 51.0, 3.0, 3.0, 0.0, 0.0, false);
let mut term = Term::new(&MockConfig::default(), size, Mock);
// Title None by default.