From bea6ece3f6e4f116e9f0319b6d0002943f28e3b8 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sun, 1 Mar 2020 03:27:23 +0000 Subject: [PATCH] Fix tabs across linewrap This resolves an issue with tabs not breaking across line boundaries, instead the characters would just all get written to the last column and thus be lost. It also tweaks the behavior of what happens when the terminal resizes with the default tabspaces changed, using something like the `tabs` program. Previously all tabstops would be reset to the default on resize, which is what URxvt does. Now the tabspaces are kept and the new columns are filled with the default tabstops, which emulates Termite. --- CHANGELOG.md | 2 ++ alacritty_terminal/src/term/mod.rs | 34 ++++++++++++++++++++++-------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53506f4..f3e6ded 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Config reload creating alternate screen history instead of updating scrollback - Crash on Wayland compositors supporting `wl_seat` version 7+ - Message bar not hiding after fixing wrong color value in config +- Tabstops cleared on resize +- Tabstops not breaking across lines ### Removed diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs index a91f41e..f198c59 100644 --- a/alacritty_terminal/src/term/mod.rs +++ b/alacritty_terminal/src/term/mod.rs @@ -44,7 +44,7 @@ pub mod color; /// Used to match equal brackets, when performing a bracket-pair selection. const BRACKET_PAIRS: [(char, char); 4] = [('(', ')'), ('[', ']'), ('{', '}'), ('<', '>')]; -/// Max size of the window title stack +/// Max size of the window title stack. const TITLE_STACK_MAX_DEPTH: usize = 4096; /// A type that can expand a given point to a region @@ -812,9 +812,6 @@ pub struct Term { /// Whether to permit updating the terminal title dynamic_title: bool, - /// Number of spaces in one tab - tabspaces: usize, - /// Clipboard access coupled to the active window clipboard: Clipboard, @@ -947,7 +944,6 @@ impl Term { cursor_style: None, default_cursor_style: config.cursor.style, dynamic_title: config.dynamic_title(), - tabspaces, clipboard, event_proxy, is_focused: true, @@ -1188,7 +1184,7 @@ impl Term { self.cursor_save_alt.point.line = min(self.cursor_save_alt.point.line, num_lines - 1); // Recreate tabs list - self.tabs = TabStops::new(self.grid.num_cols(), self.tabspaces); + self.tabs.resize(self.grid.num_cols()); } #[inline] @@ -1542,9 +1538,14 @@ impl Handler for Term { self.goto(move_to, Column(0)) } + /// Insert tab at cursor position. #[inline] fn put_tab(&mut self, mut count: i64) { - trace!("Putting tab: {}", count); + // A tab after the last column is the same as a linebreak + if self.input_needs_wrap { + self.wrapline(); + return; + } while self.cursor.point.col < self.grid.num_cols() && count != 0 { count -= 1; @@ -1566,8 +1567,6 @@ impl Handler for Term { } } } - - self.input_needs_wrap = false; } /// Backspace `count` characters @@ -2155,22 +2154,39 @@ impl Handler for Term { struct TabStops { tabs: Vec, + tabspaces: usize, } impl TabStops { + #[inline] fn new(num_cols: Column, tabspaces: usize) -> TabStops { TabStops { + tabspaces, tabs: IndexRange::from(Column(0)..num_cols) .map(|i| (*i as usize) % tabspaces == 0) .collect::>(), } } + /// Remove all tabstops. + #[inline] fn clear_all(&mut self) { unsafe { ptr::write_bytes(self.tabs.as_mut_ptr(), 0, self.tabs.len()); } } + + /// Increase tabstop capacity. + #[inline] + fn resize(&mut self, num_cols: Column) { + let tabspaces = self.tabspaces; + let mut index = self.tabs.len(); + self.tabs.resize_with(num_cols.0, || { + let is_tabstop = index % tabspaces == 0; + index += 1; + is_tabstop + }); + } } impl Index for TabStops {