1
0
Fork 0
mirror of https://github.com/alacritty/alacritty.git synced 2024-11-18 13:55:23 -05:00

Dynamically resize terminal for errors/warnings

The warning and error messages now don't overwrite other terminal
content anymore but instead resize the terminal to make sure that text
can always be read.

Instead of just showing that there is a new error and pointing to the log,
errors will now be displayed fully in multiple lines of text, assuming that
there is enough space left in the terminal.

Explicit mouse click handling has also been added to the message bar,
which made it possible to add a simple `close` button in the form of
`[X]`.

Alacritty's log file location is now stored in the `$ALACRITTY_LOG`
environment variable which the shell inherits automatically.

Previously there were some issues with the log file only being deleted
when certain methods for closing Alacritty were used (like typing
`exit`). This has been reworked and now Ctrl+D, exit and signals should
all work properly.

Before the config is reloaded, all current messages are now dropped.
This should help with multiple terminals all getting clogged up at the
same time when the config is broken.

When one message is removed, all other duplicate messages are
automatically removed too.
This commit is contained in:
Christian Duerr 2019-02-07 22:36:45 +00:00 committed by GitHub
parent e561ae3733
commit 35efb4619c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 1054 additions and 478 deletions

View file

@ -9,11 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Window class on Wayland is set to `Alacritty` by default - Window class on Wayland is set to `Alacritty` by default
- Log file location is stored in the `ALACRITTY_LOG` environment variable
- Close button has been added to the error/warning messages
### Changed ### Changed
- Improve scrolling accuracy with devices sending fractional updates (like touchpads) - Improve scrolling accuracy with devices sending fractional updates (like touchpads)
- `scrolling.multiplier` now affects normal scrolling with touchpads - `scrolling.multiplier` now affects normal scrolling with touchpads
- Error/Warning bar doesn't overwrite the terminal anymore
- Full error/warning messages are displayed
- Config error messages are automatically removed when the config is fixed
### Fixed ### Fixed
@ -25,6 +30,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Corrected the `window.decorations` config documentation for macOS - Corrected the `window.decorations` config documentation for macOS
- Fix IME position on HiDPI displays - Fix IME position on HiDPI displays
- URLs not opening while terminal is scrolled - URLs not opening while terminal is scrolled
- Reliably remove log file when Alacritty is closed and persistent logging is disabled
### Removed
- `clear` doesn't remove error/warning messages anymore
## Version 0.2.7 ## Version 0.2.7

63
Cargo.lock generated
View file

@ -39,6 +39,7 @@ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"copypasta 0.0.1", "copypasta 0.0.1",
"crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"dunce 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "dunce 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"embed-resource 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "embed-resource 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -56,7 +57,7 @@ dependencies = [
"mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"notify 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "notify 4.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -65,7 +66,7 @@ dependencies = [
"serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)",
"static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"terminfo 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "terminfo 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -168,7 +169,7 @@ name = "backtrace-sys"
version = "0.1.28" version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -250,13 +251,13 @@ name = "bzip2-sys"
version = "0.1.7" version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.28" version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -341,7 +342,7 @@ name = "cmake"
version = "0.1.35" version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -809,7 +810,7 @@ dependencies = [
[[package]] [[package]]
name = "fuchsia-cprng" name = "fuchsia-cprng"
version = "0.1.0" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -970,7 +971,7 @@ dependencies = [
"tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-timer 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1032,12 +1033,8 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1115,7 +1112,7 @@ name = "libloading"
version = "0.5.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1124,7 +1121,7 @@ name = "libz-sys"
version = "1.0.25" version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1322,7 +1319,7 @@ dependencies = [
"schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"security-framework 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"security-framework-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1341,7 +1338,7 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1371,7 +1368,7 @@ dependencies = [
[[package]] [[package]]
name = "notify" name = "notify"
version = "4.0.7" version = "4.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1493,7 +1490,7 @@ name = "openssl-sys"
version = "0.9.40" version = "0.9.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1650,7 +1647,7 @@ name = "rand"
version = "0.4.6" version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1668,7 +1665,7 @@ dependencies = [
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1715,7 +1712,7 @@ dependencies = [
[[package]] [[package]]
name = "rand_jitter" name = "rand_jitter"
version = "0.1.2" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1729,7 +1726,7 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1878,7 +1875,7 @@ dependencies = [
"tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-timer 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -2167,7 +2164,7 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.0.5" version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2258,7 +2255,7 @@ dependencies = [
"tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-timer 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -2338,7 +2335,7 @@ dependencies = [
[[package]] [[package]]
name = "tokio-timer" name = "tokio-timer"
version = "0.2.9" version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2650,7 +2647,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bindgen 0.33.2 (registry+https://github.com/rust-lang/crates.io-index)", "bindgen 0.33.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -2756,7 +2753,7 @@ dependencies = [
"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
"checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" "checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
"checksum bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6584aa36f5ad4c9247f5323b0a42f37802b37a836f0ad87084d7a33961abe25f" "checksum bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6584aa36f5ad4c9247f5323b0a42f37802b37a836f0ad87084d7a33961abe25f"
"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" "checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e"
"checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c" "checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c"
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
"checksum cgl 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "55e7ec0b74fe5897894cbc207092c577e87c52f8a59e8ca8d97ef37551f60a49" "checksum cgl 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "55e7ec0b74fe5897894cbc207092c577e87c52f8a59e8ca8d97ef37551f60a49"
@ -2814,7 +2811,7 @@ dependencies = [
"checksum freetype-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9c8666cce7cf6e51a290623647febfbab92480b4c3e0f495cb9d4d312b5d38" "checksum freetype-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9c8666cce7cf6e51a290623647febfbab92480b4c3e0f495cb9d4d312b5d38"
"checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05" "checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05"
"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874" "checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874"
"checksum fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81f7f8eb465745ea9b02e2704612a9946a59fa40572086c6fd49d6ddcf30bf31" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b"
@ -2875,7 +2872,7 @@ dependencies = [
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" "checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"
"checksum nom 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b30adc557058ce00c9d0d7cb3c6e0b5bc6f36e2e2eabe74b0ba726d194abd588" "checksum nom 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b30adc557058ce00c9d0d7cb3c6e0b5bc6f36e2e2eabe74b0ba726d194abd588"
"checksum notify 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c968cf37cf949114b00d51b0b23536d1c3a4a3963767cf4c969c65a6af78dc7d" "checksum notify 4.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c9b605e417814e88bb051c88a84f83655d6ad4fa32fc36d9a96296d86087692d"
"checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d" "checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d"
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
@ -2915,7 +2912,7 @@ dependencies = [
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
"checksum rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "080723c6145e37503a2224f801f252e14ac5531cb450f4502698542d188cb3c0" "checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832"
"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" "checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d"
"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" "checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
@ -2965,7 +2962,7 @@ dependencies = [
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
"checksum tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2" "checksum tempfile 3.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "37daa55a7240c4931c84559f03b3cad7d19535840d1c4a0cc4e9b2fb0dcf70ff"
"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
"checksum terminfo 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8e51065bafd2abe106b6036483b69d1741f4a1ec56ce8a2378de341637de689e" "checksum terminfo 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8e51065bafd2abe106b6036483b69d1741f4a1ec56ce8a2378de341637de689e"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
@ -2980,7 +2977,7 @@ dependencies = [
"checksum tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f" "checksum tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f"
"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" "checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119"
"checksum tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c3fd86cb15547d02daa2b21aadaf4e37dee3368df38a526178a5afa3c034d2fb" "checksum tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c3fd86cb15547d02daa2b21aadaf4e37dee3368df38a526178a5afa3c034d2fb"
"checksum tokio-timer 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "21c04a314a1f69f73c0227beba6250e06cdc1e9a62e7eff912bf54a59b6d1b94" "checksum tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2910970404ba6fa78c5539126a9ae2045d62e3713041e447f695f41405a120c6"
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"

View file

@ -49,6 +49,7 @@ static_assertions = "0.3.0"
terminfo = "0.6.1" terminfo = "0.6.1"
url = "1.7.1" url = "1.7.1"
time = "0.1.40" time = "0.1.40"
crossbeam-channel = "0.3.8"
[target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd"))'.dependencies] [target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd"))'.dependencies]
x11-dl = "2" x11-dl = "2"

View file

@ -21,7 +21,8 @@ use vte;
use base64; use base64;
use crate::index::{Column, Line, Contains}; use crate::index::{Column, Line, Contains};
use crate::{MouseCursor, Rgb}; use crate::MouseCursor;
use crate::term::color::Rgb;
// Parse color arguments // Parse color arguments
// //
@ -1395,7 +1396,7 @@ mod tests {
use std::io; use std::io;
use crate::index::{Line, Column}; use crate::index::{Line, Column};
use super::{Processor, Handler, Attr, TermInfo, Color, StandardCharset, CharsetIndex, parse_rgb_color, parse_number}; use super::{Processor, Handler, Attr, TermInfo, Color, StandardCharset, CharsetIndex, parse_rgb_color, parse_number};
use crate::Rgb; use crate::term::color::Rgb;
/// The /dev/null of `io::Write` /// The /dev/null of `io::Write`
struct Void; struct Void;

View file

@ -5,7 +5,7 @@
//! the config file will also hold user and platform specific keybindings. //! the config file will also hold user and platform specific keybindings.
use std::borrow::Cow; use std::borrow::Cow;
use std::{env, fmt}; use std::{env, fmt};
use std::fs::{self, File}; use std::fs::File;
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
@ -13,7 +13,6 @@ use std::sync::mpsc;
use std::time::Duration; use std::time::Duration;
use std::collections::HashMap; use std::collections::HashMap;
use crate::Rgb;
use font::Size; use font::Size;
use serde_yaml; use serde_yaml;
use serde::{self, de, Deserialize}; use serde::{self, de, Deserialize};
@ -26,9 +25,11 @@ use crate::cli::Options;
use crate::input::{Action, Binding, MouseBinding, KeyBinding}; use crate::input::{Action, Binding, MouseBinding, KeyBinding};
use crate::index::{Line, Column}; use crate::index::{Line, Column};
use crate::ansi::{CursorStyle, NamedColor, Color}; use crate::ansi::{CursorStyle, NamedColor, Color};
use crate::term::color::Rgb;
mod bindings; mod bindings;
pub const SOURCE_FILE_PATH: &str = file!();
const MAX_SCROLLBACK_LINES: u32 = 100_000; const MAX_SCROLLBACK_LINES: u32 = 100_000;
static DEFAULT_ALACRITTY_CONFIG: &'static str = static DEFAULT_ALACRITTY_CONFIG: &'static str =
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty.yml")); include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty.yml"));
@ -1691,7 +1692,7 @@ impl Config {
path = path.join("alacritty/alacritty.yml"); path = path.join("alacritty/alacritty.yml");
fs::create_dir_all(path.parent().unwrap())?; std::fs::create_dir_all(path.parent().unwrap())?;
File::create(&path)?.write_all(DEFAULT_ALACRITTY_CONFIG.as_bytes())?; File::create(&path)?.write_all(DEFAULT_ALACRITTY_CONFIG.as_bytes())?;
@ -1868,16 +1869,6 @@ impl Config {
self.persistent_logging self.persistent_logging
} }
pub fn load_from<P: Into<PathBuf>>(path: P) -> Result<Config> {
let path = path.into();
let raw = Config::read_file(path.as_path())?;
let mut config: Config = serde_yaml::from_str(&raw)?;
config.config_path = Some(path);
config.print_deprecation_warnings();
Ok(config)
}
/// Overrides the `dynamic_title` configuration based on `--title`. /// Overrides the `dynamic_title` configuration based on `--title`.
pub fn update_dynamic_title(mut self, options: &Options) -> Self { pub fn update_dynamic_title(mut self, options: &Options) -> Self {
if options.title.is_some() { if options.title.is_some() {
@ -1886,15 +1877,35 @@ impl Config {
self self
} }
fn read_file<P: AsRef<Path>>(path: P) -> Result<String> { pub fn load_from(path: PathBuf) -> Config {
let mut f = fs::File::open(path)?; let mut config = Config::reload_from(&path).unwrap_or_else(|_| Config::default());
config.config_path = Some(path);
config
}
pub fn reload_from(path: &PathBuf) -> Result<Config> {
match Config::read_config(path) {
Ok(config) => Ok(config),
Err(err) => {
error!("Unable to load config {:?}: {}", path, err);
Err(err)
}
}
}
fn read_config(path: &PathBuf) -> Result<Config> {
let mut contents = String::new(); let mut contents = String::new();
f.read_to_string(&mut contents)?; File::open(path)?.read_to_string(&mut contents)?;
// Prevent parsing error with empty string
if contents.is_empty() { if contents.is_empty() {
return Err(Error::Empty); return Ok(Config::default());
} }
Ok(contents) let mut config: Config = serde_yaml::from_str(&contents)?;
config.print_deprecation_warnings();
Ok(config)
} }
fn print_deprecation_warnings(&mut self) { fn print_deprecation_warnings(&mut self) {
@ -2201,7 +2212,7 @@ impl SecondaryFontDescription {
pub struct Monitor { pub struct Monitor {
_thread: ::std::thread::JoinHandle<()>, _thread: ::std::thread::JoinHandle<()>,
rx: mpsc::Receiver<Config>, rx: mpsc::Receiver<PathBuf>,
} }
pub trait OnConfigReload { pub trait OnConfigReload {
@ -2216,7 +2227,7 @@ impl OnConfigReload for crate::display::Notifier {
impl Monitor { impl Monitor {
/// Get pending config changes /// Get pending config changes
pub fn pending_config(&self) -> Option<Config> { pub fn pending(&self) -> Option<PathBuf> {
let mut config = None; let mut config = None;
while let Ok(new) = self.rx.try_recv() { while let Ok(new) = self.rx.try_recv() {
config = Some(new); config = Some(new);
@ -2224,6 +2235,7 @@ impl Monitor {
config config
} }
pub fn new<H, P>(path: P, mut handler: H) -> Monitor pub fn new<H, P>(path: P, mut handler: H) -> Monitor
where H: OnConfigReload + Send + 'static, where H: OnConfigReload + Send + 'static,
P: Into<PathBuf> P: Into<PathBuf>
@ -2260,22 +2272,7 @@ impl Monitor {
continue; continue;
} }
let config = match Config::load_from(&path) { let _ = config_tx.send(path);
Ok(config) => {
config
},
Err(err) => {
if let Error::Empty = err {
info!("Config file {:?} is empty; loading default", path);
Config::default()
} else {
error!("Ignoring invalid config: {}", err);
continue;
}
}
};
let _ = config_tx.send(config);
handler.on_config_reload(); handler.on_config_reload();
} }
_ => {} _ => {}

View file

@ -25,12 +25,13 @@ use crate::config::Config;
use font::{self, Rasterize}; use font::{self, Rasterize};
use crate::meter::Meter; use crate::meter::Meter;
use crate::renderer::{self, GlyphCache, QuadRenderer}; use crate::renderer::{self, GlyphCache, QuadRenderer};
use crate::renderer::lines::Lines; use crate::renderer::rects::{Rects, Rect};
use crate::term::{Term, SizeInfo, RenderableCell}; use crate::term::{Term, SizeInfo, RenderableCell};
use crate::sync::FairMutex; use crate::sync::FairMutex;
use crate::window::{self, Window}; use crate::window::{self, Window};
use crate::logging::LoggerProxy; use crate::term::color::Rgb;
use crate::Rgb; use crate::index::Line;
use crate::message_bar::Message;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -101,7 +102,7 @@ pub struct Display {
meter: Meter, meter: Meter,
font_size: font::Size, font_size: font::Size,
size_info: SizeInfo, size_info: SizeInfo,
logger_proxy: LoggerProxy, last_message: Option<Message>,
} }
/// Can wakeup the render loop from other threads /// Can wakeup the render loop from other threads
@ -132,11 +133,7 @@ impl Display {
&self.size_info &self.size_info
} }
pub fn new( pub fn new(config: &Config, options: &cli::Options) -> Result<Display, Error> {
config: &Config,
options: &cli::Options,
logger_proxy: LoggerProxy
) -> Result<Display, Error> {
// Extract some properties from config // Extract some properties from config
let render_timer = config.render_timer(); let render_timer = config.render_timer();
@ -229,7 +226,7 @@ impl Display {
meter: Meter::new(), meter: Meter::new(),
font_size: font::Size::new(0.), font_size: font::Size::new(0.),
size_info, size_info,
logger_proxy, last_message: None,
}) })
} }
@ -297,7 +294,8 @@ impl Display {
&mut self, &mut self,
terminal: &mut MutexGuard<'_, Term>, terminal: &mut MutexGuard<'_, Term>,
config: &Config, config: &Config,
items: &mut [&mut dyn OnResize], pty_resize_handle: &mut dyn OnResize,
processor_resize_handle: &mut dyn OnResize,
) { ) {
// Resize events new_size and are handled outside the poll_events // Resize events new_size and are handled outside the poll_events
// iterator. This has the effect of coalescing multiple resize // iterator. This has the effect of coalescing multiple resize
@ -313,7 +311,10 @@ impl Display {
let dpr = self.window.hidpi_factor(); let dpr = self.window.hidpi_factor();
// Font size/DPI factor modification detected // Font size/DPI factor modification detected
if terminal.font_size != self.font_size || (dpr - self.size_info.dpr).abs() > f64::EPSILON { let font_changed = terminal.font_size != self.font_size
|| (dpr - self.size_info.dpr).abs() > f64::EPSILON;
if font_changed || self.last_message != terminal.message_buffer_mut().message() {
if new_size == None { if new_size == None {
// Force a resize to refresh things // Force a resize to refresh things
new_size = Some(PhysicalSize::new( new_size = Some(PhysicalSize::new(
@ -323,8 +324,11 @@ impl Display {
} }
self.font_size = terminal.font_size; self.font_size = terminal.font_size;
self.last_message = terminal.message_buffer_mut().message();
self.size_info.dpr = dpr; self.size_info.dpr = dpr;
}
if font_changed {
self.update_glyph_cache(config); self.update_glyph_cache(config);
} }
@ -350,10 +354,14 @@ impl Display {
let size = &self.size_info; let size = &self.size_info;
terminal.resize(size); terminal.resize(size);
processor_resize_handle.on_resize(size);
for item in items { // Subtract message bar lines for pty size
item.on_resize(size) let mut pty_size = *size;
if let Some(message) = terminal.message_buffer_mut().message() {
pty_size.height -= pty_size.cell_height * message.text(&size).len() as f32;
} }
pty_resize_handle.on_resize(&pty_size);
self.window.resize(psize); self.window.resize(psize);
self.renderer.resize(psize, self.size_info.padding_x, self.size_info.padding_y); self.renderer.resize(psize, self.size_info.padding_x, self.size_info.padding_y);
@ -376,6 +384,9 @@ impl Display {
.renderable_cells(config, window_focused) .renderable_cells(config, window_focused)
.collect(); .collect();
// Get message from terminal to ignore modifications after lock is dropped
let message_buffer = terminal.message_buffer_mut().message();
// Clear dirty flag // Clear dirty flag
terminal.dirty = !terminal.visual_bell.completed(); terminal.dirty = !terminal.visual_bell.completed();
@ -413,7 +424,7 @@ impl Display {
{ {
let glyph_cache = &mut self.glyph_cache; let glyph_cache = &mut self.glyph_cache;
let metrics = glyph_cache.font_metrics(); let metrics = glyph_cache.font_metrics();
let mut cell_line_rects = Lines::new(&metrics, &size_info); let mut rects = Rects::new(&metrics, &size_info);
// Draw grid // Draw grid
{ {
@ -423,7 +434,7 @@ impl Display {
// Iterate over all non-empty cells in the grid // Iterate over all non-empty cells in the grid
for cell in grid_cells { for cell in grid_cells {
// Update underline/strikeout // Update underline/strikeout
cell_line_rects.update_lines(&cell); rects.update_lines(&cell);
// Draw the cell // Draw the cell
api.render_cell(cell, glyph_cache); api.render_cell(cell, glyph_cache);
@ -431,8 +442,35 @@ impl Display {
}); });
} }
// Draw rectangles if let Some(message) = message_buffer {
self.renderer.draw_rects(config, &size_info, visual_bell_intensity, cell_line_rects); let text = message.text(&size_info);
// Create a new rectangle for the background
let start_line = size_info.lines().0 - text.len();
let y = size_info.padding_y + size_info.cell_height * start_line as f32;
let rect = Rect::new(0., y, size_info.width, size_info.height - y);
rects.push(rect, message.color());
// Draw rectangles including the new background
self.renderer.draw_rects(config, &size_info, visual_bell_intensity, rects);
// Relay messages to the user
let mut offset = 1;
for message_text in text.iter().rev() {
self.renderer.with_api(config, &size_info, |mut api| {
api.render_string(
&message_text,
Line(size_info.lines().saturating_sub(offset)),
glyph_cache,
None,
);
});
offset += 1;
}
} else {
// Draw rectangles
self.renderer.draw_rects(config, &size_info, visual_bell_intensity, rects);
}
// Draw render timer // Draw render timer
if self.render_timer { if self.render_timer {
@ -443,36 +481,7 @@ impl Display {
b: 0x53, b: 0x53,
}; };
self.renderer.with_api(config, &size_info, |mut api| { self.renderer.with_api(config, &size_info, |mut api| {
api.render_string(&timing[..], size_info.lines() - 2, glyph_cache, color); api.render_string(&timing[..], size_info.lines() - 2, glyph_cache, Some(color));
});
}
// Display errors and warnings
if self.logger_proxy.errors() {
let msg = match self.logger_proxy.log_path() {
Some(path) => format!(" ERROR! See log at {} ", path),
None => " ERROR! See log in stderr ".into(),
};
let color = Rgb {
r: 0xff,
g: 0x00,
b: 0x00,
};
self.renderer.with_api(config, &size_info, |mut api| {
api.render_string(&msg, size_info.lines() - 1, glyph_cache, color);
});
} else if self.logger_proxy.warnings() {
let msg = match self.logger_proxy.log_path() {
Some(path) => format!(" WARNING! See log at {} ", path),
None => " WARNING! See log in stderr ".into(),
};
let color = Rgb {
r: 0xff,
g: 0xff,
b: 0x00,
};
self.renderer.with_api(config, &size_info, |mut api| {
api.render_string(&msg, size_info.lines() - 1, glyph_cache, color);
}); });
} }
} }

View file

@ -16,7 +16,6 @@ use glutin::dpi::PhysicalSize;
#[cfg(unix)] #[cfg(unix)]
use crate::tty; use crate::tty;
use crate::ansi::{Handler, ClearMode};
use crate::grid::Scroll; use crate::grid::Scroll;
use crate::config::{self, Config}; use crate::config::{self, Config};
use crate::cli::Options; use crate::cli::Options;
@ -25,7 +24,7 @@ use crate::index::{Line, Column, Side, Point};
use crate::input::{self, MouseBinding, KeyBinding}; use crate::input::{self, MouseBinding, KeyBinding};
use crate::selection::Selection; use crate::selection::Selection;
use crate::sync::FairMutex; use crate::sync::FairMutex;
use crate::term::{Term, SizeInfo, TermMode, Search}; use crate::term::{Term, SizeInfo};
use crate::term::cell::Cell; use crate::term::cell::Cell;
use crate::util::{limit, start_daemon}; use crate::util::{limit, start_daemon};
use crate::util::fmt::Red; use crate::util::fmt::Red;
@ -55,10 +54,6 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
self.notifier.notify(val); self.notifier.notify(val);
} }
fn terminal_mode(&self) -> TermMode {
*self.terminal.mode()
}
fn size_info(&self) -> SizeInfo { fn size_info(&self) -> SizeInfo {
*self.size_info *self.size_info
} }
@ -78,10 +73,6 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
} }
} }
fn clear_history(&mut self) {
self.terminal.clear_screen(ClearMode::Saved);
}
fn copy_selection(&self, buffer: ClipboardBuffer) { fn copy_selection(&self, buffer: ClipboardBuffer) {
if let Some(selected) = self.terminal.selection_to_string() { if let Some(selected) = self.terminal.selection_to_string() {
if !selected.is_empty() { if !selected.is_empty() {
@ -126,10 +117,6 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
self.terminal.dirty = true; self.terminal.dirty = true;
} }
fn url(&self, point: Point<usize>) -> Option<String> {
self.terminal.url_search(point)
}
fn line_selection(&mut self, point: Point) { fn line_selection(&mut self, point: Point) {
let point = self.terminal.visible_to_buffer(point); let point = self.terminal.visible_to_buffer(point);
*self.terminal.selection_mut() = Some(Selection::lines(point)); *self.terminal.selection_mut() = Some(Selection::lines(point));
@ -140,14 +127,6 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
self.terminal.pixels_to_coords(self.mouse.x as usize, self.mouse.y as usize) self.terminal.pixels_to_coords(self.mouse.x as usize, self.mouse.y as usize)
} }
fn change_font_size(&mut self, delta: f32) {
self.terminal.change_font_size(delta);
}
fn reset_font_size(&mut self) {
self.terminal.reset_font_size();
}
#[inline] #[inline]
fn mouse_mut(&mut self) -> &mut Mouse { fn mouse_mut(&mut self) -> &mut Mouse {
self.mouse self.mouse
@ -179,8 +158,13 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
} }
#[inline] #[inline]
fn clear_log(&mut self) { fn terminal(&self) -> &Term {
self.terminal.clear_log(); self.terminal
}
#[inline]
fn terminal_mut(&mut self) -> &mut Term {
self.terminal
} }
fn spawn_new_instance(&mut self) { fn spawn_new_instance(&mut self) {
@ -393,8 +377,7 @@ impl<N: Notify> Processor<N> {
.expect("write config.json"); .expect("write config.json");
} }
// FIXME should do a more graceful shutdown processor.ctx.terminal.exit();
::std::process::exit(0);
}, },
Resized(lsize) => { Resized(lsize) => {
// Resize events are emitted via glutin/winit with logical sizes // Resize events are emitted via glutin/winit with logical sizes

View file

@ -29,10 +29,12 @@ use crate::config::{self, Key};
use crate::grid::Scroll; use crate::grid::Scroll;
use crate::event::{ClickState, Mouse}; use crate::event::{ClickState, Mouse};
use crate::index::{Line, Column, Side, Point}; use crate::index::{Line, Column, Side, Point};
use crate::term::SizeInfo; use crate::term::{Term, SizeInfo, Search};
use crate::term::mode::TermMode; use crate::term::mode::TermMode;
use crate::util::fmt::Red; use crate::util::fmt::Red;
use crate::util::start_daemon; use crate::util::start_daemon;
use crate::message_bar;
use crate::ansi::{Handler, ClearMode};
pub const FONT_SIZE_STEP: f32 = 0.5; pub const FONT_SIZE_STEP: f32 = 0.5;
@ -54,7 +56,6 @@ pub struct Processor<'a, A: 'a> {
pub trait ActionContext { pub trait ActionContext {
fn write_to_pty<B: Into<Cow<'static, [u8]>>>(&mut self, _: B); fn write_to_pty<B: Into<Cow<'static, [u8]>>>(&mut self, _: B);
fn terminal_mode(&self) -> TermMode;
fn size_info(&self) -> SizeInfo; fn size_info(&self) -> SizeInfo;
fn copy_selection(&self, _: ClipboardBuffer); fn copy_selection(&self, _: ClipboardBuffer);
fn clear_selection(&mut self); fn clear_selection(&mut self);
@ -69,13 +70,10 @@ pub trait ActionContext {
fn received_count(&mut self) -> &mut usize; fn received_count(&mut self) -> &mut usize;
fn suppress_chars(&mut self) -> &mut bool; fn suppress_chars(&mut self) -> &mut bool;
fn last_modifiers(&mut self) -> &mut ModifiersState; fn last_modifiers(&mut self) -> &mut ModifiersState;
fn change_font_size(&mut self, delta: f32);
fn reset_font_size(&mut self);
fn scroll(&mut self, scroll: Scroll); fn scroll(&mut self, scroll: Scroll);
fn clear_history(&mut self);
fn hide_window(&mut self); fn hide_window(&mut self);
fn url(&self, _: Point<usize>) -> Option<String>; fn terminal(&self) -> &Term;
fn clear_log(&mut self); fn terminal_mut(&mut self) -> &mut Term;
fn spawn_new_instance(&mut self); fn spawn_new_instance(&mut self);
} }
@ -296,17 +294,16 @@ impl Action {
ctx.hide_window(); ctx.hide_window();
}, },
Action::Quit => { Action::Quit => {
// FIXME should do a more graceful shutdown ctx.terminal_mut().exit();
::std::process::exit(0);
}, },
Action::IncreaseFontSize => { Action::IncreaseFontSize => {
ctx.change_font_size(FONT_SIZE_STEP); ctx.terminal_mut().change_font_size(FONT_SIZE_STEP);
}, },
Action::DecreaseFontSize => { Action::DecreaseFontSize => {
ctx.change_font_size(-FONT_SIZE_STEP); ctx.terminal_mut().change_font_size(-FONT_SIZE_STEP);
} }
Action::ResetFontSize => { Action::ResetFontSize => {
ctx.reset_font_size(); ctx.terminal_mut().reset_font_size();
}, },
Action::ScrollPageUp => { Action::ScrollPageUp => {
ctx.scroll(Scroll::PageUp); ctx.scroll(Scroll::PageUp);
@ -321,10 +318,10 @@ impl Action {
ctx.scroll(Scroll::Bottom); ctx.scroll(Scroll::Bottom);
}, },
Action::ClearHistory => { Action::ClearHistory => {
ctx.clear_history(); ctx.terminal_mut().clear_screen(ClearMode::Saved);
}, },
Action::ClearLogNotice => { Action::ClearLogNotice => {
ctx.clear_log(); ctx.terminal_mut().message_buffer_mut().pop();
}, },
Action::SpawnNewInstance => { Action::SpawnNewInstance => {
ctx.spawn_new_instance(); ctx.spawn_new_instance();
@ -334,7 +331,7 @@ impl Action {
} }
fn paste<A: ActionContext>(&self, ctx: &mut A, contents: &str) { fn paste<A: ActionContext>(&self, ctx: &mut A, contents: &str) {
if ctx.terminal_mode().contains(TermMode::BRACKETED_PASTE) { if ctx.terminal().mode().contains(TermMode::BRACKETED_PASTE) {
ctx.write_to_pty(&b"\x1b[200~"[..]); ctx.write_to_pty(&b"\x1b[200~"[..]);
ctx.write_to_pty(contents.replace("\x1b","").into_bytes()); ctx.write_to_pty(contents.replace("\x1b","").into_bytes());
ctx.write_to_pty(&b"\x1b[201~"[..]); ctx.write_to_pty(&b"\x1b[201~"[..]);
@ -396,8 +393,13 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
self.ctx.mouse_mut().block_url_launcher = true; self.ctx.mouse_mut().block_url_launcher = true;
} }
// Ignore motions over the message bar
if self.mouse_over_message_bar(point) {
return;
}
if self.ctx.mouse().left_button_state == ElementState::Pressed if self.ctx.mouse().left_button_state == ElementState::Pressed
&& (modifiers.shift || !self.ctx.terminal_mode().intersects(report_mode)) && (modifiers.shift || !self.ctx.terminal().mode().intersects(report_mode))
{ {
self.ctx.update_selection( self.ctx.update_selection(
Point { Point {
@ -406,7 +408,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
}, },
cell_side, cell_side,
); );
} else if self.ctx.terminal_mode().intersects(motion_mode) } else if self.ctx.terminal().mode().intersects(motion_mode)
// Only report motion when changing cells // Only report motion when changing cells
&& (prev_line != self.ctx.mouse().line || prev_col != self.ctx.mouse().column) && (prev_line != self.ctx.mouse().line || prev_col != self.ctx.mouse().column)
&& size_info.contains_point(x, y) && size_info.contains_point(x, y)
@ -417,7 +419,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
self.mouse_report(33, ElementState::Pressed, modifiers); self.mouse_report(33, ElementState::Pressed, modifiers);
} else if self.ctx.mouse().right_button_state == ElementState::Pressed { } else if self.ctx.mouse().right_button_state == ElementState::Pressed {
self.mouse_report(34, ElementState::Pressed, modifiers); self.mouse_report(34, ElementState::Pressed, modifiers);
} else if self.ctx.terminal_mode().contains(TermMode::MOUSE_MOTION) { } else if self.ctx.terminal().mode().contains(TermMode::MOUSE_MOTION) {
self.mouse_report(35, ElementState::Pressed, modifiers); self.mouse_report(35, ElementState::Pressed, modifiers);
} }
} }
@ -430,7 +432,8 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
let cell_x = x.saturating_sub(size_info.padding_x as usize) % size_info.cell_width as usize; let cell_x = x.saturating_sub(size_info.padding_x as usize) % size_info.cell_width as usize;
let half_cell_width = (size_info.cell_width / 2.0) as usize; let half_cell_width = (size_info.cell_width / 2.0) as usize;
let additional_padding = (size_info.width - size_info.padding_x * 2.) % size_info.cell_width; let additional_padding =
(size_info.width - size_info.padding_x * 2.) % size_info.cell_width;
let end_of_grid = size_info.width - size_info.padding_x - additional_padding; let end_of_grid = size_info.width - size_info.padding_x - additional_padding;
if cell_x > half_cell_width if cell_x > half_cell_width
@ -485,7 +488,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
} }
// Report mouse events // Report mouse events
if self.ctx.terminal_mode().contains(TermMode::SGR_MOUSE) { if self.ctx.terminal().mode().contains(TermMode::SGR_MOUSE) {
self.sgr_mouse_report(button + mods, state); self.sgr_mouse_report(button + mods, state);
} else if let ElementState::Released = state { } else if let ElementState::Released = state {
self.normal_mouse_report(3 + mods); self.normal_mouse_report(3 + mods);
@ -494,19 +497,24 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
} }
} }
pub fn on_mouse_double_click(&mut self, button: MouseButton) { pub fn on_mouse_double_click(&mut self, button: MouseButton, point: Point) {
if let (Some(point) , MouseButton::Left) = (self.ctx.mouse_coords(), button) { if button == MouseButton::Left {
self.ctx.semantic_selection(point); self.ctx.semantic_selection(point);
} }
} }
pub fn on_mouse_triple_click(&mut self, button: MouseButton) { pub fn on_mouse_triple_click(&mut self, button: MouseButton, point: Point) {
if let (Some(point), MouseButton::Left) = (self.ctx.mouse_coords(), button) { if button == MouseButton::Left {
self.ctx.line_selection(point); self.ctx.line_selection(point);
} }
} }
pub fn on_mouse_press(&mut self, button: MouseButton, modifiers: ModifiersState) { pub fn on_mouse_press(
&mut self,
button: MouseButton,
modifiers: ModifiersState,
point: Point,
) {
let now = Instant::now(); let now = Instant::now();
let elapsed = self.ctx.mouse().last_click_timestamp.elapsed(); let elapsed = self.ctx.mouse().last_click_timestamp.elapsed();
self.ctx.mouse_mut().last_click_timestamp = now; self.ctx.mouse_mut().last_click_timestamp = now;
@ -518,14 +526,14 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
if !button_changed && elapsed < self.mouse_config.double_click.threshold => if !button_changed && elapsed < self.mouse_config.double_click.threshold =>
{ {
self.ctx.mouse_mut().block_url_launcher = true; self.ctx.mouse_mut().block_url_launcher = true;
self.on_mouse_double_click(button); self.on_mouse_double_click(button, point);
ClickState::DoubleClick ClickState::DoubleClick
}, },
ClickState::DoubleClick ClickState::DoubleClick
if !button_changed && elapsed < self.mouse_config.triple_click.threshold => if !button_changed && elapsed < self.mouse_config.triple_click.threshold =>
{ {
self.ctx.mouse_mut().block_url_launcher = true; self.ctx.mouse_mut().block_url_launcher = true;
self.on_mouse_triple_click(button); self.on_mouse_triple_click(button, point);
ClickState::TripleClick ClickState::TripleClick
}, },
_ => { _ => {
@ -535,20 +543,20 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
self.ctx.clear_selection(); self.ctx.clear_selection();
// Start new empty selection // Start new empty selection
if let Some(point) = self.ctx.mouse_coords() { let side = self.ctx.mouse().cell_side;
let side = self.ctx.mouse().cell_side; self.ctx.simple_selection(point, side);
self.ctx.simple_selection(point, side);
}
let report_modes = TermMode::MOUSE_REPORT_CLICK | TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION; let report_modes =
if !modifiers.shift && self.ctx.terminal_mode().intersects(report_modes) { TermMode::MOUSE_REPORT_CLICK | TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION;
match button { if !modifiers.shift && self.ctx.terminal().mode().intersects(report_modes) {
MouseButton::Left => self.mouse_report(0, ElementState::Pressed, modifiers), let code = match button {
MouseButton::Middle => self.mouse_report(1, ElementState::Pressed, modifiers), MouseButton::Left => 0,
MouseButton::Right => self.mouse_report(2, ElementState::Pressed, modifiers), MouseButton::Middle => 1,
MouseButton::Right => 2,
// Can't properly report more than three buttons. // Can't properly report more than three buttons.
MouseButton::Other(_) => (), MouseButton::Other(_) => return,
}; };
self.mouse_report(code, ElementState::Pressed, modifiers);
return; return;
} }
@ -557,38 +565,40 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
}; };
} }
pub fn on_mouse_release(&mut self, button: MouseButton, modifiers: ModifiersState) { pub fn on_mouse_release(
let report_modes = TermMode::MOUSE_REPORT_CLICK | TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION; &mut self,
if !modifiers.shift && self.ctx.terminal_mode().intersects(report_modes) button: MouseButton,
{ modifiers: ModifiersState,
match button { point: Point,
MouseButton::Left => self.mouse_report(0, ElementState::Released, modifiers), ) {
MouseButton::Middle => self.mouse_report(1, ElementState::Released, modifiers), let report_modes =
MouseButton::Right => self.mouse_report(2, ElementState::Released, modifiers), TermMode::MOUSE_REPORT_CLICK | TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION;
if !modifiers.shift && self.ctx.terminal().mode().intersects(report_modes) {
let code = match button {
MouseButton::Left => 0,
MouseButton::Middle => 1,
MouseButton::Right => 2,
// Can't properly report more than three buttons. // Can't properly report more than three buttons.
MouseButton::Other(_) => (), MouseButton::Other(_) => return,
}; };
self.mouse_report(code, ElementState::Released, modifiers);
return; return;
} else if button == MouseButton::Left { } else if button == MouseButton::Left {
self.launch_url(modifiers); self.launch_url(modifiers, point);
} }
if self.save_to_clipboard { self.copy_selection();
self.ctx.copy_selection(ClipboardBuffer::Primary);
}
self.ctx.copy_selection(ClipboardBuffer::Selection);
} }
// Spawn URL launcher when clicking on URLs // Spawn URL launcher when clicking on URLs
fn launch_url(&self, modifiers: ModifiersState) -> Option<()> { fn launch_url(&self, modifiers: ModifiersState, point: Point) -> Option<()> {
if !self.mouse_config.url.modifiers.relaxed_eq(modifiers) if !self.mouse_config.url.modifiers.relaxed_eq(modifiers)
|| self.ctx.mouse().block_url_launcher || self.ctx.mouse().block_url_launcher
{ {
return None; return None;
} }
let point = self.ctx.mouse_coords()?; let text = self.ctx.terminal().url_search(point.into())?;
let text = self.ctx.url(point.into())?;
let launcher = self.mouse_config.url.launcher.as_ref()?; let launcher = self.mouse_config.url.launcher.as_ref()?;
let mut args = launcher.args().to_vec(); let mut args = launcher.args().to_vec();
@ -602,7 +612,12 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
Some(()) Some(())
} }
pub fn on_mouse_wheel(&mut self, delta: MouseScrollDelta, phase: TouchPhase, modifiers: ModifiersState) { pub fn on_mouse_wheel(
&mut self,
delta: MouseScrollDelta,
phase: TouchPhase,
modifiers: ModifiersState,
) {
match delta { match delta {
MouseScrollDelta::LineDelta(_columns, lines) => { MouseScrollDelta::LineDelta(_columns, lines) => {
let new_scroll_px = lines * self.ctx.size_info().cell_height; let new_scroll_px = lines * self.ctx.size_info().cell_height;
@ -634,7 +649,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
.faux_scrollback_lines .faux_scrollback_lines
.unwrap_or(self.scrolling_config.faux_multiplier as usize); .unwrap_or(self.scrolling_config.faux_multiplier as usize);
if self.ctx.terminal_mode().intersects(mouse_modes) { if self.ctx.terminal().mode().intersects(mouse_modes) {
self.ctx.mouse_mut().scroll_px += new_scroll_px; self.ctx.mouse_mut().scroll_px += new_scroll_px;
let code = if new_scroll_px > 0 { 64 } else { 65 }; let code = if new_scroll_px > 0 { 64 } else { 65 };
@ -643,7 +658,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
for _ in 0..lines { for _ in 0..lines {
self.mouse_report(code, ElementState::Pressed, modifiers); self.mouse_report(code, ElementState::Pressed, modifiers);
} }
} else if self.ctx.terminal_mode().contains(TermMode::ALT_SCREEN) } else if self.ctx.terminal().mode().contains(TermMode::ALT_SCREEN)
&& faux_multiplier > 0 && faux_multiplier > 0
&& !modifiers.shift && !modifiers.shift
{ {
@ -672,7 +687,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
} }
pub fn on_focus_change(&mut self, is_focused: bool) { pub fn on_focus_change(&mut self, is_focused: bool) {
if self.ctx.terminal_mode().contains(TermMode::FOCUS_IN_OUT) { if self.ctx.terminal().mode().contains(TermMode::FOCUS_IN_OUT) {
let chr = if is_focused { let chr = if is_focused {
"I" "I"
} else { } else {
@ -684,7 +699,12 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
} }
} }
pub fn mouse_input(&mut self, state: ElementState, button: MouseButton, modifiers: ModifiersState) { pub fn mouse_input(
&mut self,
state: ElementState,
button: MouseButton,
modifiers: ModifiersState
) {
match button { match button {
MouseButton::Left => self.ctx.mouse_mut().left_button_state = state, MouseButton::Left => self.ctx.mouse_mut().left_button_state = state,
MouseButton::Middle => self.ctx.mouse_mut().middle_button_state = state, MouseButton::Middle => self.ctx.mouse_mut().middle_button_state = state,
@ -692,12 +712,22 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
_ => (), _ => (),
} }
match state { let point = match self.ctx.mouse_coords() {
ElementState::Pressed => { Some(point) => point,
self.process_mouse_bindings(modifiers, button); None => return,
self.on_mouse_press(button, modifiers); };
},
ElementState::Released => self.on_mouse_release(button, modifiers), // Skip normal mouse events if the message bar has been clicked
if self.mouse_over_message_bar(point) {
self.on_message_bar_click(state, point);
} else {
match state {
ElementState::Pressed => {
self.process_mouse_bindings(modifiers, button);
self.on_mouse_press(button, modifiers, point);
},
ElementState::Released => self.on_mouse_release(button, modifiers, point),
}
} }
self.ctx.mouse_mut().last_button = button; self.ctx.mouse_mut().last_button = button;
@ -759,14 +789,19 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
for binding in self.key_bindings { for binding in self.key_bindings {
let is_triggered = match binding.trigger { let is_triggered = match binding.trigger {
Key::Scancode(_) => binding.is_triggered_by( Key::Scancode(_) => binding.is_triggered_by(
self.ctx.terminal_mode(), *self.ctx.terminal().mode(),
input.modifiers, input.modifiers,
&Key::Scancode(input.scancode), &Key::Scancode(input.scancode),
false, false,
), ),
_ => if let Some(key) = input.virtual_keycode { _ => if let Some(key) = input.virtual_keycode {
let key = Key::from_glutin_input(key); let key = Key::from_glutin_input(key);
binding.is_triggered_by(self.ctx.terminal_mode(), input.modifiers, &key, false) binding.is_triggered_by(
*self.ctx.terminal().mode(),
input.modifiers,
&key,
false
)
} else { } else {
false false
}, },
@ -791,9 +826,9 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
fn process_mouse_bindings(&mut self, mods: ModifiersState, button: MouseButton) -> bool { fn process_mouse_bindings(&mut self, mods: ModifiersState, button: MouseButton) -> bool {
let mut has_binding = false; let mut has_binding = false;
for binding in self.mouse_bindings { for binding in self.mouse_bindings {
if binding.is_triggered_by(self.ctx.terminal_mode(), mods, &button, true) { if binding.is_triggered_by(*self.ctx.terminal().mode(), mods, &button, true) {
// binding was triggered; run the action // binding was triggered; run the action
let mouse_mode = !mods.shift && self.ctx.terminal_mode().intersects( let mouse_mode = !mods.shift && self.ctx.terminal().mode().intersects(
TermMode::MOUSE_REPORT_CLICK TermMode::MOUSE_REPORT_CLICK
| TermMode::MOUSE_DRAG | TermMode::MOUSE_DRAG
| TermMode::MOUSE_MOTION | TermMode::MOUSE_MOTION
@ -805,6 +840,43 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
has_binding has_binding
} }
/// Check if a point is within the message bar
fn mouse_over_message_bar(&mut self, point: Point) -> bool {
if let Some(message) = self.ctx.terminal_mut().message_buffer_mut().message() {
let size = self.ctx.size_info();
point.line.0 >= size.lines().saturating_sub(message.text(&size).len())
} else {
false
}
}
/// Handle clicks on the message bar.
fn on_message_bar_click(&mut self, button_state: ElementState, point: Point) {
match button_state {
ElementState::Released => self.copy_selection(),
ElementState::Pressed => {
let size = self.ctx.size_info();
if let Some(message) = self.ctx.terminal_mut().message_buffer_mut().message() {
if point.col + message_bar::CLOSE_BUTTON_TEXT.len() >= size.cols()
&& point.line == size.lines() - message.text(&size).len()
{
self.ctx.terminal_mut().message_buffer_mut().pop();
}
}
self.ctx.clear_selection();
}
}
}
/// Copy text selection.
fn copy_selection(&mut self) {
if self.save_to_clipboard {
self.ctx.copy_selection(ClipboardBuffer::Primary);
}
self.ctx.copy_selection(ClipboardBuffer::Selection);
}
} }
#[cfg(test)] #[cfg(test)]
@ -820,6 +892,7 @@ mod tests {
use crate::index::{Point, Side}; use crate::index::{Point, Side};
use crate::selection::Selection; use crate::selection::Selection;
use crate::grid::Scroll; use crate::grid::Scroll;
use crate::message_bar::MessageBuffer;
use super::{Action, Binding, Processor}; use super::{Action, Binding, Processor};
use copypasta::Buffer as ClipboardBuffer; use copypasta::Buffer as ClipboardBuffer;
@ -851,15 +924,15 @@ mod tests {
fn simple_selection(&mut self, _point: Point, _side: Side) {} fn simple_selection(&mut self, _point: Point, _side: Side) {}
fn copy_selection(&self, _buffer: ClipboardBuffer) {} fn copy_selection(&self, _buffer: ClipboardBuffer) {}
fn clear_selection(&mut self) {} fn clear_selection(&mut self) {}
fn change_font_size(&mut self, _delta: f32) {}
fn reset_font_size(&mut self) {}
fn clear_history(&mut self) {}
fn clear_log(&mut self) {}
fn hide_window(&mut self) {} fn hide_window(&mut self) {}
fn spawn_new_instance(&mut self) {} fn spawn_new_instance(&mut self) {}
fn terminal_mode(&self) -> TermMode { fn terminal(&self) -> &Term {
*self.terminal.mode() &self.terminal
}
fn terminal_mut(&mut self) -> &mut Term {
&mut self.terminal
} }
fn size_info(&self) -> SizeInfo { fn size_info(&self) -> SizeInfo {
@ -897,10 +970,6 @@ mod tests {
self.mouse self.mouse
} }
fn url(&self, _: Point<usize>) -> Option<String> {
None
}
fn received_count(&mut self) -> &mut usize { fn received_count(&mut self) -> &mut usize {
&mut self.received_count &mut self.received_count
} }
@ -936,7 +1005,7 @@ mod tests {
dpr: 1.0, dpr: 1.0,
}; };
let mut terminal = Term::new(&config, size); let mut terminal = Term::new(&config, size, MessageBuffer::new());
let mut mouse = Mouse::default(); let mut mouse = Mouse::default();
mouse.click_state = $initial_state; mouse.click_state = $initial_state;

View file

@ -46,10 +46,9 @@ pub mod term;
pub mod tty; pub mod tty;
pub mod util; pub mod util;
pub mod window; pub mod window;
pub mod message_bar;
mod url; mod url;
use std::ops::Mul;
pub use crate::grid::Grid; pub use crate::grid::Grid;
pub use crate::term::Term; pub use crate::term::Term;
@ -60,31 +59,6 @@ pub enum MouseCursor {
Text, Text,
} }
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default, Serialize, Deserialize)]
pub struct Rgb {
pub r: u8,
pub g: u8,
pub b: u8,
}
// a multiply function for Rgb, as the default dim is just *2/3
impl Mul<f32> for Rgb {
type Output = Rgb;
fn mul(self, rhs: f32) -> Rgb {
let result = Rgb {
r: (f32::from(self.r) * rhs).max(0.0).min(255.0) as u8,
g: (f32::from(self.g) * rhs).max(0.0).min(255.0) as u8,
b: (f32::from(self.b) * rhs).max(0.0).min(255.0) as u8
};
trace!("Scaling RGB by {} from {:?} to {:?}", rhs, self, result);
result
}
}
pub mod gl { pub mod gl {
#![allow(clippy::all)] #![allow(clippy::all)]
include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs")); include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));

View file

@ -17,85 +17,52 @@
//! The main executable is supposed to call `initialize()` exactly once during //! The main executable is supposed to call `initialize()` exactly once during
//! startup. All logging messages are written to stdout, given that their //! startup. All logging messages are written to stdout, given that their
//! log-level is sufficient for the level configured in `cli::Options`. //! log-level is sufficient for the level configured in `cli::Options`.
use crate::cli;
use log::{self, Level};
use time;
use std::env; use std::env;
use std::fs::{self, File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::io::{self, LineWriter, Stdout, Write}; use std::io::{self, LineWriter, Stdout, Write};
use std::path::PathBuf; use std::path::PathBuf;
use std::process; use std::process;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
pub fn initialize(options: &cli::Options) -> Result<LoggerProxy, log::SetLoggerError> { use crossbeam_channel::Sender;
use log::{self, Level};
use time;
use crate::cli;
use crate::message_bar::Message;
use crate::term::color;
const ALACRITTY_LOG_ENV: &str = "ALACRITTY_LOG";
pub fn initialize(
options: &cli::Options,
message_tx: Sender<Message>,
) -> Result<Option<PathBuf>, log::SetLoggerError> {
// Use env_logger if RUST_LOG environment variable is defined. Otherwise, // Use env_logger if RUST_LOG environment variable is defined. Otherwise,
// use the alacritty-only logger. // use the alacritty-only logger.
if ::std::env::var("RUST_LOG").is_ok() { if ::std::env::var("RUST_LOG").is_ok() {
::env_logger::try_init()?; ::env_logger::try_init()?;
Ok(LoggerProxy::default()) Ok(None)
} else { } else {
let logger = Logger::new(options.log_level); let logger = Logger::new(options.log_level, message_tx);
let proxy = logger.proxy(); let path = logger.file_path();
log::set_boxed_logger(Box::new(logger))?; log::set_boxed_logger(Box::new(logger))?;
Ok(path)
Ok(proxy)
} }
} }
/// Proxy object for bidirectional communicating with the global logger. pub struct Logger {
#[derive(Clone, Default)]
pub struct LoggerProxy {
errors: Arc<AtomicBool>,
warnings: Arc<AtomicBool>,
logfile_proxy: OnDemandLogFileProxy,
}
impl LoggerProxy {
/// Check for new logged errors.
pub fn errors(&self) -> bool {
self.errors.load(Ordering::Relaxed)
}
/// Check for new logged warnings.
pub fn warnings(&self) -> bool {
self.warnings.load(Ordering::Relaxed)
}
/// Get the path of the log file if it has been created.
pub fn log_path(&self) -> Option<&str> {
if self.logfile_proxy.created.load(Ordering::Relaxed) {
Some(&self.logfile_proxy.path)
} else {
None
}
}
/// Clear log warnings/errors from the Alacritty UI.
pub fn clear(&mut self) {
self.errors.store(false, Ordering::Relaxed);
self.warnings.store(false, Ordering::Relaxed);
}
pub fn delete_log(&mut self) {
self.logfile_proxy.delete_log();
}
}
struct Logger {
level: log::LevelFilter, level: log::LevelFilter,
logfile: Mutex<OnDemandLogFile>, logfile: Mutex<OnDemandLogFile>,
stdout: Mutex<LineWriter<Stdout>>, stdout: Mutex<LineWriter<Stdout>>,
errors: Arc<AtomicBool>, message_tx: Sender<Message>,
warnings: Arc<AtomicBool>,
} }
impl Logger { impl Logger {
// False positive, see: https://github.com/rust-lang-nursery/rust-clippy/issues/734 // False positive, see: https://github.com/rust-lang-nursery/rust-clippy/issues/734
#[allow(clippy::new_ret_no_self)] #[allow(clippy::new_ret_no_self)]
fn new(level: log::LevelFilter) -> Self { fn new(level: log::LevelFilter, message_tx: Sender<Message>) -> Self {
log::set_max_level(level); log::set_max_level(level);
let logfile = Mutex::new(OnDemandLogFile::new()); let logfile = Mutex::new(OnDemandLogFile::new());
@ -105,16 +72,15 @@ impl Logger {
level, level,
logfile, logfile,
stdout, stdout,
errors: Arc::new(AtomicBool::new(false)), message_tx,
warnings: Arc::new(AtomicBool::new(false)),
} }
} }
fn proxy(&self) -> LoggerProxy { fn file_path(&self) -> Option<PathBuf> {
LoggerProxy { if let Ok(logfile) = self.logfile.lock() {
errors: self.errors.clone(), Some(logfile.path().clone())
warnings: self.warnings.clone(), } else {
logfile_proxy: self.logfile.lock().expect("").proxy(), None
} }
} }
} }
@ -125,61 +91,62 @@ impl log::Log for Logger {
} }
fn log(&self, record: &log::Record<'_>) { fn log(&self, record: &log::Record<'_>) {
if self.enabled(record.metadata()) && if self.enabled(record.metadata()) && record.target().starts_with("alacritty") {
record.target().starts_with("alacritty")
{
let now = time::strftime("%F %R", &time::now()).unwrap(); let now = time::strftime("%F %R", &time::now()).unwrap();
let msg = if record.level() >= Level::Trace { let msg = if record.level() >= Level::Trace {
format!("[{}] [{}] [{}:{}] {}\n", format!(
now, "[{}] [{}] [{}:{}] {}\n",
record.level(), now,
record.file().unwrap_or("?"), record.level(),
record.line() record.file().unwrap_or("?"),
.map(|l| l.to_string()) record
.unwrap_or_else(|| "?".into()), .line()
record.args()) .map(|l| l.to_string())
.unwrap_or_else(|| "?".into()),
record.args()
)
} else { } else {
format!("[{}] [{}] {}\n", format!("[{}] [{}] {}\n", now, record.level(), record.args())
now,
record.level(),
record.args())
}; };
if let Ok(ref mut logfile) = self.logfile.lock() { if let Ok(ref mut logfile) = self.logfile.lock() {
let _ = logfile.write_all(msg.as_ref()); let _ = logfile.write_all(msg.as_ref());
if record.level() <= Level::Warn {
#[cfg(not(windows))]
let env_var = format!("${}", ALACRITTY_LOG_ENV);
#[cfg(windows)]
let env_var = format!("%{}%", ALACRITTY_LOG_ENV);
let msg = format!(
"[{}] See log at {} ({}):\n{}",
record.level(),
logfile.path.to_string_lossy(),
env_var,
record.args(),
);
let color = match record.level() {
Level::Error => color::RED,
Level::Warn => color::YELLOW,
_ => unreachable!(),
};
let mut message = Message::new(msg, color);
message.set_topic(record.file().unwrap_or("?").into());
let _ = self.message_tx.send(message);
}
} }
if let Ok(ref mut stdout) = self.stdout.lock() { if let Ok(ref mut stdout) = self.stdout.lock() {
let _ = stdout.write_all(msg.as_ref()); let _ = stdout.write_all(msg.as_ref());
} }
match record.level() {
Level::Error => self.errors.store(true, Ordering::Relaxed),
Level::Warn => self.warnings.store(true, Ordering::Relaxed),
_ => (),
}
} }
} }
fn flush(&self) {} fn flush(&self) {}
} }
#[derive(Clone, Default)]
struct OnDemandLogFileProxy {
created: Arc<AtomicBool>,
path: String,
}
impl OnDemandLogFileProxy {
fn delete_log(&mut self) {
if self.created.load(Ordering::Relaxed) && fs::remove_file(&self.path).is_ok() {
let _ = writeln!(io::stdout(), "Deleted log file at {:?}", self.path);
self.created.store(false, Ordering::Relaxed);
}
}
}
struct OnDemandLogFile { struct OnDemandLogFile {
file: Option<LineWriter<File>>, file: Option<LineWriter<File>>,
created: Arc<AtomicBool>, created: Arc<AtomicBool>,
@ -191,6 +158,9 @@ impl OnDemandLogFile {
let mut path = env::temp_dir(); let mut path = env::temp_dir();
path.push(format!("Alacritty-{}.log", process::id())); path.push(format!("Alacritty-{}.log", process::id()));
// Set log path as an environment variable
env::set_var(ALACRITTY_LOG_ENV, path.as_os_str());
OnDemandLogFile { OnDemandLogFile {
path, path,
file: None, file: None,
@ -227,11 +197,8 @@ impl OnDemandLogFile {
Ok(self.file.as_mut().unwrap()) Ok(self.file.as_mut().unwrap())
} }
fn proxy(&self) -> OnDemandLogFileProxy { fn path(&self) -> &PathBuf {
OnDemandLogFileProxy { &self.path
created: self.created.clone(),
path: self.path.to_string_lossy().to_string(),
}
} }
} }

View file

@ -33,6 +33,8 @@ use log::{info, error};
use std::error::Error; use std::error::Error;
use std::sync::Arc; use std::sync::Arc;
use std::io::{self, Write};
use std::fs;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
use std::env; use std::env;
@ -43,15 +45,16 @@ use std::os::unix::io::AsRawFd;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
use alacritty::locale; use alacritty::locale;
use alacritty::{cli, event, die}; use alacritty::{cli, event, die};
use alacritty::config::{self, Config, Error as ConfigError}; use alacritty::config::{self, Config};
use alacritty::display::Display; use alacritty::display::Display;
use alacritty::event_loop::{self, EventLoop, Msg}; use alacritty::event_loop::{self, EventLoop, Msg};
use alacritty::logging::{self, LoggerProxy}; use alacritty::logging;
use alacritty::panic; use alacritty::panic;
use alacritty::sync::FairMutex; use alacritty::sync::FairMutex;
use alacritty::term::Term; use alacritty::term::Term;
use alacritty::tty::{self, process_should_exit}; use alacritty::tty;
use alacritty::util::fmt::Red; use alacritty::util::fmt::Red;
use alacritty::message_bar::MessageBuffer;
fn main() { fn main() {
panic::attach_handler(); panic::attach_handler();
@ -65,11 +68,25 @@ fn main() {
// Load command line options // Load command line options
let options = cli::Options::load(); let options = cli::Options::load();
// Setup storage for message UI
let message_buffer = MessageBuffer::new();
// Initialize the logger as soon as possible as to capture output from other subsystems // Initialize the logger as soon as possible as to capture output from other subsystems
let logger_proxy = logging::initialize(&options).expect("Unable to initialize logger"); let log_file =
logging::initialize(&options, message_buffer.tx()).expect("Unable to initialize logger");
// Load configuration file // Load configuration file
let config = load_config(&options).update_dynamic_title(&options); // If the file is a command line argument, we won't write a generated default file
let config_path = options.config_path()
.or_else(Config::installed_config)
.or_else(|| Config::write_defaults().ok())
.map(|path| path.to_path_buf());
let config = if let Some(path) = config_path {
Config::load_from(path).update_dynamic_title(&options)
} else {
error!("Unable to write the default config");
Config::default()
};
// Switch to home directory // Switch to home directory
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
@ -78,34 +95,19 @@ fn main() {
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
locale::set_locale_environment(); locale::set_locale_environment();
// Store if log file should be deleted before moving config
let persistent_logging = options.persistent_logging || config.persistent_logging();
// Run alacritty // Run alacritty
if let Err(err) = run(config, &options, logger_proxy) { if let Err(err) = run(config, &options, message_buffer) {
die!("Alacritty encountered an unrecoverable error:\n\n\t{}\n", Red(err)); die!("Alacritty encountered an unrecoverable error:\n\n\t{}\n", Red(err));
} }
}
/// Load configuration // Clean up logfile
/// if let Some(log_file) = log_file {
/// If a configuration file is given as a command line argument we don't if !persistent_logging && fs::remove_file(&log_file).is_ok() {
/// generate a default file. If an empty configuration file is given, i.e. let _ = writeln!(io::stdout(), "Deleted log file at {:?}", log_file);
/// /dev/null, we load the compiled-in defaults.) }
fn load_config(options: &cli::Options) -> Config {
let config_path = options.config_path()
.or_else(Config::installed_config)
.or_else(|| Config::write_defaults().ok());
if let Some(config_path) = config_path {
Config::load_from(&*config_path).unwrap_or_else(|err| {
match err {
ConfigError::Empty => info!("Config file {:?} is empty; loading default", config_path),
_ => error!("Unable to load default config: {}", err),
}
Config::default()
})
} else {
error!("Unable to write the default config");
Config::default()
} }
} }
@ -116,7 +118,7 @@ fn load_config(options: &cli::Options) -> Config {
fn run( fn run(
mut config: Config, mut config: Config,
options: &cli::Options, options: &cli::Options,
mut logger_proxy: LoggerProxy, message_buffer: MessageBuffer,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
info!("Welcome to Alacritty"); info!("Welcome to Alacritty");
if let Some(config_path) = config.path() { if let Some(config_path) = config.path() {
@ -129,7 +131,7 @@ fn run(
// Create a display. // Create a display.
// //
// The display manages a window and can draw the terminal // The display manages a window and can draw the terminal
let mut display = Display::new(&config, options, logger_proxy.clone())?; let mut display = Display::new(&config, options)?;
info!( info!(
"PTY Dimensions: {:?} x {:?}", "PTY Dimensions: {:?} x {:?}",
@ -142,8 +144,7 @@ fn run(
// This object contains all of the state about what's being displayed. It's // This object contains all of the state about what's being displayed. It's
// wrapped in a clonable mutex since both the I/O loop and display need to // wrapped in a clonable mutex since both the I/O loop and display need to
// access it. // access it.
let mut terminal = Term::new(&config, display.size().to_owned()); let terminal = Term::new(&config, display.size().to_owned(), message_buffer);
terminal.set_logger_proxy(logger_proxy.clone());
let terminal = Arc::new(FairMutex::new(terminal)); let terminal = Arc::new(FairMutex::new(terminal));
// Find the window ID for setting $WINDOWID // Find the window ID for setting $WINDOWID
@ -220,17 +221,25 @@ fn run(
let mut terminal_lock = processor.process_events(&terminal, display.window()); let mut terminal_lock = processor.process_events(&terminal, display.window());
// Handle config reloads // Handle config reloads
if let Some(new_config) = config_monitor if let Some(ref path) = config_monitor.as_ref().and_then(|monitor| monitor.pending()) {
.as_ref() // Clear old config messages from bar
.and_then(|monitor| monitor.pending_config()) terminal_lock.message_buffer_mut().remove_topic(config::SOURCE_FILE_PATH);
{
config = new_config.update_dynamic_title(options); if let Ok(new_config) = Config::reload_from(path) {
display.update_config(&config); config = new_config.update_dynamic_title(options);
processor.update_config(&config); display.update_config(&config);
terminal_lock.update_config(&config); processor.update_config(&config);
terminal_lock.update_config(&config);
}
terminal_lock.dirty = true; terminal_lock.dirty = true;
} }
// Begin shutdown if the flag was raised
if terminal_lock.should_exit() {
break;
}
// Maybe draw the terminal // Maybe draw the terminal
if terminal_lock.needs_draw() { if terminal_lock.needs_draw() {
// Try to update the position of the input method editor // Try to update the position of the input method editor
@ -241,18 +250,13 @@ fn run(
// //
// The second argument is a list of types that want to be notified // The second argument is a list of types that want to be notified
// of display size changes. // of display size changes.
display.handle_resize(&mut terminal_lock, &config, &mut [&mut resize_handle, &mut processor]); display.handle_resize(&mut terminal_lock, &config, &mut resize_handle, &mut processor);
drop(terminal_lock); drop(terminal_lock);
// Draw the current state of the terminal // Draw the current state of the terminal
display.draw(&terminal, &config); display.draw(&terminal, &config);
} }
// Begin shutdown if the flag was raised.
if process_should_exit() {
break;
}
} }
loop_tx loop_tx
@ -268,9 +272,5 @@ fn run(
info!("Goodbye"); info!("Goodbye");
if !options.persistent_logging && !config.persistent_logging() {
logger_proxy.delete_log();
}
Ok(()) Ok(())
} }

517
src/message_bar.rs Normal file
View file

@ -0,0 +1,517 @@
// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crossbeam_channel::{Receiver, Sender};
use crate::term::color::Rgb;
use crate::term::SizeInfo;
pub const CLOSE_BUTTON_TEXT: &str = "[X]";
const CLOSE_BUTTON_PADDING: usize = 1;
const MIN_FREE_LINES: usize = 3;
const TRUNCATED_MESSAGE: &str = "[MESSAGE TRUNCATED]";
/// Message for display in the MessageBuffer
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Message {
text: String,
color: Rgb,
topic: Option<String>,
}
impl Message {
/// Create a new message
pub fn new(text: String, color: Rgb) -> Message {
Message {
text,
color,
topic: None,
}
}
/// Formatted message text lines
pub fn text(&self, size_info: &SizeInfo) -> Vec<String> {
let num_cols = size_info.cols().0;
let max_lines = size_info.lines().saturating_sub(MIN_FREE_LINES);
let button_len = CLOSE_BUTTON_TEXT.len();
// Split line to fit the screen
let mut lines = Vec::new();
let mut line = String::new();
for c in self.text.trim().chars() {
if c == '\n'
|| line.len() == num_cols
// Keep space in first line for button
|| (lines.is_empty()
&& num_cols >= button_len
&& line.len() == num_cols.saturating_sub(button_len + CLOSE_BUTTON_PADDING))
{
// Attempt to wrap on word boundaries
if let (Some(index), true) = (line.rfind(char::is_whitespace), c != '\n') {
let split = line.split_off(index + 1);
line.pop();
lines.push(Self::pad_text(line, num_cols));
line = split
} else {
lines.push(Self::pad_text(line, num_cols));
line = String::new();
}
}
if c != '\n' {
line.push(c);
}
}
lines.push(Self::pad_text(line, num_cols));
// Truncate output if it's too long
if lines.len() > max_lines {
lines.truncate(max_lines);
if TRUNCATED_MESSAGE.len() <= num_cols {
if let Some(line) = lines.iter_mut().last() {
*line = Self::pad_text(TRUNCATED_MESSAGE.into(), num_cols);
}
}
}
// Append close button to first line
if button_len <= num_cols {
if let Some(line) = lines.get_mut(0) {
line.truncate(num_cols - button_len);
line.push_str(CLOSE_BUTTON_TEXT);
}
}
lines
}
/// Message color
#[inline]
pub fn color(&self) -> Rgb {
self.color
}
/// Message topic
#[inline]
pub fn topic(&self) -> Option<&String> {
self.topic.as_ref()
}
/// Update the message topic
#[inline]
pub fn set_topic(&mut self, topic: String) {
self.topic = Some(topic);
}
/// Right-pad text to fit a specific number of columns
#[inline]
fn pad_text(mut text: String, num_cols: usize) -> String {
let padding_len = num_cols.saturating_sub(text.len());
text.extend(vec![' '; padding_len]);
text
}
}
/// Storage for message bar
#[derive(Debug)]
pub struct MessageBuffer {
current: Option<Message>,
messages: Receiver<Message>,
tx: Sender<Message>,
}
impl MessageBuffer {
/// Create new message buffer
pub fn new() -> MessageBuffer {
let (tx, messages) = crossbeam_channel::unbounded();
MessageBuffer {
current: None,
messages,
tx,
}
}
/// Check if there are any messages queued
#[inline]
pub fn is_empty(&self) -> bool {
self.current.is_none()
}
/// Current message
#[inline]
pub fn message(&mut self) -> Option<Message> {
if let Some(current) = &self.current {
Some(current.clone())
} else {
self.current = self.messages.try_recv().ok();
self.current.clone()
}
}
/// Channel for adding new messages
#[inline]
pub fn tx(&self) -> Sender<Message> {
self.tx.clone()
}
/// Remove the currently visible message
#[inline]
pub fn pop(&mut self) {
// Remove all duplicates
for msg in self
.messages
.try_iter()
.take(self.messages.len())
.filter(|m| Some(m) != self.current.as_ref())
{
let _ = self.tx.send(msg);
}
// Remove the message itself
self.current = self.messages.try_recv().ok();
}
/// Remove all messages with a specific topic
#[inline]
pub fn remove_topic(&mut self, topic: &str) {
// Filter messages currently pending
for msg in self
.messages
.try_iter()
.take(self.messages.len())
.filter(|m| m.topic().map(|s| s.as_str()) != Some(topic))
{
let _ = self.tx.send(msg);
}
// Remove the currently active message
self.current = self.messages.try_recv().ok();
}
}
impl Default for MessageBuffer {
fn default() -> MessageBuffer {
MessageBuffer::new()
}
}
#[cfg(test)]
mod test {
use super::{Message, MessageBuffer, MIN_FREE_LINES};
use crate::term::{color, SizeInfo};
#[test]
fn appends_close_button() {
let input = "a";
let mut message_buffer = MessageBuffer::new();
message_buffer
.tx()
.send(Message::new(input.into(), color::RED))
.unwrap();
let size = SizeInfo {
width: 7.,
height: 10.,
cell_width: 1.,
cell_height: 1.,
padding_x: 0.,
padding_y: 0.,
dpr: 0.,
};
let lines = message_buffer.message().unwrap().text(&size);
assert_eq!(lines, vec![String::from("a [X]")]);
}
#[test]
fn multiline_close_button_first_line() {
let input = "fo\nbar";
let mut message_buffer = MessageBuffer::new();
message_buffer
.tx()
.send(Message::new(input.into(), color::RED))
.unwrap();
let size = SizeInfo {
width: 6.,
height: 10.,
cell_width: 1.,
cell_height: 1.,
padding_x: 0.,
padding_y: 0.,
dpr: 0.,
};
let lines = message_buffer.message().unwrap().text(&size);
assert_eq!(lines, vec![String::from("fo [X]"), String::from("bar ")]);
}
#[test]
fn splits_on_newline() {
let input = "a\nb";
let mut message_buffer = MessageBuffer::new();
message_buffer
.tx()
.send(Message::new(input.into(), color::RED))
.unwrap();
let size = SizeInfo {
width: 6.,
height: 10.,
cell_width: 1.,
cell_height: 1.,
padding_x: 0.,
padding_y: 0.,
dpr: 0.,
};
let lines = message_buffer.message().unwrap().text(&size);
assert_eq!(lines.len(), 2);
}
#[test]
fn splits_on_length() {
let input = "foobar1";
let mut message_buffer = MessageBuffer::new();
message_buffer
.tx()
.send(Message::new(input.into(), color::RED))
.unwrap();
let size = SizeInfo {
width: 6.,
height: 10.,
cell_width: 1.,
cell_height: 1.,
padding_x: 0.,
padding_y: 0.,
dpr: 0.,
};
let lines = message_buffer.message().unwrap().text(&size);
assert_eq!(lines.len(), 2);
}
#[test]
fn empty_with_shortterm() {
let input = "foobar";
let mut message_buffer = MessageBuffer::new();
message_buffer
.tx()
.send(Message::new(input.into(), color::RED))
.unwrap();
let size = SizeInfo {
width: 6.,
height: 0.,
cell_width: 1.,
cell_height: 1.,
padding_x: 0.,
padding_y: 0.,
dpr: 0.,
};
let lines = message_buffer.message().unwrap().text(&size);
assert_eq!(lines.len(), 0);
}
#[test]
fn truncates_long_messages() {
let input = "hahahahahahahahahahaha truncate this because it's too long for the term";
let mut message_buffer = MessageBuffer::new();
message_buffer
.tx()
.send(Message::new(input.into(), color::RED))
.unwrap();
let size = SizeInfo {
width: 22.,
height: (MIN_FREE_LINES + 2) as f32,
cell_width: 1.,
cell_height: 1.,
padding_x: 0.,
padding_y: 0.,
dpr: 0.,
};
let lines = message_buffer.message().unwrap().text(&size);
assert_eq!(
lines,
vec![
String::from("hahahahahahahahaha [X]"),
String::from("[MESSAGE TRUNCATED] ")
]
);
}
#[test]
fn hide_button_when_too_narrow() {
let input = "ha";
let mut message_buffer = MessageBuffer::new();
message_buffer
.tx()
.send(Message::new(input.into(), color::RED))
.unwrap();
let size = SizeInfo {
width: 2.,
height: 10.,
cell_width: 1.,
cell_height: 1.,
padding_x: 0.,
padding_y: 0.,
dpr: 0.,
};
let lines = message_buffer.message().unwrap().text(&size);
assert_eq!(lines, vec![String::from("ha")]);
}
#[test]
fn hide_truncated_when_too_narrow() {
let input = "hahahahahahahahaha";
let mut message_buffer = MessageBuffer::new();
message_buffer
.tx()
.send(Message::new(input.into(), color::RED))
.unwrap();
let size = SizeInfo {
width: 2.,
height: (MIN_FREE_LINES + 2) as f32,
cell_width: 1.,
cell_height: 1.,
padding_x: 0.,
padding_y: 0.,
dpr: 0.,
};
let lines = message_buffer.message().unwrap().text(&size);
assert_eq!(lines, vec![String::from("ha"), String::from("ha")]);
}
#[test]
fn add_newline_for_button() {
let input = "test";
let mut message_buffer = MessageBuffer::new();
message_buffer
.tx()
.send(Message::new(input.into(), color::RED))
.unwrap();
let size = SizeInfo {
width: 5.,
height: 10.,
cell_width: 1.,
cell_height: 1.,
padding_x: 0.,
padding_y: 0.,
dpr: 0.,
};
let lines = message_buffer.message().unwrap().text(&size);
assert_eq!(lines, vec![String::from("t [X]"), String::from("est ")]);
}
#[test]
fn remove_topic() {
let mut message_buffer = MessageBuffer::new();
for i in 0..10 {
let mut msg = Message::new(i.to_string(), color::RED);
if i % 2 == 0 && i < 5 {
msg.set_topic("topic".into());
}
message_buffer.tx().send(msg).unwrap();
}
message_buffer.remove_topic("topic");
// Count number of messages
let mut num_messages = 0;
while message_buffer.message().is_some() {
num_messages += 1;
message_buffer.pop();
}
assert_eq!(num_messages, 7);
}
#[test]
fn pop() {
let mut message_buffer = MessageBuffer::new();
let one = Message::new(String::from("one"), color::RED);
message_buffer.tx().send(one.clone()).unwrap();
let two = Message::new(String::from("two"), color::YELLOW);
message_buffer.tx().send(two.clone()).unwrap();
assert_eq!(message_buffer.message(), Some(one));
message_buffer.pop();
assert_eq!(message_buffer.message(), Some(two));
}
#[test]
fn wrap_on_words() {
let input = "a\nbc defg";
let mut message_buffer = MessageBuffer::new();
message_buffer
.tx()
.send(Message::new(input.into(), color::RED))
.unwrap();
let size = SizeInfo {
width: 5.,
height: 10.,
cell_width: 1.,
cell_height: 1.,
padding_x: 0.,
padding_y: 0.,
dpr: 0.,
};
let lines = message_buffer.message().unwrap().text(&size);
assert_eq!(
lines,
vec![
String::from("a [X]"),
String::from("bc "),
String::from("defg ")
]
);
}
#[test]
fn remove_duplicates() {
let mut message_buffer = MessageBuffer::new();
for _ in 0..10 {
let msg = Message::new(String::from("test"), color::RED);
message_buffer.tx().send(msg).unwrap();
}
message_buffer.tx().send(Message::new(String::from("other"), color::RED)).unwrap();
message_buffer.tx().send(Message::new(String::from("test"), color::YELLOW)).unwrap();
let _ = message_buffer.message();
message_buffer.pop();
// Count number of messages
let mut num_messages = 0;
while message_buffer.message().is_some() {
num_messages += 1;
message_buffer.pop();
}
assert_eq!(num_messages, 2);
}
}

View file

@ -29,12 +29,12 @@ use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
use crate::gl::types::*; use crate::gl::types::*;
use crate::gl; use crate::gl;
use crate::index::{Column, Line, RangeInclusive}; use crate::index::{Column, Line, RangeInclusive};
use crate::Rgb; use crate::term::color::Rgb;
use crate::config::{self, Config, Delta}; use crate::config::{self, Config, Delta};
use crate::term::{self, cell, RenderableCell}; use crate::term::{self, cell, RenderableCell};
use crate::renderer::lines::Lines; use crate::renderer::rects::{Rect, Rects};
pub mod lines; pub mod rects;
// Shader paths for live reload // Shader paths for live reload
static TEXT_SHADER_F_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.f.glsl"); static TEXT_SHADER_F_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.f.glsl");
@ -668,7 +668,7 @@ impl QuadRenderer {
config: &Config, config: &Config,
props: &term::SizeInfo, props: &term::SizeInfo,
visual_bell_intensity: f64, visual_bell_intensity: f64,
cell_line_rects: Lines, cell_line_rects: Rects,
) { ) {
// Swap to rectangle rendering program // Swap to rectangle rendering program
unsafe { unsafe {
@ -866,20 +866,6 @@ impl QuadRenderer {
} }
} }
#[derive(Debug, Copy, Clone)]
pub struct Rect<T> {
x: T,
y: T,
width: T,
height: T,
}
impl<T> Rect<T> {
pub fn new(x: T, y: T, width: T, height: T) -> Self {
Rect { x, y, width, height }
}
}
impl<'a> RenderApi<'a> { impl<'a> RenderApi<'a> {
pub fn clear(&self, color: Rgb) { pub fn clear(&self, color: Rgb) {
let alpha = self.config.background_opacity().get(); let alpha = self.config.background_opacity().get();
@ -941,8 +927,9 @@ impl<'a> RenderApi<'a> {
string: &str, string: &str,
line: Line, line: Line,
glyph_cache: &mut GlyphCache, glyph_cache: &mut GlyphCache,
color: Rgb color: Option<Rgb>
) { ) {
let bg_alpha = color.map(|_| 1.0).unwrap_or(0.0);
let col = Column(0); let col = Column(0);
let cells = string let cells = string
@ -956,10 +943,10 @@ impl<'a> RenderApi<'a> {
chars[0] = c; chars[0] = c;
chars chars
}, },
bg: color, bg: color.unwrap_or(Rgb { r: 0, g: 0, b: 0}),
fg: Rgb { r: 0, g: 0, b: 0 }, fg: Rgb { r: 0, g: 0, b: 0 },
flags: cell::Flags::empty(), flags: cell::Flags::empty(),
bg_alpha: 1.0, bg_alpha,
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();

View file

@ -13,14 +13,27 @@
// limitations under the License. // limitations under the License.
use std::collections::HashMap; use std::collections::HashMap;
use crate::renderer::Rect;
use crate::term::cell::Flags; use crate::term::cell::Flags;
use crate::term::{RenderableCell, SizeInfo}; use crate::term::{RenderableCell, SizeInfo};
use crate::Rgb; use crate::term::color::Rgb;
use font::Metrics; use font::Metrics;
/// Lines for underline and strikeout. #[derive(Debug, Copy, Clone)]
pub struct Lines<'a> { pub struct Rect<T> {
pub x: T,
pub y: T,
pub width: T,
pub height: T,
}
impl<T> Rect<T> {
pub fn new(x: T, y: T, width: T, height: T) -> Self {
Rect { x, y, width, height }
}
}
/// Rects for underline, strikeout and more.
pub struct Rects<'a> {
inner: Vec<(Rect<f32>, Rgb)>, inner: Vec<(Rect<f32>, Rgb)>,
last_starts: HashMap<Flags, Option<RenderableCell>>, last_starts: HashMap<Flags, Option<RenderableCell>>,
last_cell: Option<RenderableCell>, last_cell: Option<RenderableCell>,
@ -28,7 +41,7 @@ pub struct Lines<'a> {
size: &'a SizeInfo, size: &'a SizeInfo,
} }
impl<'a> Lines<'a> { impl<'a> Rects<'a> {
pub fn new(metrics: &'a Metrics, size: &'a SizeInfo) -> Self { pub fn new(metrics: &'a Metrics, size: &'a SizeInfo) -> Self {
let mut last_starts = HashMap::new(); let mut last_starts = HashMap::new();
last_starts.insert(Flags::UNDERLINE, None); last_starts.insert(Flags::UNDERLINE, None);
@ -43,7 +56,7 @@ impl<'a> Lines<'a> {
} }
} }
/// Convert the stored lines to rectangles for the renderer. /// Convert the stored rects to rectangles for the renderer.
pub fn rects(mut self) -> Vec<(Rect<f32>, Rgb)> { pub fn rects(mut self) -> Vec<(Rect<f32>, Rgb)> {
// If there's still a line pending, draw it until the last cell // If there's still a line pending, draw it until the last cell
for (flag, start_cell) in self.last_starts.iter_mut() { for (flag, start_cell) in self.last_starts.iter_mut() {
@ -107,6 +120,11 @@ impl<'a> Lines<'a> {
self.last_cell = Some(*cell); self.last_cell = Some(*cell);
} }
// Add a rectangle
pub fn push(&mut self, rect: Rect<f32>, color: Rgb) {
self.inner.push((rect, color));
}
} }
/// Create a rectangle that starts on the left of `start` and ends on the right /// Create a rectangle that starts on the left of `start` and ends on the right

View file

@ -1,11 +1,38 @@
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut, Mul};
use std::fmt; use std::fmt;
use crate::{Rgb, ansi}; use crate::ansi;
use crate::config::Colors; use crate::config::Colors;
pub const COUNT: usize = 270; pub const COUNT: usize = 270;
pub const RED: Rgb = Rgb { r: 0xff, g: 0x0, b: 0x0 };
pub const YELLOW: Rgb = Rgb { r: 0xff, g: 0xff, b: 0x0 };
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default, Serialize, Deserialize)]
pub struct Rgb {
pub r: u8,
pub g: u8,
pub b: u8,
}
// a multiply function for Rgb, as the default dim is just *2/3
impl Mul<f32> for Rgb {
type Output = Rgb;
fn mul(self, rhs: f32) -> Rgb {
let result = Rgb {
r: (f32::from(self.r) * rhs).max(0.0).min(255.0) as u8,
g: (f32::from(self.g) * rhs).max(0.0).min(255.0) as u8,
b: (f32::from(self.b) * rhs).max(0.0).min(255.0) as u8
};
trace!("Scaling RGB by {} from {:?} to {:?}", rhs, self, result);
result
}
}
/// List of indexed colors /// List of indexed colors
/// ///
/// The first 16 entries are the standard ansi named colors. Items 16..232 are /// The first 16 entries are the standard ansi named colors. Items 16..232 are

View file

@ -27,16 +27,17 @@ use crate::grid::{BidirectionalIterator, Grid, Indexed, IndexRegion, DisplayIter
use crate::index::{self, Point, Column, Line, IndexRange, Contains, RangeInclusive, Linear}; use crate::index::{self, Point, Column, Line, IndexRange, Contains, RangeInclusive, Linear};
use crate::selection::{self, Selection, Locations}; use crate::selection::{self, Selection, Locations};
use crate::config::{Config, VisualBellAnimation}; use crate::config::{Config, VisualBellAnimation};
use crate::{MouseCursor, Rgb}; use crate::MouseCursor;
use copypasta::{Clipboard, Load, Store}; use copypasta::{Clipboard, Load, Store};
use crate::input::FONT_SIZE_STEP; use crate::input::FONT_SIZE_STEP;
use crate::logging::LoggerProxy;
use crate::url::UrlParser; use crate::url::UrlParser;
use crate::message_bar::MessageBuffer;
use crate::term::color::Rgb;
use crate::term::cell::{LineLength, Cell};
use crate::tty;
pub mod cell; pub mod cell;
pub mod color; pub mod color;
pub use self::cell::Cell;
use self::cell::LineLength;
/// A type that can expand a given point to a region /// A type that can expand a given point to a region
/// ///
@ -793,8 +794,11 @@ pub struct Term {
/// Automatically scroll to bottom when new lines are added /// Automatically scroll to bottom when new lines are added
auto_scroll: bool, auto_scroll: bool,
/// Proxy object for clearing displayed errors and warnings /// Buffer to store messages for the message bar
logger_proxy: Option<LoggerProxy>, message_buffer: MessageBuffer,
/// Hint that Alacritty should be closed
should_exit: bool,
} }
/// Terminal size info /// Terminal size info
@ -835,10 +839,10 @@ impl SizeInfo {
} }
pub fn contains_point(&self, x: usize, y:usize) -> bool { pub fn contains_point(&self, x: usize, y:usize) -> bool {
x <= (self.width - self.padding_x) as usize && x < (self.width - self.padding_x) as usize
x >= self.padding_x as usize && && x >= self.padding_x as usize
y <= (self.height - self.padding_y) as usize && && y < (self.height - self.padding_y) as usize
y >= self.padding_y as usize && y >= self.padding_y as usize
} }
pub fn pixels_to_coords(&self, x: usize, y: usize) -> Point { pub fn pixels_to_coords(&self, x: usize, y: usize) -> Point {
@ -858,14 +862,6 @@ impl Term {
&self.grid.selection &self.grid.selection
} }
/// Clear displayed errors and warnings.
pub fn clear_log(&mut self) {
if let Some(ref mut logger_proxy) = self.logger_proxy {
logger_proxy.clear();
}
}
pub fn selection_mut(&mut self) -> &mut Option<Selection> { pub fn selection_mut(&mut self) -> &mut Option<Selection> {
&mut self.grid.selection &mut self.grid.selection
} }
@ -885,7 +881,7 @@ impl Term {
self.next_mouse_cursor.take() self.next_mouse_cursor.take()
} }
pub fn new(config: &Config, size: SizeInfo) -> Term { pub fn new(config: &Config, size: SizeInfo, message_buffer: MessageBuffer) -> Term {
let num_cols = size.cols(); let num_cols = size.cols();
let num_lines = size.lines(); let num_lines = size.lines();
@ -929,14 +925,11 @@ impl Term {
dynamic_title: config.dynamic_title(), dynamic_title: config.dynamic_title(),
tabspaces, tabspaces,
auto_scroll: config.scrolling().auto_scroll, auto_scroll: config.scrolling().auto_scroll,
logger_proxy: None, message_buffer,
should_exit: false,
} }
} }
pub fn set_logger_proxy(&mut self, logger_proxy: LoggerProxy) {
self.logger_proxy = Some(logger_proxy);
}
pub fn change_font_size(&mut self, delta: f32) { pub fn change_font_size(&mut self, delta: f32) {
// Saturating addition with minimum font size FONT_SIZE_STEP // Saturating addition with minimum font size FONT_SIZE_STEP
let new_size = self.font_size + Size::new(delta); let new_size = self.font_size + Size::new(delta);
@ -1169,7 +1162,7 @@ impl Term {
} }
/// Resize terminal to new dimensions /// Resize terminal to new dimensions
pub fn resize(&mut self, size : &SizeInfo) { pub fn resize(&mut self, size: &SizeInfo) {
debug!("Resizing terminal"); debug!("Resizing terminal");
// Bounds check; lots of math assumes width and height are > 0 // Bounds check; lots of math assumes width and height are > 0
@ -1184,6 +1177,10 @@ impl Term {
let mut num_cols = size.cols(); let mut num_cols = size.cols();
let mut num_lines = size.lines(); let mut num_lines = size.lines();
if let Some(message) = self.message_buffer.message() {
num_lines -= message.text(size).len();
}
self.size_info = *size; self.size_info = *size;
if old_cols == num_cols && old_lines == num_lines { if old_cols == num_cols && old_lines == num_lines {
@ -1315,6 +1312,26 @@ impl Term {
pub fn background_color(&self) -> Rgb { pub fn background_color(&self) -> Rgb {
self.colors[NamedColor::Background] self.colors[NamedColor::Background]
} }
#[inline]
pub fn message_buffer_mut(&mut self) -> &mut MessageBuffer {
&mut self.message_buffer
}
#[inline]
pub fn message_buffer(&self) -> &MessageBuffer {
&self.message_buffer
}
#[inline]
pub fn exit(&mut self) {
self.should_exit = true;
}
#[inline]
pub fn should_exit(&self) -> bool {
tty::process_should_exit() || self.should_exit
}
} }
impl ansi::TermInfo for Term { impl ansi::TermInfo for Term {
@ -1859,10 +1876,7 @@ impl ansi::Handler for Term {
.each(|cell| cell.reset(&template)); .each(|cell| cell.reset(&template));
} }
}, },
ansi::ClearMode::All => { ansi::ClearMode::All => self.grid.region_mut(..).each(|c| c.reset(&template)),
self.clear_log();
self.grid.region_mut(..).each(|c| c.reset(&template));
},
ansi::ClearMode::Above => { ansi::ClearMode::Above => {
// If clearing more than one line // If clearing more than one line
if self.cursor.point.line > Line(1) { if self.cursor.point.line > Line(1) {
@ -2129,6 +2143,7 @@ mod tests {
use crate::input::FONT_SIZE_STEP; use crate::input::FONT_SIZE_STEP;
use font::Size; use font::Size;
use crate::config::Config; use crate::config::Config;
use crate::message_bar::MessageBuffer;
#[test] #[test]
fn semantic_selection_works() { fn semantic_selection_works() {
@ -2141,7 +2156,7 @@ mod tests {
padding_y: 0.0, padding_y: 0.0,
dpr: 1.0, dpr: 1.0,
}; };
let mut term = Term::new(&Default::default(), size); let mut term = Term::new(&Default::default(), size, MessageBuffer::new());
let mut grid: Grid<Cell> = Grid::new(Line(3), Column(5), 0, Cell::default()); let mut grid: Grid<Cell> = Grid::new(Line(3), Column(5), 0, Cell::default());
for i in 0..5 { for i in 0..5 {
for j in 0..2 { for j in 0..2 {
@ -2185,7 +2200,7 @@ mod tests {
padding_y: 0.0, padding_y: 0.0,
dpr: 1.0, dpr: 1.0,
}; };
let mut term = Term::new(&Default::default(), size); let mut term = Term::new(&Default::default(), size, MessageBuffer::new());
let mut grid: Grid<Cell> = Grid::new(Line(1), Column(5), 0, Cell::default()); let mut grid: Grid<Cell> = Grid::new(Line(1), Column(5), 0, Cell::default());
for i in 0..5 { for i in 0..5 {
grid[Line(0)][Column(i)].c = 'a'; grid[Line(0)][Column(i)].c = 'a';
@ -2211,7 +2226,7 @@ mod tests {
padding_y: 0.0, padding_y: 0.0,
dpr: 1.0, dpr: 1.0,
}; };
let mut term = Term::new(&Default::default(), size); let mut term = Term::new(&Default::default(), size, MessageBuffer::new());
let mut grid: Grid<Cell> = Grid::new(Line(3), Column(3), 0, Cell::default()); let mut grid: Grid<Cell> = Grid::new(Line(3), Column(3), 0, Cell::default());
for l in 0..3 { for l in 0..3 {
if l != 1 { if l != 1 {
@ -2256,7 +2271,7 @@ mod tests {
padding_y: 0.0, padding_y: 0.0,
dpr: 1.0, dpr: 1.0,
}; };
let mut term = Term::new(&Default::default(), size); let mut term = Term::new(&Default::default(), size, MessageBuffer::new());
let cursor = Point::new(Line(0), Column(0)); let cursor = Point::new(Line(0), Column(0));
term.configure_charset(CharsetIndex::G0, term.configure_charset(CharsetIndex::G0,
StandardCharset::SpecialCharacterAndLineDrawing); StandardCharset::SpecialCharacterAndLineDrawing);
@ -2276,7 +2291,7 @@ mod tests {
dpr: 1.0, dpr: 1.0,
}; };
let config: Config = Default::default(); let config: Config = Default::default();
let mut term: Term = Term::new(&config, size); let mut term: Term = Term::new(&config, size, MessageBuffer::new());
term.change_font_size(font_size); term.change_font_size(font_size);
let expected_font_size: Size = config.font().size() + Size::new(font_size); let expected_font_size: Size = config.font().size() + Size::new(font_size);
@ -2305,7 +2320,7 @@ mod tests {
dpr: 1.0, dpr: 1.0,
}; };
let config: Config = Default::default(); let config: Config = Default::default();
let mut term: Term = Term::new(&config, size); let mut term: Term = Term::new(&config, size, MessageBuffer::new());
term.change_font_size(-100.0); term.change_font_size(-100.0);
@ -2325,7 +2340,7 @@ mod tests {
dpr: 1.0, dpr: 1.0,
}; };
let config: Config = Default::default(); let config: Config = Default::default();
let mut term: Term = Term::new(&config, size); let mut term: Term = Term::new(&config, size, MessageBuffer::new());
term.change_font_size(10.0); term.change_font_size(10.0);
term.reset_font_size(); term.reset_font_size();
@ -2346,7 +2361,7 @@ mod tests {
dpr: 1.0 dpr: 1.0
}; };
let config: Config = Default::default(); let config: Config = Default::default();
let mut term: Term = Term::new(&config, size); let mut term: Term = Term::new(&config, size, MessageBuffer::new());
// Add one line of scrollback // Add one line of scrollback
term.grid.scroll_up(&(Line(0)..Line(1)), Line(1), &Cell::default()); term.grid.scroll_up(&(Line(0)..Line(1)), Line(1), &Cell::default());
@ -2373,6 +2388,7 @@ mod benches {
use crate::grid::Grid; use crate::grid::Grid;
use crate::config::Config; use crate::config::Config;
use crate::message_bar::MessageBuffer;
use super::{SizeInfo, Term}; use super::{SizeInfo, Term};
use super::cell::Cell; use super::cell::Cell;
@ -2411,7 +2427,7 @@ mod benches {
let config = Config::default(); let config = Config::default();
let mut terminal = Term::new(&config, size); let mut terminal = Term::new(&config, size, MessageBuffer::new());
mem::swap(&mut terminal.grid, &mut grid); mem::swap(&mut terminal.grid, &mut grid);
b.iter(|| { b.iter(|| {

View file

@ -128,7 +128,9 @@ mod tests {
use crate::grid::Grid; use crate::grid::Grid;
use crate::index::{Column, Line, Point}; use crate::index::{Column, Line, Point};
use crate::term::{Cell, Search, SizeInfo, Term}; use crate::term::{Search, SizeInfo, Term};
use crate::term::cell::Cell;
use crate::message_bar::MessageBuffer;
fn url_create_term(input: &str) -> Term { fn url_create_term(input: &str) -> Term {
let size = SizeInfo { let size = SizeInfo {
@ -141,7 +143,7 @@ mod tests {
dpr: 1.0, dpr: 1.0,
}; };
let mut term = Term::new(&Default::default(), size); let mut term = Term::new(&Default::default(), size, MessageBuffer::new());
let mut grid: Grid<Cell> = Grid::new(Line(1), Column(input.len()), 0, Cell::default()); let mut grid: Grid<Cell> = Grid::new(Line(1), Column(input.len()), 0, Cell::default());
for (i, c) in input.chars().enumerate() { for (i, c) in input.chars().enumerate() {

View file

@ -10,10 +10,11 @@ use alacritty::Grid;
use alacritty::Term; use alacritty::Term;
use alacritty::ansi; use alacritty::ansi;
use alacritty::index::Column; use alacritty::index::Column;
use alacritty::term::Cell; use alacritty::term::cell::Cell;
use alacritty::term::SizeInfo; use alacritty::term::SizeInfo;
use alacritty::util::fmt::{Red, Green}; use alacritty::util::fmt::{Red, Green};
use alacritty::config::Config; use alacritty::config::Config;
use alacritty::message_bar::MessageBuffer;
macro_rules! ref_tests { macro_rules! ref_tests {
($($name:ident)*) => { ($($name:ident)*) => {
@ -90,7 +91,7 @@ fn ref_test(dir: &Path) {
let mut config: Config = Default::default(); let mut config: Config = Default::default();
config.set_history(ref_config.history_size); config.set_history(ref_config.history_size);
let mut terminal = Term::new(&config, size); let mut terminal = Term::new(&config, size, MessageBuffer::new());
let mut parser = ansi::Processor::new(); let mut parser = ansi::Processor::new();
for byte in recording { for byte in recording {