mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-18 13:55:23 -05:00
Implement ansi::ClearMode::Saved
The clearing the screen for the `ansi::ClearMode::Saved` enum value has been implemented. This is used to clear all lines which are currently outside of the visible region but still inside the scrollback buffer. The specifications of XTerm indicate that the clearing of saved lines should only clear the saved lines and not the saved lines plus the currently visible part of the grid. Applications like `clear` send both the escape for clearing history plus the escape for clearing history when requested, so all sources seem to agree here. To allow both clearing the screen and the saved lines when a key is pressed the `process_key_bindings` method has been altered so multiple bindings can be specified. So it is now possible to execute both `^L` and `ClearHistory` with just a single binding. The `process_mouse_bindings` method has also been changed for consistency. To make sure everything works properly a test has been added which clears the history and then attempts to scroll. Since scrolling is the only way for a user to check if scrollback is available, this seems like a nice abstraction to check if there is a scrollback.
This commit is contained in:
parent
8e8ecdd0f9
commit
72495172c2
6 changed files with 57 additions and 16 deletions
|
@ -315,6 +315,8 @@ key_bindings:
|
||||||
- { key: Key0, mods: Command, action: ResetFontSize }
|
- { key: Key0, mods: Command, action: ResetFontSize }
|
||||||
- { key: Equals, mods: Command, action: IncreaseFontSize }
|
- { key: Equals, mods: Command, action: IncreaseFontSize }
|
||||||
- { key: Minus, mods: Command, action: DecreaseFontSize }
|
- { key: Minus, mods: Command, action: DecreaseFontSize }
|
||||||
|
- { key: K, mods: Command, action: ClearHistory }
|
||||||
|
- { key: K, mods: Command, chars: "\x0c" }
|
||||||
- { key: PageUp, mods: Shift, chars: "\x1b[5;2~" }
|
- { key: PageUp, mods: Shift, chars: "\x1b[5;2~" }
|
||||||
- { key: PageUp, mods: Control, chars: "\x1b[5;5~" }
|
- { key: PageUp, mods: Control, chars: "\x1b[5;5~" }
|
||||||
- { key: PageUp, chars: "\x1b[5~" }
|
- { key: PageUp, chars: "\x1b[5~" }
|
||||||
|
|
|
@ -598,7 +598,7 @@ impl<'a> de::Deserialize<'a> for ActionWrapper {
|
||||||
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.write_str("Paste, Copy, PasteSelection, IncreaseFontSize, DecreaseFontSize, \
|
f.write_str("Paste, Copy, PasteSelection, IncreaseFontSize, DecreaseFontSize, \
|
||||||
ResetFontSize, ScrollPageUp, ScrollPageDown, ScrollToTop, \
|
ResetFontSize, ScrollPageUp, ScrollPageDown, ScrollToTop, \
|
||||||
ScrollToBottom, Hide, or Quit")
|
ScrollToBottom, ClearHistory, Hide, or Quit")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> ::std::result::Result<ActionWrapper, E>
|
fn visit_str<E>(self, value: &str) -> ::std::result::Result<ActionWrapper, E>
|
||||||
|
@ -615,6 +615,7 @@ impl<'a> de::Deserialize<'a> for ActionWrapper {
|
||||||
"ScrollPageDown" => Action::ScrollPageDown,
|
"ScrollPageDown" => Action::ScrollPageDown,
|
||||||
"ScrollToTop" => Action::ScrollToTop,
|
"ScrollToTop" => Action::ScrollToTop,
|
||||||
"ScrollToBottom" => Action::ScrollToBottom,
|
"ScrollToBottom" => Action::ScrollToBottom,
|
||||||
|
"ClearHistory" => Action::ClearHistory,
|
||||||
"Hide" => Action::Hide,
|
"Hide" => Action::Hide,
|
||||||
"Quit" => Action::Quit,
|
"Quit" => Action::Quit,
|
||||||
_ => return Err(E::invalid_value(Unexpected::Str(value), &self)),
|
_ => return Err(E::invalid_value(Unexpected::Str(value), &self)),
|
||||||
|
|
|
@ -10,6 +10,7 @@ use parking_lot::MutexGuard;
|
||||||
use glutin::{self, ModifiersState, Event, ElementState};
|
use glutin::{self, ModifiersState, Event, ElementState};
|
||||||
use copypasta::{Clipboard, Load, Store};
|
use copypasta::{Clipboard, Load, Store};
|
||||||
|
|
||||||
|
use ansi::{Handler, ClearMode};
|
||||||
use grid::Scroll;
|
use grid::Scroll;
|
||||||
use config::{self, Config};
|
use config::{self, Config};
|
||||||
use cli::Options;
|
use cli::Options;
|
||||||
|
@ -59,6 +60,10 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
|
||||||
self.terminal.scroll_display(scroll);
|
self.terminal.scroll_display(scroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clear_history(&mut self) {
|
||||||
|
self.terminal.clear_screen(ClearMode::Saved);
|
||||||
|
}
|
||||||
|
|
||||||
fn copy_selection(&self, buffer: ::copypasta::Buffer) {
|
fn copy_selection(&self, buffer: ::copypasta::Buffer) {
|
||||||
if let Some(selected) = self.terminal.selection_to_string() {
|
if let Some(selected) = self.terminal.selection_to_string() {
|
||||||
if !selected.is_empty() {
|
if !selected.is_empty() {
|
||||||
|
|
|
@ -219,14 +219,9 @@ impl<T: Copy + Clone> Grid<T> {
|
||||||
|
|
||||||
/// Add lines to the visible area
|
/// Add lines to the visible area
|
||||||
///
|
///
|
||||||
/// The behavior in Terminal.app and iTerm.app is to keep the cursor at the
|
/// Alacritty keeps the cursor at the bottom of the terminal as long as there
|
||||||
/// bottom of the screen as long as there is scrollback available. Once
|
/// is scrollback available. Once scrollback is exhausted, new lines are
|
||||||
/// scrollback is exhausted, new lines are simply added to the bottom of the
|
/// simply added to the bottom of the screen.
|
||||||
/// screen.
|
|
||||||
///
|
|
||||||
/// Alacritty takes a different approach. Rather than trying to move with
|
|
||||||
/// the scrollback, we simply pull additional lines from the back of the
|
|
||||||
/// buffer in order to populate the new area.
|
|
||||||
fn grow_lines(
|
fn grow_lines(
|
||||||
&mut self,
|
&mut self,
|
||||||
new_line_count: index::Line,
|
new_line_count: index::Line,
|
||||||
|
|
19
src/input.rs
19
src/input.rs
|
@ -69,6 +69,7 @@ pub trait ActionContext {
|
||||||
fn change_font_size(&mut self, delta: f32);
|
fn change_font_size(&mut self, delta: f32);
|
||||||
fn reset_font_size(&mut self);
|
fn reset_font_size(&mut self);
|
||||||
fn scroll(&mut self, scroll: Scroll);
|
fn scroll(&mut self, scroll: Scroll);
|
||||||
|
fn clear_history(&mut self);
|
||||||
fn hide_window(&mut self);
|
fn hide_window(&mut self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,6 +184,9 @@ pub enum Action {
|
||||||
/// Scroll all the way to the bottom
|
/// Scroll all the way to the bottom
|
||||||
ScrollToBottom,
|
ScrollToBottom,
|
||||||
|
|
||||||
|
/// Clear the display buffer(s) to remove history
|
||||||
|
ClearHistory,
|
||||||
|
|
||||||
/// Run given command
|
/// Run given command
|
||||||
Command(String, Vec<String>),
|
Command(String, Vec<String>),
|
||||||
|
|
||||||
|
@ -272,6 +276,9 @@ impl Action {
|
||||||
Action::ScrollToBottom => {
|
Action::ScrollToBottom => {
|
||||||
ctx.scroll(Scroll::Bottom);
|
ctx.scroll(Scroll::Bottom);
|
||||||
},
|
},
|
||||||
|
Action::ClearHistory => {
|
||||||
|
ctx.clear_history();
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -634,15 +641,16 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
///
|
///
|
||||||
/// Returns true if an action is executed.
|
/// Returns true if an action is executed.
|
||||||
fn process_key_bindings(&mut self, mods: ModifiersState, key: VirtualKeyCode) -> bool {
|
fn process_key_bindings(&mut self, mods: ModifiersState, key: VirtualKeyCode) -> bool {
|
||||||
|
let mut has_binding = false;
|
||||||
for binding in self.key_bindings {
|
for binding in self.key_bindings {
|
||||||
if binding.is_triggered_by(self.ctx.terminal_mode(), mods, &key) {
|
if binding.is_triggered_by(self.ctx.terminal_mode(), mods, &key) {
|
||||||
// binding was triggered; run the action
|
// binding was triggered; run the action
|
||||||
binding.execute(&mut self.ctx);
|
binding.execute(&mut self.ctx);
|
||||||
return true;
|
has_binding = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
has_binding
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to find a binding and execute its action
|
/// Attempts to find a binding and execute its action
|
||||||
|
@ -652,15 +660,16 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
///
|
///
|
||||||
/// Returns true if an action is executed.
|
/// Returns true if an action is executed.
|
||||||
fn process_mouse_bindings(&mut self, mods: ModifiersState, button: MouseButton) -> bool {
|
fn process_mouse_bindings(&mut self, mods: ModifiersState, button: MouseButton) -> bool {
|
||||||
|
let mut has_binding = false;
|
||||||
for binding in self.mouse_bindings {
|
for binding in self.mouse_bindings {
|
||||||
if binding.is_triggered_by(self.ctx.terminal_mode(), mods, &button) {
|
if binding.is_triggered_by(self.ctx.terminal_mode(), mods, &button) {
|
||||||
// binding was triggered; run the action
|
// binding was triggered; run the action
|
||||||
binding.execute(&mut self.ctx);
|
binding.execute(&mut self.ctx);
|
||||||
return true;
|
has_binding = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
has_binding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,6 +765,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
fn reset_font_size(&mut self) {
|
fn reset_font_size(&mut self) {
|
||||||
}
|
}
|
||||||
|
fn clear_history(&mut self) {
|
||||||
|
}
|
||||||
fn hide_window(&mut self) {
|
fn hide_window(&mut self) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1797,7 +1797,9 @@ impl ansi::Handler for Term {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// If scrollback is implemented, this should clear it
|
// If scrollback is implemented, this should clear it
|
||||||
ansi::ClearMode::Saved => return
|
ansi::ClearMode::Saved => {
|
||||||
|
self.grid.clear_history();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2006,9 +2008,9 @@ mod tests {
|
||||||
use super::{Cell, Term, SizeInfo};
|
use super::{Cell, Term, SizeInfo};
|
||||||
use term::cell;
|
use term::cell;
|
||||||
|
|
||||||
use grid::Grid;
|
use grid::{Grid, Scroll};
|
||||||
use index::{Point, Line, Column};
|
use index::{Point, Line, Column};
|
||||||
use ansi::{Handler, CharsetIndex, StandardCharset};
|
use ansi::{self, Handler, CharsetIndex, StandardCharset};
|
||||||
use selection::Selection;
|
use selection::Selection;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use input::FONT_SIZE_STEP;
|
use input::FONT_SIZE_STEP;
|
||||||
|
@ -2183,6 +2185,31 @@ mod tests {
|
||||||
let expected_font_size: Size = config.font().size();
|
let expected_font_size: Size = config.font().size();
|
||||||
assert_eq!(term.font_size, expected_font_size);
|
assert_eq!(term.font_size, expected_font_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
};
|
||||||
|
let config: Config = Default::default();
|
||||||
|
let mut term: Term = Term::new(&config, size);
|
||||||
|
|
||||||
|
// Add one line of scrollback
|
||||||
|
term.grid.scroll_up(&(Line(0)..Line(1)), Line(1), &Cell::default());
|
||||||
|
|
||||||
|
// Clear the history
|
||||||
|
term.clear_screen(ansi::ClearMode::Saved);
|
||||||
|
|
||||||
|
// Make sure that scrolling does not change the grid
|
||||||
|
let mut scrolled_grid = term.grid.clone();
|
||||||
|
scrolled_grid.scroll_display(Scroll::Top);
|
||||||
|
assert_eq!(term.grid, scrolled_grid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(test, feature = "bench"))]
|
#[cfg(all(test, feature = "bench"))]
|
||||||
|
|
Loading…
Reference in a new issue