aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--.agignore1
-rw-r--r--.builds/freebsd.yml5
-rw-r--r--.builds/linux.yml5
-rw-r--r--.gitattributes1
-rw-r--r--.github/workflows/ci.yml10
-rw-r--r--.github/workflows/release.yml12
-rw-r--r--CHANGELOG.md38
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--Cargo.lock264
-rw-r--r--INSTALL.md27
-rw-r--r--Makefile35
-rw-r--r--alacritty.yml35
-rw-r--r--alacritty/Cargo.toml10
-rw-r--r--alacritty/build.rs12
-rw-r--r--alacritty/res/text.f.glsl2
-rw-r--r--alacritty/res/text.v.glsl2
-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
-rw-r--r--alacritty/windows/alacritty.ico (renamed from extra/windows/alacritty.ico)bin318658 -> 318658 bytes
-rw-r--r--alacritty/windows/alacritty.manifest (renamed from extra/windows/alacritty.manifest)0
-rw-r--r--alacritty/windows/windows.rc (renamed from extra/windows/windows.rc)0
-rw-r--r--alacritty/windows/wix/alacritty.wxs (renamed from extra/windows/wix/alacritty.wxs)2
-rw-r--r--alacritty/windows/wix/license.rtf (renamed from extra/windows/wix/license.rtf)0
-rw-r--r--alacritty_terminal/Cargo.toml8
-rw-r--r--alacritty_terminal/src/event_loop.rs114
-rw-r--r--alacritty_terminal/src/lib.rs2
-rw-r--r--alacritty_terminal/src/sync.rs18
-rw-r--r--alacritty_terminal/src/term/mod.rs82
-rw-r--r--alacritty_terminal/src/term/search.rs8
-rw-r--r--alacritty_terminal/src/tty/unix.rs8
-rw-r--r--alacritty_terminal/src/vi_mode.rs86
-rw-r--r--extra/alacritty.info2
-rw-r--r--extra/alacritty.man2
-rw-r--r--extra/linux/io.alacritty.Alacritty.appdata.xml3
-rw-r--r--extra/osx/Alacritty.app/Contents/Info.plist2
l---------extra/windows1
50 files changed, 916 insertions, 565 deletions
diff --git a/.agignore b/.agignore
deleted file mode 100644
index 2231d1fa..00000000
--- a/.agignore
+++ /dev/null
@@ -1 +0,0 @@
-tests/ref
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
index 70ee6d43..88232e5d 100644
--- a/.builds/freebsd.yml
+++ b/.builds/freebsd.yml
@@ -8,6 +8,7 @@ packages:
- x11-fonts/fontconfig
- x11-fonts/dejavu
- x11/libxcb
+ - x11/libxkbcommon
sources:
- https://github.com/alacritty/alacritty
@@ -23,8 +24,8 @@ tasks:
cargo test
- oldstable: |
cd alacritty
- rustup toolchain install --profile minimal 1.45.2
- rustup default 1.45.2
+ rustup toolchain install --profile minimal 1.46.0
+ rustup default 1.46.0
cargo test
- clippy: |
cd alacritty
diff --git a/.builds/linux.yml b/.builds/linux.yml
index 3f793175..3dc36553 100644
--- a/.builds/linux.yml
+++ b/.builds/linux.yml
@@ -7,6 +7,7 @@ packages:
- freetype2
- fontconfig
- libxcb
+ - libxkbcommon
sources:
- https://github.com/alacritty/alacritty
@@ -26,8 +27,8 @@ tasks:
cargo +nightly fmt -- --check
- oldstable: |
cd alacritty
- rustup toolchain install --profile minimal 1.45.2
- rustup default 1.45.2
+ rustup toolchain install --profile minimal 1.46.0
+ rustup default 1.46.0
cargo test
- clippy: |
cd alacritty
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 23379ab5..f0b713cb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,9 +19,17 @@ jobs:
run: cargo test
- name: Oldstable
run: |
- rustup default 1.45.2
+ rustup default 1.46.0
cargo test
- name: Clippy
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 30085858..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
@@ -63,7 +67,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get install cmake pkg-config libfreetype6-dev libfontconfig1-dev \
- libxcb-xfixes0-dev python3
+ libxcb-xfixes0-dev libxkbcommon-dev python3
- name: Test
run: cargo test --release
- name: Gzip manpage
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4ad3d89a..269d4537 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,23 @@ The sections should follow the order `Packaging`, `Added`, `Changed`, `Fixed` an
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
-## 0.9.0-dev
+## 0.10.0-dev
+
+### Added
+
+- Option `colors.transparent_background_colors` to allow applying opacity to all background colors
+
+### Changed
+
+- `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
+
+### Packaging
+
+- Minimum Rust version has been bumped to 1.46.0
### Added
@@ -16,7 +32,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Regression in rendering performance with dense grids since 0.6.0
- Crash/Freezes with partially visible fullwidth characters due to alt screen resize
-- Incorrect vi cursor position after invoking `ScrollPageHalfUp` action
+- Incorrect vi cursor position after invoking `ScrollPage*` action
+- Slow PTY read performance with extremely dense grids
+- Crash when resizing during vi mode
+- Unintentional text selection range change after leaving vi mode
+- Deadlock on Windows during high frequency output
+- Search without vi mode not starting at the correct location when scrolled into history
+- Crash when starting a vi mode search from the bottommost line
+- Original scroll position not restored after canceling search
+- Clipboard copy skipping non-empty cells when encountering an interrupted tab character
+- Vi mode cursor moving downward when scrolled in history with active output
+- Crash when moving fullwidth characters off the side of the terminal in insert mode
+- Broken bitmap font rendering with FreeType 2.11+
+- Crash with non-utf8 font paths on Linux
+- Newly installed fonts not rendering until Alacritty restart
## 0.8.0
@@ -24,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/CONTRIBUTING.md b/CONTRIBUTING.md
index 351bb5de..5794fc8a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -42,7 +42,7 @@ and
[easy](https://github.com/alacritty/alacritty/issues?q=is%3Aopen+is%3Aissue+label%3A%22D+-+easy%22)
issues.
-Please note that the minimum supported version of Alacritty is Rust 1.43.0. All patches are expected
+Please note that the minimum supported version of Alacritty is Rust 1.46.0. All patches are expected
to work with the minimum supported version.
Since `alacritty_terminal`'s version always tracks the next release, make sure that the version is
diff --git a/Cargo.lock b/Cargo.lock
index 73453dde..985cc4e6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -16,12 +16,11 @@ checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "alacritty"
-version = "0.9.0-dev"
+version = "0.10.0-dev"
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",
@@ -63,7 +63,7 @@ dependencies = [
[[package]]
name = "alacritty_terminal"
-version = "0.13.1-dev"
+version = "0.15.1-dev"
dependencies = [
"alacritty_config_derive",
"base64",
@@ -75,7 +75,7 @@ dependencies = [
"mio-anonymous-pipes",
"mio-extras",
"miow 0.3.7",
- "nix 0.20.0",
+ "nix 0.22.0",
"parking_lot",
"regex-automata",
"serde",
@@ -151,12 +151,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
-name = "byteorder"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
-
-[[package]]
name = "calloop"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -168,9 +162,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.0.67"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
+checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
[[package]]
name = "cfg-if"
@@ -393,9 +387,9 @@ dependencies = [
[[package]]
name = "crossfont"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc52c750165ecb41cf02bfa8fd6731dc6796dddd87a3713fc9fbe9e08e71d48b"
+checksum = "b6c0967e93a0440865bf1d867c3a50d6993f5054b2a10186fc2830397918241d"
dependencies = [
"cocoa 0.24.0",
"core-foundation 0.9.1",
@@ -530,9 +524,9 @@ dependencies = [
[[package]]
name = "embed-resource"
-version = "1.6.2"
+version = "1.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0ea6debf1262982d24274dc85f3374b42534df140897c25cea86b81e017d470"
+checksum = "45de30eb317b4cd3882ee16623cb3004e5fb99a8f4cd40097cadf61efbc54adc"
dependencies = [
"cc",
"vswhom",
@@ -668,9 +662,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]]
name = "getrandom"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if 1.0.0",
"libc",
@@ -761,10 +755,19 @@ 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.18"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
@@ -797,9 +800,9 @@ dependencies = [
[[package]]
name = "instant"
-version = "0.1.9"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
+checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d"
dependencies = [
"cfg-if 1.0.0",
]
@@ -861,9 +864,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
-version = "0.2.94"
+version = "0.2.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
+checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
[[package]]
name = "libloading"
@@ -927,9 +930,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
[[package]]
name = "memchr"
-version = "2.4.0"
+version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
+checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "memmap2"
@@ -941,10 +944,19 @@ dependencies = [
]
[[package]]
+name = "memmap2"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "memoffset"
-version = "0.6.1"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
+checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
dependencies = [
"autocfg",
]
@@ -979,12 +991,13 @@ dependencies = [
[[package]]
name = "mio-anonymous-pipes"
-version = "0.1.0"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8c274c3c52dcd1d78c5d7ed841eca1e9ea2db8353f3b8ec25789cc62c471aaf"
+checksum = "6bc513025fe5005a3aa561b50fdb2cda5a150b84800ae02acd8aa9ed62ca1a6b"
dependencies = [
"mio",
"miow 0.3.7",
+ "parking_lot",
"spsc-buffer",
"winapi 0.3.9",
]
@@ -1103,10 +1116,23 @@ dependencies = [
]
[[package]]
+name = "nix"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1e25ee6b412c2a1e3fcb6a4499a5c1bfe7f43e014bdce9a6b6666e5aa2d187"
+dependencies = [
+ "bitflags",
+ "cc",
+ "cfg-if 1.0.0",
+ "libc",
+ "memoffset",
+]
+
+[[package]]
name = "nom"
-version = "6.1.2"
+version = "6.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
+checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6"
dependencies = [
"memchr",
"version_check",
@@ -1114,9 +1140,9 @@ dependencies = [
[[package]]
name = "notify"
-version = "4.0.16"
+version = "4.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2599080e87c9bd051ddb11b10074f4da7b1223298df65d4c2ec5bcf309af1533"
+checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257"
dependencies = [
"bitflags",
"filetime",
@@ -1183,9 +1209,9 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.7.2"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
+checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "osmesa-sys"
@@ -1263,10 +1289,34 @@ 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.26"
+version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
+checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
dependencies = [
"unicode-xid",
]
@@ -1291,9 +1341,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.2.7"
+version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85dd92e586f7355c633911e11f77f3d12f04b1b1bd76a198bd34ae3af8341ef2"
+checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
dependencies = [
"bitflags",
]
@@ -1310,19 +1360,18 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.1.9"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
- "byteorder",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
-version = "0.6.24"
+version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00efb87459ba4f6fb2169d20f68565555688e1250ee6825cdf6254f8b48fafb2"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rusttype"
@@ -1363,18 +1412,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
-version = "1.0.125"
+version = "1.0.127"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
+checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.125"
+version = "1.0.127"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
+checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc"
dependencies = [
"proc-macro2",
"quote",
@@ -1383,9 +1432,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.64"
+version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
+checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127"
dependencies = [
"itoa",
"ryu",
@@ -1448,9 +1497,9 @@ dependencies = [
[[package]]
name = "signal-hook-registry"
-version = "1.3.0"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
+checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
dependencies = [
"libc",
]
@@ -1479,7 +1528,7 @@ dependencies = [
"dlib 0.4.2",
"lazy_static",
"log",
- "memmap2",
+ "memmap2 0.1.0",
"nix 0.18.0",
"wayland-client",
"wayland-cursor",
@@ -1487,12 +1536,29 @@ dependencies = [
]
[[package]]
+name = "smithay-client-toolkit"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec783683499a2cfc85b6df3d04f83b1907b5cbd98a1aed44667dbdf1eac4e64c"
+dependencies = [
+ "bitflags",
+ "dlib 0.5.0",
+ "lazy_static",
+ "log",
+ "memmap2 0.2.3",
+ "nix 0.20.0",
+ "wayland-client",
+ "wayland-cursor",
+ "wayland-protocols",
+]
+
+[[package]]
name = "smithay-clipboard"
-version = "0.6.3"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06384dfaf645908220d976ae24ed39f6cf92efecb0225ea0a948e403014de527"
+checksum = "986c5b4a7bd4f50d4c51f81f844745535cb488360f9cf63293780b109b9295f3"
dependencies = [
- "smithay-client-toolkit",
+ "smithay-client-toolkit 0.14.0",
"wayland-client",
]
@@ -1515,10 +1581,34 @@ 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.71"
+version = "1.0.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad184cc9470f9117b2ac6817bfe297307418819ba40552f9b3846f05c33d5373"
+checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c"
dependencies = [
"proc-macro2",
"quote",
@@ -1536,18 +1626,18 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.24"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
+checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.24"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
+checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
dependencies = [
"proc-macro2",
"quote",
@@ -1580,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"
@@ -1668,9 +1764,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wayland-client"
-version = "0.28.5"
+version = "0.28.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ca44d86554b85cf449f1557edc6cc7da935cc748c8e4bf1c507cbd43bae02c"
+checksum = "e3ab332350e502f159382201394a78e3cc12d0f04db863429260164ea40e0355"
dependencies = [
"bitflags",
"downcast-rs",
@@ -1684,9 +1780,9 @@ dependencies = [
[[package]]
name = "wayland-commons"
-version = "0.28.5"
+version = "0.28.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bd75ae380325dbcff2707f0cd9869827ea1d2d6d534cff076858d3f0460fd5a"
+checksum = "a21817947c7011bbd0a27e11b17b337bfd022e8544b071a2641232047966fbda"
dependencies = [
"nix 0.20.0",
"once_cell",
@@ -1696,9 +1792,9 @@ dependencies = [
[[package]]
name = "wayland-cursor"
-version = "0.28.5"
+version = "0.28.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b37e5455ec72f5de555ec39b5c3704036ac07c2ecd50d0bffe02d5fe2d4e65ab"
+checksum = "be610084edd1586d45e7bdd275fe345c7c1873598caa464c4fb835dee70fa65a"
dependencies = [
"nix 0.20.0",
"wayland-client",
@@ -1707,9 +1803,9 @@ dependencies = [
[[package]]
name = "wayland-egl"
-version = "0.28.5"
+version = "0.28.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9461a67930ec16da7a4fd8b50e9ffa23f4417240b43ec84008bd1b2c94421c94"
+checksum = "99ba1ab1e18756b23982d36f08856d521d7df45015f404a2d7c4f0b2d2f66956"
dependencies = [
"wayland-client",
"wayland-sys",
@@ -1717,9 +1813,9 @@ dependencies = [
[[package]]
name = "wayland-protocols"
-version = "0.28.5"
+version = "0.28.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95df3317872bcf9eec096c864b69aa4769a1d5d6291a5b513f8ba0af0efbd52c"
+checksum = "286620ea4d803bacf61fa087a4242ee316693099ee5a140796aaba02b29f861f"
dependencies = [
"bitflags",
"wayland-client",
@@ -1729,9 +1825,9 @@ dependencies = [
[[package]]
name = "wayland-scanner"
-version = "0.28.5"
+version = "0.28.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "389d680d7bd67512dc9c37f39560224327038deb0f0e8d33f870900441b68720"
+checksum = "ce923eb2deb61de332d1f356ec7b6bf37094dc5573952e1c8936db03b54c03f1"
dependencies = [
"proc-macro2",
"quote",
@@ -1740,9 +1836,9 @@ dependencies = [
[[package]]
name = "wayland-sys"
-version = "0.28.5"
+version = "0.28.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2907bd297eef464a95ba9349ea771611771aa285b932526c633dc94d5400a8e2"
+checksum = "d841fca9aed7febf9bed2e9796c49bf58d4152ceda8ac949ebe00868d8f0feb8"
dependencies = [
"dlib 0.5.0",
"lazy_static",
@@ -1818,7 +1914,7 @@ dependencies = [
"percent-encoding",
"raw-window-handle",
"serde",
- "smithay-client-toolkit",
+ "smithay-client-toolkit 0.12.3",
"wayland-client",
"winapi 0.3.9",
"x11-dl",
@@ -1826,9 +1922,9 @@ dependencies = [
[[package]]
name = "winreg"
-version = "0.8.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d107f8c6e916235c4c01cabb3e8acf7bea8ef6a63ca2e7fa0527c049badfc48c"
+checksum = "16cdb3898397cf7f624c294948669beafaeebc5577d5ec53d0afb76633593597"
dependencies = [
"winapi 0.3.9",
]
@@ -1854,9 +1950,9 @@ dependencies = [
[[package]]
name = "x11-clipboard"
-version = "0.5.1"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5e937afd03b64b7be4f959cc044e09260a47241b71e56933f37db097bf7859d"
+checksum = "b397ace6e980510de59a4fe3d4c758dffab231d6d747ce9fa1aba6b6035d5f32"
dependencies = [
"xcb",
]
@@ -1900,9 +1996,9 @@ checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
[[package]]
name = "xml-rs"
-version = "0.8.3"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"
+checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
[[package]]
name = "yaml-rust"
diff --git a/INSTALL.md b/INSTALL.md
index d12b1639..d8f6ef89 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -9,6 +9,9 @@ install it directly through cargo:
cargo install alacritty
```
+Note that you will still need to install the dependencies for your OS of choice.
+Please refer to the [Dependencies](#dependencies) section.
+
# Manual Installation
1. [Prerequisites](#prerequisites)
@@ -81,7 +84,7 @@ to build Alacritty. Here's an apt command that should install all of them. If
something is still found to be missing, please open an issue.
```sh
-apt-get install cmake pkg-config libfreetype6-dev libfontconfig1-dev libxcb-xfixes0-dev python3
+apt-get install cmake pkg-config libfreetype6-dev libfontconfig1-dev libxcb-xfixes0-dev libxkbcommon-dev python3
```
#### Arch Linux
@@ -91,7 +94,7 @@ On Arch Linux, you need a few extra libraries to build Alacritty. Here's a
to be missing, please open an issue.
```sh
-pacman -S cmake freetype2 fontconfig pkg-config make libxcb
+pacman -S cmake freetype2 fontconfig pkg-config make libxcb libxkbcommon python
```
#### Fedora
@@ -101,7 +104,7 @@ command that should install all of them. If something is still found to be
missing, please open an issue.
```sh
-dnf install cmake freetype-devel fontconfig-devel libxcb-devel g++
+dnf install cmake freetype-devel fontconfig-devel libxcb-devel libxkbcommon-devel g++
```
#### CentOS/RHEL 7
@@ -111,7 +114,7 @@ command that should install all of them. If something is still found to be
missing, please open an issue.
```sh
-yum install cmake freetype-devel fontconfig-devel libxcb-devel xcb-util-devel
+yum install cmake freetype-devel fontconfig-devel libxcb-devel libxkbcommon-devel xcb-util-devel
yum group install "Development Tools"
```
@@ -122,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
@@ -131,7 +134,7 @@ Compiles out of the box for 14.2
#### Void Linux
-On [Void Linux](https://voidlinux.eu), install following packages before
+On [Void Linux](https://voidlinux.org), install following packages before
compiling Alacritty:
```sh
@@ -145,7 +148,7 @@ command that should install all of them. If something is still found to be
missing, please open an issue.
```sh
-pkg install cmake freetype2 fontconfig pkgconf
+pkg install cmake freetype2 fontconfig pkgconf python3
```
#### OpenBSD
@@ -248,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.yml b/alacritty.yml
index 21f06fd0..04654e56 100644
--- a/alacritty.yml
+++ b/alacritty.yml
@@ -63,6 +63,12 @@
# - buttonless: Title bar, transparent background and no title bar buttons
#decorations: full
+ # Background opacity
+ #
+ # Window opacity as a floating point number from `0.0` to `1.0`.
+ # The value `0.0` is completely transparent and `1.0` is opaque.
+ #opacity: 1.0
+
# Startup Mode (changes require restart)
#
# Values for `startup_mode`:
@@ -312,6 +318,13 @@
#
#indexed_colors: []
+ # Transparent cell backgrounds
+ #
+ # Whether or not `window.opacity` applies to all cell backgrounds or only to
+ # the default background. When set to `true` all cells will be transparent
+ # regardless of their background color.
+ #transparent_background_colors: false
+
# Bell
#
# The bell is rung every time the BEL control character is received.
@@ -353,12 +366,6 @@
#
#command: None
-# Background opacity
-#
-# Window opacity as a floating point number from `0.0` to `1.0`.
-# The value `0.0` is completely transparent and `1.0` is opaque.
-#background_opacity: 1.0
-
#selection:
# This string contains all characters that are used as separators for
# "semantic words" in Alacritty.
@@ -458,7 +465,7 @@
# Each hint must have a `regex` and either an `action` or a `command` field.
# The fields `mouse`, `binding` and `post_processing` are optional.
#
- # The fields `command`, `binding.key`, `binding.mods`, `binding.mode` and
+ # The fields `command`, `binding.key`, `binding.mods`, `binding.mode` and
# `mouse.mods` accept the same values as they do in the `key_bindings` section.
#
# The `mouse.enabled` field controls if the hint should be underlined while
@@ -507,13 +514,19 @@
# - Right
# - Numeric identifier such as `5`
#
-# - `action` (see key bindings)
+# - `action` (see key bindings for actions not exclusive to mouse mode)
+#
+# - Mouse exclusive actions:
+#
+# - ExpandSelection
+# Expand the selection to the current mouse cursor location.
#
# And optionally:
#
# - `mods` (see key bindings)
#mouse_bindings:
-# - { mouse: Middle, action: PasteSelection }
+# - { mouse: Right, action: ExpandSelection }
+# - { mouse: Middle, mode: ~Vi, action: PasteSelection }
# Key bindings
#
@@ -730,11 +743,11 @@
#- { key: End, mods: Shift, mode: ~Alt, action: ScrollToBottom }
# Vi Mode
- #- { key: Space, mods: Shift|Control, mode: Vi|~Search, action: ScrollToBottom }
#- { key: Space, mods: Shift|Control, mode: ~Search, action: ToggleViMode }
+ #- { key: Space, mods: Shift|Control, mode: Vi|~Search, action: ScrollToBottom }
#- { key: Escape, mode: Vi|~Search, action: ClearSelection }
- #- { key: I, mode: Vi|~Search, action: ScrollToBottom }
#- { key: I, mode: Vi|~Search, action: ToggleViMode }
+ #- { key: I, mode: Vi|~Search, action: ScrollToBottom }
#- { key: C, mods: Control, mode: Vi|~Search, action: ToggleViMode }
#- { key: Y, mods: Control, mode: Vi|~Search, action: ScrollLineUp }
#- { key: E, mods: Control, mode: Vi|~Search, action: ScrollLineDown }
diff --git a/alacritty/Cargo.toml b/alacritty/Cargo.toml
index 99e61f56..74366c43 100644
--- a/alacritty/Cargo.toml
+++ b/alacritty/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "alacritty"
-version = "0.9.0-dev"
+version = "0.10.0-dev"
authors = ["Christian Duerr <contact@christianduerr.com>", "Joe Wilm <joe@jwilm.com>"]
license = "Apache-2.0"
description = "A fast, cross-platform, OpenGL terminal emulator"
@@ -10,7 +10,7 @@ edition = "2018"
[dependencies.alacritty_terminal]
path = "../alacritty_terminal"
-version = "0.13.1-dev"
+version = "0.15.1-dev"
default-features = false
[dependencies.alacritty_config_derive]
@@ -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"
@@ -28,13 +28,13 @@ serde_json = "1"
glutin = { version = "0.26.0", default-features = false, features = ["serde"] }
notify = "4"
parking_lot = "0.11.0"
-crossfont = { version = "0.3.0", features = ["force_system_fontconfig"] }
+crossfont = { version = "0.3.1", features = ["force_system_fontconfig"] }
copypasta = { version = "0.7.0", default-features = false }
libc = "0.2"
unicode-width = "0.1"
bitflags = "1"
dirs = "3.0.1"
-memoffset = "0.6.1"
+memoffset = "0.6.4"
[build-dependencies]
gl_generator = "0.14.0"
diff --git a/alacritty/build.rs b/alacritty/build.rs
index 48841ca8..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();
@@ -16,14 +20,14 @@ fn main() {
.unwrap();
#[cfg(windows)]
- embed_resource::compile("../extra/windows/windows.rc");
+ 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/res/text.f.glsl b/alacritty/res/text.f.glsl
index d5e26881..5b4e3da6 100644
--- a/alacritty/res/text.f.glsl
+++ b/alacritty/res/text.f.glsl
@@ -18,7 +18,7 @@ void main() {
}
alphaMask = vec4(1.0);
- color = vec4(bg.rgb, 1.0);
+ color = vec4(bg.rgb, bg.a);
} else if ((int(fg.a) & COLORED) != 0) {
// Color glyphs, like emojis.
vec4 glyphColor = texture(mask, TexCoords);
diff --git a/alacritty/res/text.v.glsl b/alacritty/res/text.v.glsl
index 31e6f934..a4a31382 100644
--- a/alacritty/res/text.v.glsl
+++ b/alacritty/res/text.v.glsl
@@ -65,6 +65,6 @@ void main() {
TexCoords = uvOffset + position * uvSize;
}
- bg = vec4(backgroundColor.rgb / 255.0, backgroundColor.a);
+ bg = backgroundColor / 255.0;
fg = vec4(textColor.rgb / 255.0, textColor.a);
}
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.
diff --git a/extra/windows/alacritty.ico b/alacritty/windows/alacritty.ico
index a84db555..a84db555 100644
--- a/extra/windows/alacritty.ico
+++ b/alacritty/windows/alacritty.ico
Binary files differ
diff --git a/extra/windows/alacritty.manifest b/alacritty/windows/alacritty.manifest
index 82039bf7..82039bf7 100644
--- a/extra/windows/alacritty.manifest
+++ b/alacritty/windows/alacritty.manifest
diff --git a/extra/windows/windows.rc b/alacritty/windows/windows.rc
index b265d4bc..b265d4bc 100644
--- a/extra/windows/windows.rc
+++ b/alacritty/windows/windows.rc
diff --git a/extra/windows/wix/alacritty.wxs b/alacritty/windows/wix/alacritty.wxs
index 961faeb8..a8c97d39 100644
--- a/extra/windows/wix/alacritty.wxs
+++ b/alacritty/windows/wix/alacritty.wxs
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="windows-1252"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
- <Product Name="Alacritty" Id="*" UpgradeCode="87c21c74-dbd5-4584-89d5-46d9cd0c40a7" Language="1033" Codepage="1252" Version="0.8.0-dev" Manufacturer="Alacritty">
+ <Product Name="Alacritty" Id="*" UpgradeCode="87c21c74-dbd5-4584-89d5-46d9cd0c40a7" Language="1033" Codepage="1252" Version="0.10.0-dev" Manufacturer="Alacritty">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine"/>
<MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of [ProductName] is already installed."/>
<Icon Id="AlacrittyIco" SourceFile=".\extra\windows\alacritty.ico"/>
diff --git a/extra/windows/wix/license.rtf b/alacritty/windows/wix/license.rtf
index ea025032..ea025032 100644
--- a/extra/windows/wix/license.rtf
+++ b/alacritty/windows/wix/license.rtf
diff --git a/alacritty_terminal/Cargo.toml b/alacritty_terminal/Cargo.toml
index 89bc26a5..c25c4cab 100644
--- a/alacritty_terminal/Cargo.toml
+++ b/alacritty_terminal/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "alacritty_terminal"
-version = "0.13.1-dev"
+version = "0.15.1-dev"
authors = ["Christian Duerr <contact@christianduerr.com>", "Joe Wilm <joe@jwilm.com>"]
license = "Apache-2.0"
description = "Library for writing terminal emulators"
@@ -28,16 +28,16 @@ regex-automata = "0.1.9"
dirs = "3.0.1"
[target.'cfg(unix)'.dependencies]
-nix = "0.20.0"
+nix = "0.22.0"
signal-hook = { version = "0.1", features = ["mio-support"] }
[target.'cfg(windows)'.dependencies]
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.1"
+mio-anonymous-pipes = "0.2"
[dev-dependencies]
serde_json = "1.0.0"
diff --git a/alacritty_terminal/src/event_loop.rs b/alacritty_terminal/src/event_loop.rs
index 098ee896..b4c0a5e4 100644
--- a/alacritty_terminal/src/event_loop.rs
+++ b/alacritty_terminal/src/event_loop.rs
@@ -22,8 +22,11 @@ use crate::term::{SizeInfo, Term};
use crate::thread;
use crate::tty;
-/// Max bytes to read from the PTY.
-const MAX_READ: usize = u16::max_value() as usize;
+/// Max bytes to read from the PTY before forced terminal synchronization.
+const READ_BUFFER_SIZE: usize = 0x10_0000;
+
+/// Max bytes to read from the PTY while the terminal is locked.
+const MAX_LOCKED_READ: usize = u16::max_value() as usize;
/// Messages that may be sent to the `EventLoop`.
#[derive(Debug)]
@@ -213,48 +216,58 @@ where
where
X: Write,
{
+ let mut unprocessed = 0;
let mut processed = 0;
+
+ // Reserve the next terminal lock for PTY reading.
+ let _terminal_lease = Some(self.terminal.lease());
let mut terminal = None;
loop {
- match self.pty.reader().read(buf) {
- Ok(0) => break,
- Ok(got) => {
- // Record bytes read; used to limit time spent in pty_read.
- processed += got;
-
- // Send a copy of bytes read to a subscriber. Used for
- // example with ref test recording.
- writer = writer.map(|w| {
- w.write_all(&buf[..got]).unwrap();
- w
- });
-
- // Get reference to terminal. Lock is acquired on initial
- // iteration and held until there's no bytes left to parse
- // or we've reached `MAX_READ`.
- if terminal.is_none() {
- terminal = Some(self.terminal.lock());
- }
- let terminal = terminal.as_mut().unwrap();
-
- // Run the parser.
- for byte in &buf[..got] {
- state.parser.advance(&mut **terminal, *byte);
- }
-
- // Exit if we've processed enough bytes.
- if processed > MAX_READ {
- break;
- }
- },
+ // Read from the PTY.
+ match self.pty.reader().read(&mut buf[unprocessed..]) {
+ // This is received on Windows/macOS when no more data is readable from the PTY.
+ Ok(0) if unprocessed == 0 => break,
+ Ok(got) => unprocessed += got,
Err(err) => match err.kind() {
ErrorKind::Interrupted | ErrorKind::WouldBlock => {
- break;
+ // Go back to mio if we're caught up on parsing and the PTY would block.
+ if unprocessed == 0 {
+ break;
+ }
},
_ => return Err(err),
},
}
+
+ // Attempt to lock the terminal.
+ let terminal = match &mut terminal {
+ Some(terminal) => terminal,
+ None => terminal.insert(match self.terminal.try_lock_unfair() {
+ // Force block if we are at the buffer size limit.
+ None if unprocessed >= READ_BUFFER_SIZE => self.terminal.lock_unfair(),
+ None => continue,
+ Some(terminal) => terminal,
+ }),
+ };
+
+ // Write a copy of the bytes to the ref test file.
+ if let Some(writer) = &mut writer {
+ writer.write_all(&buf[..unprocessed]).unwrap();
+ }
+
+ // Parse the incoming bytes.
+ for byte in &buf[..unprocessed] {
+ state.parser.advance(&mut **terminal, *byte);
+ }
+
+ processed += unprocessed;
+ unprocessed = 0;
+
+ // Assure we're not blocking the terminal too long unnecessarily.
+ if processed >= MAX_LOCKED_READ {
+ break;
+ }
}
// Queue terminal redraw unless all processed bytes were synchronized.
@@ -300,7 +313,7 @@ where
pub fn spawn(mut self) -> JoinHandle<(Self, State)> {
thread::spawn_named("PTY reader", move || {
let mut state = State::default();
- let mut buf = [0u8; MAX_READ];
+ let mut buf = [0u8; READ_BUFFER_SIZE];
let mut tokens = (0..).map(Into::into);
@@ -381,7 +394,7 @@ where
// This sucks, but checking the process is either racy or
// blocking.
#[cfg(target_os = "linux")]
- if err.kind() == ErrorKind::Other {
+ if err.raw_os_error() == Some(libc::EIO) {
continue;
}
@@ -418,3 +431,32 @@ where
})
}
}
+
+trait OptionInsert {
+ type T;
+ fn insert(&mut self, value: Self::T) -> &mut Self::T;
+}
+
+// TODO: Remove when MSRV is >= 1.53.0.
+//
+/// Trait implementation to support Rust version < 1.53.0.
+///
+/// This is taken [from STD], further license information can be found in the [rust-lang/rust
+/// repository].
+///
+///
+/// [from STD]: https://github.com/rust-lang/rust/blob/6e0b554619a3bb7e75b3334e97f191af20ef5d76/library/core/src/option.rs#L829-L858
+/// [rust-lang/rust repository]: https://github.com/rust-lang/rust/blob/master/LICENSE-MIT
+impl<T> OptionInsert for Option<T> {
+ type T = T;
+
+ fn insert(&mut self, value: T) -> &mut T {
+ *self = Some(value);
+
+ match self {
+ Some(v) => v,
+ // SAFETY: the code above just filled the option
+ None => unsafe { std::hint::unreachable_unchecked() },
+ }
+ }
+}
diff --git a/alacritty_terminal/src/lib.rs b/alacritty_terminal/src/lib.rs
index 59b2fe05..ea4a2a24 100644
--- a/alacritty_terminal/src/lib.rs
+++ b/alacritty_terminal/src/lib.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))]
pub mod ansi;
diff --git a/alacritty_terminal/src/sync.rs b/alacritty_terminal/src/sync.rs
index 43148a78..848bab62 100644
--- a/alacritty_terminal/src/sync.rs
+++ b/alacritty_terminal/src/sync.rs
@@ -21,6 +21,14 @@ impl<T> FairMutex<T> {
FairMutex { data: Mutex::new(data), next: Mutex::new(()) }
}
+ /// Acquire a lease to reserve the mutex lock.
+ ///
+ /// This will prevent others from acquiring a terminal lock, but block if anyone else is
+ /// already holding a lease.
+ pub fn lease(&self) -> MutexGuard<'_, ()> {
+ self.next.lock()
+ }
+
/// Lock the mutex.
pub fn lock(&self) -> MutexGuard<'_, T> {
// Must bind to a temporary or the lock will be freed before going
@@ -28,4 +36,14 @@ impl<T> FairMutex<T> {
let _next = self.next.lock();
self.data.lock()
}
+
+ /// Unfairly lock the mutex.
+ pub fn lock_unfair(&self) -> MutexGuard<'_, T> {
+ self.data.lock()
+ }
+
+ /// Unfairly try to lock the mutex.
+ pub fn try_lock_unfair(&self) -> Option<MutexGuard<'_, T>> {
+ self.data.try_lock()
+ }
}
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs
index 959f99ef..90af5ce7 100644
--- a/alacritty_terminal/src/term/mod.rs
+++ b/alacritty_terminal/src/term/mod.rs
@@ -419,7 +419,7 @@ impl<T> Term<T> {
// Skip over cells until next tab-stop once a tab was found.
if tab_mode {
- if self.tabs[column] {
+ if self.tabs[column] || cell.c != ' ' {
tab_mode = false;
} else {
continue;
@@ -531,8 +531,10 @@ impl<T> Term<T> {
// Clamp vi cursor to viewport.
let vi_point = self.vi_mode_cursor.point;
- self.vi_mode_cursor.point.column = min(vi_point.column, Column(num_cols - 1));
- self.vi_mode_cursor.point.line = min(vi_point.line, Line(num_lines as i32 - 1));
+ let viewport_top = Line(-(self.grid.display_offset() as i32));
+ let viewport_bottom = viewport_top + self.bottommost_line();
+ self.vi_mode_cursor.point.line = max(min(vi_point.line, viewport_bottom), viewport_top);
+ self.vi_mode_cursor.point.column = min(vi_point.column, self.last_column());
// Reset scrolling region.
self.scroll_region = Line(0)..Line(self.screen_lines() as i32);
@@ -579,6 +581,12 @@ impl<T> Term<T> {
self.selection =
self.selection.take().and_then(|s| s.rotate(self, &region, -(lines as i32)));
+ // Scroll vi mode cursor.
+ let line = &mut self.vi_mode_cursor.point.line;
+ if region.start <= *line && region.end > *line {
+ *line = min(*line + lines, region.end - 1);
+ }
+
// Scroll between origin and bottom
self.grid.scroll_down(&region, lines);
}
@@ -598,6 +606,14 @@ impl<T> Term<T> {
// Scroll selection.
self.selection = self.selection.take().and_then(|s| s.rotate(self, &region, lines as i32));
+ // Scroll vi mode cursor.
+ let viewport_top = Line(-(self.grid.display_offset() as i32));
+ let top = if region.start == 0 { viewport_top } else { region.start };
+ let line = &mut self.vi_mode_cursor.point.line;
+ if (top <= *line) && region.end > *line {
+ *line = max(*line - lines, top);
+ }
+
// Scroll from origin to bottom less number of lines.
self.grid.scroll_up(&region, lines);
}
@@ -795,9 +811,9 @@ impl<T> Term<T> {
// Remove wide char and spacer.
let wide = cursor_cell.flags.contains(Flags::WIDE_CHAR);
let point = self.grid.cursor.point;
- if wide && point.column + 1 < self.columns() {
+ if wide && point.column < self.last_column() {
self.grid[point.line][point.column + 1].flags.remove(Flags::WIDE_CHAR_SPACER);
- } else {
+ } else if point.column > 0 {
self.grid[point.line][point.column - 1].clear_wide();
}
@@ -2069,6 +2085,62 @@ mod tests {
use crate::term::cell::{Cell, Flags};
#[test]
+ fn scroll_display_page_up() {
+ let size = SizeInfo::new(5., 10., 1.0, 1.0, 0.0, 0.0, false);
+ let mut term = Term::new(&MockConfig::default(), size, ());
+
+ // Create 11 lines of scrollback.
+ for _ in 0..20 {
+ term.newline();
+ }
+
+ // Scrollable amount to top is 11.
+ term.scroll_display(Scroll::PageUp);
+ assert_eq!(term.vi_mode_cursor.point, Point::new(Line(-1), Column(0)));
+ assert_eq!(term.grid.display_offset(), 10);
+
+ // Scrollable amount to top is 1.
+ term.scroll_display(Scroll::PageUp);
+ assert_eq!(term.vi_mode_cursor.point, Point::new(Line(-2), Column(0)));
+ assert_eq!(term.grid.display_offset(), 11);
+
+ // Scrollable amount to top is 0.
+ term.scroll_display(Scroll::PageUp);
+ assert_eq!(term.vi_mode_cursor.point, Point::new(Line(-2), Column(0)));
+ assert_eq!(term.grid.display_offset(), 11);
+ }
+
+ #[test]
+ fn scroll_display_page_down() {
+ let size = SizeInfo::new(5., 10., 1.0, 1.0, 0.0, 0.0, false);
+ let mut term = Term::new(&MockConfig::default(), size, ());
+
+ // Create 11 lines of scrollback.
+ for _ in 0..20 {
+ term.newline();
+ }
+
+ // Change display_offset to topmost.
+ term.grid_mut().scroll_display(Scroll::Top);
+ term.vi_mode_cursor = ViModeCursor::new(Point::new(Line(-11), Column(0)));
+
+ // Scrollable amount to bottom is 11.
+ term.scroll_display(Scroll::PageDown);
+ assert_eq!(term.vi_mode_cursor.point, Point::new(Line(-1), Column(0)));
+ assert_eq!(term.grid.display_offset(), 1);
+
+ // Scrollable amount to bottom is 1.
+ term.scroll_display(Scroll::PageDown);
+ assert_eq!(term.vi_mode_cursor.point, Point::new(Line(0), Column(0)));
+ assert_eq!(term.grid.display_offset(), 0);
+
+ // Scrollable amount to bottom is 0.
+ term.scroll_display(Scroll::PageDown);
+ assert_eq!(term.vi_mode_cursor.point, Point::new(Line(0), Column(0)));
+ assert_eq!(term.grid.display_offset(), 0);
+ }
+
+ #[test]
fn semantic_selection_works() {
let size = SizeInfo::new(5., 3., 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&MockConfig::default(), size, ());
diff --git a/alacritty_terminal/src/term/search.rs b/alacritty_terminal/src/term/search.rs
index bf7f43d1..ff6060af 100644
--- a/alacritty_terminal/src/term/search.rs
+++ b/alacritty_terminal/src/term/search.rs
@@ -88,14 +88,14 @@ impl<T> Term<T> {
_ => end.sub(self, Boundary::None, 1),
};
- let mut regex_iter = RegexIter::new(start, end, Direction::Right, &self, dfas).peekable();
+ let mut regex_iter = RegexIter::new(start, end, Direction::Right, self, dfas).peekable();
// Check if there's any match at all.
let first_match = regex_iter.peek()?.clone();
let regex_match = regex_iter
.find(|regex_match| {
- let match_point = Self::match_side(&regex_match, side);
+ let match_point = Self::match_side(regex_match, side);
// If the match's point is beyond the origin, we're done.
match_point.line < start.line
@@ -127,14 +127,14 @@ impl<T> Term<T> {
_ => end.add(self, Boundary::None, 1),
};
- let mut regex_iter = RegexIter::new(start, end, Direction::Left, &self, dfas).peekable();
+ let mut regex_iter = RegexIter::new(start, end, Direction::Left, self, dfas).peekable();
// Check if there's any match at all.
let first_match = regex_iter.peek()?.clone();
let regex_match = regex_iter
.find(|regex_match| {
- let match_point = Self::match_side(&regex_match, side);
+ let match_point = Self::match_side(regex_match, side);
// If the match's point is beyond the origin, we're done.
match_point.line > start.line
diff --git a/alacritty_terminal/src/tty/unix.rs b/alacritty_terminal/src/tty/unix.rs
index ba59bb66..a3c35f95 100644
--- a/alacritty_terminal/src/tty/unix.rs
+++ b/alacritty_terminal/src/tty/unix.rs
@@ -82,10 +82,6 @@ fn set_controlling_terminal(fd: c_int) {
#[derive(Debug)]
struct Passwd<'a> {
name: &'a str,
- passwd: &'a str,
- uid: libc::uid_t,
- gid: libc::gid_t,
- gecos: &'a str,
dir: &'a str,
shell: &'a str,
}
@@ -122,10 +118,6 @@ fn get_pw_entry(buf: &mut [i8; 1024]) -> Passwd<'_> {
// Build a borrowed Passwd struct.
Passwd {
name: unsafe { CStr::from_ptr(entry.pw_name).to_str().unwrap() },
- passwd: unsafe { CStr::from_ptr(entry.pw_passwd).to_str().unwrap() },
- uid: entry.pw_uid,
- gid: entry.pw_gid,
- gecos: unsafe { CStr::from_ptr(entry.pw_gecos).to_str().unwrap() },
dir: unsafe { CStr::from_ptr(entry.pw_dir).to_str().unwrap() },
shell: unsafe { CStr::from_ptr(entry.pw_shell).to_str().unwrap() },
}
diff --git a/alacritty_terminal/src/vi_mode.rs b/alacritty_terminal/src/vi_mode.rs
index 6f370642..5bf5eaed 100644
--- a/alacritty_terminal/src/vi_mode.rs
+++ b/alacritty_terminal/src/vi_mode.rs
@@ -1,4 +1,4 @@
-use std::cmp::{max, min};
+use std::cmp::min;
use alacritty_config_derive::ConfigDeserialize;
@@ -160,21 +160,11 @@ impl ViModeCursor {
/// Get target cursor point for vim-like page movement.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn scroll<T: EventListener>(mut self, term: &Term<T>, lines: i32) -> Self {
- // Check number of lines the cursor needs to be moved.
- let overscroll = if lines > 0 {
- let max_scroll = term.history_size() - term.grid().display_offset();
- max(0, lines - max_scroll as i32)
- } else {
- let max_scroll = term.grid().display_offset();
- min(0, lines + max_scroll as i32)
- };
-
// Clamp movement to within visible region.
- let line = (self.point.line - overscroll).grid_clamp(term, Boundary::Grid);
+ let line = (self.point.line - lines).grid_clamp(term, Boundary::Grid);
// Find the first occupied cell after scrolling has been performed.
- let target_line = (self.point.line - lines).grid_clamp(term, Boundary::Grid);
- let column = first_occupied_in_line(term, target_line).unwrap_or_default().column;
+ let column = first_occupied_in_line(term, line).unwrap_or_default().column;
// Move cursor.
self.point = Point::new(line, column);
@@ -388,6 +378,7 @@ fn is_boundary<T>(term: &Term<T>, point: Point, direction: Direction) -> bool {
mod tests {
use super::*;
+ use crate::ansi::Handler;
use crate::config::MockConfig;
use crate::index::{Column, Line};
use crate::term::{SizeInfo, Term};
@@ -756,4 +747,73 @@ mod tests {
cursor = cursor.motion(&mut term, ViMotion::WordLeft);
assert_eq!(cursor.point, Point::new(Line(0), Column(0)));
}
+
+ #[test]
+ fn scroll_simple() {
+ let mut term = term();
+
+ // Create 1 line of scrollback.
+ for _ in 0..20 {
+ term.newline();
+ }
+
+ let mut cursor = ViModeCursor::new(Point::new(Line(0), Column(0)));
+
+ cursor = cursor.scroll(&term, -1);
+ assert_eq!(cursor.point, Point::new(Line(1), Column(0)));
+
+ cursor = cursor.scroll(&term, 1);
+ assert_eq!(cursor.point, Point::new(Line(0), Column(0)));
+
+ cursor = cursor.scroll(&term, 1);
+ assert_eq!(cursor.point, Point::new(Line(-1), Column(0)));
+ }
+
+ #[test]
+ fn scroll_over_top() {
+ let mut term = term();
+
+ // Create 40 lines of scrollback.
+ for _ in 0..59 {
+ term.newline();
+ }
+
+ let mut cursor = ViModeCursor::new(Point::new(Line(19), Column(0)));
+
+ cursor = cursor.scroll(&term, 20);
+ assert_eq!(cursor.point, Point::new(Line(-1), Column(0)));
+
+ cursor = cursor.scroll(&term, 20);
+ assert_eq!(cursor.point, Point::new(Line(-21), Column(0)));
+
+ cursor = cursor.scroll(&term, 20);
+ assert_eq!(cursor.point, Point::new(Line(-40), Column(0)));
+
+ cursor = cursor.scroll(&term, 20);
+ assert_eq!(cursor.point, Point::new(Line(-40), Column(0)));
+ }
+
+ #[test]
+ fn scroll_over_bottom() {
+ let mut term = term();
+
+ // Create 40 lines of scrollback.
+ for _ in 0..59 {
+ term.newline();
+ }
+
+ let mut cursor = ViModeCursor::new(Point::new(Line(-40), Column(0)));
+
+ cursor = cursor.scroll(&term, -20);
+ assert_eq!(cursor.point, Point::new(Line(-20), Column(0)));
+
+ cursor = cursor.scroll(&term, -20);
+ assert_eq!(cursor.point, Point::new(Line(0), Column(0)));
+
+ cursor = cursor.scroll(&term, -20);
+ assert_eq!(cursor.point, Point::new(Line(19), Column(0)));
+
+ cursor = cursor.scroll(&term, -20);
+ assert_eq!(cursor.point, Point::new(Line(19), Column(0)));
+ }
}
diff --git a/extra/alacritty.info b/extra/alacritty.info
index eaa73f07..29171438 100644
--- a/extra/alacritty.info
+++ b/extra/alacritty.info
@@ -27,7 +27,7 @@ alacritty+common|base fragment for alacritty,
OTbs, am, bce, km, mir, msgr, xenl, AX, XT,
colors#8, cols#80, it#8, lines#24, pairs#64,
acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
- bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, civis=\E[?25l,
+ bel=^G, bold=\E[1m, cbt=\E[Z, civis=\E[?25l,
clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, cr=\r,
csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H,
cud=\E[%p1%dB, cud1=\n, cuf=\E[%p1%dC, cuf1=\E[C,
diff --git a/extra/alacritty.man b/extra/alacritty.man
index 48b05de9..fbc28c25 100644
--- a/extra/alacritty.man
+++ b/extra/alacritty.man
@@ -1,4 +1,4 @@
-.TH ALACRITTY "1" "August 2018" "alacritty 0.8.0-dev" "User Commands"
+.TH ALACRITTY "1" "August 2018" "alacritty 0.10.0-dev" "User Commands"
.SH NAME
Alacritty \- A fast, cross-platform, OpenGL terminal emulator
.SH "SYNOPSIS"
diff --git a/extra/linux/io.alacritty.Alacritty.appdata.xml b/extra/linux/io.alacritty.Alacritty.appdata.xml
index d9f5e1f2..af82c474 100644
--- a/extra/linux/io.alacritty.Alacritty.appdata.xml
+++ b/extra/linux/io.alacritty.Alacritty.appdata.xml
@@ -28,9 +28,6 @@
</keywords>
<url type="homepage">https://github.com/alacritty/alacritty</url>
<url type="bugtracker">https://github.com/alacritty/alacritty/issues</url>
- <releases>
- <release version="0.7.0-dev" date="2019-06-16" unix_timestamp="1560694196"/>
- </releases>
<update_contact>https://github.com/alacritty/alacritty/blob/master/CONTRIBUTING.md#contact</update_contact>
<developer_name>Christian Duerr</developer_name>
</component>
diff --git a/extra/osx/Alacritty.app/Contents/Info.plist b/extra/osx/Alacritty.app/Contents/Info.plist
index 8c88e53b..4a7460f1 100644
--- a/extra/osx/Alacritty.app/Contents/Info.plist
+++ b/extra/osx/Alacritty.app/Contents/Info.plist
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>0.8.0-dev</string>
+ <string>0.10.0-dev</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
diff --git a/extra/windows b/extra/windows
new file mode 120000
index 00000000..1c83ac5e
--- /dev/null
+++ b/extra/windows
@@ -0,0 +1 @@
+../alacritty/windows \ No newline at end of file