Add live config reload for font family and style

Fixes #2737.
This commit is contained in:
wayne 2019-11-03 13:02:26 -06:00 committed by Christian Duerr
parent 4dd327f0ae
commit fa6ceacfa4
5 changed files with 101 additions and 90 deletions

View File

@ -24,11 +24,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Terminal escape bindings with combined modifiers - Terminal escape bindings with combined modifiers
- Bindings for ScrollToTop and ScrollToBottom actions - Bindings for ScrollToTop and ScrollToBottom actions
- `ReceiveChar` key binding action to insert the key's text character - `ReceiveChar` key binding action to insert the key's text character
- Live reload font size from config
- New CLI flag `--hold` for keeping Alacritty opened after its child process exits - New CLI flag `--hold` for keeping Alacritty opened after its child process exits
- Escape sequence to save and restore window title from stack - Escape sequence to save and restore window title from stack
- Alternate scroll escape sequence (`CSI ? 1007 h` / `CSI ? 1007 l`) - Alternate scroll escape sequence (`CSI ? 1007 h` / `CSI ? 1007 l`)
- Print name of launch command if Alacritty failed to execute it - Print name of launch command if Alacritty failed to execute it
- Live reload font settings from config
### Changed ### Changed

View File

@ -99,7 +99,7 @@
# change the `it` value in terminfo when altering this setting. # change the `it` value in terminfo when altering this setting.
#tabspaces: 8 #tabspaces: 8
# Font configuration (changes require restart) # Font configuration
#font: #font:
# Normal (roman) font face # Normal (roman) font face
#normal: #normal:

View File

@ -14,7 +14,6 @@
//! The display subsystem including window management, font rasterization, and //! The display subsystem including window management, font rasterization, and
//! GPU drawing. //! GPU drawing.
use std::cmp::max;
use std::f64; use std::f64;
use std::fmt; use std::fmt;
use std::time::Instant; use std::time::Instant;
@ -24,9 +23,9 @@ use glutin::event_loop::EventLoop;
use log::{debug, info}; use log::{debug, info};
use parking_lot::MutexGuard; use parking_lot::MutexGuard;
use font::{self, Rasterize, Size}; use font::{self, Rasterize};
use alacritty_terminal::config::StartupMode; use alacritty_terminal::config::{Font, StartupMode};
use alacritty_terminal::event::{Event, OnResize}; use alacritty_terminal::event::{Event, OnResize};
use alacritty_terminal::index::Line; use alacritty_terminal::index::Line;
use alacritty_terminal::message_bar::MessageBuffer; use alacritty_terminal::message_bar::MessageBuffer;
@ -37,12 +36,9 @@ use alacritty_terminal::term::color::Rgb;
use alacritty_terminal::term::{RenderableCell, SizeInfo, Term}; use alacritty_terminal::term::{RenderableCell, SizeInfo, Term};
use crate::config::Config; use crate::config::Config;
use crate::event::{FontResize, Resize}; use crate::event::DisplayUpdate;
use crate::window::{self, Window}; use crate::window::{self, Window};
/// Font size change interval
pub const FONT_SIZE_STEP: f32 = 0.5;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// Error with window management /// Error with window management
@ -116,7 +112,6 @@ impl From<glutin::ContextError> for Error {
/// The display wraps a window, font rasterizer, and GPU renderer /// The display wraps a window, font rasterizer, and GPU renderer
pub struct Display { pub struct Display {
pub size_info: SizeInfo, pub size_info: SizeInfo,
pub font_size: Size,
pub window: Window, pub window: Window,
renderer: QuadRenderer, renderer: QuadRenderer,
@ -228,14 +223,7 @@ impl Display {
_ => (), _ => (),
} }
Ok(Display { Ok(Display { window, renderer, glyph_cache, meter: Meter::new(), size_info })
window,
renderer,
glyph_cache,
meter: Meter::new(),
size_info,
font_size: config.font.size,
})
} }
fn new_glyph_cache( fn new_glyph_cache(
@ -270,12 +258,10 @@ impl Display {
} }
/// Update font size and cell dimensions /// Update font size and cell dimensions
fn update_glyph_cache(&mut self, config: &Config, size: Size) { fn update_glyph_cache(&mut self, config: &Config, font: Font) {
let size_info = &mut self.size_info; let size_info = &mut self.size_info;
let cache = &mut self.glyph_cache; let cache = &mut self.glyph_cache;
let font = config.font.clone().with_size(size);
self.renderer.with_loader(|mut api| { self.renderer.with_loader(|mut api| {
let _ = cache.update_font_size(font, size_info.dpr, &mut api); let _ = cache.update_font_size(font, size_info.dpr, &mut api);
}); });
@ -286,27 +272,22 @@ impl Display {
size_info.cell_height = cell_height; size_info.cell_height = cell_height;
} }
/// Process resize events /// Process update events
pub fn handle_resize<T>( pub fn handle_update<T>(
&mut self, &mut self,
terminal: &mut Term<T>, terminal: &mut Term<T>,
pty_resize_handle: &mut dyn OnResize, pty_resize_handle: &mut dyn OnResize,
message_buffer: &MessageBuffer, message_buffer: &MessageBuffer,
config: &Config, config: &Config,
resize_pending: Resize, update_pending: DisplayUpdate,
) { ) {
// Update font size and cell dimensions // Update font size and cell dimensions
if let Some(resize) = resize_pending.font_size { if let Some(font) = update_pending.font {
self.font_size = match resize { self.update_glyph_cache(config, font);
FontResize::Delta(delta) => max(self.font_size + delta, FONT_SIZE_STEP.into()),
FontResize::Reset => config.font.size,
};
self.update_glyph_cache(config, self.font_size);
} }
// Update the window dimensions // Update the window dimensions
if let Some(size) = resize_pending.dimensions { if let Some(size) = update_pending.dimensions {
self.size_info.width = size.width as f32; self.size_info.width = size.width as f32;
self.size_info.height = size.height as f32; self.size_info.height = size.height as f32;
} }

View File

@ -1,5 +1,6 @@
//! Process window events //! Process window events
use std::borrow::Cow; use std::borrow::Cow;
use std::cmp::max;
use std::env; use std::env;
#[cfg(unix)] #[cfg(unix)]
use std::fs; use std::fs;
@ -20,6 +21,7 @@ use serde_json as json;
use font::Size; use font::Size;
use alacritty_terminal::clipboard::ClipboardType; use alacritty_terminal::clipboard::ClipboardType;
use alacritty_terminal::config::Font;
use alacritty_terminal::config::LOG_TARGET_CONFIG; use alacritty_terminal::config::LOG_TARGET_CONFIG;
use alacritty_terminal::event::OnResize; use alacritty_terminal::event::OnResize;
use alacritty_terminal::event::{Event, EventListener, Notify}; use alacritty_terminal::event::{Event, EventListener, Notify};
@ -36,25 +38,19 @@ use alacritty_terminal::util::{limit, start_daemon};
use crate::config; use crate::config;
use crate::config::Config; use crate::config::Config;
use crate::display::Display; use crate::display::Display;
use crate::input::{self, ActionContext as _, Modifiers}; use crate::input::{self, ActionContext as _, Modifiers, FONT_SIZE_STEP};
use crate::window::Window; use crate::window::Window;
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Default, Clone, Debug, PartialEq)]
pub enum FontResize { pub struct DisplayUpdate {
Delta(f32),
Reset,
}
#[derive(Default, Copy, Clone, Debug, PartialEq)]
pub struct Resize {
pub dimensions: Option<PhysicalSize>, pub dimensions: Option<PhysicalSize>,
pub message_buffer: Option<()>, pub message_buffer: Option<()>,
pub font_size: Option<FontResize>, pub font: Option<Font>,
} }
impl Resize { impl DisplayUpdate {
fn is_empty(&self) -> bool { fn is_empty(&self) -> bool {
self.dimensions.is_none() && self.font_size.is_none() && self.message_buffer.is_none() self.dimensions.is_none() && self.font.is_none() && self.message_buffer.is_none()
} }
} }
@ -68,8 +64,9 @@ pub struct ActionContext<'a, N, T> {
pub modifiers: &'a mut Modifiers, pub modifiers: &'a mut Modifiers,
pub window: &'a mut Window, pub window: &'a mut Window,
pub message_buffer: &'a mut MessageBuffer, pub message_buffer: &'a mut MessageBuffer,
pub resize_pending: &'a mut Resize, pub display_update_pending: &'a mut DisplayUpdate,
pub font_size: &'a Size, pub config: &'a mut Config,
font_size: &'a mut Size,
} }
impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionContext<'a, N, T> { impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionContext<'a, N, T> {
@ -227,23 +224,30 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
} }
fn change_font_size(&mut self, delta: f32) { fn change_font_size(&mut self, delta: f32) {
self.resize_pending.font_size = Some(FontResize::Delta(delta)); *self.font_size = max(*self.font_size + delta, Size::new(FONT_SIZE_STEP));
let font = self.config.font.clone().with_size(*self.font_size);
self.display_update_pending.font = Some(font);
self.terminal.dirty = true; self.terminal.dirty = true;
} }
fn reset_font_size(&mut self) { fn reset_font_size(&mut self) {
self.resize_pending.font_size = Some(FontResize::Reset); *self.font_size = self.config.font.size;
self.display_update_pending.font = Some(self.config.font.clone());
self.terminal.dirty = true; self.terminal.dirty = true;
} }
fn pop_message(&mut self) { fn pop_message(&mut self) {
self.resize_pending.message_buffer = Some(()); self.display_update_pending.message_buffer = Some(());
self.message_buffer.pop(); self.message_buffer.pop();
} }
fn message(&self) -> Option<&Message> { fn message(&self) -> Option<&Message> {
self.message_buffer.message() self.message_buffer.message()
} }
fn config(&self) -> &Config {
self.config
}
} }
pub enum ClickState { pub enum ClickState {
@ -306,6 +310,7 @@ pub struct Processor<N> {
pty_resize_handle: Box<dyn OnResize>, pty_resize_handle: Box<dyn OnResize>,
message_buffer: MessageBuffer, message_buffer: MessageBuffer,
display: Display, display: Display,
font_size: Size,
} }
impl<N: Notify> Processor<N> { impl<N: Notify> Processor<N> {
@ -326,6 +331,7 @@ impl<N: Notify> Processor<N> {
received_count: 0, received_count: 0,
suppress_chars: false, suppress_chars: false,
modifiers: Default::default(), modifiers: Default::default(),
font_size: config.font.size,
config, config,
pty_resize_handle, pty_resize_handle,
message_buffer, message_buffer,
@ -374,7 +380,7 @@ impl<N: Notify> Processor<N> {
let mut terminal = terminal.lock(); let mut terminal = terminal.lock();
let mut resize_pending = Resize::default(); let mut display_update_pending = DisplayUpdate::default();
let context = ActionContext { let context = ActionContext {
terminal: &mut terminal, terminal: &mut terminal,
@ -385,11 +391,12 @@ impl<N: Notify> Processor<N> {
suppress_chars: &mut self.suppress_chars, suppress_chars: &mut self.suppress_chars,
modifiers: &mut self.modifiers, modifiers: &mut self.modifiers,
message_buffer: &mut self.message_buffer, message_buffer: &mut self.message_buffer,
resize_pending: &mut resize_pending, display_update_pending: &mut display_update_pending,
window: &mut self.display.window, window: &mut self.display.window,
font_size: &self.display.font_size, font_size: &mut self.font_size,
config: &mut self.config,
}; };
let mut processor = input::Processor::new(context, &mut self.config); let mut processor = input::Processor::new(context);
for event in event_queue.drain(..) { for event in event_queue.drain(..) {
Processor::handle_event(event, &mut processor); Processor::handle_event(event, &mut processor);
@ -407,21 +414,21 @@ impl<N: Notify> Processor<N> {
let size = self.display.window.inner_size().to_physical(dpr); let size = self.display.window.inner_size().to_physical(dpr);
resize_pending.font_size = Some(FontResize::Delta(0.)); display_update_pending.font = Some(self.config.font.clone());
resize_pending.dimensions = Some(size); display_update_pending.dimensions = Some(size);
terminal.dirty = true; terminal.dirty = true;
} }
} }
// Process resize events // Process DisplayUpdate events
if !resize_pending.is_empty() { if !display_update_pending.is_empty() {
self.display.handle_resize( self.display.handle_update(
&mut terminal, &mut terminal,
self.pty_resize_handle.as_mut(), self.pty_resize_handle.as_mut(),
&self.message_buffer, &self.message_buffer,
&self.config, &self.config,
resize_pending, display_update_pending,
); );
} }
@ -460,23 +467,29 @@ impl<N: Notify> Processor<N> {
}, },
Event::ConfigReload(path) => { Event::ConfigReload(path) => {
processor.ctx.message_buffer.remove_target(LOG_TARGET_CONFIG); processor.ctx.message_buffer.remove_target(LOG_TARGET_CONFIG);
processor.ctx.resize_pending.message_buffer = Some(()); processor.ctx.display_update_pending.message_buffer = Some(());
if let Ok(config) = config::reload_from(&path) { if let Ok(config) = config::reload_from(&path) {
processor.ctx.terminal.update_config(&config); processor.ctx.terminal.update_config(&config);
if *processor.ctx.font_size == processor.config.font.size { if processor.ctx.config.font != config.font {
processor.ctx.resize_pending.font_size = Some(FontResize::Reset); // Do not update font size if it has been changed at runtime
if *processor.ctx.font_size == processor.ctx.config.font.size {
*processor.ctx.font_size = config.font.size;
}
let font = config.font.clone().with_size(*processor.ctx.font_size);
processor.ctx.display_update_pending.font = Some(font);
} }
*processor.config = config; *processor.ctx.config = config;
processor.ctx.terminal.dirty = true; processor.ctx.terminal.dirty = true;
} }
}, },
Event::Message(message) => { Event::Message(message) => {
processor.ctx.message_buffer.push(message); processor.ctx.message_buffer.push(message);
processor.ctx.resize_pending.message_buffer = Some(()); processor.ctx.display_update_pending.message_buffer = Some(());
processor.ctx.terminal.dirty = true; processor.ctx.terminal.dirty = true;
}, },
Event::MouseCursorDirty => processor.reset_mouse_cursor(), Event::MouseCursorDirty => processor.reset_mouse_cursor(),
@ -488,14 +501,14 @@ impl<N: Notify> Processor<N> {
CloseRequested => processor.ctx.terminal.exit(), CloseRequested => processor.ctx.terminal.exit(),
Resized(lsize) => { Resized(lsize) => {
let psize = lsize.to_physical(processor.ctx.size_info.dpr); let psize = lsize.to_physical(processor.ctx.size_info.dpr);
processor.ctx.resize_pending.dimensions = Some(psize); processor.ctx.display_update_pending.dimensions = Some(psize);
processor.ctx.terminal.dirty = true; processor.ctx.terminal.dirty = true;
}, },
KeyboardInput { input, .. } => { KeyboardInput { input, .. } => {
processor.process_key(input); processor.process_key(input);
if input.state == ElementState::Pressed { if input.state == ElementState::Pressed {
// Hide cursor while typing // Hide cursor while typing
if processor.config.ui_config.mouse.hide_when_typing { if processor.ctx.config.ui_config.mouse.hide_when_typing {
processor.ctx.window.set_mouse_visible(false); processor.ctx.window.set_mouse_visible(false);
} }
} }
@ -540,17 +553,18 @@ impl<N: Notify> Processor<N> {
}, },
HiDpiFactorChanged(dpr) => { HiDpiFactorChanged(dpr) => {
let dpr_change = (dpr / processor.ctx.size_info.dpr) as f32; let dpr_change = (dpr / processor.ctx.size_info.dpr) as f32;
let resize_pending = &mut processor.ctx.resize_pending; let display_update_pending = &mut processor.ctx.display_update_pending;
// Push current font to update its DPR // Push current font to update its DPR
resize_pending.font_size = Some(FontResize::Delta(0.)); display_update_pending.font = Some(processor.ctx.config.font.clone());
// Scale window dimensions with new DPR // Scale window dimensions with new DPR
let old_width = processor.ctx.size_info.width; let old_width = processor.ctx.size_info.width;
let old_height = processor.ctx.size_info.height; let old_height = processor.ctx.size_info.height;
let dimensions = resize_pending.dimensions.get_or_insert_with(|| { let dimensions =
PhysicalSize::new(f64::from(old_width), f64::from(old_height)) display_update_pending.dimensions.get_or_insert_with(|| {
}); PhysicalSize::new(f64::from(old_width), f64::from(old_height))
});
dimensions.width *= f64::from(dpr_change); dimensions.width *= f64::from(dpr_change);
dimensions.height *= f64::from(dpr_change); dimensions.height *= f64::from(dpr_change);

View File

@ -42,17 +42,18 @@ use alacritty_terminal::url::Url;
use alacritty_terminal::util::start_daemon; use alacritty_terminal::util::start_daemon;
use crate::config::{Action, Binding, Config, Key, RelaxedEq}; use crate::config::{Action, Binding, Config, Key, RelaxedEq};
use crate::display::FONT_SIZE_STEP;
use crate::event::{ClickState, Mouse}; use crate::event::{ClickState, Mouse};
use crate::window::Window; use crate::window::Window;
/// Font size change interval
pub const FONT_SIZE_STEP: f32 = 0.5;
/// Processes input from glutin. /// Processes input from glutin.
/// ///
/// An escape sequence may be emitted in case specific keys or key combinations /// An escape sequence may be emitted in case specific keys or key combinations
/// are activated. /// are activated.
pub struct Processor<'a, T: EventListener, A: ActionContext<T> + 'a> { pub struct Processor<T: EventListener, A: ActionContext<T>> {
pub ctx: A, pub ctx: A,
pub config: &'a mut Config,
_phantom: PhantomData<T>, _phantom: PhantomData<T>,
} }
@ -83,6 +84,7 @@ pub trait ActionContext<T: EventListener> {
fn reset_font_size(&mut self); fn reset_font_size(&mut self);
fn pop_message(&mut self); fn pop_message(&mut self);
fn message(&self) -> Option<&Message>; fn message(&self) -> Option<&Message>;
fn config(&self) -> &Config;
} }
#[derive(Debug, Default, Copy, Clone)] #[derive(Debug, Default, Copy, Clone)]
@ -226,9 +228,9 @@ impl From<MouseState> for CursorIcon {
} }
} }
impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> { impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
pub fn new(ctx: A, config: &'a mut Config) -> Self { pub fn new(ctx: A) -> Self {
Self { ctx, config, _phantom: Default::default() } Self { ctx, _phantom: Default::default() }
} }
fn mouse_state(&mut self, point: Point, mods: ModifiersState) -> MouseState { fn mouse_state(&mut self, point: Point, mods: ModifiersState) -> MouseState {
@ -245,9 +247,9 @@ impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> {
} }
// Check for URL at point with required modifiers held // Check for URL at point with required modifiers held
if self.config.ui_config.mouse.url.mods().relaxed_eq(mods) if self.ctx.config().ui_config.mouse.url.mods().relaxed_eq(mods)
&& (!self.ctx.terminal().mode().intersects(mouse_mode) || mods.shift) && (!self.ctx.terminal().mode().intersects(mouse_mode) || mods.shift)
&& self.config.ui_config.mouse.url.launcher.is_some() && self.ctx.config().ui_config.mouse.url.launcher.is_some()
&& self.ctx.selection_is_empty() && self.ctx.selection_is_empty()
&& self.ctx.mouse().left_button_state != ElementState::Pressed && self.ctx.mouse().left_button_state != ElementState::Pressed
{ {
@ -426,7 +428,7 @@ impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> {
self.ctx.mouse_mut().click_state = match self.ctx.mouse().click_state { self.ctx.mouse_mut().click_state = match self.ctx.mouse().click_state {
ClickState::Click ClickState::Click
if !button_changed if !button_changed
&& elapsed < self.config.ui_config.mouse.double_click.threshold => && elapsed < self.ctx.config().ui_config.mouse.double_click.threshold =>
{ {
self.ctx.mouse_mut().block_url_launcher = true; self.ctx.mouse_mut().block_url_launcher = true;
self.on_mouse_double_click(button, point); self.on_mouse_double_click(button, point);
@ -434,7 +436,7 @@ impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> {
} }
ClickState::DoubleClick ClickState::DoubleClick
if !button_changed if !button_changed
&& elapsed < self.config.ui_config.mouse.triple_click.threshold => && elapsed < self.ctx.config().ui_config.mouse.triple_click.threshold =>
{ {
self.ctx.mouse_mut().block_url_launcher = true; self.ctx.mouse_mut().block_url_launcher = true;
self.on_mouse_triple_click(button, point); self.on_mouse_triple_click(button, point);
@ -512,7 +514,7 @@ impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> {
return; return;
} }
if let Some(ref launcher) = self.config.ui_config.mouse.url.launcher { if let Some(ref launcher) = self.ctx.config().ui_config.mouse.url.launcher {
let mut args = launcher.args().to_vec(); let mut args = launcher.args().to_vec();
args.push(self.ctx.terminal().url_to_string(url)); args.push(self.ctx.terminal().url_to_string(url));
@ -566,10 +568,11 @@ impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> {
} }
} else if self.ctx.terminal().mode().contains(alt_scroll_modes) && !modifiers.shift { } else if self.ctx.terminal().mode().contains(alt_scroll_modes) && !modifiers.shift {
let multiplier = i32::from( let multiplier = i32::from(
self.config self.ctx
.config()
.scrolling .scrolling
.faux_multiplier() .faux_multiplier()
.unwrap_or_else(|| self.config.scrolling.multiplier()), .unwrap_or_else(|| self.ctx.config().scrolling.multiplier()),
); );
self.ctx.mouse_mut().scroll_px += new_scroll_px * multiplier; self.ctx.mouse_mut().scroll_px += new_scroll_px * multiplier;
@ -584,7 +587,7 @@ impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> {
} }
self.ctx.write_to_pty(content); self.ctx.write_to_pty(content);
} else { } else {
let multiplier = i32::from(self.config.scrolling.multiplier()); let multiplier = i32::from(self.ctx.config().scrolling.multiplier());
self.ctx.mouse_mut().scroll_px += new_scroll_px * multiplier; self.ctx.mouse_mut().scroll_px += new_scroll_px * multiplier;
let lines = self.ctx.mouse().scroll_px / height; let lines = self.ctx.mouse().scroll_px / height;
@ -677,7 +680,7 @@ impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> {
c.encode_utf8(&mut bytes[..]); c.encode_utf8(&mut bytes[..]);
} }
if self.config.alt_send_esc() if self.ctx.config().alt_send_esc()
&& *self.ctx.received_count() == 0 && *self.ctx.received_count() == 0
&& self.ctx.modifiers().alt() && self.ctx.modifiers().alt()
&& utf8_len == 1 && utf8_len == 1
@ -698,7 +701,9 @@ impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> {
fn process_key_bindings(&mut self, input: KeyboardInput) { fn process_key_bindings(&mut self, input: KeyboardInput) {
let mut suppress_chars = None; let mut suppress_chars = None;
for binding in &self.config.ui_config.key_bindings { for i in 0..self.ctx.config().ui_config.key_bindings.len() {
let binding = &self.ctx.config().ui_config.key_bindings[i];
let key = match (binding.trigger, input.virtual_keycode) { let key = match (binding.trigger, input.virtual_keycode) {
(Key::Scancode(_), _) => Key::Scancode(input.scancode), (Key::Scancode(_), _) => Key::Scancode(input.scancode),
(_, Some(key)) => Key::from_glutin_input(key), (_, Some(key)) => Key::from_glutin_input(key),
@ -707,6 +712,7 @@ impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> {
if binding.is_triggered_by(*self.ctx.terminal().mode(), input.modifiers, &key, false) { if binding.is_triggered_by(*self.ctx.terminal().mode(), input.modifiers, &key, false) {
// Binding was triggered; run the action // Binding was triggered; run the action
let binding = binding.clone();
binding.execute(&mut self.ctx, false); binding.execute(&mut self.ctx, false);
// Don't suppress when there has been a `ReceiveChar` action // Don't suppress when there has been a `ReceiveChar` action
@ -723,7 +729,9 @@ impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> {
/// The provided mode, mods, and key must match what is allowed by a binding /// The provided mode, mods, and key must match what is allowed by a binding
/// for its action to be executed. /// for its action to be executed.
fn process_mouse_bindings(&mut self, mods: ModifiersState, button: MouseButton) { fn process_mouse_bindings(&mut self, mods: ModifiersState, button: MouseButton) {
for binding in &self.config.ui_config.mouse_bindings { for i in 0..self.ctx.config().ui_config.mouse_bindings.len() {
let binding = &self.ctx.config().ui_config.mouse_bindings[i];
if binding.is_triggered_by(*self.ctx.terminal().mode(), mods, &button, true) { if binding.is_triggered_by(*self.ctx.terminal().mode(), mods, &button, true) {
// binding was triggered; run the action // binding was triggered; run the action
let mouse_mode = !mods.shift let mouse_mode = !mods.shift
@ -732,6 +740,8 @@ impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> {
| TermMode::MOUSE_DRAG | TermMode::MOUSE_DRAG
| TermMode::MOUSE_MOTION, | TermMode::MOUSE_MOTION,
); );
let binding = binding.clone();
binding.execute(&mut self.ctx, mouse_mode); binding.execute(&mut self.ctx, mouse_mode);
} }
} }
@ -780,7 +790,7 @@ impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> {
/// Copy text selection. /// Copy text selection.
fn copy_selection(&mut self) { fn copy_selection(&mut self) {
if self.config.selection.save_to_clipboard { if self.ctx.config().selection.save_to_clipboard {
self.ctx.copy_selection(ClipboardType::Clipboard); self.ctx.copy_selection(ClipboardType::Clipboard);
} }
self.ctx.copy_selection(ClipboardType::Selection); self.ctx.copy_selection(ClipboardType::Selection);
@ -849,6 +859,7 @@ mod tests {
pub received_count: usize, pub received_count: usize,
pub suppress_chars: bool, pub suppress_chars: bool,
pub modifiers: Modifiers, pub modifiers: Modifiers,
config: &'a Config,
} }
impl<'a, T: EventListener> super::ActionContext<T> for ActionContext<'a, T> { impl<'a, T: EventListener> super::ActionContext<T> for ActionContext<'a, T> {
@ -947,6 +958,10 @@ mod tests {
fn message(&self) -> Option<&Message> { fn message(&self) -> Option<&Message> {
self.message_buffer.message() self.message_buffer.message()
} }
fn config(&self) -> &Config {
self.config
}
} }
macro_rules! test_clickstate { macro_rules! test_clickstate {
@ -1002,9 +1017,10 @@ mod tests {
suppress_chars: false, suppress_chars: false,
modifiers: Modifiers::default(), modifiers: Modifiers::default(),
message_buffer: &mut message_buffer, message_buffer: &mut message_buffer,
config: &cfg,
}; };
let mut processor = Processor::new(context, &mut cfg); let mut processor = Processor::new(context);
if let Event::WindowEvent { event: WindowEvent::MouseInput { state, button, modifiers, .. }, .. } = $input { if let Event::WindowEvent { event: WindowEvent::MouseInput { state, button, modifiers, .. }, .. } = $input {
processor.mouse_input(state, button, modifiers); processor.mouse_input(state, button, modifiers);