mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-18 13:55:23 -05:00
parent
4dd327f0ae
commit
fa6ceacfa4
5 changed files with 101 additions and 90 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
*processor.config = config;
|
let font = config.font.clone().with_size(*processor.ctx.font_size);
|
||||||
|
processor.ctx.display_update_pending.font = Some(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
*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,15 +553,16 @@ 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 =
|
||||||
|
display_update_pending.dimensions.get_or_insert_with(|| {
|
||||||
PhysicalSize::new(f64::from(old_width), f64::from(old_height))
|
PhysicalSize::new(f64::from(old_width), f64::from(old_height))
|
||||||
});
|
});
|
||||||
dimensions.width *= f64::from(dpr_change);
|
dimensions.width *= f64::from(dpr_change);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue