aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src
diff options
context:
space:
mode:
authorAyose <ayosec@gmail.com>2021-09-23 22:11:02 +0100
committerAyose <ayosec@gmail.com>2021-09-23 22:11:02 +0100
commit91b85669b88492bb10b832d2dc6df7641a26d3db (patch)
tree89443c85ad9396c9ac03bc3ec4689498427b5f20 /alacritty/src
parent699a7a9d13fd741bf4430514ac8d6f579a68484a (diff)
parent58985a4dcbe464230b5d2566ee68e2d34a1788c8 (diff)
downloadr-alacritty-91b85669b88492bb10b832d2dc6df7641a26d3db.tar.gz
r-alacritty-91b85669b88492bb10b832d2dc6df7641a26d3db.tar.bz2
r-alacritty-91b85669b88492bb10b832d2dc6df7641a26d3db.zip
Merge remote-tracking branch 'vendor/master' into graphics
Diffstat (limited to 'alacritty/src')
-rw-r--r--alacritty/src/cli.rs326
-rw-r--r--alacritty/src/config/bindings.rs54
-rw-r--r--alacritty/src/config/color.rs1
-rw-r--r--alacritty/src/config/mod.rs12
-rw-r--r--alacritty/src/config/monitor.rs37
-rw-r--r--alacritty/src/config/ui_config.rs11
-rw-r--r--alacritty/src/config/window.rs8
-rw-r--r--alacritty/src/display/content.rs8
-rw-r--r--alacritty/src/display/mod.rs26
-rw-r--r--alacritty/src/display/window.rs6
-rw-r--r--alacritty/src/event.rs64
-rw-r--r--alacritty/src/input.rs91
-rw-r--r--alacritty/src/logging.rs18
-rw-r--r--alacritty/src/main.rs2
-rw-r--r--alacritty/src/renderer/mod.rs12
-rw-r--r--alacritty/src/renderer/rects.rs6
16 files changed, 335 insertions, 347 deletions
diff --git a/alacritty/src/cli.rs b/alacritty/src/cli.rs
index 682bdde3..a1480807 100644
--- a/alacritty/src/cli.rs
+++ b/alacritty/src/cli.rs
@@ -1,219 +1,101 @@
use std::cmp::max;
use std::path::PathBuf;
-use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
use log::{self, error, LevelFilter};
use serde_yaml::Value;
+use structopt::StructOpt;
use alacritty_terminal::config::Program;
use crate::config::serde_utils;
-use crate::config::window::DEFAULT_NAME;
+use crate::config::window::{Class, DEFAULT_NAME};
use crate::config::Config;
-#[cfg(not(any(target_os = "macos", windows)))]
-const CONFIG_PATH: &str = "$XDG_CONFIG_HOME/alacritty/alacritty.yml";
-#[cfg(windows)]
-const CONFIG_PATH: &str = "%APPDATA%\\alacritty\\alacritty.yml";
-#[cfg(target_os = "macos")]
-const CONFIG_PATH: &str = "$HOME/.config/alacritty/alacritty.yml";
-
/// Options specified on the command line.
+#[derive(StructOpt, Debug)]
+#[structopt(author, about, version = env!("VERSION"))]
pub struct Options {
+ /// Print all events to stdout.
+ #[structopt(long)]
pub print_events: bool,
+
+ /// Generates ref test.
+ #[structopt(long)]
pub ref_test: bool,
+
+ /// Defines the window title [default: Alacritty].
+ #[structopt(short, long)]
pub title: Option<String>,
- pub class_instance: Option<String>,
- pub class_general: Option<String>,
- pub embed: Option<String>,
- pub log_level: LevelFilter,
- pub command: Option<Program>,
- pub hold: bool,
- pub working_directory: Option<PathBuf>,
- pub config_path: Option<PathBuf>,
- pub config_options: Value,
-}
-impl Default for Options {
- fn default() -> Options {
- Options {
- print_events: false,
- ref_test: false,
- title: None,
- class_instance: None,
- class_general: None,
- embed: None,
- log_level: LevelFilter::Warn,
- command: None,
- hold: false,
- working_directory: None,
- config_path: None,
- config_options: Value::Null,
- }
- }
-}
+ /// Defines window class/app_id on X11/Wayland [default: Alacritty].
+ #[structopt(long, value_name = "instance> | <instance>,<general", parse(try_from_str = parse_class))]
+ pub class: Option<Class>,
-impl Options {
- /// Build `Options` from command line arguments.
- pub fn new() -> Self {
- let mut version = crate_version!().to_owned();
- let commit_hash = env!("GIT_HASH");
- if !commit_hash.is_empty() {
- version = format!("{} ({})", version, commit_hash);
- }
+ /// Defines the X11 window ID (as a decimal integer) to embed Alacritty within.
+ #[structopt(long)]
+ pub embed: Option<String>,
- let mut options = Options::default();
-
- let matches = App::new(crate_name!())
- .version(version.as_str())
- .author(crate_authors!("\n"))
- .about(crate_description!())
- .arg(Arg::with_name("ref-test").long("ref-test").help("Generates ref test"))
- .arg(
- Arg::with_name("print-events")
- .long("print-events")
- .help("Print all events to stdout"),
- )
- .arg(
- Arg::with_name("title")
- .long("title")
- .short("t")
- .takes_value(true)
- .help(&format!("Defines the window title [default: {}]", DEFAULT_NAME)),
- )
- .arg(
- Arg::with_name("class")
- .long("class")
- .value_name("instance> | <instance>,<general")
- .takes_value(true)
- .use_delimiter(true)
- .help(&format!(
- "Defines window class/app_id on X11/Wayland [default: {}]",
- DEFAULT_NAME
- )),
- )
- .arg(
- Arg::with_name("embed").long("embed").takes_value(true).help(
- "Defines the X11 window ID (as a decimal integer) to embed Alacritty within",
- ),
- )
- .arg(
- Arg::with_name("q")
- .short("q")
- .multiple(true)
- .conflicts_with("v")
- .help("Reduces the level of verbosity (the min level is -qq)"),
- )
- .arg(
- Arg::with_name("v")
- .short("v")
- .multiple(true)
- .conflicts_with("q")
- .help("Increases the level of verbosity (the max level is -vvv)"),
- )
- .arg(
- Arg::with_name("working-directory")
- .long("working-directory")
- .takes_value(true)
- .help("Start the shell in the specified working directory"),
- )
- .arg(Arg::with_name("config-file").long("config-file").takes_value(true).help(
- &format!("Specify alternative configuration file [default: {}]", CONFIG_PATH),
- ))
- .arg(
- Arg::with_name("command")
- .long("command")
- .short("e")
- .multiple(true)
- .takes_value(true)
- .allow_hyphen_values(true)
- .help("Command and args to execute (must be last argument)"),
- )
- .arg(Arg::with_name("hold").long("hold").help("Remain open after child process exits"))
- .arg(
- Arg::with_name("option")
- .long("option")
- .short("o")
- .multiple(true)
- .takes_value(true)
- .help("Override configuration file options [example: cursor.style=Beam]"),
- )
- .get_matches();
-
- if matches.is_present("ref-test") {
- options.ref_test = true;
- }
+ /// Start the shell in the specified working directory.
+ #[structopt(long)]
+ pub working_directory: Option<PathBuf>,
- if matches.is_present("print-events") {
- options.print_events = true;
- }
+ /// Specify alternative configuration file [default: $XDG_CONFIG_HOME/alacritty/alacritty.yml].
+ #[cfg(not(any(target_os = "macos", windows)))]
+ #[structopt(long)]
+ pub config_file: Option<PathBuf>,
- if let Some(mut class) = matches.values_of("class") {
- options.class_instance = class.next().map(|instance| instance.to_owned());
- options.class_general = class.next().map(|general| general.to_owned());
- }
+ /// Specify alternative configuration file [default: %APPDATA%\alacritty\alacritty.yml].
+ #[cfg(windows)]
+ #[structopt(long)]
+ pub config_file: Option<PathBuf>,
- options.title = matches.value_of("title").map(ToOwned::to_owned);
- options.embed = matches.value_of("embed").map(ToOwned::to_owned);
+ /// Specify alternative configuration file [default: $HOME/.config/alacritty/alacritty.yml].
+ #[cfg(target_os = "macos")]
+ #[structopt(long)]
+ pub config_file: Option<PathBuf>,
- match matches.occurrences_of("q") {
- 0 => (),
- 1 => options.log_level = LevelFilter::Error,
- _ => options.log_level = LevelFilter::Off,
- }
+ /// Remain open after child process exits.
+ #[structopt(long)]
+ pub hold: bool,
- match matches.occurrences_of("v") {
- 0 if !options.print_events => options.log_level = LevelFilter::Warn,
- 0 | 1 => options.log_level = LevelFilter::Info,
- 2 => options.log_level = LevelFilter::Debug,
- _ => options.log_level = LevelFilter::Trace,
- }
+ /// CLI options for config overrides.
+ #[structopt(skip)]
+ pub config_options: Value,
- if let Some(dir) = matches.value_of("working-directory") {
- options.working_directory = Some(PathBuf::from(dir.to_string()));
- }
+ /// Reduces the level of verbosity (the min level is -qq).
+ #[structopt(short, conflicts_with("verbose"), parse(from_occurrences))]
+ quiet: u8,
- if let Some(path) = matches.value_of("config-file") {
- options.config_path = Some(PathBuf::from(path.to_string()));
- }
+ /// Increases the level of verbosity (the max level is -vvv).
+ #[structopt(short, conflicts_with("quiet"), parse(from_occurrences))]
+ verbose: u8,
- if let Some(mut args) = matches.values_of("command") {
- // The following unwrap is guaranteed to succeed.
- // If `command` exists it must also have a first item since
- // `Arg::min_values(1)` is set.
- let program = String::from(args.next().unwrap());
- let args = args.map(String::from).collect();
- options.command = Some(Program::WithArgs { program, args });
- }
+ /// Command and args to execute (must be last argument).
+ #[structopt(short = "e", long, allow_hyphen_values = true)]
+ command: Vec<String>,
- if matches.is_present("hold") {
- options.hold = true;
- }
+ /// Override configuration file options [example: cursor.style=Beam].
+ #[structopt(short = "o", long)]
+ option: Vec<String>,
+}
- if let Some(config_options) = matches.values_of("option") {
- for option in config_options {
- match option_as_value(option) {
- Ok(value) => {
- options.config_options = serde_utils::merge(options.config_options, value);
- },
- Err(_) => eprintln!("Invalid CLI config option: {:?}", option),
- }
+impl Options {
+ pub fn new() -> Self {
+ let mut options = Self::from_args();
+
+ // Convert `--option` flags into serde `Value`.
+ for option in &options.option {
+ match option_as_value(option) {
+ Ok(value) => {
+ options.config_options = serde_utils::merge(options.config_options, value);
+ },
+ Err(_) => eprintln!("Invalid CLI config option: {:?}", option),
}
}
options
}
- /// Configuration file path.
- pub fn config_path(&self) -> Option<PathBuf> {
- self.config_path.clone()
- }
-
- /// CLI config options as deserializable serde value.
- pub fn config_options(&self) -> &Value {
- &self.config_options
- }
-
/// Override configuration file with options from the CLI.
pub fn override_config(&self, config: &mut Config) {
if let Some(working_directory) = &self.working_directory {
@@ -224,8 +106,8 @@ impl Options {
}
}
- if let Some(command) = &self.command {
- config.shell = Some(command.clone());
+ if let Some(command) = self.command() {
+ config.shell = Some(command);
}
config.hold = self.hold;
@@ -233,17 +115,14 @@ impl Options {
if let Some(title) = self.title.clone() {
config.ui_config.window.title = title
}
- if let Some(class_instance) = self.class_instance.clone() {
- config.ui_config.window.class.instance = class_instance;
- }
- if let Some(class_general) = self.class_general.clone() {
- config.ui_config.window.class.general = class_general;
+ if let Some(class) = &self.class {
+ config.ui_config.window.class = class.clone();
}
config.ui_config.window.dynamic_title &= self.title.is_none();
config.ui_config.window.embed = self.embed.as_ref().and_then(|embed| embed.parse().ok());
config.ui_config.debug.print_events |= self.print_events;
- config.ui_config.debug.log_level = max(config.ui_config.debug.log_level, self.log_level);
+ config.ui_config.debug.log_level = max(config.ui_config.debug.log_level, self.log_level());
config.ui_config.debug.ref_test |= self.ref_test;
if config.ui_config.debug.print_events {
@@ -251,6 +130,32 @@ impl Options {
max(config.ui_config.debug.log_level, LevelFilter::Info);
}
}
+
+ /// Logging filter level.
+ pub fn log_level(&self) -> LevelFilter {
+ match (self.quiet, self.verbose) {
+ // Force at least `Info` level for `--print-events`.
+ (_, 0) if self.print_events => LevelFilter::Info,
+
+ // Default.
+ (0, 0) => LevelFilter::Warn,
+
+ // Verbose.
+ (_, 1) => LevelFilter::Info,
+ (_, 2) => LevelFilter::Debug,
+ (0, _) => LevelFilter::Trace,
+
+ // Quiet.
+ (1, _) => LevelFilter::Error,
+ (..) => LevelFilter::Off,
+ }
+ }
+
+ /// Shell override passed through the CLI.
+ pub fn command(&self) -> Option<Program> {
+ let (program, args) = self.command.split_first()?;
+ Some(Program::WithArgs { program: program.clone(), args: args.to_vec() })
+ }
}
/// Format an option in the format of `parent.field=value` to a serde Value.
@@ -278,6 +183,23 @@ fn option_as_value(option: &str) -> Result<Value, serde_yaml::Error> {
serde_yaml::from_str(&yaml_text)
}
+/// Parse the class CLI parameter.
+fn parse_class(input: &str) -> Result<Class, String> {
+ match input.find(',') {
+ Some(position) => {
+ let general = input[position + 1..].to_owned();
+
+ // Warn the user if they've passed too many values.
+ if general.contains(',') {
+ return Err(String::from("Too many parameters"));
+ }
+
+ Ok(Class { instance: input[..position].into(), general })
+ },
+ None => Ok(Class { instance: input.into(), general: DEFAULT_NAME.into() }),
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -289,7 +211,7 @@ mod tests {
let mut config = Config::default();
let old_dynamic_title = config.ui_config.window.dynamic_title;
- Options::default().override_config(&mut config);
+ Options::new().override_config(&mut config);
assert_eq!(old_dynamic_title, config.ui_config.window.dynamic_title);
}
@@ -298,7 +220,7 @@ mod tests {
fn dynamic_title_overridden_by_options() {
let mut config = Config::default();
- let options = Options { title: Some("foo".to_owned()), ..Options::default() };
+ let options = Options { title: Some("foo".to_owned()), ..Options::new() };
options.override_config(&mut config);
assert!(!config.ui_config.window.dynamic_title);
@@ -309,7 +231,7 @@ mod tests {
let mut config = Config::default();
config.ui_config.window.title = "foo".to_owned();
- Options::default().override_config(&mut config);
+ Options::new().override_config(&mut config);
assert!(config.ui_config.window.dynamic_title);
}
@@ -350,4 +272,24 @@ mod tests {
assert_eq!(value, Value::Mapping(expected));
}
+
+ #[test]
+ fn parse_instance_class() {
+ let class = parse_class("one").unwrap();
+ assert_eq!(class.instance, "one");
+ assert_eq!(class.general, DEFAULT_NAME);
+ }
+
+ #[test]
+ fn parse_general_class() {
+ let class = parse_class("one,two").unwrap();
+ assert_eq!(class.instance, "one");
+ assert_eq!(class.general, "two");
+ }
+
+ #[test]
+ fn parse_invalid_class() {
+ let class = parse_class("one,two,three");
+ assert!(class.is_err());
+ }
}
diff --git a/alacritty/src/config/bindings.rs b/alacritty/src/config/bindings.rs
index 12349639..a4271430 100644
--- a/alacritty/src/config/bindings.rs
+++ b/alacritty/src/config/bindings.rs
@@ -103,11 +103,15 @@ pub enum Action {
/// Perform vi mode action.
#[config(skip)]
- ViAction(ViAction),
+ Vi(ViAction),
/// Perform search mode action.
#[config(skip)]
- SearchAction(SearchAction),
+ Search(SearchAction),
+
+ /// Perform mouse binding exclusive action.
+ #[config(skip)]
+ Mouse(MouseAction),
/// Paste contents of system clipboard.
Paste,
@@ -211,7 +215,7 @@ impl From<&'static str> for Action {
impl From<ViAction> for Action {
fn from(action: ViAction) -> Self {
- Self::ViAction(action)
+ Self::Vi(action)
}
}
@@ -223,7 +227,13 @@ impl From<ViMotion> for Action {
impl From<SearchAction> for Action {
fn from(action: SearchAction) -> Self {
- Self::SearchAction(action)
+ Self::Search(action)
+ }
+}
+
+impl From<MouseAction> for Action {
+ fn from(action: MouseAction) -> Self {
+ Self::Mouse(action)
}
}
@@ -232,7 +242,8 @@ impl Display for Action {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Action::ViMotion(motion) => motion.fmt(f),
- Action::ViAction(action) => action.fmt(f),
+ Action::Vi(action) => action.fmt(f),
+ Action::Mouse(action) => action.fmt(f),
_ => write!(f, "{:?}", self),
}
}
@@ -262,6 +273,7 @@ pub enum ViAction {
}
/// Search mode specific actions.
+#[allow(clippy::enum_variant_names)]
#[derive(ConfigDeserialize, Debug, Copy, Clone, PartialEq, Eq)]
pub enum SearchAction {
/// Move the focus to the next search match.
@@ -282,6 +294,13 @@ pub enum SearchAction {
SearchHistoryNext,
}
+/// Mouse binding specific actions.
+#[derive(ConfigDeserialize, Debug, Copy, Clone, PartialEq, Eq)]
+pub enum MouseAction {
+ /// Expand the selection to the current mouse cursor position.
+ ExpandSelection,
+}
+
macro_rules! bindings {
(
KeyBinding;
@@ -342,6 +361,7 @@ macro_rules! bindings {
pub fn default_mouse_bindings() -> Vec<MouseBinding> {
bindings!(
MouseBinding;
+ MouseButton::Right; MouseAction::ExpandSelection;
MouseButton::Middle, ~BindingMode::VI; Action::PasteSelection;
)
}
@@ -423,16 +443,16 @@ pub fn default_key_bindings() -> Vec<KeyBinding> {
F19, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[33~".into());
F20, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[34~".into());
NumpadEnter, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\n".into());
- Space, ModifiersState::SHIFT | ModifiersState::CTRL, +BindingMode::VI, ~BindingMode::SEARCH;
- Action::ScrollToBottom;
Space, ModifiersState::SHIFT | ModifiersState::CTRL, ~BindingMode::SEARCH;
Action::ToggleViMode;
+ Space, ModifiersState::SHIFT | ModifiersState::CTRL, +BindingMode::VI, ~BindingMode::SEARCH;
+ Action::ScrollToBottom;
Escape, +BindingMode::VI, ~BindingMode::SEARCH;
Action::ClearSelection;
I, +BindingMode::VI, ~BindingMode::SEARCH;
- Action::ScrollToBottom;
- I, +BindingMode::VI, ~BindingMode::SEARCH;
Action::ToggleViMode;
+ I, +BindingMode::VI, ~BindingMode::SEARCH;
+ Action::ScrollToBottom;
C, ModifiersState::CTRL, +BindingMode::VI, ~BindingMode::SEARCH;
Action::ToggleViMode;
Y, ModifiersState::CTRL, +BindingMode::VI, ~BindingMode::SEARCH;
@@ -1026,6 +1046,9 @@ impl<'a> Deserialize<'a> for RawBinding {
SearchAction::deserialize(value.clone())
{
Some(search_action.into())
+ } else if let Ok(mouse_action) = MouseAction::deserialize(value.clone())
+ {
+ Some(mouse_action.into())
} else {
match Action::deserialize(value.clone()).map_err(V::Error::custom) {
Ok(action) => Some(action),
@@ -1081,7 +1104,7 @@ impl<'a> Deserialize<'a> for RawBinding {
let action = match (action, chars, command) {
(Some(action @ Action::ViMotion(_)), None, None)
- | (Some(action @ Action::ViAction(_)), None, None) => {
+ | (Some(action @ Action::Vi(_)), None, None) => {
if !mode.intersects(BindingMode::VI) || not_mode.intersects(BindingMode::VI)
{
return Err(V::Error::custom(format!(
@@ -1091,7 +1114,7 @@ impl<'a> Deserialize<'a> for RawBinding {
}
action
},
- (Some(action @ Action::SearchAction(_)), None, None) => {
+ (Some(action @ Action::Search(_)), None, None) => {
if !mode.intersects(BindingMode::SEARCH) {
return Err(V::Error::custom(format!(
"action `{}` is only available in search mode, try adding `mode: \
@@ -1101,6 +1124,15 @@ impl<'a> Deserialize<'a> for RawBinding {
}
action
},
+ (Some(action @ Action::Mouse(_)), None, None) => {
+ if mouse.is_none() {
+ return Err(V::Error::custom(format!(
+ "action `{}` is only available for mouse bindings",
+ action,
+ )));
+ }
+ action
+ },
(Some(action), None, None) => action,
(None, Some(chars), None) => Action::Esc(chars),
(None, None, Some(cmd)) => Action::Command(cmd),
diff --git a/alacritty/src/config/color.rs b/alacritty/src/config/color.rs
index ddb1da29..c0076edb 100644
--- a/alacritty/src/config/color.rs
+++ b/alacritty/src/config/color.rs
@@ -17,6 +17,7 @@ pub struct Colors {
pub search: SearchColors,
pub line_indicator: LineIndicatorColors,
pub hints: HintColors,
+ pub transparent_background_colors: bool,
}
impl Colors {
diff --git a/alacritty/src/config/mod.rs b/alacritty/src/config/mod.rs
index e2476bb2..4a3c0ae9 100644
--- a/alacritty/src/config/mod.rs
+++ b/alacritty/src/config/mod.rs
@@ -22,7 +22,9 @@ mod bindings;
mod mouse;
use crate::cli::Options;
-pub use crate::config::bindings::{Action, Binding, BindingMode, Key, SearchAction, ViAction};
+pub use crate::config::bindings::{
+ Action, Binding, BindingMode, Key, MouseAction, SearchAction, ViAction,
+};
#[cfg(test)]
pub use crate::config::mouse::{ClickHandler, Mouse};
use crate::config::ui_config::UiConfig;
@@ -99,8 +101,8 @@ impl From<serde_yaml::Error> for Error {
/// Load the configuration file.
pub fn load(options: &Options) -> Config {
- let config_options = options.config_options().clone();
- let config_path = options.config_path().or_else(installed_config);
+ let config_options = options.config_options.clone();
+ let config_path = options.config_file.clone().or_else(installed_config);
// Load the config using the following fallback behavior:
// - Config path + CLI overrides
@@ -126,7 +128,7 @@ pub fn load(options: &Options) -> Config {
/// Attempt to reload the configuration file.
pub fn reload(config_path: &Path, options: &Options) -> Result<Config> {
// Load config, propagating errors.
- let config_options = options.config_options().clone();
+ let config_options = options.config_options.clone();
let mut config = load_from(config_path, config_options)?;
after_loading(&mut config, options);
@@ -157,7 +159,7 @@ fn load_from(path: &Path, cli_config: Value) -> Result<Config> {
/// Deserialize configuration file from path.
fn read_config(path: &Path, cli_config: Value) -> Result<Config> {
let mut config_paths = Vec::new();
- let mut config_value = parse_config(&path, &mut config_paths, IMPORT_RECURSION_LIMIT)?;
+ let mut config_value = parse_config(path, &mut config_paths, IMPORT_RECURSION_LIMIT)?;
// Override config with CLI options.
config_value = serde_utils::merge(config_value, cli_config);
diff --git a/alacritty/src/config/monitor.rs b/alacritty/src/config/monitor.rs
index 4a694fac..e3dd0556 100644
--- a/alacritty/src/config/monitor.rs
+++ b/alacritty/src/config/monitor.rs
@@ -1,4 +1,3 @@
-use std::fs;
use std::path::PathBuf;
use std::sync::mpsc;
use std::time::Duration;
@@ -16,23 +15,21 @@ const DEBOUNCE_DELAY: Duration = Duration::from_millis(10);
const DEBOUNCE_DELAY: Duration = Duration::from_millis(1000);
pub fn watch(mut paths: Vec<PathBuf>, event_proxy: EventProxy) {
- // Canonicalize all paths, filtering out the ones that do not exist.
- paths = paths
- .drain(..)
- .filter_map(|path| match fs::canonicalize(&path) {
- Ok(path) => Some(path),
- Err(err) => {
- error!("Unable to canonicalize config path {:?}: {}", path, err);
- None
- },
- })
- .collect();
-
// Don't monitor config if there is no path to watch.
if paths.is_empty() {
return;
}
+ // Canonicalize paths, keeping the base paths for symlinks.
+ for i in 0..paths.len() {
+ if let Ok(canonical_path) = paths[i].canonicalize() {
+ match paths[i].symlink_metadata() {
+ Ok(metadata) if metadata.file_type().is_symlink() => paths.push(canonical_path),
+ _ => paths[i] = canonical_path,
+ }
+ }
+ }
+
// The Duration argument is a debouncing period.
let (tx, rx) = mpsc::channel();
let mut watcher = match watcher(tx, DEBOUNCE_DELAY) {
@@ -73,17 +70,15 @@ pub fn watch(mut paths: Vec<PathBuf>, event_proxy: EventProxy) {
};
match event {
- DebouncedEvent::Rename(..) => continue,
- DebouncedEvent::Write(path)
+ DebouncedEvent::Rename(_, path)
+ | DebouncedEvent::Write(path)
| DebouncedEvent::Create(path)
- | DebouncedEvent::Chmod(path) => {
- if !paths.contains(&path) {
- continue;
- }
-
+ | DebouncedEvent::Chmod(path)
+ if paths.contains(&path) =>
+ {
// Always reload the primary configuration file.
event_proxy.send_event(Event::ConfigReload(paths[0].clone()));
- },
+ }
_ => {},
}
}
diff --git a/alacritty/src/config/ui_config.rs b/alacritty/src/config/ui_config.rs
index a58c1fd3..3ce02161 100644
--- a/alacritty/src/config/ui_config.rs
+++ b/alacritty/src/config/ui_config.rs
@@ -69,7 +69,8 @@ pub struct UiConfig {
mouse_bindings: MouseBindings,
/// Background opacity from 0.0 to 1.0.
- background_opacity: Percentage,
+ #[config(deprecated = "use window.opacity instead")]
+ background_opacity: Option<Percentage>,
}
impl Default for UiConfig {
@@ -115,13 +116,13 @@ impl UiConfig {
}
#[inline]
- pub fn background_opacity(&self) -> f32 {
- self.background_opacity.as_f32()
+ pub fn window_opacity(&self) -> f32 {
+ self.background_opacity.unwrap_or(self.window.opacity).as_f32()
}
#[inline]
pub fn key_bindings(&self) -> &[KeyBinding] {
- &self.key_bindings.0.as_slice()
+ self.key_bindings.0.as_slice()
}
#[inline]
@@ -399,7 +400,7 @@ impl LazyRegexVariant {
};
// Compile the regex.
- let regex_search = match RegexSearch::new(&regex) {
+ let regex_search = match RegexSearch::new(regex) {
Ok(regex_search) => regex_search,
Err(error) => {
error!("hint regex is invalid: {}", error);
diff --git a/alacritty/src/config/window.rs b/alacritty/src/config/window.rs
index d74390d8..f7a7511c 100644
--- a/alacritty/src/config/window.rs
+++ b/alacritty/src/config/window.rs
@@ -7,7 +7,7 @@ use serde::de::{self, MapAccess, Visitor};
use serde::{Deserialize, Deserializer};
use alacritty_config_derive::ConfigDeserialize;
-use alacritty_terminal::config::LOG_TARGET_CONFIG;
+use alacritty_terminal::config::{Percentage, LOG_TARGET_CONFIG};
use alacritty_terminal::index::Column;
use crate::config::ui_config::Delta;
@@ -15,7 +15,7 @@ use crate::config::ui_config::Delta;
/// Default Alacritty name, used for window title and class.
pub const DEFAULT_NAME: &str = "Alacritty";
-#[derive(ConfigDeserialize, Debug, Clone, PartialEq, Eq)]
+#[derive(ConfigDeserialize, Debug, Clone, PartialEq)]
pub struct WindowConfig {
/// Initial position.
pub position: Option<Delta<i32>>,
@@ -45,6 +45,9 @@ pub struct WindowConfig {
/// Window class.
pub class: Class,
+ /// Background opacity from 0.0 to 1.0.
+ pub opacity: Percentage,
+
/// Pixel padding.
padding: Delta<u8>,
@@ -64,6 +67,7 @@ impl Default for WindowConfig {
gtk_theme_variant: Default::default(),
dynamic_padding: Default::default(),
class: Default::default(),
+ opacity: Default::default(),
padding: Default::default(),
dimensions: Default::default(),
}
diff --git a/alacritty/src/display/content.rs b/alacritty/src/display/content.rs
index b470343e..0bc2f46f 100644
--- a/alacritty/src/display/content.rs
+++ b/alacritty/src/display/content.rs
@@ -45,7 +45,7 @@ impl<'a> RenderableContent<'a> {
term: &'a Term<T>,
search_state: &'a SearchState,
) -> Self {
- let search = search_state.dfas().map(|dfas| Regex::new(&term, dfas));
+ let search = search_state.dfas().map(|dfas| Regex::new(term, dfas));
let focused_match = search_state.focused_match();
let terminal_content = term.renderable_content();
@@ -205,7 +205,7 @@ impl RenderableCell {
mem::swap(&mut fg, &mut bg);
1.0
} else {
- Self::compute_bg_alpha(cell.bg)
+ Self::compute_bg_alpha(&content.config.ui_config, cell.bg)
};
let is_selected = content.terminal_content.selection.map_or(false, |selection| {
@@ -353,9 +353,11 @@ impl RenderableCell {
/// using the named input color, rather than checking the RGB of the background after its color
/// is computed.
#[inline]
- fn compute_bg_alpha(bg: Color) -> f32 {
+ fn compute_bg_alpha(config: &UiConfig, bg: Color) -> f32 {
if bg == Color::Named(NamedColor::Background) {
0.
+ } else if config.colors.transparent_background_colors {
+ config.window_opacity()
} else {
1.
}
diff --git a/alacritty/src/display/mod.rs b/alacritty/src/display/mod.rs
index 162c70b9..5e958f03 100644
--- a/alacritty/src/display/mod.rs
+++ b/alacritty/src/display/mod.rs
@@ -80,7 +80,7 @@ pub enum Error {
Render(renderer::Error),
/// Error during buffer swap.
- ContextError(glutin::ContextError),
+ Context(glutin::ContextError),
}
impl std::error::Error for Error {
@@ -89,7 +89,7 @@ impl std::error::Error for Error {
Error::Window(err) => err.source(),
Error::Font(err) => err.source(),
Error::Render(err) => err.source(),
- Error::ContextError(err) => err.source(),
+ Error::Context(err) => err.source(),
}
}
}
@@ -100,7 +100,7 @@ impl fmt::Display for Error {
Error::Window(err) => err.fmt(f),
Error::Font(err) => err.fmt(f),
Error::Render(err) => err.fmt(f),
- Error::ContextError(err) => err.fmt(f),
+ Error::Context(err) => err.fmt(f),
}
}
}
@@ -125,7 +125,7 @@ impl From<renderer::Error> for Error {
impl From<glutin::ContextError> for Error {
fn from(val: glutin::ContextError) -> Self {
- Error::ContextError(val)
+ Error::Context(val)
}
}
@@ -242,7 +242,7 @@ impl Display {
// Spawn the Alacritty window.
let mut window = Window::new(
event_loop,
- &config,
+ config,
estimated_size,
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
wayland_event_queue.as_ref(),
@@ -299,7 +299,7 @@ impl Display {
// Disable shadows for transparent windows on macOS.
#[cfg(target_os = "macos")]
- window.set_has_shadow(config.ui_config.background_opacity() >= 1.0);
+ window.set_has_shadow(config.ui_config.window_opacity() >= 1.0);
// On Wayland we can safely ignore this call, since the window isn't visible until you
// actually draw something into it and commit those changes.
@@ -487,7 +487,7 @@ impl Display {
// Collect renderable content before the terminal is dropped.
let mut content = RenderableContent::new(config, self, &terminal, search_state);
let mut grid_cells = Vec::new();
- while let Some(cell) = content.next() {
+ for cell in &mut content {
grid_cells.push(cell);
}
let background_color = content.color(NamedColor::Background as usize);
@@ -611,7 +611,7 @@ impl Display {
for (i, message_text) in text.iter().enumerate() {
let point = Point::new(start_line + i, Column(0));
self.renderer.with_api(&config.ui_config, &size_info, |mut api| {
- api.render_string(glyph_cache, point, fg, bg, &message_text);
+ api.render_string(glyph_cache, point, fg, bg, message_text);
});
}
} else {
@@ -682,7 +682,7 @@ impl Display {
let vi_highlighted_hint = if term.mode().contains(TermMode::VI) {
let mods = ModifiersState::all();
let point = term.vi_mode_cursor.point;
- hint::highlighted_at(&term, config, point, mods)
+ hint::highlighted_at(term, config, point, mods)
} else {
None
};
@@ -698,7 +698,7 @@ impl Display {
// Find highlighted hint at mouse position.
let point = mouse.point(&self.size_info, term.grid().display_offset());
- let highlighted_hint = hint::highlighted_at(&term, config, point, modifiers);
+ let highlighted_hint = hint::highlighted_at(term, config, point, modifiers);
// Update cursor shape.
if highlighted_hint.is_some() {
@@ -760,7 +760,7 @@ impl Display {
let fg = config.ui_config.colors.search_bar_foreground();
let bg = config.ui_config.colors.search_bar_background();
- self.renderer.with_api(&config.ui_config, &size_info, |mut api| {
+ self.renderer.with_api(&config.ui_config, size_info, |mut api| {
api.render_string(glyph_cache, point, fg, bg, &text);
});
}
@@ -778,7 +778,7 @@ impl Display {
let fg = config.ui_config.colors.primary.background;
let bg = config.ui_config.colors.normal.red;
- self.renderer.with_api(&config.ui_config, &size_info, |mut api| {
+ self.renderer.with_api(&config.ui_config, size_info, |mut api| {
api.render_string(glyph_cache, point, fg, bg, &timing);
});
}
@@ -801,7 +801,7 @@ impl Display {
// Do not render anything if it would obscure the vi mode cursor.
if vi_mode_point.map_or(true, |point| point.line != 0 || point.column < column) {
let glyph_cache = &mut self.glyph_cache;
- self.renderer.with_api(&config.ui_config, &size_info, |mut api| {
+ self.renderer.with_api(&config.ui_config, size_info, |mut api| {
api.render_string(glyph_cache, Point::new(0, column), fg, bg, &text);
});
}
diff --git a/alacritty/src/display/window.rs b/alacritty/src/display/window.rs
index 7302c687..12416700 100644
--- a/alacritty/src/display/window.rs
+++ b/alacritty/src/display/window.rs
@@ -177,7 +177,7 @@ impl Window {
wayland_event_queue: Option<&EventQueue>,
) -> Result<Window> {
let window_config = &config.ui_config.window;
- let window_builder = Window::get_platform_window(&window_config.title, &window_config);
+ let window_builder = Window::get_platform_window(&window_config.title, window_config);
// Check if we're running Wayland to disable vsync.
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
@@ -186,9 +186,9 @@ impl Window {
let is_wayland = false;
let windowed_context =
- create_gl_window(window_builder.clone(), &event_loop, false, !is_wayland, size)
+ create_gl_window(window_builder.clone(), event_loop, false, !is_wayland, size)
.or_else(|_| {
- create_gl_window(window_builder, &event_loop, true, !is_wayland, size)
+ create_gl_window(window_builder, event_loop, true, !is_wayland, size)
})?;
// Text cursor.
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
index 64283eb7..cc817f6e 100644
--- a/alacritty/src/event.rs
+++ b/alacritty/src/event.rs
@@ -65,7 +65,7 @@ const MAX_SEARCH_HISTORY_SIZE: usize = 255;
/// Events dispatched through the UI event loop.
#[derive(Debug, Clone)]
pub enum Event {
- TerminalEvent(TerminalEvent),
+ Terminal(TerminalEvent),
DprChanged(f64, (u32, u32)),
Scroll(Scroll),
ConfigReload(PathBuf),
@@ -82,7 +82,7 @@ impl From<Event> for GlutinEvent<'_, Event> {
impl From<TerminalEvent> for Event {
fn from(event: TerminalEvent) -> Self {
- Event::TerminalEvent(event)
+ Event::Terminal(event)
}
}
@@ -421,11 +421,12 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
self.search_state.origin = self.terminal.vi_mode_cursor.point;
self.search_state.display_offset_delta = 0;
} else {
- let screen_lines = self.terminal.screen_lines();
+ let viewport_top = Line(-(self.terminal.grid().display_offset() as i32)) - 1;
+ let viewport_bottom = viewport_top + self.terminal.bottommost_line();
let last_column = self.terminal.last_column();
self.search_state.origin = match direction {
- Direction::Right => Point::new(Line(0), Column(0)),
- Direction::Left => Point::new(Line(screen_lines as i32 - 2), last_column),
+ Direction::Right => Point::new(viewport_top, Column(0)),
+ Direction::Left => Point::new(viewport_bottom, last_column),
};
}
@@ -670,6 +671,42 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
}
}
+ /// Expand the selection to the current mouse cursor position.
+ #[inline]
+ fn expand_selection(&mut self) {
+ let selection_type = match self.mouse().click_state {
+ ClickState::Click => {
+ if self.modifiers().ctrl() {
+ SelectionType::Block
+ } else {
+ SelectionType::Simple
+ }
+ },
+ ClickState::DoubleClick => SelectionType::Semantic,
+ ClickState::TripleClick => SelectionType::Lines,
+ ClickState::None => return,
+ };
+
+ // Load mouse point, treating message bar and padding as the closest cell.
+ let display_offset = self.terminal().grid().display_offset();
+ let point = self.mouse().point(&self.size_info(), display_offset);
+
+ let cell_side = self.mouse().cell_side;
+
+ let selection = match &mut self.terminal_mut().selection {
+ Some(selection) => selection,
+ None => return,
+ };
+
+ selection.ty = selection_type;
+ self.update_selection(point, cell_side);
+
+ // Move vi mode cursor to mouse click position.
+ if self.terminal().mode().contains(TermMode::VI) && !self.search_active() {
+ self.terminal_mut().vi_mode_cursor.point = point;
+ }
+ }
+
/// Paste a text into the terminal.
fn paste(&mut self, text: &str) {
if self.search_active() {
@@ -743,7 +780,7 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> {
self.search_state.dfas = None;
} else {
// Create search dfas for the new regex string.
- self.search_state.dfas = RegexSearch::new(&regex).ok();
+ self.search_state.dfas = RegexSearch::new(regex).ok();
// Update search highlighting.
self.goto_match(MAX_SEARCH_WHILE_TYPING);
@@ -770,7 +807,8 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> {
// Reset display offset and cursor position.
self.terminal.scroll_display(Scroll::Delta(self.search_state.display_offset_delta));
self.search_state.display_offset_delta = 0;
- self.terminal.vi_mode_cursor.point = self.search_state.origin;
+ self.terminal.vi_mode_cursor.point =
+ self.search_state.origin.grid_clamp(self.terminal, Boundary::Grid);
*self.dirty = true;
}
@@ -805,7 +843,7 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> {
// Store number of lines the viewport had to be moved.
let display_offset = self.terminal.grid().display_offset();
- self.search_state.display_offset_delta = old_offset - display_offset as i32;
+ self.search_state.display_offset_delta += old_offset - display_offset as i32;
// Since we found a result, we require no delayed re-search.
self.scheduler.unschedule(TimerId::DelayedSearch);
@@ -1038,7 +1076,7 @@ impl<N: Notify + OnResize> Processor<N> {
match event {
// Check for shutdown.
- GlutinEvent::UserEvent(Event::TerminalEvent(TerminalEvent::Exit)) => {
+ GlutinEvent::UserEvent(Event::Terminal(TerminalEvent::Exit)) => {
*control_flow = ControlFlow::Exit;
return;
},
@@ -1181,7 +1219,7 @@ impl<N: Notify + OnResize> Processor<N> {
processor.ctx.display.cursor_hidden ^= true;
*processor.ctx.dirty = true;
},
- Event::TerminalEvent(event) => match event {
+ Event::Terminal(event) => match event {
TerminalEvent::Title(title) => {
let ui_config = &processor.ctx.config.ui_config;
if ui_config.window.dynamic_title {
@@ -1347,7 +1385,7 @@ impl<N: Notify + OnResize> Processor<N> {
processor.ctx.display_update_pending.dirty = true;
}
- let config = match config::reload(&path, &processor.ctx.cli_options) {
+ let config = match config::reload(path, processor.ctx.cli_options) {
Ok(config) => config,
Err(_) => return,
};
@@ -1398,7 +1436,7 @@ impl<N: Notify + OnResize> Processor<N> {
// Disable shadows for transparent windows on macOS.
#[cfg(target_os = "macos")]
- processor.ctx.window().set_has_shadow(config.ui_config.background_opacity() >= 1.0);
+ processor.ctx.window().set_has_shadow(config.ui_config.window_opacity() >= 1.0);
// Update hint keys.
processor.ctx.display.hint_state.update_alphabet(config.ui_config.hints.alphabet());
@@ -1493,6 +1531,6 @@ impl EventProxy {
impl EventListener for EventProxy {
fn send_event(&self, event: TerminalEvent) {
- let _ = self.0.send_event(Event::TerminalEvent(event));
+ let _ = self.0.send_event(Event::Terminal(event));
}
}
diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs
index 948ec67f..98a1b723 100644
--- a/alacritty/src/input.rs
+++ b/alacritty/src/input.rs
@@ -29,7 +29,7 @@ use alacritty_terminal::term::{ClipboardType, SizeInfo, Term, TermMode};
use alacritty_terminal::vi_mode::ViMotion;
use crate::clipboard::Clipboard;
-use crate::config::{Action, BindingMode, Config, Key, SearchAction, ViAction};
+use crate::config::{Action, BindingMode, Config, Key, MouseAction, SearchAction, ViAction};
use crate::daemon::start_daemon;
use crate::display::hint::HintMatch;
use crate::display::window::Window;
@@ -104,6 +104,7 @@ pub trait ActionContext<T: EventListener> {
fn toggle_vi_mode(&mut self) {}
fn hint_input(&mut self, _character: char) {}
fn trigger_hint(&mut self, _hint: &HintMatch) {}
+ fn expand_selection(&mut self) {}
fn paste(&mut self, _text: &str) {}
}
@@ -148,19 +149,19 @@ impl<T: EventListener> Execute<T> for Action {
ctx.terminal_mut().vi_motion(*motion);
ctx.mark_dirty();
},
- Action::ViAction(ViAction::ToggleNormalSelection) => {
+ Action::Vi(ViAction::ToggleNormalSelection) => {
Self::toggle_selection(ctx, SelectionType::Simple);
},
- Action::ViAction(ViAction::ToggleLineSelection) => {
+ Action::Vi(ViAction::ToggleLineSelection) => {
Self::toggle_selection(ctx, SelectionType::Lines);
},
- Action::ViAction(ViAction::ToggleBlockSelection) => {
+ Action::Vi(ViAction::ToggleBlockSelection) => {
Self::toggle_selection(ctx, SelectionType::Block);
},
- Action::ViAction(ViAction::ToggleSemanticSelection) => {
+ Action::Vi(ViAction::ToggleSemanticSelection) => {
Self::toggle_selection(ctx, SelectionType::Semantic);
},
- Action::ViAction(ViAction::Open) => {
+ Action::Vi(ViAction::Open) => {
let hint = ctx.display().vi_highlighted_hint.take();
if let Some(hint) = &hint {
ctx.mouse_mut().block_hint_launcher = false;
@@ -168,7 +169,7 @@ impl<T: EventListener> Execute<T> for Action {
}
ctx.display().vi_highlighted_hint = hint;
},
- Action::ViAction(ViAction::SearchNext) => {
+ Action::Vi(ViAction::SearchNext) => {
let terminal = ctx.terminal();
let direction = ctx.search_direction();
let vi_point = terminal.vi_mode_cursor.point;
@@ -182,7 +183,7 @@ impl<T: EventListener> Execute<T> for Action {
ctx.mark_dirty();
}
},
- Action::ViAction(ViAction::SearchPrevious) => {
+ Action::Vi(ViAction::SearchPrevious) => {
let terminal = ctx.terminal();
let direction = ctx.search_direction().opposite();
let vi_point = terminal.vi_mode_cursor.point;
@@ -196,7 +197,7 @@ impl<T: EventListener> Execute<T> for Action {
ctx.mark_dirty();
}
},
- Action::ViAction(ViAction::SearchStart) => {
+ Action::Vi(ViAction::SearchStart) => {
let terminal = ctx.terminal();
let origin = terminal.vi_mode_cursor.point.sub(terminal, Boundary::None, 1);
@@ -205,7 +206,7 @@ impl<T: EventListener> Execute<T> for Action {
ctx.mark_dirty();
}
},
- Action::ViAction(ViAction::SearchEnd) => {
+ Action::Vi(ViAction::SearchEnd) => {
let terminal = ctx.terminal();
let origin = terminal.vi_mode_cursor.point.add(terminal, Boundary::None, 1);
@@ -214,25 +215,24 @@ impl<T: EventListener> Execute<T> for Action {
ctx.mark_dirty();
}
},
- Action::SearchAction(SearchAction::SearchFocusNext) => {
+ Action::Search(SearchAction::SearchFocusNext) => {
ctx.advance_search_origin(ctx.search_direction());
},
- Action::SearchAction(SearchAction::SearchFocusPrevious) => {
+ Action::Search(SearchAction::SearchFocusPrevious) => {
let direction = ctx.search_direction().opposite();
ctx.advance_search_origin(direction);
},
- Action::SearchAction(SearchAction::SearchConfirm) => ctx.confirm_search(),
- Action::SearchAction(SearchAction::SearchCancel) => ctx.cancel_search(),
- Action::SearchAction(SearchAction::SearchClear) => {
+ Action::Search(SearchAction::SearchConfirm) => ctx.confirm_search(),
+ Action::Search(SearchAction::SearchCancel) => ctx.cancel_search(),
+ Action::Search(SearchAction::SearchClear) => {
let direction = ctx.search_direction();
ctx.cancel_search();
ctx.start_search(direction);
},
- Action::SearchAction(SearchAction::SearchDeleteWord) => ctx.search_pop_word(),
- Action::SearchAction(SearchAction::SearchHistoryPrevious) => {
- ctx.search_history_previous()
- },
- Action::SearchAction(SearchAction::SearchHistoryNext) => ctx.search_history_next(),
+ Action::Search(SearchAction::SearchDeleteWord) => ctx.search_pop_word(),
+ Action::Search(SearchAction::SearchHistoryPrevious) => ctx.search_history_previous(),
+ Action::Search(SearchAction::SearchHistoryNext) => ctx.search_history_next(),
+ Action::Mouse(MouseAction::ExpandSelection) => ctx.expand_selection(),
Action::SearchForward => ctx.start_search(Direction::Right),
Action::SearchBackward => ctx.start_search(Direction::Left),
Action::Copy => ctx.copy_selection(ClipboardType::Clipboard),
@@ -533,51 +533,12 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
let display_offset = self.ctx.terminal().grid().display_offset();
let point = self.ctx.mouse().point(&self.ctx.size_info(), display_offset);
- match button {
- MouseButton::Left => self.on_left_click(point),
- MouseButton::Right => self.on_right_click(point),
- // Do nothing when using buttons other than LMB.
- _ => self.ctx.mouse_mut().click_state = ClickState::None,
+ if let MouseButton::Left = button {
+ self.on_left_click(point)
}
}
}
- /// Handle selection expansion on right click.
- fn on_right_click(&mut self, point: Point) {
- match self.ctx.mouse().click_state {
- ClickState::Click => {
- let selection_type = if self.ctx.modifiers().ctrl() {
- SelectionType::Block
- } else {
- SelectionType::Simple
- };
-
- self.expand_selection(point, selection_type);
- },
- ClickState::DoubleClick => self.expand_selection(point, SelectionType::Semantic),
- ClickState::TripleClick => self.expand_selection(point, SelectionType::Lines),
- ClickState::None => (),
- }
- }
-
- /// Expand existing selection.
- fn expand_selection(&mut self, point: Point, selection_type: SelectionType) {
- let cell_side = self.ctx.mouse().cell_side;
-
- let selection = match &mut self.ctx.terminal_mut().selection {
- Some(selection) => selection,
- None => return,
- };
-
- selection.ty = selection_type;
- self.ctx.update_selection(point, cell_side);
-
- // Move vi mode cursor to mouse click position.
- if self.ctx.terminal().mode().contains(TermMode::VI) && !self.ctx.search_active() {
- self.ctx.terminal_mut().vi_mode_cursor.point = point;
- }
- }
-
/// Handle left click selection and vi mode cursor movement.
fn on_left_click(&mut self, point: Point) {
let side = self.ctx.mouse().cell_side;
@@ -751,8 +712,9 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
} else {
match state {
ElementState::Pressed => {
- self.process_mouse_bindings(button);
+ // Process mouse press before bindings to update the `click_state`.
self.on_mouse_press(button);
+ self.process_mouse_bindings(button);
},
ElementState::Released => self.on_mouse_release(button),
}
@@ -1036,7 +998,7 @@ mod tests {
}
fn terminal(&self) -> &Term<T> {
- &self.terminal
+ self.terminal
}
fn terminal_mut(&mut self) -> &mut Term<T> {
@@ -1140,6 +1102,7 @@ mod tests {
let mut mouse = Mouse {
click_state: $initial_state,
+ last_click_button: $initial_button,
..Mouse::default()
};
@@ -1241,7 +1204,7 @@ mod tests {
},
window_id: unsafe { std::mem::transmute_copy(&0) },
},
- end_state: ClickState::None,
+ end_state: ClickState::Click,
}
test_clickstate! {
diff --git a/alacritty/src/logging.rs b/alacritty/src/logging.rs
index 36d20fa3..7cef3887 100644
--- a/alacritty/src/logging.rs
+++ b/alacritty/src/logging.rs
@@ -13,7 +13,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use glutin::event_loop::EventLoopProxy;
-use log::{self, Level};
+use log::{self, Level, LevelFilter};
use crate::cli::Options;
use crate::event::Event;
@@ -29,7 +29,7 @@ pub fn initialize(
options: &Options,
event_proxy: EventLoopProxy<Event>,
) -> Result<Option<PathBuf>, log::SetLoggerError> {
- log::set_max_level(options.log_level);
+ log::set_max_level(options.log_level());
let logger = Logger::new(event_proxy);
let path = logger.file_path();
@@ -102,13 +102,13 @@ impl log::Log for Logger {
let index = record.target().find(':').unwrap_or_else(|| record.target().len());
let target = &record.target()[..index];
- // Only log our own crates.
- if !self.enabled(record.metadata()) || !ALLOWED_TARGETS.contains(&target) {
+ // Only log our own crates, except when logging at Level::Trace.
+ if !self.enabled(record.metadata()) || !is_allowed_target(record.level(), target) {
return;
}
// Create log message for the given `record` and `target`.
- let message = create_log_message(record, &target);
+ let message = create_log_message(record, target);
if let Ok(mut logfile) = self.logfile.lock() {
// Write to logfile.
@@ -149,6 +149,14 @@ fn create_log_message(record: &log::Record<'_>, target: &str) -> String {
message
}
+/// Check if log messages from a crate should be logged.
+fn is_allowed_target(level: Level, target: &str) -> bool {
+ match (level, log::max_level()) {
+ (Level::Error, LevelFilter::Trace) | (Level::Warn, LevelFilter::Trace) => true,
+ _ => ALLOWED_TARGETS.contains(&target),
+ }
+}
+
struct OnDemandLogFile {
file: Option<LineWriter<File>>,
created: Arc<AtomicBool>,
diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs
index 85a4fc5e..f6e3c1d0 100644
--- a/alacritty/src/main.rs
+++ b/alacritty/src/main.rs
@@ -1,7 +1,7 @@
//! Alacritty - The GPU Enhanced Terminal.
#![warn(rust_2018_idioms, future_incompatible)]
-#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use, clippy::wrong_pub_self_convention)]
+#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use)]
#![cfg_attr(feature = "cargo-clippy", deny(warnings))]
// With the default subsystem, 'console', windows creates an additional console
// window for the program.
diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs
index 8d0c4b68..71ed6e28 100644
--- a/alacritty/src/renderer/mod.rs
+++ b/alacritty/src/renderer/mod.rs
@@ -194,7 +194,7 @@ impl GlyphCache {
let size = font.size();
// Load regular font.
- let regular_desc = Self::make_desc(&font.normal(), Slant::Normal, Weight::Normal);
+ let regular_desc = Self::make_desc(font.normal(), Slant::Normal, Weight::Normal);
let regular = Self::load_regular_font(rasterizer, &regular_desc, size)?;
@@ -236,7 +236,7 @@ impl GlyphCache {
error!("{}", err);
let fallback_desc =
- Self::make_desc(&Font::default().normal(), Slant::Normal, Weight::Normal);
+ Self::make_desc(Font::default().normal(), Slant::Normal, Weight::Normal);
rasterizer.load_font(&fallback_desc, size)
},
}
@@ -375,7 +375,7 @@ impl GlyphCache {
/// Calculate font metrics without access to a glyph cache.
pub fn static_metrics(font: Font, dpr: f64) -> Result<crossfont::Metrics, crossfont::Error> {
let mut rasterizer = crossfont::Rasterizer::new(dpr as f32, font.use_thin_strokes)?;
- let regular_desc = GlyphCache::make_desc(&font.normal(), Slant::Normal, Weight::Normal);
+ let regular_desc = GlyphCache::make_desc(font.normal(), Slant::Normal, Weight::Normal);
let regular = Self::load_regular_font(&mut rasterizer, &regular_desc, font.size())?;
rasterizer.get_glyph(GlyphKey { font_key: regular, character: 'm', size: font.size() })?;
@@ -785,7 +785,7 @@ impl Drop for QuadRenderer {
impl<'a> RenderApi<'a> {
pub fn clear(&self, color: Rgb) {
unsafe {
- let alpha = self.config.background_opacity();
+ let alpha = self.config.window_opacity();
gl::ClearColor(
(f32::from(color.r) / 255.0).min(1.0) * alpha,
(f32::from(color.g) / 255.0).min(1.0) * alpha,
@@ -1325,12 +1325,12 @@ impl Atlas {
}
// If there's not enough room in current row, go onto next one.
- if !self.room_in_row(&glyph) {
+ if !self.room_in_row(glyph) {
self.advance_row()?;
}
// If there's still not room, there's nothing that can be done here..
- if !self.room_in_row(&glyph) {
+ if !self.room_in_row(glyph) {
return Err(AtlasInsertError::Full);
}
diff --git a/alacritty/src/renderer/rects.rs b/alacritty/src/renderer/rects.rs
index 591c9f46..77c22011 100644
--- a/alacritty/src/renderer/rects.rs
+++ b/alacritty/src/renderer/rects.rs
@@ -158,9 +158,9 @@ impl RenderLines {
/// Update the stored lines with the next cell info.
#[inline]
pub fn update(&mut self, cell: &RenderableCell) {
- self.update_flag(&cell, Flags::UNDERLINE);
- self.update_flag(&cell, Flags::DOUBLE_UNDERLINE);
- self.update_flag(&cell, Flags::STRIKEOUT);
+ self.update_flag(cell, Flags::UNDERLINE);
+ self.update_flag(cell, Flags::DOUBLE_UNDERLINE);
+ self.update_flag(cell, Flags::STRIKEOUT);
}
/// Update the lines for a specific flag.