aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes1
-rw-r--r--.github/workflows/ci.yml8
-rw-r--r--.github/workflows/release.yml10
-rw-r--r--CHANGELOG.md6
-rw-r--r--Cargo.lock65
-rw-r--r--INSTALL.md12
-rw-r--r--Makefile35
-rw-r--r--alacritty/Cargo.toml2
-rw-r--r--alacritty/build.rs10
-rw-r--r--alacritty/src/cli.rs326
-rw-r--r--alacritty/src/config/mod.rs6
-rw-r--r--alacritty/src/config/monitor.rs37
-rw-r--r--alacritty/src/config/ui_config.rs6
-rw-r--r--alacritty/src/display/content.rs15
-rw-r--r--alacritty/src/input.rs9
-rw-r--r--alacritty/src/logging.rs2
-rw-r--r--alacritty/src/renderer/mod.rs2
-rw-r--r--alacritty/src/renderer/rects.rs201
-rw-r--r--alacritty_terminal/Cargo.toml2
-rw-r--r--alacritty_terminal/src/ansi.rs23
-rw-r--r--alacritty_terminal/src/config/mod.rs2
-rw-r--r--alacritty_terminal/src/term/cell.rs9
-rw-r--r--alacritty_terminal/src/term/mod.rs32
23 files changed, 560 insertions, 261 deletions
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 3d432e03..00000000
--- a/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-/CHANGELOG.md merge=union
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1b51876f..f0b713cb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -25,3 +25,11 @@ jobs:
run: |
rustup component add clippy
cargo clippy --all-targets
+ check-macos-arm:
+ runs-on: macos-11
+ steps:
+ - uses: actions/checkout@v2
+ - name: Install target
+ run: rustup update && rustup target add aarch64-apple-darwin
+ - name: Check build
+ run: cargo check --target=aarch64-apple-darwin
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 682e344b..ae8dc448 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -10,14 +10,18 @@ env:
jobs:
macos:
- runs-on: macos-latest
+ runs-on: macos-11
steps:
- uses: actions/checkout@v2
+ - name: Install ARM target
+ run: rustup update && rustup target add aarch64-apple-darwin
- name: Test
run: cargo test --release
- - name: Make App
- run: make dmg
+ - name: Test ARM
+ run: cargo test --release --target=aarch64-apple-darwin
+ - name: Make DMG
+ run: make dmg-universal
- name: Upload Application
run: |
mv ./target/release/osx/Alacritty.dmg ./Alacritty-${GITHUB_REF##*/}.dmg
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 788ad860..023eaec5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- `ExpandSelection` is now a configurable mouse binding action
- Config option `background_opacity`, you should use `window.opacity` instead
+- Reload configuration files when their symbolic link is replaced
## 0.9.0
@@ -52,6 +53,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Minimum Rust version has been bumped to 1.45.0
+### Packaging
+
+- Updated shell completions
+- Added ARM executable to prebuilt macOS binaries
+
### Added
- IME composition preview not appearing on Windows
diff --git a/Cargo.lock b/Cargo.lock
index 5affc07e..985cc4e6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -21,7 +21,6 @@ dependencies = [
"alacritty_config_derive",
"alacritty_terminal",
"bitflags",
- "clap",
"cocoa 0.24.0",
"copypasta",
"crossfont",
@@ -41,6 +40,7 @@ dependencies = [
"serde",
"serde_json",
"serde_yaml",
+ "structopt",
"time",
"unicode-width",
"wayland-client",
@@ -755,6 +755,15 @@ dependencies = [
]
[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1280,6 +1289,30 @@ dependencies = [
]
[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
name = "proc-macro2"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1548,6 +1581,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
+name = "structopt"
+version = "0.3.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71"
+dependencies = [
+ "clap",
+ "lazy_static",
+ "structopt-derive",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "syn"
version = "1.0.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1613,6 +1670,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc"
[[package]]
+name = "unicode-segmentation"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
+
+[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/INSTALL.md b/INSTALL.md
index bf3f0c65..a1acfb9b 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -125,7 +125,7 @@ a `zypper` command that should install all of them. If something is
still found to be missing, please open an issue.
```sh
-zypper install cmake freetype-devel fontconfig-devel libxcb-devel
+zypper install cmake freetype-devel fontconfig-devel libxcb-devel libxkbcommon-dev
```
#### Slackware
@@ -251,6 +251,16 @@ make app
cp -r target/release/osx/Alacritty.app /Applications/
```
+#### Universal Binary
+
+The following will build an executable that runs on both x86 and ARM macos
+architectures:
+
+```sh
+rustup target add x86_64-apple-darwin aarch64-apple-darwin
+make app-universal
+```
+
## Post Build
There are some extra things you might want to set up after installing Alacritty.
diff --git a/Makefile b/Makefile
index 85983fae..b8548166 100644
--- a/Makefile
+++ b/Makefile
@@ -26,15 +26,21 @@ vpath $(DMG_NAME) $(APP_DIR)
all: help
-help: ## Prints help for targets with comments
+help: ## Print this help message
@grep -E '^[a-zA-Z._-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
-binary: | $(TARGET) ## Build release binary with cargo
-$(TARGET):
+binary: $(TAGET)-native ## Build a release binary
+binary-universal: $(TAGET)-universal ## Build a universal release binary
+$(TARGET)-native:
MACOSX_DEPLOYMENT_TARGET="10.11" cargo build --release
+$(TARGET)-universal:
+ MACOSX_DEPLOYMENT_TARGET="10.11" cargo build --release --target=x86_64-apple-darwin
+ MACOSX_DEPLOYMENT_TARGET="10.11" cargo build --release --target=aarch64-apple-darwin
+ @lipo target/{x86_64,aarch64}-apple-darwin/release/$(TARGET) -create -output $(APP_BINARY)
-app: | $(APP_NAME) ## Clone Alacritty.app template and mount binary
-$(APP_NAME): $(TARGET)
+app: $(APP_NAME)-native ## Create an Alacritty.app
+app-universal: $(APP_NAME)-universal ## Create a universal Alacritty.app
+$(APP_NAME)-%: $(TARGET)-%
@mkdir -p $(APP_BINARY_DIR)
@mkdir -p $(APP_EXTRAS_DIR)
@mkdir -p $(APP_COMPLETIONS_DIR)
@@ -44,10 +50,11 @@ $(APP_NAME): $(TARGET)
@cp -fp $(APP_BINARY) $(APP_BINARY_DIR)
@cp -fp $(COMPLETIONS) $(APP_COMPLETIONS_DIR)
@touch -r "$(APP_BINARY)" "$(APP_DIR)/$(APP_NAME)"
- @echo "Created '$@' in '$(APP_DIR)'"
+ @echo "Created '$(APP_NAME)' in '$(APP_DIR)'"
-dmg: | $(DMG_NAME) ## Pack Alacritty.app into .dmg
-$(DMG_NAME): $(APP_NAME)
+dmg: $(DMG_NAME)-native ## Create an Alacritty.dmg
+dmg-universal: $(DMG_NAME)-universal ## Create a universal Alacritty.dmg
+$(DMG_NAME)-%: $(APP_NAME)-%
@echo "Packing disk image..."
@ln -sf /Applications $(DMG_DIR)/Applications
@hdiutil create $(DMG_DIR)/$(DMG_NAME) \
@@ -55,12 +62,14 @@ $(DMG_NAME): $(APP_NAME)
-fs HFS+ \
-srcfolder $(APP_DIR) \
-ov -format UDZO
- @echo "Packed '$@' in '$(APP_DIR)'"
+ @echo "Packed '$(APP_NAME)' in '$(APP_DIR)'"
-install: $(DMG_NAME) ## Mount disk image
+install: $(INSTALL)-native ## Mount disk image
+install-universal: $(INSTALL)-native ## Mount universal disk image
+$(INSTALL)-%: $(DMG_NAME)-%
@open $(DMG_DIR)/$(DMG_NAME)
-.PHONY: app binary clean dmg install $(TARGET)
+.PHONY: app binary clean dmg install $(TARGET) $(TARGET)-universal
-clean: ## Remove all artifacts
- -rm -rf $(APP_DIR)
+clean: ## Remove all build artifacts
+ @cargo clean
diff --git a/alacritty/Cargo.toml b/alacritty/Cargo.toml
index cb269350..6ac20526 100644
--- a/alacritty/Cargo.toml
+++ b/alacritty/Cargo.toml
@@ -18,7 +18,7 @@ path = "../alacritty_config_derive"
version = "0.1.0"
[dependencies]
-clap = "2"
+structopt = "0.3.22"
log = { version = "0.4", features = ["std", "serde"] }
time = "0.1.40"
fnv = "1"
diff --git a/alacritty/build.rs b/alacritty/build.rs
index c093afca..e81da150 100644
--- a/alacritty/build.rs
+++ b/alacritty/build.rs
@@ -6,7 +6,11 @@ use std::process::Command;
use gl_generator::{Api, Fallbacks, GlobalGenerator, Profile, Registry};
fn main() {
- println!("cargo:rustc-env=GIT_HASH={}", commit_hash());
+ let mut version = String::from(env!("CARGO_PKG_VERSION"));
+ if let Some(commit_hash) = commit_hash() {
+ version = format!("{} ({})", version, commit_hash);
+ }
+ println!("cargo:rustc-env=VERSION={}", version);
let dest = env::var("OUT_DIR").unwrap();
let mut file = File::create(&Path::new(&dest).join("gl_bindings.rs")).unwrap();
@@ -19,11 +23,11 @@ fn main() {
embed_resource::compile("./windows/windows.rc");
}
-fn commit_hash() -> String {
+fn commit_hash() -> Option<String> {
Command::new("git")
.args(&["rev-parse", "--short", "HEAD"])
.output()
.ok()
.and_then(|output| String::from_utf8(output.stdout).ok())
- .unwrap_or_default()
+ .map(|hash| hash.trim().into())
}
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/mod.rs b/alacritty/src/config/mod.rs
index 43cade6d..4a3c0ae9 100644
--- a/alacritty/src/config/mod.rs
+++ b/alacritty/src/config/mod.rs
@@ -101,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
@@ -128,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);
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 f0917cf5..3ce02161 100644
--- a/alacritty/src/config/ui_config.rs
+++ b/alacritty/src/config/ui_config.rs
@@ -70,7 +70,7 @@ pub struct UiConfig {
/// Background opacity from 0.0 to 1.0.
#[config(deprecated = "use window.opacity instead")]
- window_opacity: Option<Percentage>,
+ background_opacity: Option<Percentage>,
}
impl Default for UiConfig {
@@ -85,7 +85,7 @@ impl Default for UiConfig {
config_paths: Default::default(),
key_bindings: Default::default(),
mouse_bindings: Default::default(),
- window_opacity: Default::default(),
+ background_opacity: Default::default(),
bell: Default::default(),
colors: Default::default(),
draw_bold_text_with_bright_colors: Default::default(),
@@ -117,7 +117,7 @@ impl UiConfig {
#[inline]
pub fn window_opacity(&self) -> f32 {
- self.window_opacity.unwrap_or(self.window.opacity).as_f32()
+ self.background_opacity.unwrap_or(self.window.opacity).as_f32()
}
#[inline]
diff --git a/alacritty/src/display/content.rs b/alacritty/src/display/content.rs
index 85719c06..297aefd6 100644
--- a/alacritty/src/display/content.rs
+++ b/alacritty/src/display/content.rs
@@ -191,6 +191,7 @@ pub struct RenderableCell {
pub graphic: Option<GraphicCell>,
pub fg: Rgb,
pub bg: Rgb,
+ pub sp: Rgb, // Special
pub bg_alpha: f32,
pub flags: Flags,
}
@@ -200,6 +201,11 @@ impl RenderableCell {
// Lookup RGB values.
let mut fg = Self::compute_fg_rgb(content, cell.fg, cell.flags);
let mut bg = Self::compute_bg_rgb(content, cell.bg);
+ let mut sp = if cell.sp == Color::Named(NamedColor::Foreground) {
+ fg
+ } else {
+ Self::compute_bg_rgb(content, cell.sp)
+ };
let mut bg_alpha = if cell.flags.contains(Flags::INVERSE) {
mem::swap(&mut fg, &mut bg);
@@ -266,6 +272,7 @@ impl RenderableCell {
point,
fg,
bg,
+ sp,
}
}
@@ -274,7 +281,13 @@ impl RenderableCell {
self.bg_alpha == 0.
&& self.character == ' '
&& self.zerowidth.is_none()
- && !self.flags.intersects(Flags::UNDERLINE | Flags::STRIKEOUT | Flags::DOUBLE_UNDERLINE)
+ && !self.flags.intersects(
+ Flags::UNDERLINE |
+ Flags::STRIKEOUT |
+ Flags::DOUBLE_UNDERLINE |
+ Flags::UNDERCURL |
+ Flags::OVERLINE |
+ Flags::DOTTED_UNDERLINE)
}
/// Apply [`CellRgb`] colors to the cell's colors.
diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs
index 98a1b723..b8ae4b00 100644
--- a/alacritty/src/input.rs
+++ b/alacritty/src/input.rs
@@ -799,11 +799,18 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
if self.ctx.config().ui_config.alt_send_esc
&& *self.ctx.received_count() == 0
&& self.ctx.modifiers().alt()
- && utf8_len == 1
{
bytes.insert(0, b'\x1b');
}
+ if self.ctx.modifiers().logo()
+ {
+ bytes.insert(0, b'\\');
+ bytes.insert(0, b'\x1b');
+ bytes.insert(0, b'@');
+ bytes.insert(0, b'\x1b');
+ }
+
self.ctx.write_to_pty(bytes);
*self.ctx.received_count() += 1;
diff --git a/alacritty/src/logging.rs b/alacritty/src/logging.rs
index 545905a2..7cef3887 100644
--- a/alacritty/src/logging.rs
+++ b/alacritty/src/logging.rs
@@ -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();
diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs
index 71ed6e28..fba47c40 100644
--- a/alacritty/src/renderer/mod.rs
+++ b/alacritty/src/renderer/mod.rs
@@ -853,6 +853,7 @@ impl<'a> RenderApi<'a> {
bg: Rgb,
string: &str,
) {
+ let sp = Rgb { b: 0, g: 0, r: 0 };
let cells = string
.chars()
.enumerate()
@@ -865,6 +866,7 @@ impl<'a> RenderApi<'a> {
bg_alpha: 1.0,
fg,
bg,
+ sp,
})
.collect::<Vec<_>>();
diff --git a/alacritty/src/renderer/rects.rs b/alacritty/src/renderer/rects.rs
index 77c22011..25ae93d6 100644
--- a/alacritty/src/renderer/rects.rs
+++ b/alacritty/src/renderer/rects.rs
@@ -62,7 +62,18 @@ impl RenderLine {
end: Point<usize>,
color: Rgb,
) {
- let (position, thickness) = match flag {
+ match flag {
+ Flags::UNDERCURL => {
+ Self::push_undercurl_rects(
+ rects,
+ size,
+ metrics.descent,
+ start,
+ end,
+ metrics.underline_position + 1.,
+ metrics.underline_thickness,
+ color)
+ }
Flags::DOUBLE_UNDERLINE => {
// Position underlines so each one has 50% of descent available.
let top_pos = 0.25 * metrics.descent;
@@ -78,22 +89,181 @@ impl RenderLine {
color,
));
- (bottom_pos, metrics.underline_thickness)
+ rects.push(Self::create_rect(
+ size,
+ metrics.descent,
+ start,
+ end,
+ bottom_pos,
+ metrics.underline_thickness,
+ color,
+ ));
+ },
+ Flags::UNDERLINE => {
+ rects.push(Self::create_rect(
+ size,
+ metrics.descent,
+ start,
+ end,
+ metrics.underline_position + 1.,
+ metrics.underline_thickness,
+ color,
+ ));
},
- Flags::UNDERLINE => (metrics.underline_position, metrics.underline_thickness),
- Flags::STRIKEOUT => (metrics.strikeout_position, metrics.strikeout_thickness),
+ Flags::OVERLINE => {
+ let start_x = start.column.0 as f32 * size.cell_width();
+ let end_x = (end.column.0 + 1) as f32 * size.cell_width();
+ rects.push(RenderRect::new(
+ start_x + size.padding_x(),
+ (start.line as f32 * size.cell_height()) + (size.cell_height() / 8.),
+ end_x - start_x,
+ metrics.underline_thickness,
+ color,
+ 1.,
+ ));
+ },
+ Flags::STRIKEOUT => {
+ rects.push(Self::create_rect(
+ size,
+ metrics.descent,
+ start,
+ end,
+ metrics.strikeout_position,
+ metrics.strikeout_thickness,
+ color,
+ ));
+ },
+ Flags::DOTTED_UNDERLINE => {
+ Self::push_dotted_underline_rects(
+ rects,
+ size,
+ metrics.descent,
+ start,
+ end,
+ metrics.underline_position + 1.,
+ metrics.underline_thickness,
+ color)
+ }
_ => unimplemented!("Invalid flag for cell line drawing specified"),
};
+ }
- rects.push(Self::create_rect(
- size,
- metrics.descent,
- start,
- end,
- position,
- thickness,
- color,
- ));
+ fn push_undercurl_rects(
+ rects: &mut Vec<RenderRect>,
+ size: &SizeInfo,
+ descent: f32,
+ start: Point<usize>,
+ end: Point<usize>,
+ position: f32,
+ mut thickness: f32,
+ color: Rgb,
+ ) {
+ let start_x = start.column.0 as f32 * size.cell_width();
+ let end_x = (end.column.0 + 1) as f32 * size.cell_width();
+
+ // Make sure lines are always visible.
+ thickness = thickness.max(1.);
+
+ let line_bottom = (start.line as f32 + 1.) * size.cell_height();
+ let baseline = line_bottom + descent;
+
+ let mut y = (baseline - position - thickness / 2.).ceil();
+ let max_y = line_bottom - thickness;
+ if y > max_y {
+ y = max_y;
+ }
+
+ let period_div = 1.5 * (2. * std::f32::consts::PI) / size.cell_width();
+ let amplitude_mul = size.cell_height() / 10.;
+
+ let mut x = start_x;
+ let mut idx = 0;
+ while x < end_x {
+ let altr = [1., 0., -1., 0.][idx % 4];
+
+ let fl = (x * period_div).sin() * amplitude_mul;
+ let al = (fl.round() - fl).abs();
+
+ rects.push(RenderRect::new(
+ x + size.padding_x(),
+ y + size.padding_y() + fl,
+ 1.,
+ thickness,
+ color,
+ (1. - al).powf(2.),
+ ));
+
+ let fl = (x * period_div).sin() * amplitude_mul - 0.5;
+ let al = (fl.round() - fl).abs();
+
+ rects.push(RenderRect::new(
+ x + size.padding_x(),
+ y + size.padding_y() + fl,
+ 1.,
+ thickness,
+ color,
+ (1. - al).powf(2.),
+ ));
+
+ let fl = (x * period_div).sin() * amplitude_mul + 0.5;
+ let al = (fl.round() - fl).abs();
+
+ rects.push(RenderRect::new(
+ x + size.padding_x(),
+ y + size.padding_y() + fl,
+ 1.,
+ thickness,
+ color,
+ (1. - al).powf(2.),
+ ));
+
+ x += 1.;
+ idx += 1;
+ }
+ }
+
+ fn push_dotted_underline_rects(
+ rects: &mut Vec<RenderRect>,
+ size: &SizeInfo,
+ descent: f32,
+ start: Point<usize>,
+ end: Point<usize>,
+ position: f32,
+ mut thickness: f32,
+ color: Rgb,
+ ) {
+ let start_x = start.column.0 as f32 * size.cell_width();
+ let end_x = (end.column.0 + 1) as f32 * size.cell_width();
+
+ // Make sure lines are always visible.
+ thickness = thickness.max(1.);
+
+ let line_bottom = (start.line as f32 + 1.) * size.cell_height();
+ let baseline = line_bottom + descent;
+
+ let mut y = (baseline - position - thickness / 2.).ceil();
+ let max_y = line_bottom - thickness;
+ if y > max_y {
+ y = max_y;
+ }
+
+ let mut x = start_x;
+ let mut idx = 0;
+ while x < end_x {
+ if idx % 4 == 0 {
+ let rect = RenderRect::new(
+ x + size.padding_x(),
+ y + size.padding_y(),
+ thickness + 1.,
+ thickness + 1.,
+ color,
+ 1.,
+ );
+ rects.push(rect);
+ }
+ x += 1.;
+ idx += 1;
+ }
}
/// Create a line's rect at a position relative to the baseline.
@@ -161,6 +331,9 @@ impl RenderLines {
self.update_flag(cell, Flags::UNDERLINE);
self.update_flag(cell, Flags::DOUBLE_UNDERLINE);
self.update_flag(cell, Flags::STRIKEOUT);
+ self.update_flag(cell, Flags::UNDERCURL);
+ self.update_flag(cell, Flags::OVERLINE);
+ self.update_flag(cell, Flags::DOTTED_UNDERLINE);
}
/// Update the lines for a specific flag.
@@ -188,7 +361,7 @@ impl RenderLines {
}
// Start new line if there currently is none.
- let line = RenderLine { start: cell.point, end, color: cell.fg };
+ let line = RenderLine { start: cell.point, end, color: cell.sp };
match self.inner.get_mut(&flag) {
Some(lines) => lines.push(line),
None => {
diff --git a/alacritty_terminal/Cargo.toml b/alacritty_terminal/Cargo.toml
index e0a37b17..c25c4cab 100644
--- a/alacritty_terminal/Cargo.toml
+++ b/alacritty_terminal/Cargo.toml
@@ -35,7 +35,7 @@ signal-hook = { version = "0.1", features = ["mio-support"] }
miow = "0.3"
winapi = { version = "0.3.7", features = [
"impl-default", "basetsd", "libloaderapi", "minwindef", "ntdef", "processthreadsapi", "winbase",
- "wincon", "wincontypes", "winerror", "winnt", "winuser",
+ "wincon", "wincontypes", "winerror", "winnt", "winuser", "consoleapi",
]}
mio-anonymous-pipes = "0.2"
diff --git a/alacritty_terminal/src/ansi.rs b/alacritty_terminal/src/ansi.rs
index 14617de1..eaaf5d62 100644
--- a/alacritty_terminal/src/ansi.rs
+++ b/alacritty_terminal/src/ansi.rs
@@ -790,6 +790,10 @@ pub enum Attr {
Underline,
/// Underlined twice.
DoubleUnderline,
+ /// Undercurl twice.
+ Undercurl,
+ /// Underlined with dots.
+ DottedUnderline,
/// Blink cursor slowly.
BlinkSlow,
/// Blink cursor fast.
@@ -800,6 +804,8 @@ pub enum Attr {
Hidden,
/// Strikeout text.
Strike,
+ /// Strikeout text.
+ Overline,
/// Cancel bold.
CancelBold,
/// Cancel bold and dim.
@@ -816,10 +822,14 @@ pub enum Attr {
CancelHidden,
/// Cancel strikeout.
CancelStrike,
+ /// Cancel strikeout.
+ CancelOverline,
/// Set indexed foreground color.
Foreground(Color),
/// Set indexed background color.
Background(Color),
+ /// Set indexed special color (for underlines).
+ Special(Color),
}
/// Identifiers which can be assigned to a graphic character set.
@@ -1002,6 +1012,7 @@ where
.trim()
.to_owned();
self.handler.set_title(Some(title));
+
return;
}
unhandled(params);
@@ -1356,6 +1367,8 @@ fn attrs_from_sgr_parameters(params: &mut ParamsIter<'_>) -> Vec<Option<Attr>> {
[3] => Some(Attr::Italic),
[4, 0] => Some(Attr::CancelUnderline),
[4, 2] => Some(Attr::DoubleUnderline),
+ [4, 3] => Some(Attr::Undercurl),
+ [4, 4] => Some(Attr::DottedUnderline),
[4, ..] => Some(Attr::Underline),
[5] => Some(Attr::BlinkSlow),
[6] => Some(Attr::BlinkFast),
@@ -1410,6 +1423,16 @@ fn attrs_from_sgr_parameters(params: &mut ParamsIter<'_>) -> Vec<Option<Attr>> {
parse_sgr_color(&mut iter).map(Attr::Background)
},
[49] => Some(Attr::Background(Color::Named(NamedColor::Background))),
+ [53] => Some(Attr::Overline),
+ [55] => Some(Attr::CancelOverline),
+ [58, params @ ..] => {
+ let rgb_start = if params.len() > 4 { 2 } else { 1 };
+ let rgb_iter = params[rgb_start..].iter().copied();
+ let mut iter = iter::once(params[0]).chain(rgb_iter);
+
+ parse_sgr_color(&mut iter).map(Attr::Special)
+ },
+ [59] => Some(Attr::Special(Color::Named(NamedColor::Foreground))),
[90] => Some(Attr::Foreground(Color::Named(NamedColor::BrightBlack))),
[91] => Some(Attr::Foreground(Color::Named(NamedColor::BrightRed))),
[92] => Some(Attr::Foreground(Color::Named(NamedColor::BrightGreen))),
diff --git a/alacritty_terminal/src/config/mod.rs b/alacritty_terminal/src/config/mod.rs
index 0b313598..382314bd 100644
--- a/alacritty_terminal/src/config/mod.rs
+++ b/alacritty_terminal/src/config/mod.rs
@@ -66,6 +66,7 @@ pub struct Cursor {
pub style: ConfigCursorStyle,
pub vi_mode_style: Option<ConfigCursorStyle>,
pub unfocused_hollow: bool,
+ pub cursor_crosshairs: bool,
thickness: Percentage,
blink_interval: u64,
@@ -79,6 +80,7 @@ impl Default for Cursor {
blink_interval: 750,
style: Default::default(),
vi_mode_style: Default::default(),
+ cursor_crosshairs: false,
}
}
}
diff --git a/alacritty_terminal/src/term/cell.rs b/alacritty_terminal/src/term/cell.rs
index 18aad87d..14229d15 100644
--- a/alacritty_terminal/src/term/cell.rs
+++ b/alacritty_terminal/src/term/cell.rs
@@ -26,6 +26,9 @@ bitflags! {
const LEADING_WIDE_CHAR_SPACER = 0b0000_0100_0000_0000;
const DOUBLE_UNDERLINE = 0b0000_1000_0000_0000;
const GRAPHICS = 0b0001_0000_0000_0000;
+ const UNDERCURL = 0b0010_0000_0000_0000;
+ const DOTTED_UNDERLINE = 0b0100_0000_0000_0000;
+ const OVERLINE = 0b1000_0000_0000_0000;
}
}
@@ -66,6 +69,7 @@ pub struct Cell {
pub c: char,
pub fg: Color,
pub bg: Color,
+ pub sp: Color,
pub flags: Flags,
#[serde(default)]
extra: Option<Box<CellExtra>>,
@@ -78,6 +82,7 @@ impl Default for Cell {
c: ' ',
bg: Color::Named(NamedColor::Background),
fg: Color::Named(NamedColor::Foreground),
+ sp: Color::Named(NamedColor::Foreground),
flags: Flags::empty(),
extra: None,
}
@@ -135,10 +140,14 @@ impl GridCell for Cell {
(self.c == ' ' || self.c == '\t')
&& self.bg == Color::Named(NamedColor::Background)
&& self.fg == Color::Named(NamedColor::Foreground)
+ && self.sp == Color::Named(NamedColor::Foreground)
&& !self.flags.intersects(
Flags::INVERSE
| Flags::UNDERLINE
| Flags::DOUBLE_UNDERLINE
+ | Flags::UNDERCURL
+ | Flags::DOTTED_UNDERLINE
+ | Flags::OVERLINE
| Flags::STRIKEOUT
| Flags::WRAPLINE
| Flags::WIDE_CHAR_SPACER
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs
index 90af5ce7..17f64099 100644
--- a/alacritty_terminal/src/term/mod.rs
+++ b/alacritty_terminal/src/term/mod.rs
@@ -802,6 +802,7 @@ impl<T> Term<T> {
let c = self.grid.cursor.charsets[self.active_charset].map(c);
let fg = self.grid.cursor.template.fg;
let bg = self.grid.cursor.template.bg;
+ let sp = self.grid.cursor.template.sp;
let flags = self.grid.cursor.template.flags;
let mut cursor_cell = self.grid.cursor_cell();
@@ -831,6 +832,7 @@ impl<T> Term<T> {
cursor_cell.c = c;
cursor_cell.fg = fg;
cursor_cell.bg = bg;
+ cursor_cell.sp = sp;
cursor_cell.flags = flags;
}
}
@@ -1513,9 +1515,11 @@ impl<T: EventListener> Handler for Term<T> {
match attr {
Attr::Foreground(color) => cursor.template.fg = color,
Attr::Background(color) => cursor.template.bg = color,
+ Attr::Special(color) => cursor.template.sp = color,
Attr::Reset => {
cursor.template.fg = Color::Named(NamedColor::Foreground);
cursor.template.bg = Color::Named(NamedColor::Background);
+ cursor.template.sp = Color::Named(NamedColor::Foreground);
cursor.template.flags = Flags::empty();
},
Attr::Reverse => cursor.template.flags.insert(Flags::INVERSE),
@@ -1528,14 +1532,40 @@ impl<T: EventListener> Handler for Term<T> {
Attr::CancelItalic => cursor.template.flags.remove(Flags::ITALIC),
Attr::Underline => {
cursor.template.flags.remove(Flags::DOUBLE_UNDERLINE);
+ cursor.template.flags.remove(Flags::UNDERCURL);
+ cursor.template.flags.remove(Flags::DOTTED_UNDERLINE);
cursor.template.flags.insert(Flags::UNDERLINE);
},
Attr::DoubleUnderline => {
cursor.template.flags.remove(Flags::UNDERLINE);
+ cursor.template.flags.remove(Flags::UNDERCURL);
+ cursor.template.flags.remove(Flags::DOTTED_UNDERLINE);
cursor.template.flags.insert(Flags::DOUBLE_UNDERLINE);
},
+ Attr::Undercurl => {
+ cursor.template.flags.remove(Flags::UNDERLINE);
+ cursor.template.flags.remove(Flags::DOUBLE_UNDERLINE);
+ cursor.template.flags.remove(Flags::DOTTED_UNDERLINE);
+ cursor.template.flags.insert(Flags::UNDERCURL);
+ },
+ Attr::DottedUnderline => {
+ cursor.template.flags.remove(Flags::UNDERLINE);
+ cursor.template.flags.remove(Flags::DOUBLE_UNDERLINE);
+ cursor.template.flags.remove(Flags::UNDERCURL);
+ cursor.template.flags.insert(Flags::DOTTED_UNDERLINE);
+ },
Attr::CancelUnderline => {
- cursor.template.flags.remove(Flags::UNDERLINE | Flags::DOUBLE_UNDERLINE);
+ cursor.template.flags.remove(
+ Flags::UNDERLINE |
+ Flags::DOUBLE_UNDERLINE |
+ Flags::UNDERCURL |
+ Flags::DOTTED_UNDERLINE);
+ },
+ Attr::Overline => {
+ cursor.template.flags.insert(Flags::OVERLINE);
+ },
+ Attr::CancelOverline => {
+ cursor.template.flags.remove(Flags::OVERLINE);
},
Attr::Hidden => cursor.template.flags.insert(Flags::HIDDEN),
Attr::CancelHidden => cursor.template.flags.remove(Flags::HIDDEN),