From 45c2b3fbf72fa6dfd36bee590e64314c6da7c6c2 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Thu, 15 Feb 2018 18:35:49 -0800 Subject: checkpoint: very basic scrolling works Things that do not work - Limiting how far back in the buffer it's possible to scroll - Selections (need to transform to buffer offsets) --- src/input.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 2d603783..2e345c2a 100644 --- a/src/input.rs +++ b/src/input.rs @@ -64,6 +64,7 @@ pub trait ActionContext { fn last_modifiers(&mut self) -> &mut ModifiersState; fn change_font_size(&mut self, delta: i8); fn reset_font_size(&mut self); + fn scroll(&mut self, count: isize) {} } /// Describes a state and action to take in that state @@ -428,10 +429,6 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { pub fn on_mouse_wheel(&mut self, delta: MouseScrollDelta, phase: TouchPhase, modifiers: ModifiersState) { let mouse_modes = TermMode::MOUSE_REPORT_CLICK | TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION; - if !self.ctx.terminal_mode().intersects(mouse_modes | TermMode::ALT_SCREEN) { - return; - } - match delta { MouseScrollDelta::LineDelta(_columns, lines) => { let to_scroll = self.ctx.mouse_mut().lines_scrolled + lines; @@ -482,16 +479,19 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { let mouse_modes = TermMode::MOUSE_REPORT_CLICK | TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION; if self.ctx.terminal_mode().intersects(mouse_modes) { self.mouse_report(code, ElementState::Pressed, modifiers); - } else if faux_scrollback_lines > 0 { - // Faux scrolling - let cmd = code + 1; // 64 + 1 = A, 65 + 1 = B - let mut content = Vec::with_capacity(faux_scrollback_lines * 3); - for _ in 0..faux_scrollback_lines { - content.push(0x1b); - content.push(b'O'); - content.push(cmd); - } - self.ctx.write_to_pty(content); + // } else if faux_scrollback_lines > 0 { + // // Faux scrolling + // let cmd = code + 1; // 64 + 1 = A, 65 + 1 = B + // let mut content = Vec::with_capacity(faux_scrollback_lines * 3); + // for _ in 0..faux_scrollback_lines { + // content.push(0x1b); + // content.push(b'O'); + // content.push(cmd); + // } + // self.ctx.write_to_pty(content); + // } + } else { + self.ctx.scroll(-((code as isize) * 2 - 129)); } } -- cgit From 7fe67743ebffd047532f6271bf28474f9d947f64 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Fri, 16 Feb 2018 17:33:32 -0800 Subject: Scroll to bottom on character received --- src/input.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 2e345c2a..68787979 100644 --- a/src/input.rs +++ b/src/input.rs @@ -65,6 +65,7 @@ pub trait ActionContext { fn change_font_size(&mut self, delta: i8); fn reset_font_size(&mut self); fn scroll(&mut self, count: isize) {} + fn reset_scroll(&mut self) {} } /// Describes a state and action to take in that state @@ -560,6 +561,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { /// Process a received character pub fn received_char(&mut self, c: char) { if !*self.ctx.suppress_chars() { + self.ctx.reset_scroll(); self.ctx.clear_selection(); let utf8_len = c.len_utf8(); -- cgit From 452126013e9fa898b801d8e8f4f26adcaaa67c69 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Wed, 7 Mar 2018 09:56:19 -0800 Subject: Add SCROLL_MULTIPLIER Scroll wheel needs some scaling so it feels like urxvt and friends. --- src/input.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 68787979..ad9fcd39 100644 --- a/src/input.rs +++ b/src/input.rs @@ -34,6 +34,8 @@ use term::SizeInfo; use term::mode::TermMode; use util::fmt::Red; +const SCROLL_MULTIPLIER: usize = 3; + /// Processes input from glutin. /// /// An escape sequence may be emitted in case specific keys or key combinations @@ -439,7 +441,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { 65 }; - for _ in 0..(to_scroll.abs() as usize) { + for _ in 0..(to_scroll.abs() as usize * SCROLL_MULTIPLIER) { self.scroll_terminal(code, modifiers) } -- cgit From 9a5a0ec546f4cbb6206c4c7cc9900211a3bbefa5 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Fri, 9 Mar 2018 11:17:47 +0100 Subject: Add faux_scrolling back to scrollback --- src/input.rs | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index ad9fcd39..1974a348 100644 --- a/src/input.rs +++ b/src/input.rs @@ -441,8 +441,8 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { 65 }; - for _ in 0..(to_scroll.abs() as usize * SCROLL_MULTIPLIER) { - self.scroll_terminal(code, modifiers) + for _ in 0..(to_scroll.abs() as usize) { + self.scroll_terminal(code, modifiers, SCROLL_MULTIPLIER) } self.ctx.mouse_mut().lines_scrolled = to_scroll % 1.0; @@ -466,7 +466,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { 65 }; - self.scroll_terminal(code, modifiers) + self.scroll_terminal(code, modifiers, 1) } }, _ => (), @@ -475,26 +475,29 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { } } - fn scroll_terminal(&mut self, code: u8, modifiers: ModifiersState) { + fn scroll_terminal(&mut self, code: u8, modifiers: ModifiersState, scroll_multiplier: usize) { debug_assert!(code == 64 || code == 65); let faux_scrollback_lines = self.mouse_config.faux_scrollback_lines; let mouse_modes = TermMode::MOUSE_REPORT_CLICK | TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION; if self.ctx.terminal_mode().intersects(mouse_modes) { self.mouse_report(code, ElementState::Pressed, modifiers); - // } else if faux_scrollback_lines > 0 { - // // Faux scrolling - // let cmd = code + 1; // 64 + 1 = A, 65 + 1 = B - // let mut content = Vec::with_capacity(faux_scrollback_lines * 3); - // for _ in 0..faux_scrollback_lines { - // content.push(0x1b); - // content.push(b'O'); - // content.push(cmd); - // } - // self.ctx.write_to_pty(content); - // } + } else if self.ctx.terminal_mode().contains(TermMode::ALT_SCREEN) + && faux_scrollback_lines > 0 + { + // Faux scrolling + let cmd = code + 1; // 64 + 1 = A, 65 + 1 = B + let mut content = Vec::with_capacity(faux_scrollback_lines * 3); + for _ in 0..faux_scrollback_lines { + content.push(0x1b); + content.push(b'O'); + content.push(cmd); + } + self.ctx.write_to_pty(content); } else { - self.ctx.scroll(-((code as isize) * 2 - 129)); + for _ in 0..scroll_multiplier { + self.ctx.scroll(-((code as isize) * 2 - 129)); + } } } -- cgit From 786e274dd1d6dce26404a2ad5672ee33e6115ad0 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Fri, 9 Mar 2018 23:09:42 +0100 Subject: Disable faux scrolling when shift is pressed To make it possible to access the native scrollback buffer in the alternate screen without having to disable faux scrolling, faux scrolling is now disabled when the `shift` key is held down. This should allow alacritty to have the best of both worlds, a native scrollback buffer in the alternate screen buffer and faux scrolling. --- src/input.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 1974a348..35ae4a38 100644 --- a/src/input.rs +++ b/src/input.rs @@ -483,7 +483,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { if self.ctx.terminal_mode().intersects(mouse_modes) { self.mouse_report(code, ElementState::Pressed, modifiers); } else if self.ctx.terminal_mode().contains(TermMode::ALT_SCREEN) - && faux_scrollback_lines > 0 + && faux_scrollback_lines > 0 && !modifiers.shift { // Faux scrolling let cmd = code + 1; // 64 + 1 = A, 65 + 1 = B -- cgit From dab0eca4a7bbb94e728465ca0248fbbbf32e6674 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Fri, 9 Mar 2018 16:06:39 +0100 Subject: Make normal scrolling line amount configurable It is now possible to configure the amount of lines the viewport should scroll when using the normal scrolling mode. This fixes #1160. --- src/input.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 35ae4a38..20a0b25b 100644 --- a/src/input.rs +++ b/src/input.rs @@ -34,8 +34,6 @@ use term::SizeInfo; use term::mode::TermMode; use util::fmt::Red; -const SCROLL_MULTIPLIER: usize = 3; - /// Processes input from glutin. /// /// An escape sequence may be emitted in case specific keys or key combinations @@ -431,7 +429,6 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { } pub fn on_mouse_wheel(&mut self, delta: MouseScrollDelta, phase: TouchPhase, modifiers: ModifiersState) { - let mouse_modes = TermMode::MOUSE_REPORT_CLICK | TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION; match delta { MouseScrollDelta::LineDelta(_columns, lines) => { let to_scroll = self.ctx.mouse_mut().lines_scrolled + lines; @@ -441,8 +438,9 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { 65 }; + let scrolling_multiplier = self.mouse_config.normal_scrolling_lines; for _ in 0..(to_scroll.abs() as usize) { - self.scroll_terminal(code, modifiers, SCROLL_MULTIPLIER) + self.scroll_terminal(code, modifiers, scrolling_multiplier) } self.ctx.mouse_mut().lines_scrolled = to_scroll % 1.0; @@ -475,7 +473,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { } } - fn scroll_terminal(&mut self, code: u8, modifiers: ModifiersState, scroll_multiplier: usize) { + fn scroll_terminal(&mut self, code: u8, modifiers: ModifiersState, scroll_multiplier: u8) { debug_assert!(code == 64 || code == 65); let faux_scrollback_lines = self.mouse_config.faux_scrollback_lines; @@ -487,7 +485,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { { // Faux scrolling let cmd = code + 1; // 64 + 1 = A, 65 + 1 = B - let mut content = Vec::with_capacity(faux_scrollback_lines * 3); + let mut content = Vec::with_capacity(faux_scrollback_lines as usize * 3); for _ in 0..faux_scrollback_lines { content.push(0x1b); content.push(b'O'); -- cgit From d3f64072f3fe4d31f7a60eb0cb17a98096617b4b Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Fri, 9 Mar 2018 19:45:40 +0100 Subject: Merge branch #1095 Because there was some overlap with branch #1095, these two PRs have been added together and the config has been restructured to make use of a `scrolling` section. The default faux scrolling amount has also been changed to `3` because this simplifies the code and falls in line with what most other terminal emulators do. There should be no additional test failures due to this. --- src/input.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 20a0b25b..3ff631e0 100644 --- a/src/input.rs +++ b/src/input.rs @@ -44,6 +44,7 @@ pub struct Processor<'a, A: 'a> { pub key_bindings: &'a [KeyBinding], pub mouse_bindings: &'a [MouseBinding], pub mouse_config: &'a config::Mouse, + pub scrolling_config: &'a config::Scrolling, pub ctx: A, } @@ -756,8 +757,9 @@ mod tests { triple_click: ClickHandler { threshold: Duration::from_millis(1000), }, - faux_scrollback_lines: 1, + faux_scrollback_lines: None, }, + scrolling_config: &config::Scrolling::default(), key_bindings: &config.key_bindings()[..], mouse_bindings: &config.mouse_bindings()[..], }; -- cgit From a238e9ac5832cb9a40f886a3b873728cd7890d01 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Fri, 9 Mar 2018 23:02:45 +0100 Subject: Fix linux config default value --- src/input.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 3ff631e0..16fddc2c 100644 --- a/src/input.rs +++ b/src/input.rs @@ -439,7 +439,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { 65 }; - let scrolling_multiplier = self.mouse_config.normal_scrolling_lines; + let scrolling_multiplier = self.scrolling_config.multiplier; for _ in 0..(to_scroll.abs() as usize) { self.scroll_terminal(code, modifiers, scrolling_multiplier) } @@ -477,8 +477,13 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { fn scroll_terminal(&mut self, code: u8, modifiers: ModifiersState, scroll_multiplier: u8) { debug_assert!(code == 64 || code == 65); - let faux_scrollback_lines = self.mouse_config.faux_scrollback_lines; let mouse_modes = TermMode::MOUSE_REPORT_CLICK | TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION; + + // Make sure the new and deprecated setting are both allowed + let faux_scrollback_lines = self.mouse_config + .faux_scrollback_lines + .unwrap_or(self.scrolling_config.faux_multiplier as usize); + if self.ctx.terminal_mode().intersects(mouse_modes) { self.mouse_report(code, ElementState::Pressed, modifiers); } else if self.ctx.terminal_mode().contains(TermMode::ALT_SCREEN) -- cgit From d9bd21d33f7f35d1362a581cefb1c897a821fcad Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sat, 10 Mar 2018 12:14:58 +0100 Subject: Fix selection in scrollback There were a few issues with selection in scrollback that were mainly off-by-one errors. This aims at fixing these issues. This also fixes a bug that currently exists in master where the last cell is not selected when the mouse leaves the window to the right. --- src/input.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 16fddc2c..7b9eda56 100644 --- a/src/input.rs +++ b/src/input.rs @@ -278,7 +278,10 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { let cell_x = (x as usize - size_info.padding_x as usize) % size_info.cell_width as usize; let half_cell_width = (size_info.cell_width / 2.0) as usize; - let cell_side = if cell_x > half_cell_width { + let cell_side = if cell_x > half_cell_width + // Edge case when mouse leaves the window + || x as f32 >= size_info.width - size_info.padding_x + { Side::Right } else { Side::Left -- cgit From 58c69cafad3b1dafa3631d911c6bfc21f5e5dec5 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Tue, 13 Mar 2018 19:00:14 +0100 Subject: Fix multi-line selection with single cell end When the user selected multiple lines, dragging the selection downwards, and then leaves the cursor to the left side of the first cell, the first cell was still incorrectly selected. This has been fixed. The selection also did not update if the mouse was outside of the window, now all movement events are accpeted even when the mouse is outside of the window. This allows updating the selection when the user is dragging the cursor too far. Mouse movement and click events outside of the window are not propagated, these are only used for updating the selection. --- src/input.rs | 87 +++++++++++++++++++++++++++++------------------------------- 1 file changed, 42 insertions(+), 45 deletions(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 7b9eda56..98e0d241 100644 --- a/src/input.rs +++ b/src/input.rs @@ -266,55 +266,52 @@ impl From<&'static str> for Action { impl<'a, A: ActionContext + 'a> Processor<'a, A> { #[inline] - pub fn mouse_moved(&mut self, x: u32, y: u32, modifiers: ModifiersState) { + pub fn mouse_moved(&mut self, x: usize, y: usize, modifiers: ModifiersState) { self.ctx.mouse_mut().x = x; self.ctx.mouse_mut().y = y; let size_info = self.ctx.size_info(); - if let Some(point) = size_info.pixels_to_coords(x as usize, y as usize) { - let prev_line = mem::replace(&mut self.ctx.mouse_mut().line, point.line); - let prev_col = mem::replace(&mut self.ctx.mouse_mut().column, point.col); - - let cell_x = (x as usize - size_info.padding_x as usize) % size_info.cell_width as usize; - let half_cell_width = (size_info.cell_width / 2.0) as usize; - - let cell_side = if cell_x > half_cell_width - // Edge case when mouse leaves the window - || x as f32 >= size_info.width - size_info.padding_x - { - Side::Right - } else { - Side::Left - }; - self.ctx.mouse_mut().cell_side = cell_side; - - let motion_mode = TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG; - if self.ctx.mouse_mut().left_button_state == ElementState::Pressed - && ( - modifiers.shift - || !self.ctx.terminal_mode().intersects(TermMode::MOUSE_REPORT_CLICK | motion_mode) - ) - { - self.ctx.update_selection(Point { - line: point.line, - col: point.col - }, cell_side); - } else if self.ctx.terminal_mode().intersects(motion_mode) - // Only report motion when changing cells - && ( - prev_line != self.ctx.mouse_mut().line - || prev_col != self.ctx.mouse_mut().column - ) - { - if self.ctx.mouse_mut().left_button_state == ElementState::Pressed { - self.mouse_report(32, ElementState::Pressed, modifiers); - } else if self.ctx.mouse_mut().middle_button_state == ElementState::Pressed { - self.mouse_report(33, ElementState::Pressed, modifiers); - } else if self.ctx.mouse_mut().right_button_state == ElementState::Pressed { - self.mouse_report(34, ElementState::Pressed, modifiers); - } else if self.ctx.terminal_mode().contains(TermMode::MOUSE_MOTION) { - self.mouse_report(35, ElementState::Pressed, modifiers); - } + let point = size_info.pixels_to_coords(x, y); + + let prev_line = mem::replace(&mut self.ctx.mouse_mut().line, point.line); + let prev_col = mem::replace(&mut self.ctx.mouse_mut().column, point.col); + + let cell_x = x.saturating_sub(size_info.padding_x as usize) % size_info.cell_width as usize; + let half_cell_width = (size_info.cell_width / 2.0) as usize; + + let cell_side = if cell_x > half_cell_width + // Edge case when mouse leaves the window + || x as f32 >= size_info.width - size_info.padding_x + { + Side::Right + } else { + Side::Left + }; + self.ctx.mouse_mut().cell_side = cell_side; + + let motion_mode = TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG; + let report_mode = TermMode::MOUSE_REPORT_CLICK | motion_mode; + + if self.ctx.mouse_mut().left_button_state == ElementState::Pressed && + ( modifiers.shift || !self.ctx.terminal_mode().intersects(report_mode)) + { + self.ctx.update_selection(Point { + line: point.line, + col: point.col + }, cell_side); + } else if self.ctx.terminal_mode().intersects(motion_mode) + // Only report motion when changing cells + && (prev_line != self.ctx.mouse_mut().line || prev_col != self.ctx.mouse_mut().column) + && size_info.contains_point(x, y) + { + if self.ctx.mouse_mut().left_button_state == ElementState::Pressed { + self.mouse_report(32, ElementState::Pressed, modifiers); + } else if self.ctx.mouse_mut().middle_button_state == ElementState::Pressed { + self.mouse_report(33, ElementState::Pressed, modifiers); + } else if self.ctx.mouse_mut().right_button_state == ElementState::Pressed { + self.mouse_report(34, ElementState::Pressed, modifiers); + } else if self.ctx.terminal_mode().contains(TermMode::MOUSE_MOTION) { + self.mouse_report(35, ElementState::Pressed, modifiers); } } } -- cgit From 2c7bb9a4d3ce3ead6de4ca6485ca67c44c0bd1c1 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sat, 10 Mar 2018 20:24:10 +0100 Subject: Add scrollback hotkeys This offers a few additional hotkeys that can be used in combination with scrollback. None of these are used by default yet. This implements the following bindings: - ScrollPageUp: Scroll exactly one screen height up - ScrollPageDown: Scroll exactly one screen height down - ScrollToTop: Scroll as far up as possible - ScrollToBottom: Scroll as far down as possible This fixes #1151. --- src/input.rs | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 98e0d241..adce3448 100644 --- a/src/input.rs +++ b/src/input.rs @@ -65,8 +65,11 @@ pub trait ActionContext { fn last_modifiers(&mut self) -> &mut ModifiersState; fn change_font_size(&mut self, delta: i8); fn reset_font_size(&mut self); - fn scroll(&mut self, count: isize) {} - fn reset_scroll(&mut self) {} + fn scroll(&mut self, count: isize); + fn reset_scroll(&mut self); + fn scroll_to_top(&mut self); + fn scroll_page_up(&mut self); + fn scroll_page_down(&mut self); } /// Describes a state and action to take in that state @@ -168,6 +171,18 @@ pub enum Action { /// Reset font size to the config value ResetFontSize, + /// Scroll exactly one page up + ScrollPageUp, + + /// Scroll exactly one page down + ScrollPageDown, + + /// Scroll all the way to the top + ScrollToTop, + + /// Scroll all the way to the bottom + ScrollToBottom, + /// Run given command Command(String, Vec), @@ -237,7 +252,19 @@ impl Action { } Action::ResetFontSize => { ctx.reset_font_size(); - } + }, + Action::ScrollPageUp => { + ctx.scroll_page_up(); + }, + Action::ScrollPageDown => { + ctx.scroll_page_down(); + }, + Action::ScrollToTop => { + ctx.scroll_to_top(); + }, + Action::ScrollToBottom => { + ctx.reset_scroll(); + }, } } -- cgit From 0dcb9ca6a871fd6d28787142a134c9190001ac43 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sun, 11 Mar 2018 13:01:06 +0100 Subject: Replace scrolling methods with enum The different scrolling methods added a bunch of boilerplate where the call was just forwarded to the next struct, this has been removed by making the scroll amount into a struct. Now everything is called through one method and the parameter decides how far the viewport should be scrolled. --- src/input.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index adce3448..8cf11811 100644 --- a/src/input.rs +++ b/src/input.rs @@ -28,6 +28,7 @@ use copypasta::{Clipboard, Load, Buffer}; use glutin::{ElementState, VirtualKeyCode, MouseButton, TouchPhase, MouseScrollDelta, ModifiersState}; use config; +use grid::Scroll; use event::{ClickState, Mouse}; use index::{Line, Column, Side, Point}; use term::SizeInfo; @@ -65,11 +66,7 @@ pub trait ActionContext { fn last_modifiers(&mut self) -> &mut ModifiersState; fn change_font_size(&mut self, delta: i8); fn reset_font_size(&mut self); - fn scroll(&mut self, count: isize); - fn reset_scroll(&mut self); - fn scroll_to_top(&mut self); - fn scroll_page_up(&mut self); - fn scroll_page_down(&mut self); + fn scroll(&mut self, scroll: Scroll); } /// Describes a state and action to take in that state @@ -254,16 +251,16 @@ impl Action { ctx.reset_font_size(); }, Action::ScrollPageUp => { - ctx.scroll_page_up(); + ctx.scroll(Scroll::PageUp); }, Action::ScrollPageDown => { - ctx.scroll_page_down(); + ctx.scroll(Scroll::PageDown); }, Action::ScrollToTop => { - ctx.scroll_to_top(); + ctx.scroll(Scroll::Top); }, Action::ScrollToBottom => { - ctx.reset_scroll(); + ctx.scroll(Scroll::Bottom); }, } } @@ -527,7 +524,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { self.ctx.write_to_pty(content); } else { for _ in 0..scroll_multiplier { - self.ctx.scroll(-((code as isize) * 2 - 129)); + self.ctx.scroll(Scroll::Lines(-((code as isize) * 2 - 129))); } } } @@ -597,7 +594,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { /// Process a received character pub fn received_char(&mut self, c: char) { if !*self.ctx.suppress_chars() { - self.ctx.reset_scroll(); + self.ctx.scroll(Scroll::Bottom); self.ctx.clear_selection(); let utf8_len = c.len_utf8(); -- cgit From 688cabefc0bfc3224189c10235668eae5e5b0101 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Fri, 23 Mar 2018 01:01:55 +0100 Subject: 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. --- src/input.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 8cf11811..047c81aa 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 => { -- cgit From f66e3e457bdda808cc3f994a02fd6f7ce5ba381e Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sun, 25 Mar 2018 21:09:18 +0200 Subject: Fix selection tests The latest selection changes broke a few tests, these have been corrected. Two of these tests were broken because they assumed different span types, the test have been changed here because the result was correct. One test did actually catch a bug where selection of two cells from right to left would incorrectly mark the cells as selected even though they should not have been, this has been fixed in the `simple_span` method. --- src/input.rs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 047c81aa..90384198 100644 --- a/src/input.rs +++ b/src/input.rs @@ -664,6 +664,7 @@ mod tests { use config::{self, Config, ClickHandler}; use index::{Point, Side}; use selection::Selection; + use grid::Scroll; use super::{Action, Binding, Processor}; @@ -717,6 +718,10 @@ mod tests { self.last_action = MultiClick::TripleClick; } + fn scroll(&mut self, scroll: Scroll) { + self.terminal.scroll_display(scroll); + } + fn mouse_coords(&self) -> Option { self.terminal.pixels_to_coords(self.mouse.x as usize, self.mouse.y as usize) } -- cgit From cde1d8d1edb0c8001a28a2a674c46b5a581439db Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Wed, 4 Jul 2018 21:40:16 +0200 Subject: Fix incorrect cell side in selection Previously the cell side of a selection with the mouse outside of the grid has been calculated by setting the `Side` to `Right` whenever the `X` of the mouse is bigger or equal to `window_width - padding_x`. However since the grid doesn't perfectly fit the window in most cases, there was an additional few pixels where the `Side` would be `Left`, resulting in the selection jumping around. To fix this the additional padding due to not perfectly fitting window size has been included in the calculation. The `X` position is now checked to be bigger or equal to `width - padding_x - extra_padding_x`. An important note is that this will need changing when the grid is centered inside the window, so extra padding is split up evenly. Once that change is merged the calculation required will be `width - padding_x - extra_padding_x / 2.`. This fixes #1412. --- src/input.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 90384198..2d647114 100644 --- a/src/input.rs +++ b/src/input.rs @@ -304,9 +304,11 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { let cell_x = x.saturating_sub(size_info.padding_x as usize) % size_info.cell_width as usize; let half_cell_width = (size_info.cell_width / 2.0) as usize; + let additional_padding = (size_info.width - size_info.padding_x * 2.) % size_info.cell_width; + let end_of_grid = size_info.width - size_info.padding_x - additional_padding; let cell_side = if cell_x > half_cell_width // Edge case when mouse leaves the window - || x as f32 >= size_info.width - size_info.padding_x + || x as f32 >= end_of_grid { Side::Right } else { -- cgit From f50ca1a54c94fe324d22d985c1acae1ff7c16a80 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sat, 21 Jul 2018 17:17:41 +0000 Subject: Scrollback cleanup There were some unneeded codeblocks and TODO/XXX comments in the code that have been removed. All issues marked with TODO/XXX have either been already resolved or tracking issues exist. --- src/input.rs | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index 2d647114..f2337d6a 100644 --- a/src/input.rs +++ b/src/input.rs @@ -35,6 +35,8 @@ use term::SizeInfo; use term::mode::TermMode; use util::fmt::Red; +pub const FONT_SIZE_STEP: f32 = 0.5; + /// Processes input from glutin. /// /// An escape sequence may be emitted in case specific keys or key combinations @@ -64,7 +66,7 @@ pub trait ActionContext { fn received_count(&mut self) -> &mut usize; fn suppress_chars(&mut self) -> &mut bool; fn last_modifiers(&mut self) -> &mut ModifiersState; - fn change_font_size(&mut self, delta: i8); + fn change_font_size(&mut self, delta: f32); fn reset_font_size(&mut self); fn scroll(&mut self, scroll: Scroll); } @@ -103,15 +105,15 @@ impl Binding { fn is_triggered_by( &self, mode: TermMode, - mods: &ModifiersState, + mods: ModifiersState, input: &T ) -> bool { // Check input first since bindings are stored in one big list. This is // the most likely item to fail so prioritizing it here allows more // checks to be short circuited. self.trigger == *input && - self.mode_matches(&mode) && - self.not_mode_matches(&mode) && + self.mode_matches(mode) && + self.not_mode_matches(mode) && self.mods_match(mods) } } @@ -124,12 +126,12 @@ impl Binding { } #[inline] - fn mode_matches(&self, mode: &TermMode) -> bool { + fn mode_matches(&self, mode: TermMode) -> bool { self.mode.is_empty() || mode.intersects(self.mode) } #[inline] - fn not_mode_matches(&self, mode: &TermMode) -> bool { + fn not_mode_matches(&self, mode: TermMode) -> bool { self.notmode.is_empty() || !mode.intersects(self.notmode) } @@ -137,10 +139,10 @@ impl Binding { /// /// Optimized to use single check instead of four (one per modifier) #[inline] - fn mods_match(&self, mods: &ModifiersState) -> bool { - debug_assert!(4 == mem::size_of::()); + fn mods_match(&self, mods: ModifiersState) -> bool { + assert_eq_size!(ModifiersState, u32); unsafe { - mem::transmute_copy::<_, u32>(&self.mods) == mem::transmute_copy::<_, u32>(mods) + mem::transmute_copy::<_, u32>(&self.mods) == mem::transmute_copy::<_, u32>(&mods) } } } @@ -243,10 +245,10 @@ impl Action { ::std::process::exit(0); }, Action::IncreaseFontSize => { - ctx.change_font_size(1); + ctx.change_font_size(FONT_SIZE_STEP); }, Action::DecreaseFontSize => { - ctx.change_font_size(-1); + ctx.change_font_size(-FONT_SIZE_STEP); } Action::ResetFontSize => { ctx.reset_font_size(); @@ -507,19 +509,19 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { let mouse_modes = TermMode::MOUSE_REPORT_CLICK | TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION; // Make sure the new and deprecated setting are both allowed - let faux_scrollback_lines = self.mouse_config + let faux_scrolling_lines = self.mouse_config .faux_scrollback_lines .unwrap_or(self.scrolling_config.faux_multiplier as usize); if self.ctx.terminal_mode().intersects(mouse_modes) { self.mouse_report(code, ElementState::Pressed, modifiers); } else if self.ctx.terminal_mode().contains(TermMode::ALT_SCREEN) - && faux_scrollback_lines > 0 && !modifiers.shift + && faux_scrolling_lines > 0 && !modifiers.shift { // Faux scrolling let cmd = code + 1; // 64 + 1 = A, 65 + 1 = B - let mut content = Vec::with_capacity(faux_scrollback_lines as usize * 3); - for _ in 0..faux_scrollback_lines { + let mut content = Vec::with_capacity(faux_scrolling_lines as usize * 3); + for _ in 0..faux_scrolling_lines { content.push(0x1b); content.push(b'O'); content.push(cmd); @@ -527,7 +529,8 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { self.ctx.write_to_pty(content); } else { for _ in 0..scroll_multiplier { - self.ctx.scroll(Scroll::Lines(-((code as isize) * 2 - 129))); + // Transform the reported button codes 64 and 65 into 1 and -1 lines to scroll + self.ctx.scroll(Scroll::Lines(-(code as isize * 2 - 129))); } } } @@ -567,7 +570,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { return; } - self.process_mouse_bindings(&ModifiersState::default(), button); + self.process_mouse_bindings(ModifiersState::default(), button); } /// Process key input @@ -577,11 +580,11 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { &mut self, state: ElementState, key: Option, - mods: &ModifiersState, + mods: ModifiersState, ) { match (key, state) { (Some(key), ElementState::Pressed) => { - *self.ctx.last_modifiers() = *mods; + *self.ctx.last_modifiers() = mods; *self.ctx.received_count() = 0; *self.ctx.suppress_chars() = false; @@ -623,7 +626,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { /// for its action to be 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 { for binding in self.key_bindings { if binding.is_triggered_by(self.ctx.terminal_mode(), mods, &key) { // binding was triggered; run the action @@ -641,7 +644,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { /// for its action to be 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 { for binding in self.mouse_bindings { if binding.is_triggered_by(self.ctx.terminal_mode(), mods, &button) { // binding was triggered; run the action @@ -741,7 +744,7 @@ mod tests { fn last_modifiers(&mut self) -> &mut ModifiersState { &mut self.last_modifiers } - fn change_font_size(&mut self, _delta: i8) { + fn change_font_size(&mut self, _delta: f32) { } fn reset_font_size(&mut self) { } @@ -824,9 +827,9 @@ mod tests { #[test] fn $name() { if $triggers { - assert!($binding.is_triggered_by($mode, &$mods, &KEY)); + assert!($binding.is_triggered_by($mode, $mods, &KEY)); } else { - assert!(!$binding.is_triggered_by($mode, &$mods, &KEY)); + assert!(!$binding.is_triggered_by($mode, $mods, &KEY)); } } } -- cgit From c4a0f9c4cb7e8d73914800c4ba64413970f98540 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sat, 28 Jul 2018 23:10:13 +0000 Subject: Merge master into scrollback * Allow disabling DPI scaling This makes it possible to disable DPI scaling completely, instead the the display pixel ration will always be fixed to 1.0. By default nothing has changed and DPI is still enabled, this just seems like a better way than running `WINIT_HIDPI_FACTOR=1.0 alacritty` every time the user wants to start alacritty. It would be possible to allow specifying any DPR, however I've decided against this since I'd assume it's a very rare usecase. It's also still possible to make use of `WINIT_HIDPI_FACTOR` to do this on X11. Currently this is not updated at runtime using the live config update, there is not really much of a technical limitation why this woudn't be possible, however a solution for that issue should be first added in jwilm/alacritty#1346, once a system is established for changing DPI at runtime, porting that functionality to this PR should be simple. * Add working --class and --title CLI parameters * Reduce Increase-/DecreaseFontSize step to 0.5 Until now the Increase-/DecreaseFontSize keybinds hand a step size of 1.0. Since the font size however is multiplied by two to allow more granular font size control, this lead to the bindings skipping one font size (incrementing/decrementing by +-2). To fix this the step size of the Increase-/DecreaseFontSize bindings has been reduced to the minimum step size that exists with the current font configuration (0.5). This should allow users to increment and decrement the font size by a single point instead of two. This also adds a few tests to make sure the methods for increasing/decreasing/resetting font size work properly. * Add Copy/Cut/Paste keys This just adds support for the Copy/Cut/Paste keys and sets up Copy/Paste as alternative defaults for Ctrl+Shift+C/V. * Move to cargo clippy Using clippy as a library has been deprecated, instead the `cargo clippy` command should be used instead. To comply with this change clippy has been removed from the `Cargo.toml` and is now installed with cargo when building in CI. This has also lead to a few new clippy issues to show up, this includes everything in the `font` subdirectory. This has been fixed and `font` should now be covered by clippy CI too. This also upgrades all dependencies, as a result this fixes #1341 and this fixes #1344. * Override dynamic_title when --title is specified * Change green implementation to use the macro * Ignore mouse input if window is unfocused * Make compilation of binary a phony target * Add opensuse zypper install method to readme * Fix clippy issues * Update manpage to document all CLI options The introduction of `--class` has added a flag to the CLI without adding it to the manpage. This has been fixed by updating the manpage. This also adds the default values of `--class` and `--title` to the CLI options. * Remove unnecessary clippy lint annotations We moved to "cargo clippy" in 5ba34d4f9766a55a06ed5e3e44cc384af1b09f65 and removing the clippy lint annotations in `src/lib.rs` does not cause any additional warnings. This also changes `cargo clippy` to use the flags required for checking integration tests. * Enable clippy in font/copypasta crates Enabled clippy in the sub-crates font and copypasta. All issues that were discovered by this change have also been fixed. * Remove outdated comment about NixOS * Replace debug asserts with static_assertions To check that transmutes will work correctly without having to rely on error-prone runtime checking, the `static_assertions` crate has been introduced. This allows comparing the size of types at compile time, preventing potentially silent breakage. This fixes #1417. * Add `cargo deb` build instructions Updated the `Cargo.toml` file and added a `package.metadata.deb` subsection to define how to build a debian "deb" install file using `cargo deb`. This will allow debian/ubuntu users to install `alacritty` using their system's package manager. It also will make it easier to provide pre-built binaries for those systems. Also fixed a stray debug line in the bash autocomplete script that was writting to a tempfile. * Add config for unfocused window cursor change * Add support for cursor shape escape sequence * Add bright foreground color option It was requested in jwilm/alacritty#825 that it should be possible to add an optional bright foreground color. This is now added to the primary colors structure and allows the user to set a foreground color for bold normal text. This has no effect unless the draw_bold_text_with_bright_colors option is also enabled. If the color is not specified, the bright foreground color will fall back to the normal foreground color. This fixes #825. * Fix clone URL in deb install instructions * Fix 'cargo-deb' desktop file name * Remove redundant dependency from deb build * Switch from deprecated `std::env::home_dir` to `dirs::home_dir` * Allow specifying modifiers for mouse bindings * Send newline with NumpadEnter * Add support for LCD-V pixel mode * Add binding action for hiding the window * Switch to rustup clippy component * Add optional dim foreground color Add optional color for the dim foreground (`\e[2m;`) Defaults to 2/3 of the foreground color. (same as other colors). If a bright color is dimmed, it's displayed as the normal color. The exception for this is when the bright foreground is dimmed when no bright foreground color is set. In that case it's treated as a normal foreground color and dimmed to DimForeground. To minimize the surprise for the user, the bright and dim colors have been completely removed from the default configuration file. Some documentation has also been added to make it clear to users what these options can be used for. This fixes #1448. * Fix clippy lints and run font tests on travis This fixes some existing clippy issues and runs the `font` tests through travis. Testing of copypasta crate was omitted due to problens when running on headless travis-ci environment (x11 clipboard would fail). * Ignore errors when logger can't write to output The (e)print macro will panic when there is no output available to write to, however in our scenario where we only log user errors to stderr, the better choice would be to ignore when writing to stdout or stderr is not possible. This changes the (e)print macro to make use of `write` and ignore any potential errors. Since (e)println rely on (e)print, this also solves potential failuers when calling (e)println. With this change implemented, all of logging, (e)println and (e)print should never fail even if the stdout/stderr is not available. --- src/input.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index f2337d6a..cccb3bb4 100644 --- a/src/input.rs +++ b/src/input.rs @@ -69,6 +69,7 @@ pub trait ActionContext { fn change_font_size(&mut self, delta: f32); fn reset_font_size(&mut self); fn scroll(&mut self, scroll: Scroll); + fn hide_window(&mut self); } /// Describes a state and action to take in that state @@ -185,6 +186,9 @@ pub enum Action { /// Run given command Command(String, Vec), + /// Hides the Alacritty window + Hide, + /// Quits Alacritty. Quit, } @@ -240,6 +244,9 @@ impl Action { }, } }, + Action::Hide => { + ctx.hide_window(); + }, Action::Quit => { // FIXME should do a more graceful shutdown ::std::process::exit(0); @@ -570,7 +577,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { return; } - self.process_mouse_bindings(ModifiersState::default(), button); + self.process_mouse_bindings(modifiers, button); } /// Process key input @@ -665,7 +672,7 @@ mod tests { use glutin::{VirtualKeyCode, Event, WindowEvent, ElementState, MouseButton, ModifiersState}; use term::{SizeInfo, Term, TermMode}; - use event::{Mouse, ClickState}; + use event::{Mouse, ClickState, WindowChanges}; use config::{self, Config, ClickHandler}; use index::{Point, Side}; use selection::Selection; @@ -691,6 +698,7 @@ mod tests { pub received_count: usize, pub suppress_chars: bool, pub last_modifiers: ModifiersState, + pub window_changes: &'a mut WindowChanges, } impl <'a>super::ActionContext for ActionContext<'a> { @@ -748,6 +756,8 @@ mod tests { } fn reset_font_size(&mut self) { } + fn hide_window(&mut self) { + } } macro_rules! test_clickstate { @@ -786,6 +796,7 @@ mod tests { received_count: 0, suppress_chars: false, last_modifiers: ModifiersState::default(), + window_changes: &mut WindowChanges::default(), }; let mut processor = Processor { -- cgit From 72495172c25e00799f29eb2e79fe40ddfa189866 Mon Sep 17 00:00:00 2001 From: Nathan Lilienthal Date: Sat, 1 Sep 2018 20:30:03 -0400 Subject: 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. --- src/input.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'src/input.rs') diff --git a/src/input.rs b/src/input.rs index cccb3bb4..3c20fe36 100644 --- a/src/input.rs +++ b/src/input.rs @@ -69,6 +69,7 @@ pub trait ActionContext { fn change_font_size(&mut self, delta: f32); fn reset_font_size(&mut self); fn scroll(&mut self, scroll: Scroll); + fn clear_history(&mut self); fn hide_window(&mut self); } @@ -183,6 +184,9 @@ pub enum Action { /// Scroll all the way to the bottom ScrollToBottom, + /// Clear the display buffer(s) to remove history + ClearHistory, + /// Run given command Command(String, Vec), @@ -272,6 +276,9 @@ impl Action { Action::ScrollToBottom => { 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. fn process_key_bindings(&mut self, mods: ModifiersState, key: VirtualKeyCode) -> bool { + let mut has_binding = false; for binding in self.key_bindings { if binding.is_triggered_by(self.ctx.terminal_mode(), mods, &key) { // binding was triggered; run the action binding.execute(&mut self.ctx); - return true; + has_binding = true; } } - false + has_binding } /// 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. fn process_mouse_bindings(&mut self, mods: ModifiersState, button: MouseButton) -> bool { + let mut has_binding = false; for binding in self.mouse_bindings { if binding.is_triggered_by(self.ctx.terminal_mode(), mods, &button) { // binding was triggered; run the action 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 clear_history(&mut self) { + } fn hide_window(&mut self) { } } -- cgit