diff options
author | Christian Duerr <chrisduerr@users.noreply.github.com> | 2019-05-10 11:36:16 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-10 11:36:16 +0000 |
commit | 5d173f6df3b20308eb318cef4b58147b2197d5f9 (patch) | |
tree | 05638837bef25d65a818253814331a4f429f57ac /alacritty | |
parent | 7738c52ed4eb177ead9f43d14207ecb129cfe617 (diff) | |
download | r-alacritty-5d173f6df3b20308eb318cef4b58147b2197d5f9.tar.gz r-alacritty-5d173f6df3b20308eb318cef4b58147b2197d5f9.tar.bz2 r-alacritty-5d173f6df3b20308eb318cef4b58147b2197d5f9.zip |
Refactor config parsing files
This is a large refactor of the config parsing structure, attempting to
reduce the size of the file a bit by splitting it up into different
modules with more specific purposes.
This also fixes #2279.
Diffstat (limited to 'alacritty')
-rw-r--r-- | alacritty/Cargo.toml | 6 | ||||
-rw-r--r-- | alacritty/build.rs | 3 | ||||
-rw-r--r-- | alacritty/src/cli.rs | 417 | ||||
-rw-r--r-- | alacritty/src/config.rs | 210 | ||||
-rw-r--r-- | alacritty/src/logging.rs | 18 | ||||
-rw-r--r-- | alacritty/src/main.rs | 52 |
6 files changed, 511 insertions, 195 deletions
diff --git a/alacritty/Cargo.toml b/alacritty/Cargo.toml index 742492fe..7a3f5f89 100644 --- a/alacritty/Cargo.toml +++ b/alacritty/Cargo.toml @@ -15,11 +15,15 @@ log = "0.4" time = "0.1.40" env_logger = "0.6.0" crossbeam-channel = "0.3.8" +serde_yaml = "0.8" [build-dependencies] rustc_tools_util = "0.1" -[target.'cfg(target_os = "macos")'.dependencies] +[target.'cfg(not(windows))'.dependencies] +xdg = "2" + +[target.'cfg(any(target_os = "macos", windows))'.dependencies] dirs = "1.0.2" [target.'cfg(windows)'.dependencies] diff --git a/alacritty/build.rs b/alacritty/build.rs index 2a1ce9e0..1ad0def4 100644 --- a/alacritty/build.rs +++ b/alacritty/build.rs @@ -13,7 +13,6 @@ // limitations under the License. fn main() { - let hash = rustc_tools_util::get_commit_hash() - .expect("couldn't get commit hash"); + let hash = rustc_tools_util::get_commit_hash().expect("couldn't get commit hash"); println!("cargo:rustc-env=GIT_HASH={}", hash); } diff --git a/alacritty/src/cli.rs b/alacritty/src/cli.rs index 90906218..3ecea644 100644 --- a/alacritty/src/cli.rs +++ b/alacritty/src/cli.rs @@ -12,184 +12,293 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::path::PathBuf; +use std::borrow::Cow; +use std::cmp::max; +use std::path::{Path, PathBuf}; -use ::log; use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg}; +use log::{self, LevelFilter}; -use alacritty_terminal::config::{Options, Delta, Dimensions, Shell}; +use alacritty_terminal::config::{Config, Delta, Dimensions, Shell}; use alacritty_terminal::index::{Column, Line}; use alacritty_terminal::window::DEFAULT_NAME; -/// Build `Options` from command line arguments. -pub fn options() -> Options { - let mut options = Options::default(); - - let version_string = format!("{} ({})", - crate_version!(), - env!("GIT_HASH")); - - let matches = App::new(crate_name!()) - .version(version_string.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("live-config-reload") - .long("live-config-reload") - .help("Enable automatic config reloading"), - ) - .arg( - Arg::with_name("no-live-config-reload") - .long("no-live-config-reload") - .help("Disable automatic config reloading") - .conflicts_with("live-config-reload"), - ) - .arg( - Arg::with_name("print-events") - .long("print-events") - .help("Print all events to stdout"), - ) - .arg( - Arg::with_name("persistent-logging") - .long("persistent-logging") - .help("Keep the log file after quitting Alacritty"), - ) - .arg( - Arg::with_name("dimensions") - .long("dimensions") - .short("d") - .value_names(&["columns", "lines"]) - .help( - "Defines the window dimensions. Falls back to size specified by window \ - manager if set to 0x0 [default: 0x0]", - ), - ) - .arg( - Arg::with_name("position") - .long("position") - .allow_hyphen_values(true) - .value_names(&["x-pos", "y-pos"]) - .help( - "Defines the window position. Falls back to position specified by window \ - manager if unset [default: unset]", - ), - ) - .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") - .takes_value(true) - .help(&format!("Defines window class on Linux [default: {}]", DEFAULT_NAME)), - ) - .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( - "Specify alternative configuration file [default: \ - $XDG_CONFIG_HOME/alacritty/alacritty.yml]", - )) - .arg( - Arg::with_name("command") - .long("command") - .short("e") - .multiple(true) - .takes_value(true) - .min_values(1) - .allow_hyphen_values(true) - .help("Command and args to execute (must be last argument)"), - ) - .get_matches(); - - if matches.is_present("ref-test") { - options.ref_test = true; - } +/// Options specified on the command line +pub struct Options { + pub live_config_reload: Option<bool>, + pub print_events: bool, + pub ref_test: bool, + pub dimensions: Option<Dimensions>, + pub position: Option<Delta<i32>>, + pub title: Option<String>, + pub class: Option<String>, + pub log_level: LevelFilter, + pub command: Option<Shell<'static>>, + pub working_dir: Option<PathBuf>, + pub config: Option<PathBuf>, + pub persistent_logging: bool, +} - if matches.is_present("print-events") { - options.print_events = true; +impl Default for Options { + fn default() -> Options { + Options { + live_config_reload: None, + print_events: false, + ref_test: false, + dimensions: None, + position: None, + title: None, + class: None, + log_level: LevelFilter::Warn, + command: None, + working_dir: None, + config: None, + persistent_logging: false, + } } +} - if matches.is_present("live-config-reload") { - options.live_config_reload = Some(true); - } else if matches.is_present("no-live-config-reload") { - options.live_config_reload = Some(false); - } +impl Options { + /// Build `Options` from command line arguments. + pub fn new() -> Self { + let mut options = Options::default(); - if matches.is_present("persistent-logging") { - options.persistent_logging = true; - } + let version_string = format!("{} ({})", crate_version!(), env!("GIT_HASH")); - if let Some(mut dimensions) = matches.values_of("dimensions") { - let width = dimensions.next().map(|w| w.parse().map(Column)); - let height = dimensions.next().map(|h| h.parse().map(Line)); - if let (Some(Ok(width)), Some(Ok(height))) = (width, height) { - options.dimensions = Some(Dimensions::new(width, height)); + let matches = App::new(crate_name!()) + .version(version_string.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("live-config-reload") + .long("live-config-reload") + .help("Enable automatic config reloading"), + ) + .arg( + Arg::with_name("no-live-config-reload") + .long("no-live-config-reload") + .help("Disable automatic config reloading") + .conflicts_with("live-config-reload"), + ) + .arg( + Arg::with_name("print-events") + .long("print-events") + .help("Print all events to stdout"), + ) + .arg( + Arg::with_name("persistent-logging") + .long("persistent-logging") + .help("Keep the log file after quitting Alacritty"), + ) + .arg( + Arg::with_name("dimensions") + .long("dimensions") + .short("d") + .value_names(&["columns", "lines"]) + .help( + "Defines the window dimensions. Falls back to size specified by window \ + manager if set to 0x0 [default: 0x0]", + ), + ) + .arg( + Arg::with_name("position") + .long("position") + .allow_hyphen_values(true) + .value_names(&["x-pos", "y-pos"]) + .help( + "Defines the window position. Falls back to position specified by window \ + manager if unset [default: unset]", + ), + ) + .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") + .takes_value(true) + .help(&format!("Defines window class on Linux [default: {}]", DEFAULT_NAME)), + ) + .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( + "Specify alternative configuration file [default: \ + $XDG_CONFIG_HOME/alacritty/alacritty.yml]", + )) + .arg( + Arg::with_name("command") + .long("command") + .short("e") + .multiple(true) + .takes_value(true) + .min_values(1) + .allow_hyphen_values(true) + .help("Command and args to execute (must be last argument)"), + ) + .get_matches(); + + if matches.is_present("ref-test") { + options.ref_test = true; } - } - if let Some(mut position) = matches.values_of("position") { - let x = position.next().map(str::parse); - let y = position.next().map(str::parse); - if let (Some(Ok(x)), Some(Ok(y))) = (x, y) { - options.position = Some(Delta { x, y }); + if matches.is_present("print-events") { + options.print_events = true; + } + + if matches.is_present("live-config-reload") { + options.live_config_reload = Some(true); + } else if matches.is_present("no-live-config-reload") { + options.live_config_reload = Some(false); } - } - options.class = matches.value_of("class").map(ToOwned::to_owned); - options.title = matches.value_of("title").map(ToOwned::to_owned); + if matches.is_present("persistent-logging") { + options.persistent_logging = true; + } + + if let Some(mut dimensions) = matches.values_of("dimensions") { + let width = dimensions.next().map(|w| w.parse().map(Column)); + let height = dimensions.next().map(|h| h.parse().map(Line)); + if let (Some(Ok(width)), Some(Ok(height))) = (width, height) { + options.dimensions = Some(Dimensions::new(width, height)); + } + } + + if let Some(mut position) = matches.values_of("position") { + let x = position.next().map(str::parse); + let y = position.next().map(str::parse); + if let (Some(Ok(x)), Some(Ok(y))) = (x, y) { + options.position = Some(Delta { x, y }); + } + } + + options.class = matches.value_of("class").map(ToOwned::to_owned); + options.title = matches.value_of("title").map(ToOwned::to_owned); - match matches.occurrences_of("q") { - 0 => {}, - 1 => options.log_level = log::LevelFilter::Error, - 2 | _ => options.log_level = log::LevelFilter::Off, + match matches.occurrences_of("q") { + 0 => {}, + 1 => options.log_level = LevelFilter::Error, + 2 | _ => options.log_level = LevelFilter::Off, + } + + 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, + 3 | _ => options.log_level = LevelFilter::Trace, + } + + if let Some(dir) = matches.value_of("working-directory") { + options.working_dir = Some(PathBuf::from(dir.to_string())); + } + + if let Some(path) = matches.value_of("config-file") { + options.config = Some(PathBuf::from(path.to_string())); + } + + 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 command = String::from(args.next().unwrap()); + let args = args.map(String::from).collect(); + options.command = Some(Shell::new_with_args(command, args)); + } + + options } - match matches.occurrences_of("v") { - 0 if !options.print_events => {}, - 0 | 1 => options.log_level = log::LevelFilter::Info, - 2 => options.log_level = log::LevelFilter::Debug, - 3 | _ => options.log_level = log::LevelFilter::Trace, + pub fn config_path(&self) -> Option<Cow<'_, Path>> { + self.config.as_ref().map(|p| Cow::Borrowed(p.as_path())) } - if let Some(dir) = matches.value_of("working-directory") { - options.working_dir = Some(PathBuf::from(dir.to_string())); + pub fn into_config(self, mut config: Config) -> Config { + config.set_live_config_reload( + self.live_config_reload.unwrap_or_else(|| config.live_config_reload()), + ); + config.set_working_directory( + self.working_dir.or_else(|| config.working_directory().to_owned()), + ); + config.shell = self.command.or(config.shell); + + config.window.dimensions = self.dimensions.unwrap_or(config.window.dimensions); + config.window.position = self.position.or(config.window.position); + config.window.title = self.title.or(config.window.title); + config.window.class = self.class.or(config.window.class); + + config.set_dynamic_title(config.dynamic_title() && config.window.title.is_none()); + + config.debug.print_events = self.print_events || config.debug.print_events; + config.debug.log_level = max(config.debug.log_level, self.log_level); + config.debug.ref_test = self.ref_test || config.debug.ref_test; + + if config.debug.print_events { + config.debug.log_level = max(config.debug.log_level, LevelFilter::Info); + } + + config } +} + +#[cfg(test)] +mod test { + use alacritty_terminal::config::{Config, DEFAULT_ALACRITTY_CONFIG}; + + use crate::cli::Options; + + #[test] + fn dynamic_title_ignoring_options_by_default() { + let config: Config = + ::serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG).expect("deserialize config"); + let old_dynamic_title = config.dynamic_title(); + + let config = Options::default().into_config(config); - if let Some(path) = matches.value_of("config-file") { - options.config = Some(PathBuf::from(path.to_string())); + assert_eq!(old_dynamic_title, config.dynamic_title()); } - 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 command = String::from(args.next().unwrap()); - let args = args.map(String::from).collect(); - options.command = Some(Shell::new_with_args(command, args)); + #[test] + fn dynamic_title_overridden_by_options() { + let config: Config = + ::serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG).expect("deserialize config"); + + let mut options = Options::default(); + options.title = Some("foo".to_owned()); + let config = options.into_config(config); + + assert!(!config.dynamic_title()); } - options + #[test] + fn dynamic_title_overridden_by_config() { + let mut config: Config = + ::serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG).expect("deserialize config"); + + config.window.title = Some("foo".to_owned()); + let config = Options::default().into_config(config); + + assert!(!config.dynamic_title()); + } } diff --git a/alacritty/src/config.rs b/alacritty/src/config.rs new file mode 100644 index 00000000..ea487ecd --- /dev/null +++ b/alacritty/src/config.rs @@ -0,0 +1,210 @@ +use std::borrow::Cow; +use std::env; +use std::fs::File; +use std::io::{self, Read, Write}; +use std::path::{Path, PathBuf}; + +#[cfg(windows)] +use dirs; +use log::{error, warn}; +use serde_yaml; +#[cfg(not(windows))] +use xdg; + +use alacritty_terminal::config::{Config, DEFAULT_ALACRITTY_CONFIG}; + +pub const SOURCE_FILE_PATH: &str = file!(); + +/// Result from config loading +pub type Result<T> = ::std::result::Result<T, Error>; + +/// Errors occurring during config loading +#[derive(Debug)] +pub enum Error { + /// Config file not found + NotFound, + + /// Couldn't read $HOME environment variable + ReadingEnvHome(env::VarError), + + /// io error reading file + Io(io::Error), + + /// Not valid yaml or missing parameters + Yaml(serde_yaml::Error), +} + +impl ::std::error::Error for Error { + fn cause(&self) -> Option<&dyn (::std::error::Error)> { + match *self { + Error::NotFound => None, + Error::ReadingEnvHome(ref err) => Some(err), + Error::Io(ref err) => Some(err), + Error::Yaml(ref err) => Some(err), + } + } + + fn description(&self) -> &str { + match *self { + Error::NotFound => "Couldn't locate config file", + Error::ReadingEnvHome(ref err) => err.description(), + Error::Io(ref err) => err.description(), + Error::Yaml(ref err) => err.description(), + } + } +} + +impl ::std::fmt::Display for Error { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Error::NotFound => write!(f, "{}", ::std::error::Error::description(self)), + Error::ReadingEnvHome(ref err) => { + write!(f, "Couldn't read $HOME environment variable: {}", err) + }, + Error::Io(ref err) => write!(f, "Error reading config file: {}", err), + Error::Yaml(ref err) => write!(f, "Problem with config: {}", err), + } + } +} + +impl From<env::VarError> for Error { + fn from(val: env::VarError) -> Error { + Error::ReadingEnvHome(val) + } +} + +impl From<io::Error> for Error { + fn from(val: io::Error) -> Error { + if val.kind() == io::ErrorKind::NotFound { + Error::NotFound + } else { + Error::Io(val) + } + } +} + +impl From<serde_yaml::Error> for Error { + fn from(val: serde_yaml::Error) -> Error { + Error::Yaml(val) + } +} + +/// Get the location of the first found default config file paths +/// according to the following order: +/// +/// 1. $XDG_CONFIG_HOME/alacritty/alacritty.yml +/// 2. $XDG_CONFIG_HOME/alacritty.yml +/// 3. $HOME/.config/alacritty/alacritty.yml +/// 4. $HOME/.alacritty.yml +#[cfg(not(windows))] +pub fn installed_config<'a>() -> Option<Cow<'a, Path>> { + // Try using XDG location by default + xdg::BaseDirectories::with_prefix("alacritty") + .ok() + .and_then(|xdg| xdg.find_config_file("alacritty.yml")) + .or_else(|| { + xdg::BaseDirectories::new() + .ok() + .and_then(|fallback| fallback.find_config_file("alacritty.yml")) + }) + .or_else(|| { + if let Ok(home) = env::var("HOME") { + // Fallback path: $HOME/.config/alacritty/alacritty.yml + let fallback = PathBuf::from(&home).join(".config/alacritty/alacritty.yml"); + if fallback.exists() { + return Some(fallback); + } + // Fallback path: $HOME/.alacritty.yml + let fallback = PathBuf::from(&home).join(".alacritty.yml"); + if fallback.exists() { + return Some(fallback); + } + } + None + }) + .map(Into::into) +} + +#[cfg(windows)] +pub fn installed_config<'a>() -> Option<Cow<'a, Path>> { + dirs::config_dir() + .map(|path| path.join("alacritty\\alacritty.yml")) + .filter(|new| new.exists()) + .map(Cow::from) +} + +#[cfg(not(windows))] +pub fn write_defaults() -> io::Result<Cow<'static, Path>> { + let path = xdg::BaseDirectories::with_prefix("alacritty") + .map_err(|err| io::Error::new(io::ErrorKind::NotFound, err.to_string().as_str())) + .and_then(|p| p.place_config_file("alacritty.yml"))?; + + File::create(&path)?.write_all(DEFAULT_ALACRITTY_CONFIG.as_bytes())?; + + Ok(path.into()) +} + +#[cfg(windows)] +pub fn write_defaults() -> io::Result<Cow<'static, Path>> { + let mut path = dirs::config_dir().ok_or_else(|| { + io::Error::new(io::ErrorKind::NotFound, "Couldn't find profile directory") + })?; + + path = path.join("alacritty/alacritty.yml"); + + std::fs::create_dir_all(path.parent().unwrap())?; + + File::create(&path)?.write_all(DEFAULT_ALACRITTY_CONFIG.as_bytes())?; + + Ok(path.into()) +} + +pub fn load_from(path: PathBuf) -> Config { + let mut config = reload_from(&path).unwrap_or_else(|_| Config::default()); + config.config_path = Some(path); + config +} + +pub fn reload_from(path: &PathBuf) -> Result<Config> { + match read_config(path) { + Ok(config) => Ok(config), + Err(err) => { + error!("Unable to load config {:?}: {}", path, err); + Err(err) + }, + } +} + +fn read_config(path: &PathBuf) -> Result<Config> { + let mut contents = String::new(); + File::open(path)?.read_to_string(&mut contents)?; + + // Prevent parsing error with empty string + if contents.is_empty() { + return Ok(Config::default()); + } + + let config = serde_yaml::from_str(&contents)?; + + print_deprecation_warnings(&config); + + Ok(config) +} + +fn print_deprecation_warnings(config: &Config) { + if config.window.start_maximized.is_some() { + warn!( + "Config window.start_maximized is deprecated; please use window.startup_mode instead" + ); + } + + if config.render_timer.is_some() { + warn!("Config render_timer is deprecated; please use debug.render_timer instead"); + } + + if config.persistent_logging.is_some() { + warn!( + "Config persistent_logging is deprecated; please use debug.persistent_logging instead" + ); + } +} diff --git a/alacritty/src/logging.rs b/alacritty/src/logging.rs index 0b67440d..d4cb70c5 100644 --- a/alacritty/src/logging.rs +++ b/alacritty/src/logging.rs @@ -29,23 +29,26 @@ use crossbeam_channel::Sender; use log::{self, Level}; use time; -use alacritty_terminal::config::Options; use alacritty_terminal::message_bar::Message; use alacritty_terminal::term::color; +use crate::cli::Options; + const ALACRITTY_LOG_ENV: &str = "ALACRITTY_LOG"; pub fn initialize( options: &Options, message_tx: Sender<Message>, ) -> Result<Option<PathBuf>, log::SetLoggerError> { + log::set_max_level(options.log_level); + // Use env_logger if RUST_LOG environment variable is defined. Otherwise, // use the alacritty-only logger. if ::std::env::var("RUST_LOG").is_ok() { ::env_logger::try_init()?; Ok(None) } else { - let logger = Logger::new(options.log_level, message_tx); + let logger = Logger::new(message_tx); let path = logger.file_path(); log::set_boxed_logger(Box::new(logger))?; Ok(path) @@ -53,22 +56,17 @@ pub fn initialize( } pub struct Logger { - level: log::LevelFilter, logfile: Mutex<OnDemandLogFile>, stdout: Mutex<LineWriter<Stdout>>, message_tx: Sender<Message>, } impl Logger { - // False positive, see: https://github.com/rust-lang-nursery/rust-clippy/issues/734 - #[allow(clippy::new_ret_no_self)] - fn new(level: log::LevelFilter, message_tx: Sender<Message>) -> Self { - log::set_max_level(level); - + fn new(message_tx: Sender<Message>) -> Self { let logfile = Mutex::new(OnDemandLogFile::new()); let stdout = Mutex::new(LineWriter::new(io::stdout())); - Logger { level, logfile, stdout, message_tx } + Logger { logfile, stdout, message_tx } } fn file_path(&self) -> Option<PathBuf> { @@ -82,7 +80,7 @@ impl Logger { impl log::Log for Logger { fn enabled(&self, metadata: &log::Metadata<'_>) -> bool { - metadata.level() <= self.level + metadata.level() <= log::max_level() } fn log(&self, record: &log::Record<'_>) { diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs index 24f2d6c9..54533d72 100644 --- a/alacritty/src/main.rs +++ b/alacritty/src/main.rs @@ -42,7 +42,7 @@ use std::env; use std::os::unix::io::AsRawFd; use alacritty_terminal::clipboard::Clipboard; -use alacritty_terminal::config::{self, Config, Options, Monitor}; +use alacritty_terminal::config::{Config, Monitor}; use alacritty_terminal::display::Display; use alacritty_terminal::event_loop::{self, EventLoop, Msg}; #[cfg(target_os = "macos")] @@ -56,8 +56,11 @@ use alacritty_terminal::util::fmt::Red; use alacritty_terminal::{die, event}; mod cli; +mod config; mod logging; +use crate::cli::Options; + fn main() { panic::attach_handler(); @@ -70,7 +73,7 @@ fn main() { } // Load command line options - let options = cli::options(); + let options = Options::new(); // Setup storage for message UI let message_buffer = MessageBuffer::new(); @@ -83,15 +86,19 @@ fn main() { // If the file is a command line argument, we won't write a generated default file let config_path = options .config_path() - .or_else(Config::installed_config) - .or_else(|| Config::write_defaults().ok()) + .or_else(config::installed_config) + .or_else(|| config::write_defaults().ok()) .map(|path| path.to_path_buf()); let config = if let Some(path) = config_path { - Config::load_from(path).update_dynamic_title(&options) + config::load_from(path) } else { error!("Unable to write the default config"); Config::default() }; + let config = options.into_config(config); + + // Update the log level from config + log::set_max_level(config.debug.log_level); // Switch to home directory #[cfg(target_os = "macos")] @@ -101,10 +108,10 @@ fn main() { locale::set_locale_environment(); // Store if log file should be deleted before moving config - let persistent_logging = options.persistent_logging || config.persistent_logging(); + let persistent_logging = config.persistent_logging(); // Run alacritty - if let Err(err) = run(config, &options, message_buffer) { + if let Err(err) = run(config, message_buffer) { die!("Alacritty encountered an unrecoverable error:\n\n\t{}\n", Red(err)); } @@ -120,13 +127,9 @@ fn main() { /// /// Creates a window, the terminal state, pty, I/O event loop, input processor, /// config change monitor, and runs the main display loop. -fn run( - mut config: Config, - options: &Options, - message_buffer: MessageBuffer, -) -> Result<(), Box<dyn Error>> { +fn run(config: Config, message_buffer: MessageBuffer) -> Result<(), Box<dyn Error>> { info!("Welcome to Alacritty"); - if let Some(config_path) = config.path() { + if let Some(config_path) = &config.config_path { info!("Configuration loaded from {:?}", config_path.display()); }; @@ -136,7 +139,7 @@ fn run( // Create a display. // // The display manages a window and can draw the terminal - let mut display = Display::new(&config, options)?; + let mut display = Display::new(&config)?; info!("PTY Dimensions: {:?} x {:?}", display.size().lines(), display.size().cols()); @@ -162,7 +165,7 @@ fn run( // The pty forks a process to run the shell on the slave side of the // pseudoterminal. A file descriptor for the master side is retained for // reading/writing to the shell. - let pty = tty::new(&config, options, &display.size(), window_id); + let pty = tty::new(&config, &display.size(), window_id); // Get a reference to something that we can resize // @@ -181,7 +184,7 @@ fn run( // synchronized since the I/O loop updates the state, and the display // consumes it periodically. let event_loop = - EventLoop::new(Arc::clone(&terminal), display.notifier(), pty, options.ref_test); + EventLoop::new(Arc::clone(&terminal), display.notifier(), pty, config.debug.ref_test); // The event loop channel allows write requests from the event processor // to be sent to the loop and ultimately written to the pty. @@ -193,9 +196,7 @@ fn run( let mut processor = event::Processor::new( event_loop::Notifier(event_loop.channel()), display.resize_channel(), - options, &config, - options.ref_test, display.size().to_owned(), ); @@ -203,14 +204,10 @@ fn run( // // The monitor watches the config file for changes and reloads it. Pending // config changes are processed in the main loop. - let config_monitor = match (options.live_config_reload, config.live_config_reload()) { - // Start monitor if CLI flag says yes - (Some(true), _) | - // Or if no CLI flag was passed and the config says yes - (None, true) => config.path() - .map(|path| config::Monitor::new(path, display.notifier())), - // Otherwise, don't start the monitor - _ => None, + let config_monitor = if config.live_config_reload() { + config.config_path.as_ref().map(|path| Monitor::new(path, display.notifier())) + } else { + None }; // Kick off the I/O thread @@ -228,8 +225,7 @@ fn run( // Clear old config messages from bar terminal_lock.message_buffer_mut().remove_topic(config::SOURCE_FILE_PATH); - if let Ok(new_config) = Config::reload_from(path) { - config = new_config.update_dynamic_title(options); + if let Ok(config) = config::reload_from(path) { display.update_config(&config); processor.update_config(&config); terminal_lock.update_config(&config); |