From 9ee1cf2455d5512b087757e09451f9d122548da2 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Fri, 23 Mar 2018 01:01:55 +0100 Subject: [PATCH] Rework auto-scrolling options This changes two things, the first thing it does is that now whenever a keybinding sends an escape sequence, the viewport is automatically scrolled to the bottom. This is enabled by default and fixes #1187. The second thing is automatic scrolling when a command writes to the terminal. So when running a command like `sleep 3; ls -lah`, alacritty will scroll to the bottom once the output is sent, even if the viewport is currently not at the bottom of the scrollback. Because this can have an impact on performance, and is not enabled by default in terminals like iTerm or Termite (VTE), it is an opt-in setting in the config. --- alacritty.yml | 4 ++++ alacritty_macos.yml | 4 ++++ src/config.rs | 3 +++ src/event_loop.rs | 15 +++++++++++---- src/input.rs | 1 + src/term/mod.rs | 10 ++++++++++ 6 files changed, 33 insertions(+), 4 deletions(-) diff --git a/alacritty.yml b/alacritty.yml index 0cb866d7..b45359b7 100644 --- a/alacritty.yml +++ b/alacritty.yml @@ -52,6 +52,10 @@ scrolling: # To disable this completely, set `faux_multiplier` to 0. faux_multiplier: 3 + # Automatically scroll to the bottom when new text is written + # to the terminal. + auto_scroll: false + # Display tabs using this many cells (changes require restart) tabspaces: 8 diff --git a/alacritty_macos.yml b/alacritty_macos.yml index e7646fbc..cb782a00 100644 --- a/alacritty_macos.yml +++ b/alacritty_macos.yml @@ -50,6 +50,10 @@ scrolling: # To disable this completely, set `faux_multiplier` to 0. faux_multiplier: 3 + # Automatically scroll to the bottom when new text is written + # to the terminal. + auto_scroll: false + # Display tabs using this many cells (changes require restart) tabspaces: 8 diff --git a/src/config.rs b/src/config.rs index 57a23719..45099419 100644 --- a/src/config.rs +++ b/src/config.rs @@ -478,6 +478,8 @@ pub struct Scrolling { #[serde(deserialize_with="deserialize_scrolling_multiplier")] #[serde(default="default_scrolling_multiplier")] pub faux_multiplier: u8, + #[serde(default, deserialize_with="failure_default")] + pub auto_scroll: bool, } fn default_scrolling_history() -> u32 { @@ -495,6 +497,7 @@ impl Default for Scrolling { history: default_scrolling_history(), multiplier: default_scrolling_multiplier(), faux_multiplier: default_scrolling_multiplier(), + auto_scroll: false, } } } diff --git a/src/event_loop.rs b/src/event_loop.rs index ce034ff0..c81d83c9 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -255,6 +255,9 @@ impl EventLoop let mut processed = 0; let mut terminal = None; + // Flag to keep track if wakeup has already been sent + let mut send_wakeup = false; + loop { match self.pty.read(&mut buf[..]) { Ok(0) => break, @@ -272,10 +275,14 @@ impl EventLoop // Get reference to terminal. Lock is acquired on initial // iteration and held until there's no bytes left to parse // or we've reached MAX_READ. - if terminal.is_none() { + let terminal = if terminal.is_none() { terminal = Some(self.terminal.lock()); - } - let terminal = terminal.as_mut().unwrap(); + let terminal = terminal.as_mut().unwrap(); + send_wakeup = !terminal.dirty; + terminal + } else { + terminal.as_mut().unwrap() + }; // Run the parser for byte in &buf[..got] { @@ -301,7 +308,7 @@ impl EventLoop // Only request a draw if one hasn't already been requested. if let Some(mut terminal) = terminal { - if !terminal.dirty { + if send_wakeup { self.display.notify(); terminal.dirty = true; } diff --git a/src/input.rs b/src/input.rs index 904f252a..57b49ffc 100644 --- a/src/input.rs +++ b/src/input.rs @@ -192,6 +192,7 @@ impl Action { fn execute(&self, ctx: &mut A) { match *self { Action::Esc(ref s) => { + ctx.scroll(Scroll::Bottom); ctx.write_to_pty(s.clone().into_bytes()) }, Action::Copy => { diff --git a/src/term/mod.rs b/src/term/mod.rs index c97cd84d..dee758ab 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -755,6 +755,9 @@ pub struct Term { /// Number of spaces in one tab tabspaces: usize, + + /// Automatically scroll to bottom when new lines are added + auto_scroll: bool, } /// Terminal size info @@ -878,6 +881,7 @@ impl Term { default_cursor_style: config.cursor_style(), dynamic_title: config.dynamic_title(), tabspaces, + auto_scroll: config.scrolling().auto_scroll, } } @@ -904,6 +908,7 @@ impl Term { self.visual_bell.update_config(config); self.default_cursor_style = config.cursor_style(); self.dynamic_title = config.dynamic_title(); + self.auto_scroll = config.scrolling().auto_scroll; } #[inline] @@ -1253,6 +1258,11 @@ impl ansi::Handler for Term { /// A character to be displayed #[inline] fn input(&mut self, c: char) { + // If enabled, scroll to bottom when character is received + if self.auto_scroll { + self.scroll_display(Scroll::Bottom); + } + if self.input_needs_wrap { if !self.mode.contains(mode::TermMode::LINE_WRAP) { return;