Refactor config parsing files
This is a large refactor of the config parsing structure, attempting to reduce the size of the file a bit by splitting it up into different modules with more specific purposes. This also fixes #2279.
This commit is contained in:
parent
7738c52ed4
commit
5d173f6df3
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -17,15 +17,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Added ToggleFullscreen action
|
- Added ToggleFullscreen action
|
||||||
- On macOS, there's a ToggleSimpleFullscreen action which allows switching to
|
- On macOS, there's a ToggleSimpleFullscreen action which allows switching to
|
||||||
fullscreen without occupying another space
|
fullscreen without occupying another space
|
||||||
- A new window option `startup_mode` which controls how the window is created
|
- A new window option `window.startup_mode` which controls how the window is created
|
||||||
- `_NET_WM_ICON` property is set on X11 now, allowing for WMs to show icons in titlebars
|
- `_NET_WM_ICON` property is set on X11 now, allowing for WMs to show icons in titlebars
|
||||||
- Current Git commit hash to `alacritty --version`
|
- Current Git commit hash to `alacritty --version`
|
||||||
|
- Config options `window.title` and `window.class`
|
||||||
|
- Config option `working_directory`
|
||||||
|
- Config group `debug` with the options `debug.log_level`, `debug.print_events`
|
||||||
|
and `debug.ref_test`
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- On Windows, Alacritty will now use the native DirectWrite font API
|
- On Windows, Alacritty will now use the native DirectWrite font API
|
||||||
- The `start_maximized` window option is now `startup_mode: Maximized`
|
- The `start_maximized` window option is now `startup_mode: Maximized`
|
||||||
- Cells with identical foreground and background will now show their text upon selection/inversion
|
- Cells with identical foreground and background will now show their text upon selection/inversion
|
||||||
|
- Default Window padding to 0x0
|
||||||
|
- Moved config option `render_timer` and `persistent_logging` to the `debug` group
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
@ -36,6 +42,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Mouse mode generating events when the cell has not changed
|
- Mouse mode generating events when the cell has not changed
|
||||||
- Selections not automatically expanding across double-width characters
|
- Selections not automatically expanding across double-width characters
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Deprecated `mouse.faux_scrollback_lines` config field
|
||||||
|
- Deprecated `custom_cursor_colors` config field
|
||||||
|
- Deprecated `hide_cursor_when_typing` config field
|
||||||
|
- Deprecated `cursor_style` config field
|
||||||
|
- Deprecated `unfocused_hollow_cursor` config field
|
||||||
|
- Deprecated `dimensions` config field
|
||||||
|
|
||||||
## Version 0.3.2
|
## Version 0.3.2
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -32,8 +32,10 @@ dependencies = [
|
||||||
"env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc_tools_util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc_tools_util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_yaml 0.8.9 (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)",
|
||||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -44,7 +46,6 @@ 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)",
|
||||||
"clipboard 0.5.0 (git+https://github.com/chrisduerr/rust-clipboard)",
|
"clipboard 0.5.0 (git+https://github.com/chrisduerr/rust-clipboard)",
|
||||||
"crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"dunce 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dunce 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -77,7 +78,6 @@ dependencies = [
|
||||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winpty 0.1.0",
|
"winpty 0.1.0",
|
||||||
"x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -544,7 +544,7 @@ name = "derivative"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -681,7 +681,7 @@ name = "euclid_macros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -709,7 +709,7 @@ name = "failure_derive"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1373,9 +1373,9 @@ dependencies = [
|
||||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"openssl 0.10.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"openssl 0.10.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"openssl-sys 0.9.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
"openssl-sys 0.9.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1461,7 +1461,7 @@ name = "num-derive"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -1538,7 +1538,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
version = "0.10.21"
|
version = "0.10.22"
|
||||||
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)",
|
||||||
|
@ -1546,7 +1546,7 @@ dependencies = [
|
||||||
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"openssl-sys 0.9.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
"openssl-sys 0.9.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1556,7 +1556,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.45"
|
version = "0.9.46"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1679,7 +1679,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "0.4.29"
|
version = "0.4.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1712,7 +1712,7 @@ name = "quote"
|
||||||
version = "0.6.12"
|
version = "0.6.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2047,7 +2047,7 @@ name = "serde_derive"
|
||||||
version = "1.0.91"
|
version = "1.0.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -2243,7 +2243,7 @@ name = "syn"
|
||||||
version = "0.15.34"
|
version = "0.15.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -2253,7 +2253,7 @@ name = "synstructure"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -2690,7 +2690,7 @@ name = "wayland-scanner"
|
||||||
version = "0.21.12"
|
version = "0.21.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -2700,7 +2700,7 @@ name = "wayland-scanner"
|
||||||
version = "0.22.2"
|
version = "0.22.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -3068,9 +3068,9 @@ dependencies = [
|
||||||
"checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d"
|
"checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d"
|
||||||
"checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
"checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||||
"checksum objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
"checksum objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||||
"checksum openssl 0.10.21 (registry+https://github.com/rust-lang/crates.io-index)" = "615b325b964d8fb0533e7fad5867f63677bbc79a274c9cd7a19443e1a6fcdd9e"
|
"checksum openssl 0.10.22 (registry+https://github.com/rust-lang/crates.io-index)" = "a51f452b82d622fc8dd973d7266e9055ac64af25b957d9ced3989142dc61cb6b"
|
||||||
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
||||||
"checksum openssl-sys 0.9.45 (registry+https://github.com/rust-lang/crates.io-index)" = "ce906a1d521507a94645974fc9ab0fb70ceeb789f7240b85617ca3d8d2cd2f46"
|
"checksum openssl-sys 0.9.46 (registry+https://github.com/rust-lang/crates.io-index)" = "05636e06b4f8762d4b81d24a351f3966f38bd25ccbcfd235606c91fdb82cc60f"
|
||||||
"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
|
"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
|
||||||
"checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b"
|
"checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b"
|
||||||
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
||||||
|
@ -3085,7 +3085,7 @@ dependencies = [
|
||||||
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
|
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
|
||||||
"checksum png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "63daf481fdd0defa2d1d2be15c674fbfa1b0fd71882c303a91f9a79b3252c359"
|
"checksum png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "63daf481fdd0defa2d1d2be15c674fbfa1b0fd71882c303a91f9a79b3252c359"
|
||||||
"checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd"
|
"checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd"
|
||||||
"checksum proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)" = "64c827cea7a7ab30ce4593e5e04d7a11617ad6ece2fa230605a78b00ff965316"
|
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||||
"checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d"
|
"checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d"
|
||||||
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
||||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||||
|
|
|
@ -34,8 +34,8 @@ window:
|
||||||
# Blank space added around the window in pixels. This padding is scaled
|
# Blank space added around the window in pixels. This padding is scaled
|
||||||
# by DPI and the specified value is always added at both opposing sides.
|
# by DPI and the specified value is always added at both opposing sides.
|
||||||
padding:
|
padding:
|
||||||
x: 2
|
x: 0
|
||||||
y: 2
|
y: 0
|
||||||
|
|
||||||
# Spread additional padding evenly around the terminal content.
|
# Spread additional padding evenly around the terminal content.
|
||||||
dynamic_padding: false
|
dynamic_padding: false
|
||||||
|
@ -62,6 +62,12 @@ window:
|
||||||
# - SimpleFullscreen
|
# - SimpleFullscreen
|
||||||
startup_mode: Windowed
|
startup_mode: Windowed
|
||||||
|
|
||||||
|
# Window title
|
||||||
|
#title: Alacritty
|
||||||
|
|
||||||
|
# Window class (Linux only):
|
||||||
|
#class: Alacritty
|
||||||
|
|
||||||
scrolling:
|
scrolling:
|
||||||
# Maximum number of lines in the scrollback buffer.
|
# Maximum number of lines in the scrollback buffer.
|
||||||
# Specifying '0' will disable scrolling.
|
# Specifying '0' will disable scrolling.
|
||||||
|
@ -161,12 +167,6 @@ font:
|
||||||
# effect.
|
# effect.
|
||||||
use_thin_strokes: true
|
use_thin_strokes: true
|
||||||
|
|
||||||
# Display the time it takes to redraw each frame.
|
|
||||||
render_timer: false
|
|
||||||
|
|
||||||
# Keep the log file after quitting Alacritty.
|
|
||||||
persistent_logging: false
|
|
||||||
|
|
||||||
# If `true`, bold text is drawn using the bright color variants.
|
# If `true`, bold text is drawn using the bright color variants.
|
||||||
draw_bold_text_with_bright_colors: true
|
draw_bold_text_with_bright_colors: true
|
||||||
|
|
||||||
|
@ -370,6 +370,12 @@ live_config_reload: true
|
||||||
# args:
|
# args:
|
||||||
# - --login
|
# - --login
|
||||||
|
|
||||||
|
# Startup directory
|
||||||
|
#
|
||||||
|
# Directory the shell is started in. If this is unset, or `None`, the working
|
||||||
|
# directory of the parent process will be used.
|
||||||
|
working_directory: None
|
||||||
|
|
||||||
# Windows 10 ConPTY backend (Windows only)
|
# Windows 10 ConPTY backend (Windows only)
|
||||||
#
|
#
|
||||||
# This will enable better color support and may resolve other issues,
|
# This will enable better color support and may resolve other issues,
|
||||||
|
@ -384,6 +390,30 @@ enable_experimental_conpty_backend: false
|
||||||
# Send ESC (\x1b) before characters when alt is pressed.
|
# Send ESC (\x1b) before characters when alt is pressed.
|
||||||
alt_send_esc: true
|
alt_send_esc: true
|
||||||
|
|
||||||
|
debug:
|
||||||
|
# Display the time it takes to redraw each frame.
|
||||||
|
render_timer: false
|
||||||
|
|
||||||
|
# Keep the log file after quitting Alacritty.
|
||||||
|
persistent_logging: false
|
||||||
|
|
||||||
|
# Log level
|
||||||
|
#
|
||||||
|
# Values for `log_level`:
|
||||||
|
# - None
|
||||||
|
# - Error
|
||||||
|
# - Warn
|
||||||
|
# - Info
|
||||||
|
# - Debug
|
||||||
|
# - Trace
|
||||||
|
log_level: Warn
|
||||||
|
|
||||||
|
# Print all received window events.
|
||||||
|
print_events: false
|
||||||
|
|
||||||
|
# Record all characters and escape sequences as test data.
|
||||||
|
ref_test: false
|
||||||
|
|
||||||
# Key bindings
|
# Key bindings
|
||||||
#
|
#
|
||||||
# Key bindings are specified as a list of objects. Each binding will specify a
|
# Key bindings are specified as a list of objects. Each binding will specify a
|
||||||
|
@ -423,6 +453,7 @@ alt_send_esc: true
|
||||||
# Values for `mods`:
|
# Values for `mods`:
|
||||||
# - Command
|
# - Command
|
||||||
# - Control
|
# - Control
|
||||||
|
# - Option
|
||||||
# - Super
|
# - Super
|
||||||
# - Shift
|
# - Shift
|
||||||
# - Alt
|
# - Alt
|
||||||
|
|
|
@ -15,11 +15,15 @@ log = "0.4"
|
||||||
time = "0.1.40"
|
time = "0.1.40"
|
||||||
env_logger = "0.6.0"
|
env_logger = "0.6.0"
|
||||||
crossbeam-channel = "0.3.8"
|
crossbeam-channel = "0.3.8"
|
||||||
|
serde_yaml = "0.8"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
rustc_tools_util = "0.1"
|
rustc_tools_util = "0.1"
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(not(windows))'.dependencies]
|
||||||
|
xdg = "2"
|
||||||
|
|
||||||
|
[target.'cfg(any(target_os = "macos", windows))'.dependencies]
|
||||||
dirs = "1.0.2"
|
dirs = "1.0.2"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let hash = rustc_tools_util::get_commit_hash()
|
let hash = rustc_tools_util::get_commit_hash().expect("couldn't get commit hash");
|
||||||
.expect("couldn't get commit hash");
|
|
||||||
println!("cargo:rustc-env=GIT_HASH={}", hash);
|
println!("cargo:rustc-env=GIT_HASH={}", hash);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,184 +12,293 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::borrow::Cow;
|
||||||
|
use std::cmp::max;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use ::log;
|
|
||||||
use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
|
use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
|
||||||
|
use log::{self, LevelFilter};
|
||||||
|
|
||||||
use alacritty_terminal::config::{Options, Delta, Dimensions, Shell};
|
use alacritty_terminal::config::{Config, Delta, Dimensions, Shell};
|
||||||
use alacritty_terminal::index::{Column, Line};
|
use alacritty_terminal::index::{Column, Line};
|
||||||
use alacritty_terminal::window::DEFAULT_NAME;
|
use alacritty_terminal::window::DEFAULT_NAME;
|
||||||
|
|
||||||
/// Build `Options` from command line arguments.
|
/// Options specified on the command line
|
||||||
pub fn options() -> Options {
|
pub struct Options {
|
||||||
let mut options = Options::default();
|
pub live_config_reload: Option<bool>,
|
||||||
|
pub print_events: bool,
|
||||||
let version_string = format!("{} ({})",
|
pub ref_test: bool,
|
||||||
crate_version!(),
|
pub dimensions: Option<Dimensions>,
|
||||||
env!("GIT_HASH"));
|
pub position: Option<Delta<i32>>,
|
||||||
|
pub title: Option<String>,
|
||||||
let matches = App::new(crate_name!())
|
pub class: Option<String>,
|
||||||
.version(version_string.as_str())
|
pub log_level: LevelFilter,
|
||||||
.author(crate_authors!("\n"))
|
pub command: Option<Shell<'static>>,
|
||||||
.about(crate_description!())
|
pub working_dir: Option<PathBuf>,
|
||||||
.arg(Arg::with_name("ref-test").long("ref-test").help("Generates ref test"))
|
pub config: Option<PathBuf>,
|
||||||
.arg(
|
pub persistent_logging: bool,
|
||||||
Arg::with_name("live-config-reload")
|
}
|
||||||
.long("live-config-reload")
|
|
||||||
.help("Enable automatic config reloading"),
|
impl Default for Options {
|
||||||
)
|
fn default() -> Options {
|
||||||
.arg(
|
Options {
|
||||||
Arg::with_name("no-live-config-reload")
|
live_config_reload: None,
|
||||||
.long("no-live-config-reload")
|
print_events: false,
|
||||||
.help("Disable automatic config reloading")
|
ref_test: false,
|
||||||
.conflicts_with("live-config-reload"),
|
dimensions: None,
|
||||||
)
|
position: None,
|
||||||
.arg(
|
title: None,
|
||||||
Arg::with_name("print-events")
|
class: None,
|
||||||
.long("print-events")
|
log_level: LevelFilter::Warn,
|
||||||
.help("Print all events to stdout"),
|
command: None,
|
||||||
)
|
working_dir: None,
|
||||||
.arg(
|
config: None,
|
||||||
Arg::with_name("persistent-logging")
|
persistent_logging: false,
|
||||||
.long("persistent-logging")
|
}
|
||||||
.help("Keep the log file after quitting Alacritty"),
|
}
|
||||||
)
|
}
|
||||||
.arg(
|
|
||||||
Arg::with_name("dimensions")
|
impl Options {
|
||||||
.long("dimensions")
|
/// Build `Options` from command line arguments.
|
||||||
.short("d")
|
pub fn new() -> Self {
|
||||||
.value_names(&["columns", "lines"])
|
let mut options = Options::default();
|
||||||
.help(
|
|
||||||
"Defines the window dimensions. Falls back to size specified by window \
|
let version_string = format!("{} ({})", crate_version!(), env!("GIT_HASH"));
|
||||||
manager if set to 0x0 [default: 0x0]",
|
|
||||||
),
|
let matches = App::new(crate_name!())
|
||||||
)
|
.version(version_string.as_str())
|
||||||
.arg(
|
.author(crate_authors!("\n"))
|
||||||
Arg::with_name("position")
|
.about(crate_description!())
|
||||||
.long("position")
|
.arg(Arg::with_name("ref-test").long("ref-test").help("Generates ref test"))
|
||||||
.allow_hyphen_values(true)
|
.arg(
|
||||||
.value_names(&["x-pos", "y-pos"])
|
Arg::with_name("live-config-reload")
|
||||||
.help(
|
.long("live-config-reload")
|
||||||
"Defines the window position. Falls back to position specified by window \
|
.help("Enable automatic config reloading"),
|
||||||
manager if unset [default: unset]",
|
)
|
||||||
),
|
.arg(
|
||||||
)
|
Arg::with_name("no-live-config-reload")
|
||||||
.arg(
|
.long("no-live-config-reload")
|
||||||
Arg::with_name("title")
|
.help("Disable automatic config reloading")
|
||||||
.long("title")
|
.conflicts_with("live-config-reload"),
|
||||||
.short("t")
|
)
|
||||||
.takes_value(true)
|
.arg(
|
||||||
.help(&format!("Defines the window title [default: {}]", DEFAULT_NAME)),
|
Arg::with_name("print-events")
|
||||||
)
|
.long("print-events")
|
||||||
.arg(
|
.help("Print all events to stdout"),
|
||||||
Arg::with_name("class")
|
)
|
||||||
.long("class")
|
.arg(
|
||||||
.takes_value(true)
|
Arg::with_name("persistent-logging")
|
||||||
.help(&format!("Defines window class on Linux [default: {}]", DEFAULT_NAME)),
|
.long("persistent-logging")
|
||||||
)
|
.help("Keep the log file after quitting Alacritty"),
|
||||||
.arg(
|
)
|
||||||
Arg::with_name("q")
|
.arg(
|
||||||
.short("q")
|
Arg::with_name("dimensions")
|
||||||
.multiple(true)
|
.long("dimensions")
|
||||||
.conflicts_with("v")
|
.short("d")
|
||||||
.help("Reduces the level of verbosity (the min level is -qq)"),
|
.value_names(&["columns", "lines"])
|
||||||
)
|
.help(
|
||||||
.arg(
|
"Defines the window dimensions. Falls back to size specified by window \
|
||||||
Arg::with_name("v")
|
manager if set to 0x0 [default: 0x0]",
|
||||||
.short("v")
|
),
|
||||||
.multiple(true)
|
)
|
||||||
.conflicts_with("q")
|
.arg(
|
||||||
.help("Increases the level of verbosity (the max level is -vvv)"),
|
Arg::with_name("position")
|
||||||
)
|
.long("position")
|
||||||
.arg(
|
.allow_hyphen_values(true)
|
||||||
Arg::with_name("working-directory")
|
.value_names(&["x-pos", "y-pos"])
|
||||||
.long("working-directory")
|
.help(
|
||||||
.takes_value(true)
|
"Defines the window position. Falls back to position specified by window \
|
||||||
.help("Start the shell in the specified working directory"),
|
manager if unset [default: unset]",
|
||||||
)
|
),
|
||||||
.arg(Arg::with_name("config-file").long("config-file").takes_value(true).help(
|
)
|
||||||
"Specify alternative configuration file [default: \
|
.arg(
|
||||||
$XDG_CONFIG_HOME/alacritty/alacritty.yml]",
|
Arg::with_name("title")
|
||||||
))
|
.long("title")
|
||||||
.arg(
|
.short("t")
|
||||||
Arg::with_name("command")
|
.takes_value(true)
|
||||||
.long("command")
|
.help(&format!("Defines the window title [default: {}]", DEFAULT_NAME)),
|
||||||
.short("e")
|
)
|
||||||
.multiple(true)
|
.arg(
|
||||||
.takes_value(true)
|
Arg::with_name("class")
|
||||||
.min_values(1)
|
.long("class")
|
||||||
.allow_hyphen_values(true)
|
.takes_value(true)
|
||||||
.help("Command and args to execute (must be last argument)"),
|
.help(&format!("Defines window class on Linux [default: {}]", DEFAULT_NAME)),
|
||||||
)
|
)
|
||||||
.get_matches();
|
.arg(
|
||||||
|
Arg::with_name("q")
|
||||||
if matches.is_present("ref-test") {
|
.short("q")
|
||||||
options.ref_test = true;
|
.multiple(true)
|
||||||
}
|
.conflicts_with("v")
|
||||||
|
.help("Reduces the level of verbosity (the min level is -qq)"),
|
||||||
if matches.is_present("print-events") {
|
)
|
||||||
options.print_events = true;
|
.arg(
|
||||||
}
|
Arg::with_name("v")
|
||||||
|
.short("v")
|
||||||
if matches.is_present("live-config-reload") {
|
.multiple(true)
|
||||||
options.live_config_reload = Some(true);
|
.conflicts_with("q")
|
||||||
} else if matches.is_present("no-live-config-reload") {
|
.help("Increases the level of verbosity (the max level is -vvv)"),
|
||||||
options.live_config_reload = Some(false);
|
)
|
||||||
}
|
.arg(
|
||||||
|
Arg::with_name("working-directory")
|
||||||
if matches.is_present("persistent-logging") {
|
.long("working-directory")
|
||||||
options.persistent_logging = true;
|
.takes_value(true)
|
||||||
}
|
.help("Start the shell in the specified working directory"),
|
||||||
|
)
|
||||||
if let Some(mut dimensions) = matches.values_of("dimensions") {
|
.arg(Arg::with_name("config-file").long("config-file").takes_value(true).help(
|
||||||
let width = dimensions.next().map(|w| w.parse().map(Column));
|
"Specify alternative configuration file [default: \
|
||||||
let height = dimensions.next().map(|h| h.parse().map(Line));
|
$XDG_CONFIG_HOME/alacritty/alacritty.yml]",
|
||||||
if let (Some(Ok(width)), Some(Ok(height))) = (width, height) {
|
))
|
||||||
options.dimensions = Some(Dimensions::new(width, height));
|
.arg(
|
||||||
}
|
Arg::with_name("command")
|
||||||
}
|
.long("command")
|
||||||
|
.short("e")
|
||||||
if let Some(mut position) = matches.values_of("position") {
|
.multiple(true)
|
||||||
let x = position.next().map(str::parse);
|
.takes_value(true)
|
||||||
let y = position.next().map(str::parse);
|
.min_values(1)
|
||||||
if let (Some(Ok(x)), Some(Ok(y))) = (x, y) {
|
.allow_hyphen_values(true)
|
||||||
options.position = Some(Delta { x, y });
|
.help("Command and args to execute (must be last argument)"),
|
||||||
}
|
)
|
||||||
}
|
.get_matches();
|
||||||
|
|
||||||
options.class = matches.value_of("class").map(ToOwned::to_owned);
|
if matches.is_present("ref-test") {
|
||||||
options.title = matches.value_of("title").map(ToOwned::to_owned);
|
options.ref_test = true;
|
||||||
|
}
|
||||||
match matches.occurrences_of("q") {
|
|
||||||
0 => {},
|
if matches.is_present("print-events") {
|
||||||
1 => options.log_level = log::LevelFilter::Error,
|
options.print_events = true;
|
||||||
2 | _ => options.log_level = log::LevelFilter::Off,
|
}
|
||||||
}
|
|
||||||
|
if matches.is_present("live-config-reload") {
|
||||||
match matches.occurrences_of("v") {
|
options.live_config_reload = Some(true);
|
||||||
0 if !options.print_events => {},
|
} else if matches.is_present("no-live-config-reload") {
|
||||||
0 | 1 => options.log_level = log::LevelFilter::Info,
|
options.live_config_reload = Some(false);
|
||||||
2 => options.log_level = log::LevelFilter::Debug,
|
}
|
||||||
3 | _ => options.log_level = log::LevelFilter::Trace,
|
|
||||||
}
|
if matches.is_present("persistent-logging") {
|
||||||
|
options.persistent_logging = true;
|
||||||
if let Some(dir) = matches.value_of("working-directory") {
|
}
|
||||||
options.working_dir = Some(PathBuf::from(dir.to_string()));
|
|
||||||
}
|
if let Some(mut dimensions) = matches.values_of("dimensions") {
|
||||||
|
let width = dimensions.next().map(|w| w.parse().map(Column));
|
||||||
if let Some(path) = matches.value_of("config-file") {
|
let height = dimensions.next().map(|h| h.parse().map(Line));
|
||||||
options.config = Some(PathBuf::from(path.to_string()));
|
if let (Some(Ok(width)), Some(Ok(height))) = (width, height) {
|
||||||
}
|
options.dimensions = Some(Dimensions::new(width, height));
|
||||||
|
}
|
||||||
if let Some(mut args) = matches.values_of("command") {
|
}
|
||||||
// The following unwrap is guaranteed to succeed.
|
|
||||||
// If 'command' exists it must also have a first item since
|
if let Some(mut position) = matches.values_of("position") {
|
||||||
// Arg::min_values(1) is set.
|
let x = position.next().map(str::parse);
|
||||||
let command = String::from(args.next().unwrap());
|
let y = position.next().map(str::parse);
|
||||||
let args = args.map(String::from).collect();
|
if let (Some(Ok(x)), Some(Ok(y))) = (x, y) {
|
||||||
options.command = Some(Shell::new_with_args(command, args));
|
options.position = Some(Delta { x, y });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
options
|
|
||||||
|
options.class = matches.value_of("class").map(ToOwned::to_owned);
|
||||||
|
options.title = matches.value_of("title").map(ToOwned::to_owned);
|
||||||
|
|
||||||
|
match matches.occurrences_of("q") {
|
||||||
|
0 => {},
|
||||||
|
1 => options.log_level = LevelFilter::Error,
|
||||||
|
2 | _ => options.log_level = LevelFilter::Off,
|
||||||
|
}
|
||||||
|
|
||||||
|
match matches.occurrences_of("v") {
|
||||||
|
0 if !options.print_events => options.log_level = LevelFilter::Warn,
|
||||||
|
0 | 1 => options.log_level = LevelFilter::Info,
|
||||||
|
2 => options.log_level = LevelFilter::Debug,
|
||||||
|
3 | _ => options.log_level = LevelFilter::Trace,
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(dir) = matches.value_of("working-directory") {
|
||||||
|
options.working_dir = Some(PathBuf::from(dir.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(path) = matches.value_of("config-file") {
|
||||||
|
options.config = Some(PathBuf::from(path.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(mut args) = matches.values_of("command") {
|
||||||
|
// The following unwrap is guaranteed to succeed.
|
||||||
|
// If 'command' exists it must also have a first item since
|
||||||
|
// Arg::min_values(1) is set.
|
||||||
|
let command = String::from(args.next().unwrap());
|
||||||
|
let args = args.map(String::from).collect();
|
||||||
|
options.command = Some(Shell::new_with_args(command, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
options
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn config_path(&self) -> Option<Cow<'_, Path>> {
|
||||||
|
self.config.as_ref().map(|p| Cow::Borrowed(p.as_path()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_config(self, mut config: Config) -> Config {
|
||||||
|
config.set_live_config_reload(
|
||||||
|
self.live_config_reload.unwrap_or_else(|| config.live_config_reload()),
|
||||||
|
);
|
||||||
|
config.set_working_directory(
|
||||||
|
self.working_dir.or_else(|| config.working_directory().to_owned()),
|
||||||
|
);
|
||||||
|
config.shell = self.command.or(config.shell);
|
||||||
|
|
||||||
|
config.window.dimensions = self.dimensions.unwrap_or(config.window.dimensions);
|
||||||
|
config.window.position = self.position.or(config.window.position);
|
||||||
|
config.window.title = self.title.or(config.window.title);
|
||||||
|
config.window.class = self.class.or(config.window.class);
|
||||||
|
|
||||||
|
config.set_dynamic_title(config.dynamic_title() && config.window.title.is_none());
|
||||||
|
|
||||||
|
config.debug.print_events = self.print_events || config.debug.print_events;
|
||||||
|
config.debug.log_level = max(config.debug.log_level, self.log_level);
|
||||||
|
config.debug.ref_test = self.ref_test || config.debug.ref_test;
|
||||||
|
|
||||||
|
if config.debug.print_events {
|
||||||
|
config.debug.log_level = max(config.debug.log_level, LevelFilter::Info);
|
||||||
|
}
|
||||||
|
|
||||||
|
config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use alacritty_terminal::config::{Config, DEFAULT_ALACRITTY_CONFIG};
|
||||||
|
|
||||||
|
use crate::cli::Options;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dynamic_title_ignoring_options_by_default() {
|
||||||
|
let config: Config =
|
||||||
|
::serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG).expect("deserialize config");
|
||||||
|
let old_dynamic_title = config.dynamic_title();
|
||||||
|
|
||||||
|
let config = Options::default().into_config(config);
|
||||||
|
|
||||||
|
assert_eq!(old_dynamic_title, config.dynamic_title());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dynamic_title_overridden_by_options() {
|
||||||
|
let config: Config =
|
||||||
|
::serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG).expect("deserialize config");
|
||||||
|
|
||||||
|
let mut options = Options::default();
|
||||||
|
options.title = Some("foo".to_owned());
|
||||||
|
let config = options.into_config(config);
|
||||||
|
|
||||||
|
assert!(!config.dynamic_title());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dynamic_title_overridden_by_config() {
|
||||||
|
let mut config: Config =
|
||||||
|
::serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG).expect("deserialize config");
|
||||||
|
|
||||||
|
config.window.title = Some("foo".to_owned());
|
||||||
|
let config = Options::default().into_config(config);
|
||||||
|
|
||||||
|
assert!(!config.dynamic_title());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,210 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{self, Read, Write};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
use dirs;
|
||||||
|
use log::{error, warn};
|
||||||
|
use serde_yaml;
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
use xdg;
|
||||||
|
|
||||||
|
use alacritty_terminal::config::{Config, DEFAULT_ALACRITTY_CONFIG};
|
||||||
|
|
||||||
|
pub const SOURCE_FILE_PATH: &str = file!();
|
||||||
|
|
||||||
|
/// Result from config loading
|
||||||
|
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
/// Errors occurring during config loading
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Config file not found
|
||||||
|
NotFound,
|
||||||
|
|
||||||
|
/// Couldn't read $HOME environment variable
|
||||||
|
ReadingEnvHome(env::VarError),
|
||||||
|
|
||||||
|
/// io error reading file
|
||||||
|
Io(io::Error),
|
||||||
|
|
||||||
|
/// Not valid yaml or missing parameters
|
||||||
|
Yaml(serde_yaml::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::error::Error for Error {
|
||||||
|
fn cause(&self) -> Option<&dyn (::std::error::Error)> {
|
||||||
|
match *self {
|
||||||
|
Error::NotFound => None,
|
||||||
|
Error::ReadingEnvHome(ref err) => Some(err),
|
||||||
|
Error::Io(ref err) => Some(err),
|
||||||
|
Error::Yaml(ref err) => Some(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
match *self {
|
||||||
|
Error::NotFound => "Couldn't locate config file",
|
||||||
|
Error::ReadingEnvHome(ref err) => err.description(),
|
||||||
|
Error::Io(ref err) => err.description(),
|
||||||
|
Error::Yaml(ref err) => err.description(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
|
match *self {
|
||||||
|
Error::NotFound => write!(f, "{}", ::std::error::Error::description(self)),
|
||||||
|
Error::ReadingEnvHome(ref err) => {
|
||||||
|
write!(f, "Couldn't read $HOME environment variable: {}", err)
|
||||||
|
},
|
||||||
|
Error::Io(ref err) => write!(f, "Error reading config file: {}", err),
|
||||||
|
Error::Yaml(ref err) => write!(f, "Problem with config: {}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<env::VarError> for Error {
|
||||||
|
fn from(val: env::VarError) -> Error {
|
||||||
|
Error::ReadingEnvHome(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error {
|
||||||
|
fn from(val: io::Error) -> Error {
|
||||||
|
if val.kind() == io::ErrorKind::NotFound {
|
||||||
|
Error::NotFound
|
||||||
|
} else {
|
||||||
|
Error::Io(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<serde_yaml::Error> for Error {
|
||||||
|
fn from(val: serde_yaml::Error) -> Error {
|
||||||
|
Error::Yaml(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the location of the first found default config file paths
|
||||||
|
/// according to the following order:
|
||||||
|
///
|
||||||
|
/// 1. $XDG_CONFIG_HOME/alacritty/alacritty.yml
|
||||||
|
/// 2. $XDG_CONFIG_HOME/alacritty.yml
|
||||||
|
/// 3. $HOME/.config/alacritty/alacritty.yml
|
||||||
|
/// 4. $HOME/.alacritty.yml
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
pub fn installed_config<'a>() -> Option<Cow<'a, Path>> {
|
||||||
|
// Try using XDG location by default
|
||||||
|
xdg::BaseDirectories::with_prefix("alacritty")
|
||||||
|
.ok()
|
||||||
|
.and_then(|xdg| xdg.find_config_file("alacritty.yml"))
|
||||||
|
.or_else(|| {
|
||||||
|
xdg::BaseDirectories::new()
|
||||||
|
.ok()
|
||||||
|
.and_then(|fallback| fallback.find_config_file("alacritty.yml"))
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
if let Ok(home) = env::var("HOME") {
|
||||||
|
// Fallback path: $HOME/.config/alacritty/alacritty.yml
|
||||||
|
let fallback = PathBuf::from(&home).join(".config/alacritty/alacritty.yml");
|
||||||
|
if fallback.exists() {
|
||||||
|
return Some(fallback);
|
||||||
|
}
|
||||||
|
// Fallback path: $HOME/.alacritty.yml
|
||||||
|
let fallback = PathBuf::from(&home).join(".alacritty.yml");
|
||||||
|
if fallback.exists() {
|
||||||
|
return Some(fallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.map(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn installed_config<'a>() -> Option<Cow<'a, Path>> {
|
||||||
|
dirs::config_dir()
|
||||||
|
.map(|path| path.join("alacritty\\alacritty.yml"))
|
||||||
|
.filter(|new| new.exists())
|
||||||
|
.map(Cow::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
pub fn write_defaults() -> io::Result<Cow<'static, Path>> {
|
||||||
|
let path = xdg::BaseDirectories::with_prefix("alacritty")
|
||||||
|
.map_err(|err| io::Error::new(io::ErrorKind::NotFound, err.to_string().as_str()))
|
||||||
|
.and_then(|p| p.place_config_file("alacritty.yml"))?;
|
||||||
|
|
||||||
|
File::create(&path)?.write_all(DEFAULT_ALACRITTY_CONFIG.as_bytes())?;
|
||||||
|
|
||||||
|
Ok(path.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn write_defaults() -> io::Result<Cow<'static, Path>> {
|
||||||
|
let mut path = dirs::config_dir().ok_or_else(|| {
|
||||||
|
io::Error::new(io::ErrorKind::NotFound, "Couldn't find profile directory")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
path = path.join("alacritty/alacritty.yml");
|
||||||
|
|
||||||
|
std::fs::create_dir_all(path.parent().unwrap())?;
|
||||||
|
|
||||||
|
File::create(&path)?.write_all(DEFAULT_ALACRITTY_CONFIG.as_bytes())?;
|
||||||
|
|
||||||
|
Ok(path.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_from(path: PathBuf) -> Config {
|
||||||
|
let mut config = reload_from(&path).unwrap_or_else(|_| Config::default());
|
||||||
|
config.config_path = Some(path);
|
||||||
|
config
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reload_from(path: &PathBuf) -> Result<Config> {
|
||||||
|
match read_config(path) {
|
||||||
|
Ok(config) => Ok(config),
|
||||||
|
Err(err) => {
|
||||||
|
error!("Unable to load config {:?}: {}", path, err);
|
||||||
|
Err(err)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_config(path: &PathBuf) -> Result<Config> {
|
||||||
|
let mut contents = String::new();
|
||||||
|
File::open(path)?.read_to_string(&mut contents)?;
|
||||||
|
|
||||||
|
// Prevent parsing error with empty string
|
||||||
|
if contents.is_empty() {
|
||||||
|
return Ok(Config::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
let config = serde_yaml::from_str(&contents)?;
|
||||||
|
|
||||||
|
print_deprecation_warnings(&config);
|
||||||
|
|
||||||
|
Ok(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_deprecation_warnings(config: &Config) {
|
||||||
|
if config.window.start_maximized.is_some() {
|
||||||
|
warn!(
|
||||||
|
"Config window.start_maximized is deprecated; please use window.startup_mode instead"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.render_timer.is_some() {
|
||||||
|
warn!("Config render_timer is deprecated; please use debug.render_timer instead");
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.persistent_logging.is_some() {
|
||||||
|
warn!(
|
||||||
|
"Config persistent_logging is deprecated; please use debug.persistent_logging instead"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,23 +29,26 @@ use crossbeam_channel::Sender;
|
||||||
use log::{self, Level};
|
use log::{self, Level};
|
||||||
use time;
|
use time;
|
||||||
|
|
||||||
use alacritty_terminal::config::Options;
|
|
||||||
use alacritty_terminal::message_bar::Message;
|
use alacritty_terminal::message_bar::Message;
|
||||||
use alacritty_terminal::term::color;
|
use alacritty_terminal::term::color;
|
||||||
|
|
||||||
|
use crate::cli::Options;
|
||||||
|
|
||||||
const ALACRITTY_LOG_ENV: &str = "ALACRITTY_LOG";
|
const ALACRITTY_LOG_ENV: &str = "ALACRITTY_LOG";
|
||||||
|
|
||||||
pub fn initialize(
|
pub fn initialize(
|
||||||
options: &Options,
|
options: &Options,
|
||||||
message_tx: Sender<Message>,
|
message_tx: Sender<Message>,
|
||||||
) -> Result<Option<PathBuf>, log::SetLoggerError> {
|
) -> Result<Option<PathBuf>, log::SetLoggerError> {
|
||||||
|
log::set_max_level(options.log_level);
|
||||||
|
|
||||||
// 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(None)
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
let logger = Logger::new(options.log_level, message_tx);
|
let logger = Logger::new(message_tx);
|
||||||
let path = logger.file_path();
|
let path = logger.file_path();
|
||||||
log::set_boxed_logger(Box::new(logger))?;
|
log::set_boxed_logger(Box::new(logger))?;
|
||||||
Ok(path)
|
Ok(path)
|
||||||
|
@ -53,22 +56,17 @@ pub fn initialize(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Logger {
|
pub struct Logger {
|
||||||
level: log::LevelFilter,
|
|
||||||
logfile: Mutex<OnDemandLogFile>,
|
logfile: Mutex<OnDemandLogFile>,
|
||||||
stdout: Mutex<LineWriter<Stdout>>,
|
stdout: Mutex<LineWriter<Stdout>>,
|
||||||
message_tx: Sender<Message>,
|
message_tx: Sender<Message>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Logger {
|
impl Logger {
|
||||||
// False positive, see: https://github.com/rust-lang-nursery/rust-clippy/issues/734
|
fn new(message_tx: Sender<Message>) -> Self {
|
||||||
#[allow(clippy::new_ret_no_self)]
|
|
||||||
fn new(level: log::LevelFilter, message_tx: Sender<Message>) -> Self {
|
|
||||||
log::set_max_level(level);
|
|
||||||
|
|
||||||
let logfile = Mutex::new(OnDemandLogFile::new());
|
let logfile = Mutex::new(OnDemandLogFile::new());
|
||||||
let stdout = Mutex::new(LineWriter::new(io::stdout()));
|
let stdout = Mutex::new(LineWriter::new(io::stdout()));
|
||||||
|
|
||||||
Logger { level, logfile, stdout, message_tx }
|
Logger { logfile, stdout, message_tx }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_path(&self) -> Option<PathBuf> {
|
fn file_path(&self) -> Option<PathBuf> {
|
||||||
|
@ -82,7 +80,7 @@ impl Logger {
|
||||||
|
|
||||||
impl log::Log for Logger {
|
impl log::Log for Logger {
|
||||||
fn enabled(&self, metadata: &log::Metadata<'_>) -> bool {
|
fn enabled(&self, metadata: &log::Metadata<'_>) -> bool {
|
||||||
metadata.level() <= self.level
|
metadata.level() <= log::max_level()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log(&self, record: &log::Record<'_>) {
|
fn log(&self, record: &log::Record<'_>) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ use std::env;
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
use alacritty_terminal::clipboard::Clipboard;
|
use alacritty_terminal::clipboard::Clipboard;
|
||||||
use alacritty_terminal::config::{self, Config, Options, Monitor};
|
use alacritty_terminal::config::{Config, Monitor};
|
||||||
use alacritty_terminal::display::Display;
|
use alacritty_terminal::display::Display;
|
||||||
use alacritty_terminal::event_loop::{self, EventLoop, Msg};
|
use alacritty_terminal::event_loop::{self, EventLoop, Msg};
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
@ -56,8 +56,11 @@ use alacritty_terminal::util::fmt::Red;
|
||||||
use alacritty_terminal::{die, event};
|
use alacritty_terminal::{die, event};
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
|
mod config;
|
||||||
mod logging;
|
mod logging;
|
||||||
|
|
||||||
|
use crate::cli::Options;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
panic::attach_handler();
|
panic::attach_handler();
|
||||||
|
|
||||||
|
@ -70,7 +73,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load command line options
|
// Load command line options
|
||||||
let options = cli::options();
|
let options = Options::new();
|
||||||
|
|
||||||
// Setup storage for message UI
|
// Setup storage for message UI
|
||||||
let message_buffer = MessageBuffer::new();
|
let message_buffer = MessageBuffer::new();
|
||||||
|
@ -83,15 +86,19 @@ fn main() {
|
||||||
// If the file is a command line argument, we won't write a generated default file
|
// If the file is a command line argument, we won't write a generated default file
|
||||||
let config_path = options
|
let config_path = options
|
||||||
.config_path()
|
.config_path()
|
||||||
.or_else(Config::installed_config)
|
.or_else(config::installed_config)
|
||||||
.or_else(|| Config::write_defaults().ok())
|
.or_else(|| config::write_defaults().ok())
|
||||||
.map(|path| path.to_path_buf());
|
.map(|path| path.to_path_buf());
|
||||||
let config = if let Some(path) = config_path {
|
let config = if let Some(path) = config_path {
|
||||||
Config::load_from(path).update_dynamic_title(&options)
|
config::load_from(path)
|
||||||
} else {
|
} else {
|
||||||
error!("Unable to write the default config");
|
error!("Unable to write the default config");
|
||||||
Config::default()
|
Config::default()
|
||||||
};
|
};
|
||||||
|
let config = options.into_config(config);
|
||||||
|
|
||||||
|
// Update the log level from config
|
||||||
|
log::set_max_level(config.debug.log_level);
|
||||||
|
|
||||||
// Switch to home directory
|
// Switch to home directory
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
@ -101,10 +108,10 @@ fn main() {
|
||||||
locale::set_locale_environment();
|
locale::set_locale_environment();
|
||||||
|
|
||||||
// Store if log file should be deleted before moving config
|
// Store if log file should be deleted before moving config
|
||||||
let persistent_logging = options.persistent_logging || config.persistent_logging();
|
let persistent_logging = config.persistent_logging();
|
||||||
|
|
||||||
// Run alacritty
|
// Run alacritty
|
||||||
if let Err(err) = run(config, &options, message_buffer) {
|
if let Err(err) = run(config, message_buffer) {
|
||||||
die!("Alacritty encountered an unrecoverable error:\n\n\t{}\n", Red(err));
|
die!("Alacritty encountered an unrecoverable error:\n\n\t{}\n", Red(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,13 +127,9 @@ fn main() {
|
||||||
///
|
///
|
||||||
/// Creates a window, the terminal state, pty, I/O event loop, input processor,
|
/// Creates a window, the terminal state, pty, I/O event loop, input processor,
|
||||||
/// config change monitor, and runs the main display loop.
|
/// config change monitor, and runs the main display loop.
|
||||||
fn run(
|
fn run(config: Config, message_buffer: MessageBuffer) -> Result<(), Box<dyn Error>> {
|
||||||
mut config: Config,
|
|
||||||
options: &Options,
|
|
||||||
message_buffer: MessageBuffer,
|
|
||||||
) -> 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.config_path {
|
||||||
info!("Configuration loaded from {:?}", config_path.display());
|
info!("Configuration loaded from {:?}", config_path.display());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -136,7 +139,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)?;
|
let mut display = Display::new(&config)?;
|
||||||
|
|
||||||
info!("PTY Dimensions: {:?} x {:?}", display.size().lines(), display.size().cols());
|
info!("PTY Dimensions: {:?} x {:?}", display.size().lines(), display.size().cols());
|
||||||
|
|
||||||
|
@ -162,7 +165,7 @@ fn run(
|
||||||
// The pty forks a process to run the shell on the slave side of the
|
// The pty forks a process to run the shell on the slave side of the
|
||||||
// pseudoterminal. A file descriptor for the master side is retained for
|
// pseudoterminal. A file descriptor for the master side is retained for
|
||||||
// reading/writing to the shell.
|
// reading/writing to the shell.
|
||||||
let pty = tty::new(&config, options, &display.size(), window_id);
|
let pty = tty::new(&config, &display.size(), window_id);
|
||||||
|
|
||||||
// Get a reference to something that we can resize
|
// Get a reference to something that we can resize
|
||||||
//
|
//
|
||||||
|
@ -181,7 +184,7 @@ fn run(
|
||||||
// synchronized since the I/O loop updates the state, and the display
|
// synchronized since the I/O loop updates the state, and the display
|
||||||
// consumes it periodically.
|
// consumes it periodically.
|
||||||
let event_loop =
|
let event_loop =
|
||||||
EventLoop::new(Arc::clone(&terminal), display.notifier(), pty, options.ref_test);
|
EventLoop::new(Arc::clone(&terminal), display.notifier(), pty, config.debug.ref_test);
|
||||||
|
|
||||||
// The event loop channel allows write requests from the event processor
|
// The event loop channel allows write requests from the event processor
|
||||||
// to be sent to the loop and ultimately written to the pty.
|
// to be sent to the loop and ultimately written to the pty.
|
||||||
|
@ -193,9 +196,7 @@ fn run(
|
||||||
let mut processor = event::Processor::new(
|
let mut processor = event::Processor::new(
|
||||||
event_loop::Notifier(event_loop.channel()),
|
event_loop::Notifier(event_loop.channel()),
|
||||||
display.resize_channel(),
|
display.resize_channel(),
|
||||||
options,
|
|
||||||
&config,
|
&config,
|
||||||
options.ref_test,
|
|
||||||
display.size().to_owned(),
|
display.size().to_owned(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -203,14 +204,10 @@ fn run(
|
||||||
//
|
//
|
||||||
// The monitor watches the config file for changes and reloads it. Pending
|
// The monitor watches the config file for changes and reloads it. Pending
|
||||||
// config changes are processed in the main loop.
|
// config changes are processed in the main loop.
|
||||||
let config_monitor = match (options.live_config_reload, config.live_config_reload()) {
|
let config_monitor = if config.live_config_reload() {
|
||||||
// Start monitor if CLI flag says yes
|
config.config_path.as_ref().map(|path| Monitor::new(path, display.notifier()))
|
||||||
(Some(true), _) |
|
} else {
|
||||||
// Or if no CLI flag was passed and the config says yes
|
None
|
||||||
(None, true) => config.path()
|
|
||||||
.map(|path| config::Monitor::new(path, display.notifier())),
|
|
||||||
// Otherwise, don't start the monitor
|
|
||||||
_ => None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Kick off the I/O thread
|
// Kick off the I/O thread
|
||||||
|
@ -228,8 +225,7 @@ fn run(
|
||||||
// Clear old config messages from bar
|
// Clear old config messages from bar
|
||||||
terminal_lock.message_buffer_mut().remove_topic(config::SOURCE_FILE_PATH);
|
terminal_lock.message_buffer_mut().remove_topic(config::SOURCE_FILE_PATH);
|
||||||
|
|
||||||
if let Ok(new_config) = Config::reload_from(path) {
|
if let Ok(config) = config::reload_from(path) {
|
||||||
config = new_config.update_dynamic_title(options);
|
|
||||||
display.update_config(&config);
|
display.update_config(&config);
|
||||||
processor.update_config(&config);
|
processor.update_config(&config);
|
||||||
terminal_lock.update_config(&config);
|
terminal_lock.update_config(&config);
|
||||||
|
|
|
@ -23,7 +23,6 @@ serde_yaml = "0.8"
|
||||||
vte = "0.3"
|
vte = "0.3"
|
||||||
mio = "0.6"
|
mio = "0.6"
|
||||||
mio-extras = "2"
|
mio-extras = "2"
|
||||||
xdg = "2"
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
fnv = "1"
|
fnv = "1"
|
||||||
unicode-width = "0.1"
|
unicode-width = "0.1"
|
||||||
|
@ -48,7 +47,6 @@ mio-named-pipes = "0.1"
|
||||||
miow = "0.3"
|
miow = "0.3"
|
||||||
dunce = "1.0"
|
dunce = "1.0"
|
||||||
winapi = { version = "0.3.7", features = ["impl-default", "winuser", "synchapi", "roerrorapi", "winerror", "wincon", "wincontypes"]}
|
winapi = { version = "0.3.7", features = ["impl-default", "winuser", "synchapi", "roerrorapi", "winerror", "wincon", "wincontypes"]}
|
||||||
dirs = "1.0"
|
|
||||||
widestring = "0.4"
|
widestring = "0.4"
|
||||||
mio-anonymous-pipes = "0.1"
|
mio-anonymous-pipes = "0.1"
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ impl Clipboard {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!("Unable to load text from clipboard: {}", err);
|
debug!("Unable to load text from clipboard: {}", err);
|
||||||
String::new()
|
String::new()
|
||||||
}
|
},
|
||||||
Ok(text) => text,
|
Ok(text) => text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,16 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
use glutin::{ModifiersState, MouseButton};
|
|
||||||
|
|
||||||
use super::Key;
|
use std::fmt;
|
||||||
use crate::input::{Action, KeyBinding, MouseBinding};
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use glutin::{ModifiersState, MouseButton};
|
||||||
|
use serde::de::Error as SerdeError;
|
||||||
|
use serde::de::{self, MapAccess, Unexpected, Visitor};
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
|
use crate::input::{Action, Binding, KeyBinding, MouseBinding};
|
||||||
use crate::term::TermMode;
|
use crate::term::TermMode;
|
||||||
|
|
||||||
macro_rules! bindings {
|
macro_rules! bindings {
|
||||||
|
@ -231,3 +237,748 @@ pub fn platform_key_bindings() -> Vec<KeyBinding> {
|
||||||
pub fn platform_key_bindings() -> Vec<KeyBinding> {
|
pub fn platform_key_bindings() -> Vec<KeyBinding> {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
pub enum Key {
|
||||||
|
Scancode(u32),
|
||||||
|
Key1,
|
||||||
|
Key2,
|
||||||
|
Key3,
|
||||||
|
Key4,
|
||||||
|
Key5,
|
||||||
|
Key6,
|
||||||
|
Key7,
|
||||||
|
Key8,
|
||||||
|
Key9,
|
||||||
|
Key0,
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
D,
|
||||||
|
E,
|
||||||
|
F,
|
||||||
|
G,
|
||||||
|
H,
|
||||||
|
I,
|
||||||
|
J,
|
||||||
|
K,
|
||||||
|
L,
|
||||||
|
M,
|
||||||
|
N,
|
||||||
|
O,
|
||||||
|
P,
|
||||||
|
Q,
|
||||||
|
R,
|
||||||
|
S,
|
||||||
|
T,
|
||||||
|
U,
|
||||||
|
V,
|
||||||
|
W,
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
Z,
|
||||||
|
Escape,
|
||||||
|
F1,
|
||||||
|
F2,
|
||||||
|
F3,
|
||||||
|
F4,
|
||||||
|
F5,
|
||||||
|
F6,
|
||||||
|
F7,
|
||||||
|
F8,
|
||||||
|
F9,
|
||||||
|
F10,
|
||||||
|
F11,
|
||||||
|
F12,
|
||||||
|
F13,
|
||||||
|
F14,
|
||||||
|
F15,
|
||||||
|
F16,
|
||||||
|
F17,
|
||||||
|
F18,
|
||||||
|
F19,
|
||||||
|
F20,
|
||||||
|
F21,
|
||||||
|
F22,
|
||||||
|
F23,
|
||||||
|
F24,
|
||||||
|
Snapshot,
|
||||||
|
Scroll,
|
||||||
|
Pause,
|
||||||
|
Insert,
|
||||||
|
Home,
|
||||||
|
Delete,
|
||||||
|
End,
|
||||||
|
PageDown,
|
||||||
|
PageUp,
|
||||||
|
Left,
|
||||||
|
Up,
|
||||||
|
Right,
|
||||||
|
Down,
|
||||||
|
Back,
|
||||||
|
Return,
|
||||||
|
Space,
|
||||||
|
Compose,
|
||||||
|
Numlock,
|
||||||
|
Numpad0,
|
||||||
|
Numpad1,
|
||||||
|
Numpad2,
|
||||||
|
Numpad3,
|
||||||
|
Numpad4,
|
||||||
|
Numpad5,
|
||||||
|
Numpad6,
|
||||||
|
Numpad7,
|
||||||
|
Numpad8,
|
||||||
|
Numpad9,
|
||||||
|
AbntC1,
|
||||||
|
AbntC2,
|
||||||
|
Add,
|
||||||
|
Apostrophe,
|
||||||
|
Apps,
|
||||||
|
At,
|
||||||
|
Ax,
|
||||||
|
Backslash,
|
||||||
|
Calculator,
|
||||||
|
Capital,
|
||||||
|
Colon,
|
||||||
|
Comma,
|
||||||
|
Convert,
|
||||||
|
Decimal,
|
||||||
|
Divide,
|
||||||
|
Equals,
|
||||||
|
Grave,
|
||||||
|
Kana,
|
||||||
|
Kanji,
|
||||||
|
LAlt,
|
||||||
|
LBracket,
|
||||||
|
LControl,
|
||||||
|
LShift,
|
||||||
|
LWin,
|
||||||
|
Mail,
|
||||||
|
MediaSelect,
|
||||||
|
MediaStop,
|
||||||
|
Minus,
|
||||||
|
Multiply,
|
||||||
|
Mute,
|
||||||
|
MyComputer,
|
||||||
|
NavigateForward,
|
||||||
|
NavigateBackward,
|
||||||
|
NextTrack,
|
||||||
|
NoConvert,
|
||||||
|
NumpadComma,
|
||||||
|
NumpadEnter,
|
||||||
|
NumpadEquals,
|
||||||
|
OEM102,
|
||||||
|
Period,
|
||||||
|
PlayPause,
|
||||||
|
Power,
|
||||||
|
PrevTrack,
|
||||||
|
RAlt,
|
||||||
|
RBracket,
|
||||||
|
RControl,
|
||||||
|
RShift,
|
||||||
|
RWin,
|
||||||
|
Semicolon,
|
||||||
|
Slash,
|
||||||
|
Sleep,
|
||||||
|
Stop,
|
||||||
|
Subtract,
|
||||||
|
Sysrq,
|
||||||
|
Tab,
|
||||||
|
Underline,
|
||||||
|
Unlabeled,
|
||||||
|
VolumeDown,
|
||||||
|
VolumeUp,
|
||||||
|
Wake,
|
||||||
|
WebBack,
|
||||||
|
WebFavorites,
|
||||||
|
WebForward,
|
||||||
|
WebHome,
|
||||||
|
WebRefresh,
|
||||||
|
WebSearch,
|
||||||
|
WebStop,
|
||||||
|
Yen,
|
||||||
|
Caret,
|
||||||
|
Copy,
|
||||||
|
Paste,
|
||||||
|
Cut,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Key {
|
||||||
|
pub fn from_glutin_input(key: ::glutin::VirtualKeyCode) -> Self {
|
||||||
|
use glutin::VirtualKeyCode::*;
|
||||||
|
// Thank you, vim macros and regex!
|
||||||
|
match key {
|
||||||
|
Key1 => Key::Key1,
|
||||||
|
Key2 => Key::Key2,
|
||||||
|
Key3 => Key::Key3,
|
||||||
|
Key4 => Key::Key4,
|
||||||
|
Key5 => Key::Key5,
|
||||||
|
Key6 => Key::Key6,
|
||||||
|
Key7 => Key::Key7,
|
||||||
|
Key8 => Key::Key8,
|
||||||
|
Key9 => Key::Key9,
|
||||||
|
Key0 => Key::Key0,
|
||||||
|
A => Key::A,
|
||||||
|
B => Key::B,
|
||||||
|
C => Key::C,
|
||||||
|
D => Key::D,
|
||||||
|
E => Key::E,
|
||||||
|
F => Key::F,
|
||||||
|
G => Key::G,
|
||||||
|
H => Key::H,
|
||||||
|
I => Key::I,
|
||||||
|
J => Key::J,
|
||||||
|
K => Key::K,
|
||||||
|
L => Key::L,
|
||||||
|
M => Key::M,
|
||||||
|
N => Key::N,
|
||||||
|
O => Key::O,
|
||||||
|
P => Key::P,
|
||||||
|
Q => Key::Q,
|
||||||
|
R => Key::R,
|
||||||
|
S => Key::S,
|
||||||
|
T => Key::T,
|
||||||
|
U => Key::U,
|
||||||
|
V => Key::V,
|
||||||
|
W => Key::W,
|
||||||
|
X => Key::X,
|
||||||
|
Y => Key::Y,
|
||||||
|
Z => Key::Z,
|
||||||
|
Escape => Key::Escape,
|
||||||
|
F1 => Key::F1,
|
||||||
|
F2 => Key::F2,
|
||||||
|
F3 => Key::F3,
|
||||||
|
F4 => Key::F4,
|
||||||
|
F5 => Key::F5,
|
||||||
|
F6 => Key::F6,
|
||||||
|
F7 => Key::F7,
|
||||||
|
F8 => Key::F8,
|
||||||
|
F9 => Key::F9,
|
||||||
|
F10 => Key::F10,
|
||||||
|
F11 => Key::F11,
|
||||||
|
F12 => Key::F12,
|
||||||
|
F13 => Key::F13,
|
||||||
|
F14 => Key::F14,
|
||||||
|
F15 => Key::F15,
|
||||||
|
F16 => Key::F16,
|
||||||
|
F17 => Key::F17,
|
||||||
|
F18 => Key::F18,
|
||||||
|
F19 => Key::F19,
|
||||||
|
F20 => Key::F20,
|
||||||
|
F21 => Key::F21,
|
||||||
|
F22 => Key::F22,
|
||||||
|
F23 => Key::F23,
|
||||||
|
F24 => Key::F24,
|
||||||
|
Snapshot => Key::Snapshot,
|
||||||
|
Scroll => Key::Scroll,
|
||||||
|
Pause => Key::Pause,
|
||||||
|
Insert => Key::Insert,
|
||||||
|
Home => Key::Home,
|
||||||
|
Delete => Key::Delete,
|
||||||
|
End => Key::End,
|
||||||
|
PageDown => Key::PageDown,
|
||||||
|
PageUp => Key::PageUp,
|
||||||
|
Left => Key::Left,
|
||||||
|
Up => Key::Up,
|
||||||
|
Right => Key::Right,
|
||||||
|
Down => Key::Down,
|
||||||
|
Back => Key::Back,
|
||||||
|
Return => Key::Return,
|
||||||
|
Space => Key::Space,
|
||||||
|
Compose => Key::Compose,
|
||||||
|
Numlock => Key::Numlock,
|
||||||
|
Numpad0 => Key::Numpad0,
|
||||||
|
Numpad1 => Key::Numpad1,
|
||||||
|
Numpad2 => Key::Numpad2,
|
||||||
|
Numpad3 => Key::Numpad3,
|
||||||
|
Numpad4 => Key::Numpad4,
|
||||||
|
Numpad5 => Key::Numpad5,
|
||||||
|
Numpad6 => Key::Numpad6,
|
||||||
|
Numpad7 => Key::Numpad7,
|
||||||
|
Numpad8 => Key::Numpad8,
|
||||||
|
Numpad9 => Key::Numpad9,
|
||||||
|
AbntC1 => Key::AbntC1,
|
||||||
|
AbntC2 => Key::AbntC2,
|
||||||
|
Add => Key::Add,
|
||||||
|
Apostrophe => Key::Apostrophe,
|
||||||
|
Apps => Key::Apps,
|
||||||
|
At => Key::At,
|
||||||
|
Ax => Key::Ax,
|
||||||
|
Backslash => Key::Backslash,
|
||||||
|
Calculator => Key::Calculator,
|
||||||
|
Capital => Key::Capital,
|
||||||
|
Colon => Key::Colon,
|
||||||
|
Comma => Key::Comma,
|
||||||
|
Convert => Key::Convert,
|
||||||
|
Decimal => Key::Decimal,
|
||||||
|
Divide => Key::Divide,
|
||||||
|
Equals => Key::Equals,
|
||||||
|
Grave => Key::Grave,
|
||||||
|
Kana => Key::Kana,
|
||||||
|
Kanji => Key::Kanji,
|
||||||
|
LAlt => Key::LAlt,
|
||||||
|
LBracket => Key::LBracket,
|
||||||
|
LControl => Key::LControl,
|
||||||
|
LShift => Key::LShift,
|
||||||
|
LWin => Key::LWin,
|
||||||
|
Mail => Key::Mail,
|
||||||
|
MediaSelect => Key::MediaSelect,
|
||||||
|
MediaStop => Key::MediaStop,
|
||||||
|
Minus => Key::Minus,
|
||||||
|
Multiply => Key::Multiply,
|
||||||
|
Mute => Key::Mute,
|
||||||
|
MyComputer => Key::MyComputer,
|
||||||
|
NavigateForward => Key::NavigateForward,
|
||||||
|
NavigateBackward => Key::NavigateBackward,
|
||||||
|
NextTrack => Key::NextTrack,
|
||||||
|
NoConvert => Key::NoConvert,
|
||||||
|
NumpadComma => Key::NumpadComma,
|
||||||
|
NumpadEnter => Key::NumpadEnter,
|
||||||
|
NumpadEquals => Key::NumpadEquals,
|
||||||
|
OEM102 => Key::OEM102,
|
||||||
|
Period => Key::Period,
|
||||||
|
PlayPause => Key::PlayPause,
|
||||||
|
Power => Key::Power,
|
||||||
|
PrevTrack => Key::PrevTrack,
|
||||||
|
RAlt => Key::RAlt,
|
||||||
|
RBracket => Key::RBracket,
|
||||||
|
RControl => Key::RControl,
|
||||||
|
RShift => Key::RShift,
|
||||||
|
RWin => Key::RWin,
|
||||||
|
Semicolon => Key::Semicolon,
|
||||||
|
Slash => Key::Slash,
|
||||||
|
Sleep => Key::Sleep,
|
||||||
|
Stop => Key::Stop,
|
||||||
|
Subtract => Key::Subtract,
|
||||||
|
Sysrq => Key::Sysrq,
|
||||||
|
Tab => Key::Tab,
|
||||||
|
Underline => Key::Underline,
|
||||||
|
Unlabeled => Key::Unlabeled,
|
||||||
|
VolumeDown => Key::VolumeDown,
|
||||||
|
VolumeUp => Key::VolumeUp,
|
||||||
|
Wake => Key::Wake,
|
||||||
|
WebBack => Key::WebBack,
|
||||||
|
WebFavorites => Key::WebFavorites,
|
||||||
|
WebForward => Key::WebForward,
|
||||||
|
WebHome => Key::WebHome,
|
||||||
|
WebRefresh => Key::WebRefresh,
|
||||||
|
WebSearch => Key::WebSearch,
|
||||||
|
WebStop => Key::WebStop,
|
||||||
|
Yen => Key::Yen,
|
||||||
|
Caret => Key::Caret,
|
||||||
|
Copy => Key::Copy,
|
||||||
|
Paste => Key::Paste,
|
||||||
|
Cut => Key::Cut,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ModeWrapper {
|
||||||
|
pub mode: TermMode,
|
||||||
|
pub not_mode: TermMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deserialize<'a> for ModeWrapper {
|
||||||
|
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'a>,
|
||||||
|
{
|
||||||
|
struct ModeVisitor;
|
||||||
|
|
||||||
|
impl<'a> Visitor<'a> for ModeVisitor {
|
||||||
|
type Value = ModeWrapper;
|
||||||
|
|
||||||
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str("Combination of AppCursor | AppKeypad, possibly with negation (~)")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> ::std::result::Result<ModeWrapper, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
let mut res = ModeWrapper { mode: TermMode::empty(), not_mode: TermMode::empty() };
|
||||||
|
|
||||||
|
for modifier in value.split('|') {
|
||||||
|
match modifier.trim().to_lowercase().as_str() {
|
||||||
|
"appcursor" => res.mode |= TermMode::APP_CURSOR,
|
||||||
|
"~appcursor" => res.not_mode |= TermMode::APP_CURSOR,
|
||||||
|
"appkeypad" => res.mode |= TermMode::APP_KEYPAD,
|
||||||
|
"~appkeypad" => res.not_mode |= TermMode::APP_KEYPAD,
|
||||||
|
"~alt" => res.not_mode |= TermMode::ALT_SCREEN,
|
||||||
|
"alt" => res.mode |= TermMode::ALT_SCREEN,
|
||||||
|
_ => error!("Unknown mode {:?}", modifier),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_str(ModeVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MouseButtonWrapper(MouseButton);
|
||||||
|
|
||||||
|
impl MouseButtonWrapper {
|
||||||
|
fn into_inner(self) -> MouseButton {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deserialize<'a> for MouseButtonWrapper {
|
||||||
|
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'a>,
|
||||||
|
{
|
||||||
|
struct MouseButtonVisitor;
|
||||||
|
|
||||||
|
impl<'a> Visitor<'a> for MouseButtonVisitor {
|
||||||
|
type Value = MouseButtonWrapper;
|
||||||
|
|
||||||
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str("Left, Right, Middle, or a number")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> ::std::result::Result<MouseButtonWrapper, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
"Left" => Ok(MouseButtonWrapper(MouseButton::Left)),
|
||||||
|
"Right" => Ok(MouseButtonWrapper(MouseButton::Right)),
|
||||||
|
"Middle" => Ok(MouseButtonWrapper(MouseButton::Middle)),
|
||||||
|
_ => {
|
||||||
|
if let Ok(index) = u8::from_str(value) {
|
||||||
|
Ok(MouseButtonWrapper(MouseButton::Other(index)))
|
||||||
|
} else {
|
||||||
|
Err(E::invalid_value(Unexpected::Str(value), &self))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_str(MouseButtonVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bindings are deserialized into a `RawBinding` before being parsed as a
|
||||||
|
/// `KeyBinding` or `MouseBinding`.
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
struct RawBinding {
|
||||||
|
key: Option<Key>,
|
||||||
|
mouse: Option<MouseButton>,
|
||||||
|
mods: ModifiersState,
|
||||||
|
mode: TermMode,
|
||||||
|
notmode: TermMode,
|
||||||
|
action: Action,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawBinding {
|
||||||
|
fn into_mouse_binding(self) -> ::std::result::Result<MouseBinding, Self> {
|
||||||
|
if let Some(mouse) = self.mouse {
|
||||||
|
Ok(Binding {
|
||||||
|
trigger: mouse,
|
||||||
|
mods: self.mods,
|
||||||
|
action: self.action,
|
||||||
|
mode: self.mode,
|
||||||
|
notmode: self.notmode,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_key_binding(self) -> ::std::result::Result<KeyBinding, Self> {
|
||||||
|
if let Some(key) = self.key {
|
||||||
|
Ok(KeyBinding {
|
||||||
|
trigger: key,
|
||||||
|
mods: self.mods,
|
||||||
|
action: self.action,
|
||||||
|
mode: self.mode,
|
||||||
|
notmode: self.notmode,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deserialize<'a> for RawBinding {
|
||||||
|
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'a>,
|
||||||
|
{
|
||||||
|
enum Field {
|
||||||
|
Key,
|
||||||
|
Mods,
|
||||||
|
Mode,
|
||||||
|
Action,
|
||||||
|
Chars,
|
||||||
|
Mouse,
|
||||||
|
Command,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deserialize<'a> for Field {
|
||||||
|
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Field, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'a>,
|
||||||
|
{
|
||||||
|
struct FieldVisitor;
|
||||||
|
|
||||||
|
static FIELDS: &'static [&'static str] =
|
||||||
|
&["key", "mods", "mode", "action", "chars", "mouse", "command"];
|
||||||
|
|
||||||
|
impl<'a> Visitor<'a> for FieldVisitor {
|
||||||
|
type Value = Field;
|
||||||
|
|
||||||
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str("binding fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> ::std::result::Result<Field, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
"key" => Ok(Field::Key),
|
||||||
|
"mods" => Ok(Field::Mods),
|
||||||
|
"mode" => Ok(Field::Mode),
|
||||||
|
"action" => Ok(Field::Action),
|
||||||
|
"chars" => Ok(Field::Chars),
|
||||||
|
"mouse" => Ok(Field::Mouse),
|
||||||
|
"command" => Ok(Field::Command),
|
||||||
|
_ => Err(E::unknown_field(value, FIELDS)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_str(FieldVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RawBindingVisitor;
|
||||||
|
impl<'a> Visitor<'a> for RawBindingVisitor {
|
||||||
|
type Value = RawBinding;
|
||||||
|
|
||||||
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str("binding specification")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<V>(self, mut map: V) -> ::std::result::Result<RawBinding, V::Error>
|
||||||
|
where
|
||||||
|
V: MapAccess<'a>,
|
||||||
|
{
|
||||||
|
let mut mods: Option<ModifiersState> = None;
|
||||||
|
let mut key: Option<Key> = None;
|
||||||
|
let mut chars: Option<String> = None;
|
||||||
|
let mut action: Option<crate::input::Action> = None;
|
||||||
|
let mut mode: Option<TermMode> = None;
|
||||||
|
let mut not_mode: Option<TermMode> = None;
|
||||||
|
let mut mouse: Option<MouseButton> = None;
|
||||||
|
let mut command: Option<CommandWrapper> = None;
|
||||||
|
|
||||||
|
use ::serde::de::Error;
|
||||||
|
|
||||||
|
while let Some(struct_key) = map.next_key::<Field>()? {
|
||||||
|
match struct_key {
|
||||||
|
Field::Key => {
|
||||||
|
if key.is_some() {
|
||||||
|
return Err(<V::Error as Error>::duplicate_field("key"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let val = map.next_value::<serde_yaml::Value>()?;
|
||||||
|
if val.is_u64() {
|
||||||
|
let scancode = val.as_u64().unwrap();
|
||||||
|
if scancode > u64::from(::std::u32::MAX) {
|
||||||
|
return Err(<V::Error as Error>::custom(format!(
|
||||||
|
"Invalid key binding, scancode too big: {}",
|
||||||
|
scancode
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
key = Some(Key::Scancode(scancode as u32));
|
||||||
|
} else {
|
||||||
|
let k = Key::deserialize(val).map_err(V::Error::custom)?;
|
||||||
|
key = Some(k);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Field::Mods => {
|
||||||
|
if mods.is_some() {
|
||||||
|
return Err(<V::Error as Error>::duplicate_field("mods"));
|
||||||
|
}
|
||||||
|
|
||||||
|
mods = Some(map.next_value::<ModsWrapper>()?.into_inner());
|
||||||
|
},
|
||||||
|
Field::Mode => {
|
||||||
|
if mode.is_some() {
|
||||||
|
return Err(<V::Error as Error>::duplicate_field("mode"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mode_deserializer = map.next_value::<ModeWrapper>()?;
|
||||||
|
mode = Some(mode_deserializer.mode);
|
||||||
|
not_mode = Some(mode_deserializer.not_mode);
|
||||||
|
},
|
||||||
|
Field::Action => {
|
||||||
|
if action.is_some() {
|
||||||
|
return Err(<V::Error as Error>::duplicate_field("action"));
|
||||||
|
}
|
||||||
|
|
||||||
|
action = Some(map.next_value::<Action>()?);
|
||||||
|
},
|
||||||
|
Field::Chars => {
|
||||||
|
if chars.is_some() {
|
||||||
|
return Err(<V::Error as Error>::duplicate_field("chars"));
|
||||||
|
}
|
||||||
|
|
||||||
|
chars = Some(map.next_value()?);
|
||||||
|
},
|
||||||
|
Field::Mouse => {
|
||||||
|
if chars.is_some() {
|
||||||
|
return Err(<V::Error as Error>::duplicate_field("mouse"));
|
||||||
|
}
|
||||||
|
|
||||||
|
mouse = Some(map.next_value::<MouseButtonWrapper>()?.into_inner());
|
||||||
|
},
|
||||||
|
Field::Command => {
|
||||||
|
if command.is_some() {
|
||||||
|
return Err(<V::Error as Error>::duplicate_field("command"));
|
||||||
|
}
|
||||||
|
|
||||||
|
command = Some(map.next_value::<CommandWrapper>()?);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let action = match (action, chars, command) {
|
||||||
|
(Some(action), None, None) => action,
|
||||||
|
(None, Some(chars), None) => Action::Esc(chars),
|
||||||
|
(None, None, Some(cmd)) => match cmd {
|
||||||
|
CommandWrapper::Just(program) => Action::Command(program, vec![]),
|
||||||
|
CommandWrapper::WithArgs { program, args } => {
|
||||||
|
Action::Command(program, args)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
(None, None, None) => {
|
||||||
|
return Err(V::Error::custom("must specify chars, action or command"));
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return Err(V::Error::custom("must specify only chars, action or command"))
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let mode = mode.unwrap_or_else(TermMode::empty);
|
||||||
|
let not_mode = not_mode.unwrap_or_else(TermMode::empty);
|
||||||
|
let mods = mods.unwrap_or_else(ModifiersState::default);
|
||||||
|
|
||||||
|
if mouse.is_none() && key.is_none() {
|
||||||
|
return Err(V::Error::custom("bindings require mouse button or key"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(RawBinding { mode, notmode: not_mode, action, key, mouse, mods })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const FIELDS: &[&str] = &["key", "mods", "mode", "action", "chars", "mouse", "command"];
|
||||||
|
|
||||||
|
deserializer.deserialize_struct("RawBinding", FIELDS, RawBindingVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deserialize<'a> for MouseBinding {
|
||||||
|
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'a>,
|
||||||
|
{
|
||||||
|
let raw = RawBinding::deserialize(deserializer)?;
|
||||||
|
raw.into_mouse_binding().map_err(|_| D::Error::custom("expected mouse binding"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deserialize<'a> for KeyBinding {
|
||||||
|
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'a>,
|
||||||
|
{
|
||||||
|
let raw = RawBinding::deserialize(deserializer)?;
|
||||||
|
raw.into_key_binding().map_err(|_| D::Error::custom("expected key binding"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serde(untagged)]
|
||||||
|
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
|
||||||
|
pub enum CommandWrapper {
|
||||||
|
Just(String),
|
||||||
|
WithArgs {
|
||||||
|
program: String,
|
||||||
|
#[serde(default)]
|
||||||
|
args: Vec<String>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandWrapper {
|
||||||
|
pub fn program(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
CommandWrapper::Just(program) => program,
|
||||||
|
CommandWrapper::WithArgs { program, .. } => program,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn args(&self) -> &[String] {
|
||||||
|
match self {
|
||||||
|
CommandWrapper::Just(_) => &[],
|
||||||
|
CommandWrapper::WithArgs { args, .. } => args,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Newtype for implementing deserialize on glutin Mods
|
||||||
|
///
|
||||||
|
/// Our deserialize impl wouldn't be covered by a derive(Deserialize); see the
|
||||||
|
/// impl below.
|
||||||
|
#[derive(Debug, Copy, Clone, Hash, Default, Eq, PartialEq)]
|
||||||
|
pub struct ModsWrapper(ModifiersState);
|
||||||
|
|
||||||
|
impl ModsWrapper {
|
||||||
|
pub fn into_inner(self) -> ModifiersState {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> de::Deserialize<'a> for ModsWrapper {
|
||||||
|
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: de::Deserializer<'a>,
|
||||||
|
{
|
||||||
|
struct ModsVisitor;
|
||||||
|
|
||||||
|
impl<'a> Visitor<'a> for ModsVisitor {
|
||||||
|
type Value = ModsWrapper;
|
||||||
|
|
||||||
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str("Some subset of Command|Shift|Super|Alt|Option|Control")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> ::std::result::Result<ModsWrapper, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
let mut res = ModifiersState::default();
|
||||||
|
for modifier in value.split('|') {
|
||||||
|
match modifier.trim().to_lowercase().as_str() {
|
||||||
|
"command" | "super" => res.logo = true,
|
||||||
|
"shift" => res.shift = true,
|
||||||
|
"alt" | "option" => res.alt = true,
|
||||||
|
"control" => res.ctrl = true,
|
||||||
|
"none" => (),
|
||||||
|
_ => error!("Unknown modifier {:?}", modifier),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ModsWrapper(res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_str(ModsVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,178 @@
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
|
use crate::config::failure_default;
|
||||||
|
use crate::term::color::Rgb;
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Deserialize, Debug, Default, PartialEq, Eq)]
|
||||||
|
pub struct Colors {
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub primary: PrimaryColors,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub cursor: CursorColors,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub selection: SelectionColors,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
normal: NormalColors,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
bright: BrightColors,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub dim: Option<AnsiColors>,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub indexed_colors: Vec<IndexedColor>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Colors {
|
||||||
|
pub fn normal(&self) -> &AnsiColors {
|
||||||
|
&self.normal.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bright(&self) -> &AnsiColors {
|
||||||
|
&self.bright.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Deserialize, Default, Debug, PartialEq, Eq)]
|
||||||
|
pub struct IndexedColor {
|
||||||
|
#[serde(deserialize_with = "deserialize_color_index")]
|
||||||
|
pub index: u8,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub color: Rgb,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_color_index<'a, D>(deserializer: D) -> ::std::result::Result<u8, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'a>,
|
||||||
|
{
|
||||||
|
let value = serde_yaml::Value::deserialize(deserializer)?;
|
||||||
|
match u8::deserialize(value) {
|
||||||
|
Ok(index) => {
|
||||||
|
if index < 16 {
|
||||||
|
error!(
|
||||||
|
"Problem with config: indexed_color's index is {}, but a value bigger than 15 \
|
||||||
|
was expected; ignoring setting",
|
||||||
|
index
|
||||||
|
);
|
||||||
|
|
||||||
|
// Return value out of range to ignore this color
|
||||||
|
Ok(0)
|
||||||
|
} else {
|
||||||
|
Ok(index)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
error!("Problem with config: {}; ignoring setting", err);
|
||||||
|
|
||||||
|
// Return value out of range to ignore this color
|
||||||
|
Ok(0)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Deserialize, Debug, Copy, Clone, Default, PartialEq, Eq)]
|
||||||
|
pub struct CursorColors {
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub text: Option<Rgb>,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub cursor: Option<Rgb>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Deserialize, Debug, Copy, Clone, Default, PartialEq, Eq)]
|
||||||
|
pub struct SelectionColors {
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub text: Option<Rgb>,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub background: Option<Rgb>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Deserialize, Debug, PartialEq, Eq)]
|
||||||
|
pub struct PrimaryColors {
|
||||||
|
#[serde(default = "default_background", deserialize_with = "failure_default")]
|
||||||
|
pub background: Rgb,
|
||||||
|
#[serde(default = "default_foreground", deserialize_with = "failure_default")]
|
||||||
|
pub foreground: Rgb,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub bright_foreground: Option<Rgb>,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub dim_foreground: Option<Rgb>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PrimaryColors {
|
||||||
|
fn default() -> Self {
|
||||||
|
PrimaryColors {
|
||||||
|
background: default_background(),
|
||||||
|
foreground: default_foreground(),
|
||||||
|
bright_foreground: Default::default(),
|
||||||
|
dim_foreground: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_background() -> Rgb {
|
||||||
|
Rgb { r: 0, g: 0, b: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_foreground() -> Rgb {
|
||||||
|
Rgb { r: 0xea, g: 0xea, b: 0xea }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The 8-colors sections of config
|
||||||
|
#[derive(Deserialize, Debug, PartialEq, Eq)]
|
||||||
|
pub struct AnsiColors {
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub black: Rgb,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub red: Rgb,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub green: Rgb,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub yellow: Rgb,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub blue: Rgb,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub magenta: Rgb,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub cyan: Rgb,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub white: Rgb,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, PartialEq, Eq)]
|
||||||
|
struct NormalColors(AnsiColors);
|
||||||
|
|
||||||
|
impl Default for NormalColors {
|
||||||
|
fn default() -> Self {
|
||||||
|
NormalColors(AnsiColors {
|
||||||
|
black: Rgb { r: 0x00, g: 0x00, b: 0x00 },
|
||||||
|
red: Rgb { r: 0xd5, g: 0x4e, b: 0x53 },
|
||||||
|
green: Rgb { r: 0xb9, g: 0xca, b: 0x4a },
|
||||||
|
yellow: Rgb { r: 0xe6, g: 0xc5, b: 0x47 },
|
||||||
|
blue: Rgb { r: 0x7a, g: 0xa6, b: 0xda },
|
||||||
|
magenta: Rgb { r: 0xc3, g: 0x97, b: 0xd8 },
|
||||||
|
cyan: Rgb { r: 0x70, g: 0xc0, b: 0xba },
|
||||||
|
white: Rgb { r: 0xea, g: 0xea, b: 0xea },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, PartialEq, Eq)]
|
||||||
|
struct BrightColors(AnsiColors);
|
||||||
|
|
||||||
|
impl Default for BrightColors {
|
||||||
|
fn default() -> Self {
|
||||||
|
BrightColors(AnsiColors {
|
||||||
|
black: Rgb { r: 0x66, g: 0x66, b: 0x66 },
|
||||||
|
red: Rgb { r: 0xff, g: 0x33, b: 0x34 },
|
||||||
|
green: Rgb { r: 0x9e, g: 0xc4, b: 0x00 },
|
||||||
|
yellow: Rgb { r: 0xe7, g: 0xc5, b: 0x47 },
|
||||||
|
blue: Rgb { r: 0x7a, g: 0xa6, b: 0xda },
|
||||||
|
magenta: Rgb { r: 0xb7, g: 0x7e, b: 0xe0 },
|
||||||
|
cyan: Rgb { r: 0x54, g: 0xce, b: 0xd6 },
|
||||||
|
white: Rgb { r: 0xff, g: 0xff, b: 0xff },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
use log::LevelFilter;
|
||||||
|
use serde::Deserializer;
|
||||||
|
|
||||||
|
use crate::config::failure_default;
|
||||||
|
|
||||||
|
/// Debugging options
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Deserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct Debug {
|
||||||
|
#[serde(default = "default_log_level", deserialize_with = "deserialize_log_level")]
|
||||||
|
pub log_level: LevelFilter,
|
||||||
|
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub print_events: bool,
|
||||||
|
|
||||||
|
/// Keep the log file after quitting
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub persistent_logging: bool,
|
||||||
|
|
||||||
|
/// Should show render timer
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub render_timer: bool,
|
||||||
|
|
||||||
|
/// Record ref test
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub ref_test: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Debug {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
log_level: default_log_level(),
|
||||||
|
print_events: Default::default(),
|
||||||
|
persistent_logging: Default::default(),
|
||||||
|
render_timer: Default::default(),
|
||||||
|
ref_test: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_log_level() -> LevelFilter {
|
||||||
|
LevelFilter::Warn
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_log_level<'a, D>(deserializer: D) -> Result<LevelFilter, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'a>,
|
||||||
|
{
|
||||||
|
Ok(match failure_default::<D, String>(deserializer)?.to_lowercase().as_str() {
|
||||||
|
"off" | "none" => LevelFilter::Off,
|
||||||
|
"error" => LevelFilter::Error,
|
||||||
|
"warn" => LevelFilter::Warn,
|
||||||
|
"info" => LevelFilter::Info,
|
||||||
|
"debug" => LevelFilter::Debug,
|
||||||
|
"trace" => LevelFilter::Trace,
|
||||||
|
level => {
|
||||||
|
error!("Problem with config: invalid log level {}; using level Warn", level);
|
||||||
|
default_log_level()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,200 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use font::Size;
|
||||||
|
use serde::de::Visitor;
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
use crate::config::DefaultTrueBool;
|
||||||
|
use crate::config::{failure_default, Delta};
|
||||||
|
|
||||||
|
/// Font config
|
||||||
|
///
|
||||||
|
/// Defaults are provided at the level of this struct per platform, but not per
|
||||||
|
/// field in this struct. It might be nice in the future to have defaults for
|
||||||
|
/// each value independently. Alternatively, maybe erroring when the user
|
||||||
|
/// doesn't provide complete config is Ok.
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Font {
|
||||||
|
/// Normal font face
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
normal: FontDescription,
|
||||||
|
|
||||||
|
/// Bold font face
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
italic: SecondaryFontDescription,
|
||||||
|
|
||||||
|
/// Italic font face
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
bold: SecondaryFontDescription,
|
||||||
|
|
||||||
|
/// Font size in points
|
||||||
|
#[serde(deserialize_with = "DeserializeSize::deserialize")]
|
||||||
|
pub size: Size,
|
||||||
|
|
||||||
|
/// Extra spacing per character
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub offset: Delta<i8>,
|
||||||
|
|
||||||
|
/// Glyph offset within character cell
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub glyph_offset: Delta<i8>,
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
use_thin_strokes: DefaultTrueBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Font {
|
||||||
|
fn default() -> Font {
|
||||||
|
Font {
|
||||||
|
size: default_font_size(),
|
||||||
|
normal: Default::default(),
|
||||||
|
bold: Default::default(),
|
||||||
|
italic: Default::default(),
|
||||||
|
glyph_offset: Default::default(),
|
||||||
|
offset: Default::default(),
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
use_thin_strokes: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Font {
|
||||||
|
/// Get a font clone with a size modification
|
||||||
|
pub fn with_size(self, size: Size) -> Font {
|
||||||
|
Font { size, ..self }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get normal font description
|
||||||
|
pub fn normal(&self) -> &FontDescription {
|
||||||
|
&self.normal
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get italic font description
|
||||||
|
pub fn italic(&self) -> FontDescription {
|
||||||
|
self.italic.desc(&self.normal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get bold font description
|
||||||
|
pub fn bold(&self) -> FontDescription {
|
||||||
|
self.bold.desc(&self.normal)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
pub fn use_thin_strokes(&self) -> bool {
|
||||||
|
self.use_thin_strokes.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
pub fn use_thin_strokes(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_font_size() -> Size {
|
||||||
|
Size::new(11.)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Description of the normal font
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
|
||||||
|
pub struct FontDescription {
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub family: String,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub style: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FontDescription {
|
||||||
|
fn default() -> FontDescription {
|
||||||
|
FontDescription {
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
family: "monospace".into(),
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
family: "Menlo".into(),
|
||||||
|
#[cfg(windows)]
|
||||||
|
family: "Consolas".into(),
|
||||||
|
style: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Description of the italic and bold font
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Debug, Default, Deserialize, Clone, PartialEq, Eq)]
|
||||||
|
pub struct SecondaryFontDescription {
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
family: Option<String>,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
style: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SecondaryFontDescription {
|
||||||
|
pub fn desc(&self, fallback: &FontDescription) -> FontDescription {
|
||||||
|
FontDescription {
|
||||||
|
family: self.family.clone().unwrap_or_else(|| fallback.family.clone()),
|
||||||
|
style: self.style.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait DeserializeSize: Sized {
|
||||||
|
fn deserialize<'a, D>(_: D) -> ::std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::de::Deserializer<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeserializeSize for Size {
|
||||||
|
fn deserialize<'a, D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::de::Deserializer<'a>,
|
||||||
|
{
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
struct NumVisitor<__D> {
|
||||||
|
_marker: PhantomData<__D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, __D> Visitor<'a> for NumVisitor<__D>
|
||||||
|
where
|
||||||
|
__D: serde::de::Deserializer<'a>,
|
||||||
|
{
|
||||||
|
type Value = f64;
|
||||||
|
|
||||||
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str("f64 or u64")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_f64<E>(self, value: f64) -> ::std::result::Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: ::serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_u64<E>(self, value: u64) -> ::std::result::Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: ::serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(value as f64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = serde_yaml::Value::deserialize(deserializer)?;
|
||||||
|
let size = value
|
||||||
|
.deserialize_any(NumVisitor::<D> { _marker: PhantomData })
|
||||||
|
.map(|v| Size::new(v as _));
|
||||||
|
|
||||||
|
// Use default font size as fallback
|
||||||
|
match size {
|
||||||
|
Ok(size) => Ok(size),
|
||||||
|
Err(err) => {
|
||||||
|
let size = default_font_size();
|
||||||
|
error!("Problem with config: {}; using size {}", err, size.as_f32_pts());
|
||||||
|
Ok(size)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,79 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
|
||||||
|
|
||||||
|
pub struct Monitor {
|
||||||
|
_thread: ::std::thread::JoinHandle<()>,
|
||||||
|
rx: mpsc::Receiver<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait OnConfigReload {
|
||||||
|
fn on_config_reload(&mut self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OnConfigReload for crate::display::Notifier {
|
||||||
|
fn on_config_reload(&mut self) {
|
||||||
|
self.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Monitor {
|
||||||
|
/// Get pending config changes
|
||||||
|
pub fn pending(&self) -> Option<PathBuf> {
|
||||||
|
let mut config = None;
|
||||||
|
while let Ok(new) = self.rx.try_recv() {
|
||||||
|
config = Some(new);
|
||||||
|
}
|
||||||
|
|
||||||
|
config
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new<H, P>(path: P, mut handler: H) -> Monitor
|
||||||
|
where
|
||||||
|
H: OnConfigReload + Send + 'static,
|
||||||
|
P: Into<PathBuf>,
|
||||||
|
{
|
||||||
|
let path = path.into();
|
||||||
|
|
||||||
|
let (config_tx, config_rx) = mpsc::channel();
|
||||||
|
|
||||||
|
Monitor {
|
||||||
|
_thread: crate::util::thread::spawn_named("config watcher", move || {
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
// The Duration argument is a debouncing period.
|
||||||
|
let mut watcher =
|
||||||
|
watcher(tx, Duration::from_millis(10)).expect("Unable to spawn file watcher");
|
||||||
|
let config_path = ::std::fs::canonicalize(path).expect("canonicalize config path");
|
||||||
|
|
||||||
|
// Get directory of config
|
||||||
|
let mut parent = config_path.clone();
|
||||||
|
parent.pop();
|
||||||
|
|
||||||
|
// Watch directory
|
||||||
|
watcher
|
||||||
|
.watch(&parent, RecursiveMode::NonRecursive)
|
||||||
|
.expect("watch alacritty.yml dir");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match rx.recv().expect("watcher event") {
|
||||||
|
DebouncedEvent::Rename(..) => continue,
|
||||||
|
DebouncedEvent::Write(path)
|
||||||
|
| DebouncedEvent::Create(path)
|
||||||
|
| DebouncedEvent::Chmod(path) => {
|
||||||
|
if path != config_path {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = config_tx.send(path);
|
||||||
|
handler.on_config_reload();
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
rx: config_rx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use glutin::ModifiersState;
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
|
use crate::config::bindings::{CommandWrapper, ModsWrapper};
|
||||||
|
use crate::config::failure_default;
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Default, Clone, Debug, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct Mouse {
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub double_click: ClickHandler,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub triple_click: ClickHandler,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub hide_when_typing: bool,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub url: Url,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct Url {
|
||||||
|
// Program for opening links
|
||||||
|
#[serde(deserialize_with = "deserialize_launcher")]
|
||||||
|
pub launcher: Option<CommandWrapper>,
|
||||||
|
|
||||||
|
// Modifier used to open links
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
modifiers: ModsWrapper,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Url {
|
||||||
|
pub fn mods(&self) -> ModifiersState {
|
||||||
|
self.modifiers.into_inner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_launcher<'a, D>(
|
||||||
|
deserializer: D,
|
||||||
|
) -> ::std::result::Result<Option<CommandWrapper>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'a>,
|
||||||
|
{
|
||||||
|
let default = Url::default().launcher;
|
||||||
|
|
||||||
|
// Deserialize to generic value
|
||||||
|
let val = serde_yaml::Value::deserialize(deserializer)?;
|
||||||
|
|
||||||
|
// Accept `None` to disable the launcher
|
||||||
|
if val.as_str().filter(|v| v.to_lowercase() == "none").is_some() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
match <Option<CommandWrapper>>::deserialize(val) {
|
||||||
|
Ok(launcher) => Ok(launcher),
|
||||||
|
Err(err) => {
|
||||||
|
error!("Problem with config: {}; using {}", err, default.clone().unwrap().program());
|
||||||
|
Ok(default)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Url {
|
||||||
|
fn default() -> Url {
|
||||||
|
Url {
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
launcher: Some(CommandWrapper::Just(String::from("xdg-open"))),
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
launcher: Some(CommandWrapper::Just(String::from("open"))),
|
||||||
|
#[cfg(windows)]
|
||||||
|
launcher: Some(CommandWrapper::Just(String::from("explorer"))),
|
||||||
|
modifiers: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct ClickHandler {
|
||||||
|
#[serde(deserialize_with = "deserialize_duration_ms")]
|
||||||
|
pub threshold: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ClickHandler {
|
||||||
|
fn default() -> Self {
|
||||||
|
ClickHandler { threshold: default_threshold_ms() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_threshold_ms() -> Duration {
|
||||||
|
Duration::from_millis(300)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_duration_ms<'a, D>(deserializer: D) -> ::std::result::Result<Duration, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'a>,
|
||||||
|
{
|
||||||
|
let value = serde_yaml::Value::deserialize(deserializer)?;
|
||||||
|
match u64::deserialize(value) {
|
||||||
|
Ok(threshold_ms) => Ok(Duration::from_millis(threshold_ms)),
|
||||||
|
Err(err) => {
|
||||||
|
error!("Problem with config: {}; using default value", err);
|
||||||
|
Ok(default_threshold_ms())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,72 +0,0 @@
|
||||||
// Copyright 2019 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 ::log;
|
|
||||||
|
|
||||||
use crate::config::{Delta, Dimensions, Shell};
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
|
|
||||||
/// Options specified on the command line
|
|
||||||
pub struct Options {
|
|
||||||
pub live_config_reload: Option<bool>,
|
|
||||||
pub print_events: bool,
|
|
||||||
pub ref_test: bool,
|
|
||||||
pub dimensions: Option<Dimensions>,
|
|
||||||
pub position: Option<Delta<i32>>,
|
|
||||||
pub title: Option<String>,
|
|
||||||
pub class: Option<String>,
|
|
||||||
pub log_level: log::LevelFilter,
|
|
||||||
pub command: Option<Shell<'static>>,
|
|
||||||
pub working_dir: Option<PathBuf>,
|
|
||||||
pub config: Option<PathBuf>,
|
|
||||||
pub persistent_logging: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Options {
|
|
||||||
fn default() -> Options {
|
|
||||||
Options {
|
|
||||||
live_config_reload: None,
|
|
||||||
print_events: false,
|
|
||||||
ref_test: false,
|
|
||||||
dimensions: None,
|
|
||||||
position: None,
|
|
||||||
title: None,
|
|
||||||
class: None,
|
|
||||||
log_level: log::LevelFilter::Warn,
|
|
||||||
command: None,
|
|
||||||
working_dir: None,
|
|
||||||
config: None,
|
|
||||||
persistent_logging: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Options {
|
|
||||||
pub fn dimensions(&self) -> Option<Dimensions> {
|
|
||||||
self.dimensions
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn position(&self) -> Option<Delta<i32>> {
|
|
||||||
self.position
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn command(&self) -> Option<&Shell<'_>> {
|
|
||||||
self.command.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn config_path(&self) -> Option<Cow<'_, Path>> {
|
|
||||||
self.config.as_ref().map(|p| Cow::Borrowed(p.as_path()))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
|
use crate::config::{failure_default, MAX_SCROLLBACK_LINES};
|
||||||
|
|
||||||
|
/// Struct for scrolling related settings
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Deserialize, Copy, Clone, Default, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Scrolling {
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
history: ScrollingHistory,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
multiplier: ScrollingMultiplier,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
faux_multiplier: ScrollingMultiplier,
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub auto_scroll: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scrolling {
|
||||||
|
pub fn history(self) -> u32 {
|
||||||
|
self.history.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn multiplier(self) -> u8 {
|
||||||
|
self.multiplier.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn faux_multiplier(self) -> u8 {
|
||||||
|
self.faux_multiplier.0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the history size, used in ref tests
|
||||||
|
pub fn set_history(&mut self, history: u32) {
|
||||||
|
self.history = ScrollingHistory(history);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
|
||||||
|
struct ScrollingMultiplier(u8);
|
||||||
|
|
||||||
|
impl Default for ScrollingMultiplier {
|
||||||
|
fn default() -> Self {
|
||||||
|
ScrollingMultiplier(3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
struct ScrollingHistory(u32);
|
||||||
|
|
||||||
|
impl Default for ScrollingHistory {
|
||||||
|
fn default() -> Self {
|
||||||
|
ScrollingHistory(10_000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for ScrollingHistory {
|
||||||
|
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let value = serde_yaml::Value::deserialize(deserializer)?;
|
||||||
|
match u32::deserialize(value) {
|
||||||
|
Ok(lines) => {
|
||||||
|
if lines > MAX_SCROLLBACK_LINES {
|
||||||
|
error!(
|
||||||
|
"Problem with config: scrollback size is {}, but expected a maximum of \
|
||||||
|
{}; using {1} instead",
|
||||||
|
lines, MAX_SCROLLBACK_LINES,
|
||||||
|
);
|
||||||
|
Ok(ScrollingHistory(MAX_SCROLLBACK_LINES))
|
||||||
|
} else {
|
||||||
|
Ok(ScrollingHistory(lines))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
error!("Problem with config: {}; using default value", err);
|
||||||
|
Ok(Default::default())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
use crate::config::{Config, DEFAULT_ALACRITTY_CONFIG};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_config() {
|
||||||
|
let config: Config =
|
||||||
|
::serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG).expect("deserialize config");
|
||||||
|
|
||||||
|
// Sanity check that mouse bindings are being parsed
|
||||||
|
assert!(!config.mouse_bindings.is_empty());
|
||||||
|
|
||||||
|
// Sanity check that key bindings are being parsed
|
||||||
|
assert!(!config.key_bindings.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_match_empty() {
|
||||||
|
let default = Config::default();
|
||||||
|
|
||||||
|
let empty = serde_yaml::from_str("key: val\n").unwrap();
|
||||||
|
|
||||||
|
assert_eq!(default, empty);
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use crate::config::failure_default;
|
||||||
|
use crate::term::color::Rgb;
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct VisualBellConfig {
|
||||||
|
/// Visual bell animation function
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub animation: VisualBellAnimation,
|
||||||
|
|
||||||
|
/// Visual bell duration in milliseconds
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub duration: u16,
|
||||||
|
|
||||||
|
/// Visual bell flash color
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub color: Rgb,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VisualBellConfig {
|
||||||
|
fn default() -> VisualBellConfig {
|
||||||
|
VisualBellConfig {
|
||||||
|
animation: Default::default(),
|
||||||
|
duration: Default::default(),
|
||||||
|
color: default_visual_bell_color(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisualBellConfig {
|
||||||
|
/// Visual bell duration in milliseconds
|
||||||
|
#[inline]
|
||||||
|
pub fn duration(&self) -> Duration {
|
||||||
|
Duration::from_millis(u64::from(self.duration))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `VisualBellAnimations` are modeled after a subset of CSS transitions and Robert
|
||||||
|
/// Penner's Easing Functions.
|
||||||
|
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq)]
|
||||||
|
pub enum VisualBellAnimation {
|
||||||
|
Ease, // CSS
|
||||||
|
EaseOut, // CSS
|
||||||
|
EaseOutSine, // Penner
|
||||||
|
EaseOutQuad, // Penner
|
||||||
|
EaseOutCubic, // Penner
|
||||||
|
EaseOutQuart, // Penner
|
||||||
|
EaseOutQuint, // Penner
|
||||||
|
EaseOutExpo, // Penner
|
||||||
|
EaseOutCirc, // Penner
|
||||||
|
Linear,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VisualBellAnimation {
|
||||||
|
fn default() -> Self {
|
||||||
|
VisualBellAnimation::EaseOutExpo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_visual_bell_color() -> Rgb {
|
||||||
|
Rgb { r: 255, g: 255, b: 255 }
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
use crate::config::{failure_default, Delta};
|
||||||
|
use crate::index::{Column, Line};
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)]
|
||||||
|
pub struct WindowConfig {
|
||||||
|
/// Initial dimensions
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub dimensions: Dimensions,
|
||||||
|
|
||||||
|
/// Initial position
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub position: Option<Delta<i32>>,
|
||||||
|
|
||||||
|
/// Pixel padding
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub padding: Delta<u8>,
|
||||||
|
|
||||||
|
/// Draw the window with title bar / borders
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub decorations: Decorations,
|
||||||
|
|
||||||
|
/// Spread out additional padding evenly
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub dynamic_padding: bool,
|
||||||
|
|
||||||
|
/// Startup mode
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
startup_mode: StartupMode,
|
||||||
|
|
||||||
|
/// Window title
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub title: Option<String>,
|
||||||
|
|
||||||
|
/// Window class
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub class: Option<String>,
|
||||||
|
|
||||||
|
/// TODO: DEPRECATED
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
pub start_maximized: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowConfig {
|
||||||
|
pub fn startup_mode(&self) -> StartupMode {
|
||||||
|
match self.start_maximized {
|
||||||
|
Some(true) => StartupMode::Maximized,
|
||||||
|
_ => self.startup_mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum StartupMode {
|
||||||
|
Windowed,
|
||||||
|
Maximized,
|
||||||
|
Fullscreen,
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
SimpleFullscreen,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for StartupMode {
|
||||||
|
fn default() -> StartupMode {
|
||||||
|
StartupMode::Windowed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize)]
|
||||||
|
pub enum Decorations {
|
||||||
|
#[serde(rename = "full")]
|
||||||
|
Full,
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
#[serde(rename = "transparent")]
|
||||||
|
Transparent,
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
#[serde(rename = "buttonless")]
|
||||||
|
Buttonless,
|
||||||
|
#[serde(rename = "none")]
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Decorations {
|
||||||
|
fn default() -> Decorations {
|
||||||
|
Decorations::Full
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Window Dimensions
|
||||||
|
///
|
||||||
|
/// Newtype to avoid passing values incorrectly
|
||||||
|
#[serde(default)]
|
||||||
|
#[derive(Default, Debug, Copy, Clone, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct Dimensions {
|
||||||
|
/// Window width in character columns
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
columns: Column,
|
||||||
|
|
||||||
|
/// Window Height in character lines
|
||||||
|
#[serde(deserialize_with = "failure_default")]
|
||||||
|
lines: Line,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dimensions {
|
||||||
|
pub fn new(columns: Column, lines: Line) -> Self {
|
||||||
|
Dimensions { columns, lines }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get lines
|
||||||
|
#[inline]
|
||||||
|
pub fn lines_u32(&self) -> u32 {
|
||||||
|
self.lines.0 as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get columns
|
||||||
|
#[inline]
|
||||||
|
pub fn columns_u32(&self) -> u32 {
|
||||||
|
self.columns.0 as u32
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@
|
||||||
//! The display subsystem including window management, font rasterization, and
|
//! The display subsystem including window management, font rasterization, and
|
||||||
//! GPU drawing.
|
//! GPU drawing.
|
||||||
use std::f64;
|
use std::f64;
|
||||||
|
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ use glutin::dpi::{PhysicalPosition, PhysicalSize};
|
||||||
use glutin::EventsLoop;
|
use glutin::EventsLoop;
|
||||||
use parking_lot::MutexGuard;
|
use parking_lot::MutexGuard;
|
||||||
|
|
||||||
use crate::config::{Config, Options, StartupMode};
|
use crate::config::{Config, StartupMode};
|
||||||
use crate::index::Line;
|
use crate::index::Line;
|
||||||
use crate::message_bar::Message;
|
use crate::message_bar::Message;
|
||||||
use crate::meter::Meter;
|
use crate::meter::Meter;
|
||||||
|
@ -134,7 +135,7 @@ impl Display {
|
||||||
&self.size_info
|
&self.size_info
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(config: &Config, options: &Options) -> Result<Display, Error> {
|
pub fn new(config: &Config) -> 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();
|
||||||
|
|
||||||
|
@ -146,8 +147,7 @@ impl Display {
|
||||||
// Guess the target window dimensions
|
// Guess the target window dimensions
|
||||||
let metrics = GlyphCache::static_metrics(config, estimated_dpr as f32)?;
|
let metrics = GlyphCache::static_metrics(config, estimated_dpr as f32)?;
|
||||||
let (cell_width, cell_height) = Self::compute_cell_size(config, &metrics);
|
let (cell_width, cell_height) = Self::compute_cell_size(config, &metrics);
|
||||||
let dimensions =
|
let dimensions = Self::calculate_dimensions(config, estimated_dpr, cell_width, cell_height);
|
||||||
Self::calculate_dimensions(config, options, estimated_dpr, cell_width, cell_height);
|
|
||||||
|
|
||||||
debug!("Estimated DPR: {}", estimated_dpr);
|
debug!("Estimated DPR: {}", estimated_dpr);
|
||||||
debug!("Estimated Cell Size: {} x {}", cell_width, cell_height);
|
debug!("Estimated Cell Size: {} x {}", cell_width, cell_height);
|
||||||
|
@ -155,7 +155,7 @@ impl Display {
|
||||||
|
|
||||||
// Create the window where Alacritty will be displayed
|
// Create the window where Alacritty will be displayed
|
||||||
let logical = dimensions.map(|d| PhysicalSize::new(d.0, d.1).to_logical(estimated_dpr));
|
let logical = dimensions.map(|d| PhysicalSize::new(d.0, d.1).to_logical(estimated_dpr));
|
||||||
let mut window = Window::new(event_loop, &options, config.window(), logical)?;
|
let mut window = Window::new(event_loop, &config, logical)?;
|
||||||
|
|
||||||
let dpr = window.hidpi_factor();
|
let dpr = window.hidpi_factor();
|
||||||
info!("Device pixel ratio: {}", dpr);
|
info!("Device pixel ratio: {}", dpr);
|
||||||
|
@ -170,11 +170,11 @@ impl Display {
|
||||||
let (glyph_cache, cell_width, cell_height) =
|
let (glyph_cache, cell_width, cell_height) =
|
||||||
Self::new_glyph_cache(dpr, &mut renderer, config)?;
|
Self::new_glyph_cache(dpr, &mut renderer, config)?;
|
||||||
|
|
||||||
let mut padding_x = f64::from(config.padding().x) * dpr;
|
let mut padding_x = f64::from(config.window.padding.x) * dpr;
|
||||||
let mut padding_y = f64::from(config.padding().y) * dpr;
|
let mut padding_y = f64::from(config.window.padding.y) * dpr;
|
||||||
|
|
||||||
if let Some((width, height)) =
|
if let Some((width, height)) =
|
||||||
Self::calculate_dimensions(config, options, dpr, cell_width, cell_height)
|
Self::calculate_dimensions(config, dpr, cell_width, cell_height)
|
||||||
{
|
{
|
||||||
if dimensions == Some((width, height)) {
|
if dimensions == Some((width, height)) {
|
||||||
info!("Estimated DPR correctly, skipping resize");
|
info!("Estimated DPR correctly, skipping resize");
|
||||||
|
@ -182,7 +182,7 @@ impl Display {
|
||||||
viewport_size = PhysicalSize::new(width, height);
|
viewport_size = PhysicalSize::new(width, height);
|
||||||
window.set_inner_size(viewport_size.to_logical(dpr));
|
window.set_inner_size(viewport_size.to_logical(dpr));
|
||||||
}
|
}
|
||||||
} else if config.window().dynamic_padding() {
|
} else if config.window.dynamic_padding {
|
||||||
// Make sure additional padding is spread evenly
|
// Make sure additional padding is spread evenly
|
||||||
let cw = f64::from(cell_width);
|
let cw = f64::from(cell_width);
|
||||||
let ch = f64::from(cell_height);
|
let ch = f64::from(cell_height);
|
||||||
|
@ -219,7 +219,7 @@ impl Display {
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
// Clear screen
|
// Clear screen
|
||||||
let background_color = config.colors().primary.background;
|
let background_color = config.colors.primary.background;
|
||||||
renderer.with_api(config, &size_info, |api| {
|
renderer.with_api(config, &size_info, |api| {
|
||||||
api.clear(background_color);
|
api.clear(background_color);
|
||||||
});
|
});
|
||||||
|
@ -232,7 +232,7 @@ impl Display {
|
||||||
tx,
|
tx,
|
||||||
rx,
|
rx,
|
||||||
meter: Meter::new(),
|
meter: Meter::new(),
|
||||||
font_size: config.font().size(),
|
font_size: config.font.size,
|
||||||
size_info,
|
size_info,
|
||||||
last_message: None,
|
last_message: None,
|
||||||
})
|
})
|
||||||
|
@ -240,22 +240,21 @@ impl Display {
|
||||||
|
|
||||||
fn calculate_dimensions(
|
fn calculate_dimensions(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
options: &Options,
|
|
||||||
dpr: f64,
|
dpr: f64,
|
||||||
cell_width: f32,
|
cell_width: f32,
|
||||||
cell_height: f32,
|
cell_height: f32,
|
||||||
) -> Option<(f64, f64)> {
|
) -> Option<(f64, f64)> {
|
||||||
let dimensions = options.dimensions().unwrap_or_else(|| config.dimensions());
|
let dimensions = config.window.dimensions;
|
||||||
|
|
||||||
if dimensions.columns_u32() == 0
|
if dimensions.columns_u32() == 0
|
||||||
|| dimensions.lines_u32() == 0
|
|| dimensions.lines_u32() == 0
|
||||||
|| config.window().startup_mode() != StartupMode::Windowed
|
|| config.window.startup_mode() != StartupMode::Windowed
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let padding_x = f64::from(config.padding().x) * dpr;
|
let padding_x = f64::from(config.window.padding.x) * dpr;
|
||||||
let padding_y = f64::from(config.padding().y) * dpr;
|
let padding_y = f64::from(config.window.padding.y) * dpr;
|
||||||
|
|
||||||
// Calculate new size based on cols/lines specified in config
|
// Calculate new size based on cols/lines specified in config
|
||||||
let grid_width = cell_width as u32 * dimensions.columns_u32();
|
let grid_width = cell_width as u32 * dimensions.columns_u32();
|
||||||
|
@ -272,8 +271,8 @@ impl Display {
|
||||||
renderer: &mut QuadRenderer,
|
renderer: &mut QuadRenderer,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
) -> Result<(GlyphCache, f32, f32), Error> {
|
) -> Result<(GlyphCache, f32, f32), Error> {
|
||||||
let font = config.font().clone();
|
let font = config.font.clone();
|
||||||
let rasterizer = font::Rasterizer::new(dpr as f32, config.use_thin_strokes())?;
|
let rasterizer = font::Rasterizer::new(dpr as f32, config.font.use_thin_strokes())?;
|
||||||
|
|
||||||
// Initialize glyph cache
|
// Initialize glyph cache
|
||||||
let glyph_cache = {
|
let glyph_cache = {
|
||||||
|
@ -304,7 +303,7 @@ impl Display {
|
||||||
let size = self.font_size;
|
let size = self.font_size;
|
||||||
|
|
||||||
self.renderer.with_loader(|mut api| {
|
self.renderer.with_loader(|mut api| {
|
||||||
let _ = cache.update_font_size(config.font(), size, dpr, &mut api);
|
let _ = cache.update_font_size(&config.font, size, dpr, &mut api);
|
||||||
});
|
});
|
||||||
|
|
||||||
let (cw, ch) = Self::compute_cell_size(config, &cache.font_metrics());
|
let (cw, ch) = Self::compute_cell_size(config, &cache.font_metrics());
|
||||||
|
@ -313,8 +312,8 @@ impl Display {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_cell_size(config: &Config, metrics: &font::Metrics) -> (f32, f32) {
|
fn compute_cell_size(config: &Config, metrics: &font::Metrics) -> (f32, f32) {
|
||||||
let offset_x = f64::from(config.font().offset().x);
|
let offset_x = f64::from(config.font.offset.x);
|
||||||
let offset_y = f64::from(config.font().offset().y);
|
let offset_y = f64::from(config.font.offset.y);
|
||||||
(
|
(
|
||||||
f32::max(1., ((metrics.average_advance + offset_x) as f32).floor()),
|
f32::max(1., ((metrics.average_advance + offset_x) as f32).floor()),
|
||||||
f32::max(1., ((metrics.line_height + offset_y) as f32).floor()),
|
f32::max(1., ((metrics.line_height + offset_y) as f32).floor()),
|
||||||
|
@ -395,10 +394,10 @@ impl Display {
|
||||||
self.size_info.width = width;
|
self.size_info.width = width;
|
||||||
self.size_info.height = height;
|
self.size_info.height = height;
|
||||||
|
|
||||||
let mut padding_x = f32::from(config.padding().x) * dpr as f32;
|
let mut padding_x = f32::from(config.window.padding.x) * dpr as f32;
|
||||||
let mut padding_y = f32::from(config.padding().y) * dpr as f32;
|
let mut padding_y = f32::from(config.window.padding.y) * dpr as f32;
|
||||||
|
|
||||||
if config.window().dynamic_padding() {
|
if config.window.dynamic_padding {
|
||||||
padding_x = padding_x + ((width - 2. * padding_x) % cell_width) / 2.;
|
padding_x = padding_x + ((width - 2. * padding_x) % cell_width) / 2.;
|
||||||
padding_y = padding_y + ((height - 2. * padding_y) % cell_height) / 2.;
|
padding_y = padding_y + ((height - 2. * padding_y) % cell_height) / 2.;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use parking_lot::MutexGuard;
|
||||||
use serde_json as json;
|
use serde_json as json;
|
||||||
|
|
||||||
use crate::clipboard::ClipboardType;
|
use crate::clipboard::ClipboardType;
|
||||||
use crate::config::{self, Config, Options};
|
use crate::config::{self, Config};
|
||||||
use crate::display::OnResize;
|
use crate::display::OnResize;
|
||||||
use crate::grid::Scroll;
|
use crate::grid::Scroll;
|
||||||
use crate::index::{Column, Line, Point, Side};
|
use crate::index::{Column, Line, Point, Side};
|
||||||
|
@ -312,31 +312,29 @@ impl<N: Notify> Processor<N> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
notifier: N,
|
notifier: N,
|
||||||
resize_tx: mpsc::Sender<PhysicalSize>,
|
resize_tx: mpsc::Sender<PhysicalSize>,
|
||||||
options: &Options,
|
|
||||||
config: &Config,
|
config: &Config,
|
||||||
ref_test: bool,
|
|
||||||
size_info: SizeInfo,
|
size_info: SizeInfo,
|
||||||
) -> Processor<N> {
|
) -> Processor<N> {
|
||||||
Processor {
|
Processor {
|
||||||
key_bindings: config.key_bindings().to_vec(),
|
key_bindings: config.key_bindings.to_vec(),
|
||||||
mouse_bindings: config.mouse_bindings().to_vec(),
|
mouse_bindings: config.mouse_bindings.to_vec(),
|
||||||
mouse_config: config.mouse().to_owned(),
|
mouse_config: config.mouse.to_owned(),
|
||||||
scrolling_config: config.scrolling(),
|
scrolling_config: config.scrolling,
|
||||||
print_events: options.print_events,
|
print_events: config.debug.print_events,
|
||||||
wait_for_event: true,
|
wait_for_event: true,
|
||||||
notifier,
|
notifier,
|
||||||
resize_tx,
|
resize_tx,
|
||||||
ref_test,
|
ref_test: config.debug.ref_test,
|
||||||
mouse: Default::default(),
|
mouse: Default::default(),
|
||||||
size_info,
|
size_info,
|
||||||
hide_mouse_when_typing: config.hide_mouse_when_typing(),
|
hide_mouse_when_typing: config.mouse.hide_when_typing,
|
||||||
hide_mouse: false,
|
hide_mouse: false,
|
||||||
received_count: 0,
|
received_count: 0,
|
||||||
suppress_chars: false,
|
suppress_chars: false,
|
||||||
last_modifiers: Default::default(),
|
last_modifiers: Default::default(),
|
||||||
pending_events: Vec::with_capacity(4),
|
pending_events: Vec::with_capacity(4),
|
||||||
window_changes: Default::default(),
|
window_changes: Default::default(),
|
||||||
save_to_clipboard: config.selection().save_to_clipboard,
|
save_to_clipboard: config.selection.save_to_clipboard,
|
||||||
alt_send_esc: config.alt_send_esc(),
|
alt_send_esc: config.alt_send_esc(),
|
||||||
is_fullscreen: false,
|
is_fullscreen: false,
|
||||||
is_simple_fullscreen: false,
|
is_simple_fullscreen: false,
|
||||||
|
@ -580,10 +578,10 @@ impl<N: Notify> Processor<N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_config(&mut self, config: &Config) {
|
pub fn update_config(&mut self, config: &Config) {
|
||||||
self.key_bindings = config.key_bindings().to_vec();
|
self.key_bindings = config.key_bindings.to_vec();
|
||||||
self.mouse_bindings = config.mouse_bindings().to_vec();
|
self.mouse_bindings = config.mouse_bindings.to_vec();
|
||||||
self.mouse_config = config.mouse().to_owned();
|
self.mouse_config = config.mouse.to_owned();
|
||||||
self.save_to_clipboard = config.selection().save_to_clipboard;
|
self.save_to_clipboard = config.selection.save_to_clipboard;
|
||||||
self.alt_send_esc = config.alt_send_esc();
|
self.alt_send_esc = config.alt_send_esc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,9 +193,10 @@ impl<T> Binding<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
/// Write an escape sequence
|
/// Write an escape sequence
|
||||||
|
#[serde(skip)]
|
||||||
Esc(String),
|
Esc(String),
|
||||||
|
|
||||||
/// Paste contents of system clipboard
|
/// Paste contents of system clipboard
|
||||||
|
@ -238,6 +239,7 @@ pub enum Action {
|
||||||
ClearHistory,
|
ClearHistory,
|
||||||
|
|
||||||
/// Run given command
|
/// Run given command
|
||||||
|
#[serde(skip)]
|
||||||
Command(String, Vec<String>),
|
Command(String, Vec<String>),
|
||||||
|
|
||||||
/// Hides the Alacritty window
|
/// Hides the Alacritty window
|
||||||
|
@ -281,17 +283,13 @@ impl Action {
|
||||||
ctx.copy_selection(ClipboardType::Primary);
|
ctx.copy_selection(ClipboardType::Primary);
|
||||||
},
|
},
|
||||||
Action::Paste => {
|
Action::Paste => {
|
||||||
let text = ctx.terminal_mut()
|
let text = ctx.terminal_mut().clipboard().load(ClipboardType::Primary);
|
||||||
.clipboard()
|
|
||||||
.load(ClipboardType::Primary);
|
|
||||||
self.paste(ctx, &text);
|
self.paste(ctx, &text);
|
||||||
},
|
},
|
||||||
Action::PasteSelection => {
|
Action::PasteSelection => {
|
||||||
// Only paste if mouse events are not captured by an application
|
// Only paste if mouse events are not captured by an application
|
||||||
if !mouse_mode {
|
if !mouse_mode {
|
||||||
let text = ctx.terminal_mut()
|
let text = ctx.terminal_mut().clipboard().load(ClipboardType::Secondary);
|
||||||
.clipboard()
|
|
||||||
.load(ClipboardType::Secondary);
|
|
||||||
self.paste(ctx, &text);
|
self.paste(ctx, &text);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -454,7 +452,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG | TermMode::MOUSE_REPORT_CLICK;
|
TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG | TermMode::MOUSE_REPORT_CLICK;
|
||||||
|
|
||||||
// Only show URLs as launchable when all required modifiers are pressed
|
// Only show URLs as launchable when all required modifiers are pressed
|
||||||
let url = if self.mouse_config.url.modifiers.relaxed_eq(modifiers)
|
let url = if self.mouse_config.url.mods().relaxed_eq(modifiers)
|
||||||
&& (!self.ctx.terminal().mode().intersects(mouse_mode) || modifiers.shift)
|
&& (!self.ctx.terminal().mode().intersects(mouse_mode) || modifiers.shift)
|
||||||
&& self.mouse_config.url.launcher.is_some()
|
&& self.mouse_config.url.launcher.is_some()
|
||||||
{
|
{
|
||||||
|
@ -663,7 +661,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
|
|
||||||
// Spawn URL launcher when clicking on URLs
|
// Spawn URL launcher when clicking on URLs
|
||||||
fn launch_url(&self, modifiers: ModifiersState, point: Point) -> Option<()> {
|
fn launch_url(&self, modifiers: ModifiersState, point: Point) -> Option<()> {
|
||||||
if !self.mouse_config.url.modifiers.relaxed_eq(modifiers)
|
if !self.mouse_config.url.mods().relaxed_eq(modifiers)
|
||||||
|| self.ctx.mouse().block_url_launcher
|
|| self.ctx.mouse().block_url_launcher
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
|
@ -715,10 +713,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
let height = self.ctx.size_info().cell_height as i32;
|
let height = self.ctx.size_info().cell_height as i32;
|
||||||
|
|
||||||
// Make sure the new and deprecated setting are both allowed
|
// Make sure the new and deprecated setting are both allowed
|
||||||
let faux_multiplier = self
|
let faux_multiplier = self.scrolling_config.faux_multiplier() as usize;
|
||||||
.mouse_config
|
|
||||||
.faux_scrollback_lines
|
|
||||||
.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;
|
||||||
|
@ -746,7 +741,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
}
|
}
|
||||||
self.ctx.write_to_pty(content);
|
self.ctx.write_to_pty(content);
|
||||||
} else {
|
} else {
|
||||||
let multiplier = i32::from(self.scrolling_config.multiplier);
|
let multiplier = i32::from(self.scrolling_config.multiplier());
|
||||||
self.ctx.mouse_mut().scroll_px += new_scroll_px * multiplier;
|
self.ctx.mouse_mut().scroll_px += new_scroll_px * multiplier;
|
||||||
|
|
||||||
let lines = self.ctx.mouse().scroll_px / height;
|
let lines = self.ctx.mouse().scroll_px / height;
|
||||||
|
@ -1117,13 +1112,12 @@ mod tests {
|
||||||
threshold: Duration::from_millis(1000),
|
threshold: Duration::from_millis(1000),
|
||||||
},
|
},
|
||||||
hide_when_typing: false,
|
hide_when_typing: false,
|
||||||
faux_scrollback_lines: None,
|
|
||||||
url: Default::default(),
|
url: Default::default(),
|
||||||
},
|
},
|
||||||
scrolling_config: &config::Scrolling::default(),
|
scrolling_config: &config::Scrolling::default(),
|
||||||
key_bindings: &config.key_bindings()[..],
|
key_bindings: &config.key_bindings[..],
|
||||||
mouse_bindings: &config.mouse_bindings()[..],
|
mouse_bindings: &config.mouse_bindings[..],
|
||||||
save_to_clipboard: config.selection().save_to_clipboard,
|
save_to_clipboard: config.selection.save_to_clipboard,
|
||||||
alt_send_esc: config.alt_send_esc(),
|
alt_send_esc: config.alt_send_esc(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -197,19 +197,19 @@ impl GlyphCache {
|
||||||
// Need to load at least one glyph for the face before calling metrics.
|
// Need to load at least one glyph for the face before calling metrics.
|
||||||
// The glyph requested here ('m' at the time of writing) has no special
|
// The glyph requested here ('m' at the time of writing) has no special
|
||||||
// meaning.
|
// meaning.
|
||||||
rasterizer.get_glyph(GlyphKey { font_key: regular, c: 'm', size: font.size() })?;
|
rasterizer.get_glyph(GlyphKey { font_key: regular, c: 'm', size: font.size })?;
|
||||||
|
|
||||||
let metrics = rasterizer.metrics(regular, font.size())?;
|
let metrics = rasterizer.metrics(regular, font.size)?;
|
||||||
|
|
||||||
let mut cache = GlyphCache {
|
let mut cache = GlyphCache {
|
||||||
cache: HashMap::default(),
|
cache: HashMap::default(),
|
||||||
cursor_cache: HashMap::default(),
|
cursor_cache: HashMap::default(),
|
||||||
rasterizer,
|
rasterizer,
|
||||||
font_size: font.size(),
|
font_size: font.size,
|
||||||
font_key: regular,
|
font_key: regular,
|
||||||
bold_key: bold,
|
bold_key: bold,
|
||||||
italic_key: italic,
|
italic_key: italic,
|
||||||
glyph_offset: *font.glyph_offset(),
|
glyph_offset: font.glyph_offset,
|
||||||
metrics,
|
metrics,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ impl GlyphCache {
|
||||||
font: &config::Font,
|
font: &config::Font,
|
||||||
rasterizer: &mut Rasterizer,
|
rasterizer: &mut Rasterizer,
|
||||||
) -> Result<(FontKey, FontKey, FontKey), font::Error> {
|
) -> Result<(FontKey, FontKey, FontKey), font::Error> {
|
||||||
let size = font.size();
|
let size = font.size;
|
||||||
|
|
||||||
// Load regular font
|
// Load regular font
|
||||||
let regular_desc =
|
let regular_desc =
|
||||||
|
@ -320,7 +320,7 @@ impl GlyphCache {
|
||||||
let font = font.to_owned().with_size(size);
|
let font = font.to_owned().with_size(size);
|
||||||
let (regular, bold, italic) = Self::compute_font_keys(&font, &mut self.rasterizer)?;
|
let (regular, bold, italic) = Self::compute_font_keys(&font, &mut self.rasterizer)?;
|
||||||
|
|
||||||
self.rasterizer.get_glyph(GlyphKey { font_key: regular, c: 'm', size: font.size() })?;
|
self.rasterizer.get_glyph(GlyphKey { font_key: regular, c: 'm', size: font.size })?;
|
||||||
let metrics = self.rasterizer.metrics(regular, size)?;
|
let metrics = self.rasterizer.metrics(regular, size)?;
|
||||||
|
|
||||||
info!("Font size changed to {:?} with DPR of {}", font.size, dpr);
|
info!("Font size changed to {:?} with DPR of {}", font.size, dpr);
|
||||||
|
@ -342,15 +342,15 @@ impl GlyphCache {
|
||||||
//
|
//
|
||||||
// This should only be used *before* OpenGL is initialized and the glyph cache can be filled.
|
// This should only be used *before* OpenGL is initialized and the glyph cache can be filled.
|
||||||
pub fn static_metrics(config: &Config, dpr: f32) -> Result<font::Metrics, font::Error> {
|
pub fn static_metrics(config: &Config, dpr: f32) -> Result<font::Metrics, font::Error> {
|
||||||
let font = config.font().clone();
|
let font = config.font.clone();
|
||||||
|
|
||||||
let mut rasterizer = font::Rasterizer::new(dpr, config.use_thin_strokes())?;
|
let mut rasterizer = font::Rasterizer::new(dpr, config.font.use_thin_strokes())?;
|
||||||
let regular_desc =
|
let regular_desc =
|
||||||
GlyphCache::make_desc(&font.normal(), font::Slant::Normal, font::Weight::Normal);
|
GlyphCache::make_desc(&font.normal(), font::Slant::Normal, font::Weight::Normal);
|
||||||
let regular = rasterizer.load_font(®ular_desc, font.size())?;
|
let regular = rasterizer.load_font(®ular_desc, font.size)?;
|
||||||
rasterizer.get_glyph(GlyphKey { font_key: regular, c: 'm', size: font.size() })?;
|
rasterizer.get_glyph(GlyphKey { font_key: regular, c: 'm', size: font.size })?;
|
||||||
|
|
||||||
rasterizer.metrics(regular, font.size())
|
rasterizer.metrics(regular, font.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,7 +713,7 @@ impl QuadRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw visual bell
|
// Draw visual bell
|
||||||
let color = config.visual_bell().color();
|
let color = config.visual_bell.color;
|
||||||
let rect = Rect::new(0., 0., props.width, props.height);
|
let rect = Rect::new(0., 0., props.width, props.height);
|
||||||
self.render_rect(&rect, color, visual_bell_intensity as f32, props);
|
self.render_rect(&rect, color, visual_bell_intensity as f32, props);
|
||||||
|
|
||||||
|
@ -890,7 +890,7 @@ impl QuadRenderer {
|
||||||
|
|
||||||
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();
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::ClearColor(
|
gl::ClearColor(
|
||||||
(f32::from(color.r) / 255.0).min(1.0) * alpha,
|
(f32::from(color.r) / 255.0).min(1.0) * alpha,
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{Index, IndexMut, Mul};
|
use std::ops::{Index, IndexMut, Mul};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use serde::de::Visitor;
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
use crate::ansi;
|
use crate::ansi;
|
||||||
use crate::config::Colors;
|
use crate::config::Colors;
|
||||||
|
@ -9,7 +13,7 @@ pub const COUNT: usize = 270;
|
||||||
pub const RED: Rgb = Rgb { r: 0xff, g: 0x0, b: 0x0 };
|
pub const RED: Rgb = Rgb { r: 0xff, g: 0x0, b: 0x0 };
|
||||||
pub const YELLOW: Rgb = Rgb { r: 0xff, g: 0xff, b: 0x0 };
|
pub const YELLOW: Rgb = Rgb { r: 0xff, g: 0xff, b: 0x0 };
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default, Serialize)]
|
||||||
pub struct Rgb {
|
pub struct Rgb {
|
||||||
pub r: u8,
|
pub r: u8,
|
||||||
pub g: u8,
|
pub g: u8,
|
||||||
|
@ -33,6 +37,99 @@ impl Mul<f32> for Rgb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserialize an Rgb from a hex string
|
||||||
|
///
|
||||||
|
/// This is *not* the deserialize impl for Rgb since we want a symmetric
|
||||||
|
/// serialize/deserialize impl for ref tests.
|
||||||
|
impl<'de> Deserialize<'de> for Rgb {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct RgbVisitor;
|
||||||
|
|
||||||
|
// Used for deserializing reftests
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct RgbDerivedDeser {
|
||||||
|
r: u8,
|
||||||
|
g: u8,
|
||||||
|
b: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Visitor<'a> for RgbVisitor {
|
||||||
|
type Value = Rgb;
|
||||||
|
|
||||||
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str("hex color like 0xff00ff")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> ::std::result::Result<Rgb, E>
|
||||||
|
where
|
||||||
|
E: ::serde::de::Error,
|
||||||
|
{
|
||||||
|
Rgb::from_str(&value[..])
|
||||||
|
.map_err(|_| E::custom("failed to parse rgb; expected hex color like 0xff00ff"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an error if the syntax is incorrect
|
||||||
|
let value = serde_yaml::Value::deserialize(deserializer)?;
|
||||||
|
|
||||||
|
// Attempt to deserialize from struct form
|
||||||
|
if let Ok(RgbDerivedDeser { r, g, b }) = RgbDerivedDeser::deserialize(value.clone()) {
|
||||||
|
return Ok(Rgb { r, g, b });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize from hex notation (either 0xff00ff or #ff00ff)
|
||||||
|
match value.deserialize_str(RgbVisitor) {
|
||||||
|
Ok(rgb) => Ok(rgb),
|
||||||
|
Err(err) => {
|
||||||
|
error!("Problem with config: {}; using color #000000", err);
|
||||||
|
Ok(Rgb::default())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Rgb {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> ::std::result::Result<Rgb, ()> {
|
||||||
|
let mut chars = s.chars();
|
||||||
|
let mut rgb = Rgb::default();
|
||||||
|
|
||||||
|
macro_rules! component {
|
||||||
|
($($c:ident),*) => {
|
||||||
|
$(
|
||||||
|
match chars.next().and_then(|c| c.to_digit(16)) {
|
||||||
|
Some(val) => rgb.$c = (val as u8) << 4,
|
||||||
|
None => return Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
match chars.next().and_then(|c| c.to_digit(16)) {
|
||||||
|
Some(val) => rgb.$c |= val as u8,
|
||||||
|
None => return Err(())
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match chars.next() {
|
||||||
|
Some('0') => {
|
||||||
|
if chars.next() != Some('x') {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some('#') => (),
|
||||||
|
_ => return Err(()),
|
||||||
|
}
|
||||||
|
|
||||||
|
component!(r, g, b);
|
||||||
|
|
||||||
|
Ok(rgb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
|
@ -60,24 +157,24 @@ impl<'a> From<&'a Colors> for List {
|
||||||
impl List {
|
impl List {
|
||||||
pub fn fill_named(&mut self, colors: &Colors) {
|
pub fn fill_named(&mut self, colors: &Colors) {
|
||||||
// Normals
|
// Normals
|
||||||
self[ansi::NamedColor::Black] = colors.normal.black;
|
self[ansi::NamedColor::Black] = colors.normal().black;
|
||||||
self[ansi::NamedColor::Red] = colors.normal.red;
|
self[ansi::NamedColor::Red] = colors.normal().red;
|
||||||
self[ansi::NamedColor::Green] = colors.normal.green;
|
self[ansi::NamedColor::Green] = colors.normal().green;
|
||||||
self[ansi::NamedColor::Yellow] = colors.normal.yellow;
|
self[ansi::NamedColor::Yellow] = colors.normal().yellow;
|
||||||
self[ansi::NamedColor::Blue] = colors.normal.blue;
|
self[ansi::NamedColor::Blue] = colors.normal().blue;
|
||||||
self[ansi::NamedColor::Magenta] = colors.normal.magenta;
|
self[ansi::NamedColor::Magenta] = colors.normal().magenta;
|
||||||
self[ansi::NamedColor::Cyan] = colors.normal.cyan;
|
self[ansi::NamedColor::Cyan] = colors.normal().cyan;
|
||||||
self[ansi::NamedColor::White] = colors.normal.white;
|
self[ansi::NamedColor::White] = colors.normal().white;
|
||||||
|
|
||||||
// Brights
|
// Brights
|
||||||
self[ansi::NamedColor::BrightBlack] = colors.bright.black;
|
self[ansi::NamedColor::BrightBlack] = colors.bright().black;
|
||||||
self[ansi::NamedColor::BrightRed] = colors.bright.red;
|
self[ansi::NamedColor::BrightRed] = colors.bright().red;
|
||||||
self[ansi::NamedColor::BrightGreen] = colors.bright.green;
|
self[ansi::NamedColor::BrightGreen] = colors.bright().green;
|
||||||
self[ansi::NamedColor::BrightYellow] = colors.bright.yellow;
|
self[ansi::NamedColor::BrightYellow] = colors.bright().yellow;
|
||||||
self[ansi::NamedColor::BrightBlue] = colors.bright.blue;
|
self[ansi::NamedColor::BrightBlue] = colors.bright().blue;
|
||||||
self[ansi::NamedColor::BrightMagenta] = colors.bright.magenta;
|
self[ansi::NamedColor::BrightMagenta] = colors.bright().magenta;
|
||||||
self[ansi::NamedColor::BrightCyan] = colors.bright.cyan;
|
self[ansi::NamedColor::BrightCyan] = colors.bright().cyan;
|
||||||
self[ansi::NamedColor::BrightWhite] = colors.bright.white;
|
self[ansi::NamedColor::BrightWhite] = colors.bright().white;
|
||||||
self[ansi::NamedColor::BrightForeground] =
|
self[ansi::NamedColor::BrightForeground] =
|
||||||
colors.primary.bright_foreground.unwrap_or(colors.primary.foreground);
|
colors.primary.bright_foreground.unwrap_or(colors.primary.foreground);
|
||||||
|
|
||||||
|
@ -106,14 +203,14 @@ impl List {
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
trace!("Deriving dim colors from normal colors");
|
trace!("Deriving dim colors from normal colors");
|
||||||
self[ansi::NamedColor::DimBlack] = colors.normal.black * 0.66;
|
self[ansi::NamedColor::DimBlack] = colors.normal().black * 0.66;
|
||||||
self[ansi::NamedColor::DimRed] = colors.normal.red * 0.66;
|
self[ansi::NamedColor::DimRed] = colors.normal().red * 0.66;
|
||||||
self[ansi::NamedColor::DimGreen] = colors.normal.green * 0.66;
|
self[ansi::NamedColor::DimGreen] = colors.normal().green * 0.66;
|
||||||
self[ansi::NamedColor::DimYellow] = colors.normal.yellow * 0.66;
|
self[ansi::NamedColor::DimYellow] = colors.normal().yellow * 0.66;
|
||||||
self[ansi::NamedColor::DimBlue] = colors.normal.blue * 0.66;
|
self[ansi::NamedColor::DimBlue] = colors.normal().blue * 0.66;
|
||||||
self[ansi::NamedColor::DimMagenta] = colors.normal.magenta * 0.66;
|
self[ansi::NamedColor::DimMagenta] = colors.normal().magenta * 0.66;
|
||||||
self[ansi::NamedColor::DimCyan] = colors.normal.cyan * 0.66;
|
self[ansi::NamedColor::DimCyan] = colors.normal().cyan * 0.66;
|
||||||
self[ansi::NamedColor::DimWhite] = colors.normal.white * 0.66;
|
self[ansi::NamedColor::DimWhite] = colors.normal().white * 0.66;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,8 +227,8 @@ impl<'a> RenderableCellsIter<'a> {
|
||||||
let cursor = &term.cursor.point;
|
let cursor = &term.cursor.point;
|
||||||
let cursor_visible = term.mode.contains(TermMode::SHOW_CURSOR) && grid.contains(cursor);
|
let cursor_visible = term.mode.contains(TermMode::SHOW_CURSOR) && grid.contains(cursor);
|
||||||
let cursor_cell = if cursor_visible {
|
let cursor_cell = if cursor_visible {
|
||||||
let offset_x = config.font().offset().x;
|
let offset_x = config.font.offset.x;
|
||||||
let offset_y = config.font().offset().y;
|
let offset_y = config.font.offset.y;
|
||||||
|
|
||||||
let is_wide = grid[cursor].flags.contains(cell::Flags::WIDE_CHAR)
|
let is_wide = grid[cursor].flags.contains(cell::Flags::WIDE_CHAR)
|
||||||
&& (cursor.col + 1) < grid.num_cols();
|
&& (cursor.col + 1) < grid.num_cols();
|
||||||
|
@ -278,7 +278,7 @@ impl RenderableCell {
|
||||||
let mut fg_rgb = Self::compute_fg_rgb(config, colors, cell.fg, cell.flags);
|
let mut fg_rgb = Self::compute_fg_rgb(config, colors, cell.fg, cell.flags);
|
||||||
let mut bg_rgb = Self::compute_bg_rgb(colors, cell.bg);
|
let mut bg_rgb = Self::compute_bg_rgb(colors, cell.bg);
|
||||||
|
|
||||||
let selection_background = config.colors().selection.background;
|
let selection_background = config.colors.selection.background;
|
||||||
if let (true, Some(col)) = (selected, selection_background) {
|
if let (true, Some(col)) = (selected, selection_background) {
|
||||||
// Override selection background with config colors
|
// Override selection background with config colors
|
||||||
bg_rgb = col;
|
bg_rgb = col;
|
||||||
|
@ -294,7 +294,7 @@ impl RenderableCell {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override selection text with config colors
|
// Override selection text with config colors
|
||||||
if let (true, Some(col)) = (selected, config.colors().selection.text) {
|
if let (true, Some(col)) = (selected, config.colors.selection.text) {
|
||||||
fg_rgb = col;
|
fg_rgb = col;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +317,7 @@ impl RenderableCell {
|
||||||
// If no bright foreground is set, treat it like the BOLD flag doesn't exist
|
// If no bright foreground is set, treat it like the BOLD flag doesn't exist
|
||||||
(_, cell::Flags::DIM_BOLD)
|
(_, cell::Flags::DIM_BOLD)
|
||||||
if ansi == NamedColor::Foreground
|
if ansi == NamedColor::Foreground
|
||||||
&& config.colors().primary.bright_foreground.is_none() =>
|
&& config.colors.primary.bright_foreground.is_none() =>
|
||||||
{
|
{
|
||||||
colors[NamedColor::DimForeground]
|
colors[NamedColor::DimForeground]
|
||||||
},
|
},
|
||||||
|
@ -389,7 +389,7 @@ impl<'a> Iterator for RenderableCellsIter<'a> {
|
||||||
renderable_cell.inner =
|
renderable_cell.inner =
|
||||||
RenderableCellContent::Cursor((self.cursor_style, cursor_cell));
|
RenderableCellContent::Cursor((self.cursor_style, cursor_cell));
|
||||||
|
|
||||||
if let Some(color) = self.config.cursor_cursor_color() {
|
if let Some(color) = self.config.colors.cursor.cursor {
|
||||||
renderable_cell.fg = color;
|
renderable_cell.fg = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +401,7 @@ impl<'a> Iterator for RenderableCellsIter<'a> {
|
||||||
if self.cursor_style == CursorStyle::Block {
|
if self.cursor_style == CursorStyle::Block {
|
||||||
std::mem::swap(&mut cell.bg, &mut cell.fg);
|
std::mem::swap(&mut cell.bg, &mut cell.fg);
|
||||||
|
|
||||||
if let Some(color) = self.config.cursor_text_color() {
|
if let Some(color) = self.config.colors.cursor.text {
|
||||||
cell.fg = color;
|
cell.fg = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -563,9 +563,9 @@ fn cubic_bezier(p0: f64, p1: f64, p2: f64, p3: f64, x: f64) -> f64 {
|
||||||
|
|
||||||
impl VisualBell {
|
impl VisualBell {
|
||||||
pub fn new(config: &Config) -> VisualBell {
|
pub fn new(config: &Config) -> VisualBell {
|
||||||
let visual_bell_config = config.visual_bell();
|
let visual_bell_config = &config.visual_bell;
|
||||||
VisualBell {
|
VisualBell {
|
||||||
animation: visual_bell_config.animation(),
|
animation: visual_bell_config.animation,
|
||||||
duration: visual_bell_config.duration(),
|
duration: visual_bell_config.duration(),
|
||||||
start_time: None,
|
start_time: None,
|
||||||
}
|
}
|
||||||
|
@ -658,8 +658,8 @@ impl VisualBell {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_config(&mut self, config: &Config) {
|
pub fn update_config(&mut self, config: &Config) {
|
||||||
let visual_bell_config = config.visual_bell();
|
let visual_bell_config = &config.visual_bell;
|
||||||
self.animation = visual_bell_config.animation();
|
self.animation = visual_bell_config.animation;
|
||||||
self.duration = visual_bell_config.duration();
|
self.duration = visual_bell_config.duration();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -853,7 +853,7 @@ impl Term {
|
||||||
let num_cols = size.cols();
|
let num_cols = size.cols();
|
||||||
let num_lines = size.lines();
|
let num_lines = size.lines();
|
||||||
|
|
||||||
let history_size = config.scrolling().history as usize;
|
let history_size = config.scrolling.history() as usize;
|
||||||
let grid = Grid::new(num_lines, num_cols, history_size, Cell::default());
|
let grid = Grid::new(num_lines, num_cols, history_size, Cell::default());
|
||||||
let alt = Grid::new(num_lines, num_cols, 0 /* scroll history */, Cell::default());
|
let alt = Grid::new(num_lines, num_cols, 0 /* scroll history */, Cell::default());
|
||||||
|
|
||||||
|
@ -862,7 +862,7 @@ impl Term {
|
||||||
|
|
||||||
let scroll_region = Line(0)..grid.num_lines();
|
let scroll_region = Line(0)..grid.num_lines();
|
||||||
|
|
||||||
let colors = color::List::from(config.colors());
|
let colors = color::List::from(&config.colors);
|
||||||
|
|
||||||
Term {
|
Term {
|
||||||
next_title: None,
|
next_title: None,
|
||||||
|
@ -874,8 +874,8 @@ impl Term {
|
||||||
grid,
|
grid,
|
||||||
alt_grid: alt,
|
alt_grid: alt,
|
||||||
alt: false,
|
alt: false,
|
||||||
font_size: config.font().size(),
|
font_size: config.font.size,
|
||||||
original_font_size: config.font().size(),
|
original_font_size: config.font.size,
|
||||||
active_charset: Default::default(),
|
active_charset: Default::default(),
|
||||||
cursor: Default::default(),
|
cursor: Default::default(),
|
||||||
cursor_save: Default::default(),
|
cursor_save: Default::default(),
|
||||||
|
@ -887,12 +887,12 @@ impl Term {
|
||||||
colors,
|
colors,
|
||||||
color_modified: [false; color::COUNT],
|
color_modified: [false; color::COUNT],
|
||||||
original_colors: colors,
|
original_colors: colors,
|
||||||
semantic_escape_chars: config.selection().semantic_escape_chars.clone(),
|
semantic_escape_chars: config.selection.semantic_escape_chars().to_owned(),
|
||||||
cursor_style: None,
|
cursor_style: None,
|
||||||
default_cursor_style: config.cursor_style(),
|
default_cursor_style: config.cursor.style,
|
||||||
dynamic_title: config.dynamic_title(),
|
dynamic_title: config.dynamic_title(),
|
||||||
tabspaces,
|
tabspaces,
|
||||||
auto_scroll: config.scrolling().auto_scroll,
|
auto_scroll: config.scrolling.auto_scroll,
|
||||||
message_buffer,
|
message_buffer,
|
||||||
should_exit: false,
|
should_exit: false,
|
||||||
clipboard,
|
clipboard,
|
||||||
|
@ -912,20 +912,20 @@ impl Term {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_config(&mut self, config: &Config) {
|
pub fn update_config(&mut self, config: &Config) {
|
||||||
self.semantic_escape_chars = config.selection().semantic_escape_chars.clone();
|
self.semantic_escape_chars = config.selection.semantic_escape_chars().to_owned();
|
||||||
self.original_colors.fill_named(config.colors());
|
self.original_colors.fill_named(&config.colors);
|
||||||
self.original_colors.fill_cube(config.colors());
|
self.original_colors.fill_cube(&config.colors);
|
||||||
self.original_colors.fill_gray_ramp(config.colors());
|
self.original_colors.fill_gray_ramp(&config.colors);
|
||||||
for i in 0..color::COUNT {
|
for i in 0..color::COUNT {
|
||||||
if !self.color_modified[i] {
|
if !self.color_modified[i] {
|
||||||
self.colors[i] = self.original_colors[i];
|
self.colors[i] = self.original_colors[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.visual_bell.update_config(config);
|
self.visual_bell.update_config(config);
|
||||||
self.default_cursor_style = config.cursor_style();
|
self.default_cursor_style = config.cursor.style;
|
||||||
self.dynamic_title = config.dynamic_title();
|
self.dynamic_title = config.dynamic_title();
|
||||||
self.auto_scroll = config.scrolling().auto_scroll;
|
self.auto_scroll = config.scrolling.auto_scroll;
|
||||||
self.grid.update_history(config.scrolling().history as usize, &self.cursor.template);
|
self.grid.update_history(config.scrolling.history() as usize, &self.cursor.template);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1107,7 +1107,7 @@ impl Term {
|
||||||
let alt_screen = self.mode.contains(TermMode::ALT_SCREEN);
|
let alt_screen = self.mode.contains(TermMode::ALT_SCREEN);
|
||||||
let selection = self.grid.selection.as_ref().and_then(|s| s.to_span(self, alt_screen));
|
let selection = self.grid.selection.as_ref().and_then(|s| s.to_span(self, alt_screen));
|
||||||
|
|
||||||
let cursor = if window_focused || !config.unfocused_hollow_cursor() {
|
let cursor = if window_focused || !config.cursor.unfocused_hollow() {
|
||||||
self.cursor_style.unwrap_or(self.default_cursor_style)
|
self.cursor_style.unwrap_or(self.default_cursor_style)
|
||||||
} else {
|
} else {
|
||||||
CursorStyle::HollowBlock
|
CursorStyle::HollowBlock
|
||||||
|
@ -2285,7 +2285,7 @@ mod tests {
|
||||||
let mut term: Term = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop());
|
let mut term: Term = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop());
|
||||||
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);
|
||||||
assert_eq!(term.font_size, expected_font_size);
|
assert_eq!(term.font_size, expected_font_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2336,7 +2336,7 @@ mod tests {
|
||||||
term.change_font_size(10.0);
|
term.change_font_size(10.0);
|
||||||
term.reset_font_size();
|
term.reset_font_size();
|
||||||
|
|
||||||
let expected_font_size: Size = config.font().size();
|
let expected_font_size: Size = config.font.size;
|
||||||
assert_eq!(term.font_size, expected_font_size);
|
assert_eq!(term.font_size, expected_font_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ pub fn setup_env(config: &Config) {
|
||||||
env::set_var("COLORTERM", "truecolor");
|
env::set_var("COLORTERM", "truecolor");
|
||||||
|
|
||||||
// Set env vars from config
|
// Set env vars from config
|
||||||
for (key, value) in config.env().iter() {
|
for (key, value) in config.env.iter() {
|
||||||
env::set_var(key, value);
|
env::set_var(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
//! tty related functionality
|
//! tty related functionality
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use crate::config::{Config, Options, Shell};
|
use crate::config::{Config, Shell};
|
||||||
use crate::display::OnResize;
|
use crate::display::OnResize;
|
||||||
use crate::term::SizeInfo;
|
use crate::term::SizeInfo;
|
||||||
use crate::tty::{ChildEvent, EventedPty, EventedReadWrite};
|
use crate::tty::{ChildEvent, EventedPty, EventedReadWrite};
|
||||||
|
@ -154,12 +154,7 @@ impl Pty {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new tty and return a handle to interact with it.
|
/// Create a new tty and return a handle to interact with it.
|
||||||
pub fn new<T: ToWinsize>(
|
pub fn new<T: ToWinsize>(config: &Config, size: &T, window_id: Option<usize>) -> Pty {
|
||||||
config: &Config,
|
|
||||||
options: &Options,
|
|
||||||
size: &T,
|
|
||||||
window_id: Option<usize>,
|
|
||||||
) -> Pty {
|
|
||||||
let win_size = size.to_winsize();
|
let win_size = size.to_winsize();
|
||||||
let mut buf = [0; 1024];
|
let mut buf = [0; 1024];
|
||||||
let pw = get_pw_entry(&mut buf);
|
let pw = get_pw_entry(&mut buf);
|
||||||
|
@ -174,12 +169,10 @@ pub fn new<T: ToWinsize>(
|
||||||
} else {
|
} else {
|
||||||
Shell::new(pw.shell)
|
Shell::new(pw.shell)
|
||||||
};
|
};
|
||||||
let shell = config.shell().unwrap_or(&default_shell);
|
let shell = config.shell.as_ref().unwrap_or(&default_shell);
|
||||||
|
|
||||||
let initial_command = options.command().unwrap_or(shell);
|
let mut builder = Command::new(&*shell.program);
|
||||||
|
for arg in &shell.args {
|
||||||
let mut builder = Command::new(initial_command.program());
|
|
||||||
for arg in initial_command.args() {
|
|
||||||
builder.arg(arg);
|
builder.arg(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +223,7 @@ pub fn new<T: ToWinsize>(
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle set working directory option
|
// Handle set working directory option
|
||||||
if let Some(ref dir) = options.working_dir {
|
if let Some(ref dir) = config.working_directory() {
|
||||||
builder.current_dir(dir.as_path());
|
builder.current_dir(dir.as_path());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ use winapi::um::processthreadsapi::{
|
||||||
use winapi::um::winbase::{EXTENDED_STARTUPINFO_PRESENT, STARTF_USESTDHANDLES, STARTUPINFOEXW};
|
use winapi::um::winbase::{EXTENDED_STARTUPINFO_PRESENT, STARTF_USESTDHANDLES, STARTUPINFOEXW};
|
||||||
use winapi::um::wincontypes::{COORD, HPCON};
|
use winapi::um::wincontypes::{COORD, HPCON};
|
||||||
|
|
||||||
use crate::config::{Config, Options, Shell};
|
use crate::config::{Config, Shell};
|
||||||
use crate::display::OnResize;
|
use crate::display::OnResize;
|
||||||
use crate::term::SizeInfo;
|
use crate::term::SizeInfo;
|
||||||
|
|
||||||
|
@ -98,13 +98,8 @@ impl Drop for Conpty {
|
||||||
unsafe impl Send for Conpty {}
|
unsafe impl Send for Conpty {}
|
||||||
unsafe impl Sync for Conpty {}
|
unsafe impl Sync for Conpty {}
|
||||||
|
|
||||||
pub fn new<'a>(
|
pub fn new<'a>(config: &Config, size: &SizeInfo, _window_id: Option<usize>) -> Option<Pty<'a>> {
|
||||||
config: &Config,
|
if !config.enable_experimental_conpty_backend {
|
||||||
options: &Options,
|
|
||||||
size: &SizeInfo,
|
|
||||||
_window_id: Option<usize>,
|
|
||||||
) -> Option<Pty<'a>> {
|
|
||||||
if !config.enable_experimental_conpty_backend() {
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +138,7 @@ pub fn new<'a>(
|
||||||
|
|
||||||
let mut startup_info_ex: STARTUPINFOEXW = Default::default();
|
let mut startup_info_ex: STARTUPINFOEXW = Default::default();
|
||||||
|
|
||||||
let title = options.title.as_ref().map(String::as_str).unwrap_or("Alacritty");
|
let title = config.window.title.as_ref().map(String::as_str).unwrap_or("Alacritty");
|
||||||
let title = U16CString::from_str(title).unwrap();
|
let title = U16CString::from_str(title).unwrap();
|
||||||
startup_info_ex.StartupInfo.lpTitle = title.as_ptr() as LPWSTR;
|
startup_info_ex.StartupInfo.lpTitle = title.as_ptr() as LPWSTR;
|
||||||
|
|
||||||
|
@ -209,13 +204,12 @@ pub fn new<'a>(
|
||||||
|
|
||||||
// Get process commandline
|
// Get process commandline
|
||||||
let default_shell = &Shell::new("powershell");
|
let default_shell = &Shell::new("powershell");
|
||||||
let shell = config.shell().unwrap_or(default_shell);
|
let shell = config.shell.as_ref().unwrap_or(default_shell);
|
||||||
let initial_command = options.command().unwrap_or(shell);
|
let mut cmdline = shell.args.clone();
|
||||||
let mut cmdline = initial_command.args().to_vec();
|
cmdline.insert(0, shell.program.to_string());
|
||||||
cmdline.insert(0, initial_command.program().into());
|
|
||||||
|
|
||||||
// Warning, here be borrow hell
|
// Warning, here be borrow hell
|
||||||
let cwd = options.working_dir.as_ref().map(|dir| canonicalize(dir).unwrap());
|
let cwd = config.working_directory().as_ref().map(|dir| canonicalize(dir).unwrap());
|
||||||
let cwd = cwd.as_ref().map(|dir| dir.to_str().unwrap());
|
let cwd = cwd.as_ref().map(|dir| dir.to_str().unwrap());
|
||||||
|
|
||||||
// Create the client application, using startup info containing ConPTY info
|
// Create the client application, using startup info containing ConPTY info
|
||||||
|
|
|
@ -24,7 +24,7 @@ use winapi::shared::winerror::WAIT_TIMEOUT;
|
||||||
use winapi::um::synchapi::WaitForSingleObject;
|
use winapi::um::synchapi::WaitForSingleObject;
|
||||||
use winapi::um::winbase::WAIT_OBJECT_0;
|
use winapi::um::winbase::WAIT_OBJECT_0;
|
||||||
|
|
||||||
use crate::config::{Config, Options};
|
use crate::config::Config;
|
||||||
use crate::display::OnResize;
|
use crate::display::OnResize;
|
||||||
use crate::term::SizeInfo;
|
use crate::term::SizeInfo;
|
||||||
use crate::tty::{EventedPty, EventedReadWrite};
|
use crate::tty::{EventedPty, EventedReadWrite};
|
||||||
|
@ -83,19 +83,14 @@ impl<'a> Pty<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new<'a>(
|
pub fn new<'a>(config: &Config, size: &SizeInfo, window_id: Option<usize>) -> Pty<'a> {
|
||||||
config: &Config,
|
if let Some(pty) = conpty::new(config, size, window_id) {
|
||||||
options: &Options,
|
|
||||||
size: &SizeInfo,
|
|
||||||
window_id: Option<usize>,
|
|
||||||
) -> Pty<'a> {
|
|
||||||
if let Some(pty) = conpty::new(config, options, size, window_id) {
|
|
||||||
info!("Using Conpty agent");
|
info!("Using Conpty agent");
|
||||||
IS_CONPTY.store(true, Ordering::Relaxed);
|
IS_CONPTY.store(true, Ordering::Relaxed);
|
||||||
pty
|
pty
|
||||||
} else {
|
} else {
|
||||||
info!("Using Winpty agent");
|
info!("Using Winpty agent");
|
||||||
winpty::new(config, options, size, window_id)
|
winpty::new(config, size, window_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
|
||||||
use winpty::Config as WinptyConfig;
|
use winpty::Config as WinptyConfig;
|
||||||
use winpty::{ConfigFlags, MouseMode, SpawnConfig, SpawnFlags, Winpty};
|
use winpty::{ConfigFlags, MouseMode, SpawnConfig, SpawnFlags, Winpty};
|
||||||
|
|
||||||
use crate::config::{Config, Options, Shell};
|
use crate::config::{Config, Shell};
|
||||||
use crate::display::OnResize;
|
use crate::display::OnResize;
|
||||||
use crate::term::SizeInfo;
|
use crate::term::SizeInfo;
|
||||||
|
|
||||||
|
@ -75,12 +75,7 @@ impl<'a> Drop for Agent<'a> {
|
||||||
/// This is a placeholder value until we see how often long responses happen
|
/// This is a placeholder value until we see how often long responses happen
|
||||||
const AGENT_TIMEOUT: u32 = 10000;
|
const AGENT_TIMEOUT: u32 = 10000;
|
||||||
|
|
||||||
pub fn new<'a>(
|
pub fn new<'a>(config: &Config, size: &SizeInfo, _window_id: Option<usize>) -> Pty<'a> {
|
||||||
config: &Config,
|
|
||||||
options: &Options,
|
|
||||||
size: &SizeInfo,
|
|
||||||
_window_id: Option<usize>,
|
|
||||||
) -> Pty<'a> {
|
|
||||||
// Create config
|
// Create config
|
||||||
let mut wconfig = WinptyConfig::new(ConfigFlags::empty()).unwrap();
|
let mut wconfig = WinptyConfig::new(ConfigFlags::empty()).unwrap();
|
||||||
|
|
||||||
|
@ -94,13 +89,12 @@ pub fn new<'a>(
|
||||||
|
|
||||||
// Get process commandline
|
// Get process commandline
|
||||||
let default_shell = &Shell::new("powershell");
|
let default_shell = &Shell::new("powershell");
|
||||||
let shell = config.shell().unwrap_or(default_shell);
|
let shell = config.shell.as_ref().unwrap_or(default_shell);
|
||||||
let initial_command = options.command().unwrap_or(shell);
|
let mut cmdline = shell.args.clone();
|
||||||
let mut cmdline = initial_command.args().to_vec();
|
cmdline.insert(0, shell.program.to_string());
|
||||||
cmdline.insert(0, initial_command.program().into());
|
|
||||||
|
|
||||||
// Warning, here be borrow hell
|
// Warning, here be borrow hell
|
||||||
let cwd = options.working_dir.as_ref().map(|dir| canonicalize(dir).unwrap());
|
let cwd = config.working_directory().as_ref().map(|dir| canonicalize(dir).unwrap());
|
||||||
let cwd = cwd.as_ref().map(|dir| dir.to_str().unwrap());
|
let cwd = cwd.as_ref().map(|dir| dir.to_str().unwrap());
|
||||||
|
|
||||||
// Spawn process
|
// Spawn process
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
|
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ use glutin::{
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
use image::ImageFormat;
|
use image::ImageFormat;
|
||||||
|
|
||||||
use crate::config::{Options, Decorations, StartupMode, WindowConfig};
|
use crate::config::{Config, Decorations, StartupMode, WindowConfig};
|
||||||
|
|
||||||
// It's required to be in this directory due to the `windows.rc` file
|
// It's required to be in this directory due to the `windows.rc` file
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
@ -146,13 +147,13 @@ impl Window {
|
||||||
/// This creates a window and fully initializes a window.
|
/// This creates a window and fully initializes a window.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
event_loop: EventsLoop,
|
event_loop: EventsLoop,
|
||||||
options: &Options,
|
config: &Config,
|
||||||
window_config: &WindowConfig,
|
|
||||||
dimensions: Option<LogicalSize>,
|
dimensions: Option<LogicalSize>,
|
||||||
) -> Result<Window> {
|
) -> Result<Window> {
|
||||||
let title = options.title.as_ref().map_or(DEFAULT_NAME, |t| t);
|
let title = config.window.title.as_ref().map_or(DEFAULT_NAME, |t| t);
|
||||||
let class = options.class.as_ref().map_or(DEFAULT_NAME, |c| c);
|
let class = config.window.class.as_ref().map_or(DEFAULT_NAME, |c| c);
|
||||||
let window_builder = Window::get_platform_window(title, class, window_config);
|
|
||||||
|
let window_builder = Window::get_platform_window(title, class, &config.window);
|
||||||
let windowed_context =
|
let windowed_context =
|
||||||
create_gl_window(window_builder.clone(), &event_loop, false, dimensions)
|
create_gl_window(window_builder.clone(), &event_loop, false, dimensions)
|
||||||
.or_else(|_| create_gl_window(window_builder, &event_loop, true, dimensions))?;
|
.or_else(|_| create_gl_window(window_builder, &event_loop, true, dimensions))?;
|
||||||
|
@ -162,7 +163,7 @@ impl Window {
|
||||||
// Maximize window after mapping in X11
|
// Maximize window after mapping in X11
|
||||||
#[cfg(not(any(target_os = "macos", windows)))]
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
{
|
{
|
||||||
if event_loop.is_x11() && window_config.startup_mode() == StartupMode::Maximized {
|
if event_loop.is_x11() && config.window.startup_mode() == StartupMode::Maximized {
|
||||||
window.set_maximized(true);
|
window.set_maximized(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,21 +172,20 @@ impl Window {
|
||||||
//
|
//
|
||||||
// TODO: replace `set_position` with `with_position` once available
|
// TODO: replace `set_position` with `with_position` once available
|
||||||
// Upstream issue: https://github.com/tomaka/winit/issues/806
|
// Upstream issue: https://github.com/tomaka/winit/issues/806
|
||||||
let position = options.position().or_else(|| window_config.position());
|
if let Some(position) = config.window.position {
|
||||||
if let Some(position) = position {
|
|
||||||
let physical = PhysicalPosition::from((position.x, position.y));
|
let physical = PhysicalPosition::from((position.x, position.y));
|
||||||
let logical = physical.to_logical(window.get_hidpi_factor());
|
let logical = physical.to_logical(window.get_hidpi_factor());
|
||||||
window.set_position(logical);
|
window.set_position(logical);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let StartupMode::Fullscreen = window_config.startup_mode() {
|
if let StartupMode::Fullscreen = config.window.startup_mode() {
|
||||||
let current_monitor = window.get_current_monitor();
|
let current_monitor = window.get_current_monitor();
|
||||||
window.set_fullscreen(Some(current_monitor));
|
window.set_fullscreen(Some(current_monitor));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
{
|
{
|
||||||
if let StartupMode::SimpleFullscreen = window_config.startup_mode() {
|
if let StartupMode::SimpleFullscreen = config.window.startup_mode() {
|
||||||
use glutin::os::macos::WindowExt;
|
use glutin::os::macos::WindowExt;
|
||||||
window.set_simple_fullscreen(true);
|
window.set_simple_fullscreen(true);
|
||||||
}
|
}
|
||||||
|
@ -286,7 +286,7 @@ impl Window {
|
||||||
) -> WindowBuilder {
|
) -> WindowBuilder {
|
||||||
use glutin::os::unix::WindowBuilderExt;
|
use glutin::os::unix::WindowBuilderExt;
|
||||||
|
|
||||||
let decorations = match window_config.decorations() {
|
let decorations = match window_config.decorations {
|
||||||
Decorations::None => false,
|
Decorations::None => false,
|
||||||
_ => true,
|
_ => true,
|
||||||
};
|
};
|
||||||
|
@ -312,7 +312,7 @@ impl Window {
|
||||||
_class: &str,
|
_class: &str,
|
||||||
window_config: &WindowConfig,
|
window_config: &WindowConfig,
|
||||||
) -> WindowBuilder {
|
) -> WindowBuilder {
|
||||||
let decorations = match window_config.decorations() {
|
let decorations = match window_config.decorations {
|
||||||
Decorations::None => false,
|
Decorations::None => false,
|
||||||
_ => true,
|
_ => true,
|
||||||
};
|
};
|
||||||
|
@ -342,7 +342,7 @@ impl Window {
|
||||||
.with_transparency(true)
|
.with_transparency(true)
|
||||||
.with_maximized(window_config.startup_mode() == StartupMode::Maximized);
|
.with_maximized(window_config.startup_mode() == StartupMode::Maximized);
|
||||||
|
|
||||||
match window_config.decorations() {
|
match window_config.decorations {
|
||||||
Decorations::Full => window,
|
Decorations::Full => window,
|
||||||
Decorations::Transparent => window
|
Decorations::Transparent => window
|
||||||
.with_title_hidden(true)
|
.with_title_hidden(true)
|
||||||
|
|
|
@ -91,7 +91,7 @@ fn ref_test(dir: &Path) {
|
||||||
let ref_config: RefConfig = json::from_str(&serialized_cfg).unwrap_or_default();
|
let ref_config: RefConfig = json::from_str(&serialized_cfg).unwrap_or_default();
|
||||||
|
|
||||||
let mut config: Config = Default::default();
|
let mut config: Config = Default::default();
|
||||||
config.set_history(ref_config.history_size);
|
config.scrolling.set_history(ref_config.history_size);
|
||||||
|
|
||||||
let mut terminal = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop());
|
let mut terminal = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop());
|
||||||
let mut parser = ansi::Processor::new();
|
let mut parser = ansi::Processor::new();
|
||||||
|
|
Loading…
Reference in New Issue