From 27ef91cf4eb5f993907afd08fdb1d57f0774beae Mon Sep 17 00:00:00 2001 From: dalance Date: Thu, 28 Jan 2021 18:07:06 +0900 Subject: [PATCH] Add automatic theme detection #78 --- CHANGELOG.md | 2 + Cargo.lock | 231 +++++++++++++++++++++++++------- Cargo.toml | 1 + README.md | 120 +++++++++-------- config/large.toml | 72 +++++----- config/small.toml | 60 ++++----- src/config.rs | 332 ++++++++++++++++++++++++++++++++++++---------- src/main.rs | 17 +++ src/style.rs | 127 +++++++++--------- src/view.rs | 60 +++++++-- src/watcher.rs | 4 +- 11 files changed, 706 insertions(+), 320 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c29c5a7..8c65c7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased](https://github.com/dalance/procs/compare/v0.10.10...Unreleased) - ReleaseDate +* [Added] automatic theme detection [#78](https://github.com/dalance/procs/issues/78) + ## [v0.10.10](https://github.com/dalance/procs/compare/v0.10.9...v0.10.10) - 2020-11-26 * [Fixed] broken pager on macOS [#92](https://github.com/dalance/procs/issues/92) diff --git a/Cargo.lock b/Cargo.lock index da89550..0a161fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,9 +61,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.55" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" +checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc" dependencies = [ "addr2line", "cfg-if 1.0.0", @@ -230,6 +230,31 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crossterm" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e86d73f2a0b407b5768d10a8c720cf5d2df49a9efc10ca09176d201ead4b7fb" +dependencies = [ + "bitflags", + "crossterm_winapi", + "lazy_static", + "libc", + "mio 0.7.7", + "parking_lot", + "signal-hook", + "winapi 0.3.9", +] + +[[package]] +name = "crossterm_winapi" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2265c3f8e080075d9b6417aa72293fc71662f34b4af2612d8d1b074d29510db" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "directories" version = "3.0.1" @@ -341,13 +366,13 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe" +checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.2.4", "winapi 0.3.9", ] @@ -397,9 +422,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c70be434c505aee38639abccb918163b63158a4b4bb791b45b7023044bdc3c9c" +checksum = "da9052a1a50244d8d5aa9bf55cbc2fb6f357c86cc52e46c62ed390a7180cf150" dependencies = [ "futures-channel", "futures-core", @@ -412,9 +437,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f01c61843314e95f96cc9245702248733a3a3d744e43e2e755e3c7af8348a0a9" +checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" dependencies = [ "futures-core", "futures-sink", @@ -422,15 +447,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8d3b0917ff63a2a96173133c02818fac4a746b0a57569d3baca9ec0e945e08" +checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" [[package]] name = "futures-executor" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee9ca2f7eb4475772cf39dd1cd06208dce2670ad38f4d9c7262b3e15f127068" +checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9" dependencies = [ "futures-core", "futures-task", @@ -439,15 +464,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37c1a51b037b80922864b8eed90692c5cd8abd4c71ce49b77146caa47f3253b" +checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500" [[package]] name = "futures-macro" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f8719ca0e1f3c5e34f3efe4570ef2c0610ca6da85ae7990d472e9cbfba13664" +checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -457,24 +482,24 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6adabac1290109cfa089f79192fb6244ad2c3f1cc2281f3e1dd987592b71feb" +checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" [[package]] name = "futures-task" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92a0843a2ff66823a8f7c77bffe9a09be2b64e533562c412d63075643ec0038" +checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" dependencies = [ "once_cell", ] [[package]] name = "futures-util" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "036a2107cdeb57f6d7322f1b6c363dad67cd63ca3b7d1b925bdf75bd5d96cda9" +checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" dependencies = [ "futures-channel", "futures-core", @@ -560,9 +585,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] @@ -681,6 +706,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "iovec" version = "0.1.4" @@ -720,9 +754,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" +checksum = "7eb0c4e9c72ee9d69b767adebc5f4788462a3b45624acd919475c92597bcaf4f" [[package]] name = "libproc" @@ -735,12 +769,21 @@ dependencies = [ ] [[package]] -name = "log" -version = "0.4.13" +name = "lock_api" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" dependencies = [ - "cfg-if 0.1.10", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if 1.0.0", ] [[package]] @@ -790,6 +833,19 @@ dependencies = [ "winapi 0.2.8", ] +[[package]] +name = "mio" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" +dependencies = [ + "libc", + "log", + "miow 0.3.6", + "ntapi", + "winapi 0.3.9", +] + [[package]] name = "mio-named-pipes" version = "0.1.7" @@ -797,7 +853,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" dependencies = [ "log", - "mio", + "mio 0.6.23", "miow 0.3.6", "winapi 0.3.9", ] @@ -810,7 +866,7 @@ checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" dependencies = [ "iovec", "libc", - "mio", + "mio 0.6.23", ] [[package]] @@ -869,6 +925,15 @@ dependencies = [ "void", ] +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -900,9 +965,9 @@ dependencies = [ [[package]] name = "object" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" +checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" [[package]] name = "once_cell" @@ -920,6 +985,31 @@ dependencies = [ "libc", ] +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.1.57", + "smallvec", + "winapi 0.3.9", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -1016,9 +1106,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro-nested" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" @@ -1064,6 +1154,7 @@ dependencies = [ "serde", "serde_derive", "structopt", + "termbg", "toml", "unicode-width", "users", @@ -1086,6 +1177,15 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_syscall" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.3.5" @@ -1093,7 +1193,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.1.57", "rust-argon2", ] @@ -1142,6 +1242,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "serde" version = "1.0.123" @@ -1173,6 +1279,17 @@ dependencies = [ "serde", ] +[[package]] +name = "signal-hook" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729" +dependencies = [ + "libc", + "mio 0.7.7", + "signal-hook-registry", +] + [[package]] name = "signal-hook-registry" version = "1.3.0" @@ -1188,6 +1305,12 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + [[package]] name = "socket2" version = "0.3.19" @@ -1254,21 +1377,31 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.30" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489997b7557e9a43e192c527face4feacc78bfbe6eed67fd55c4c9e381cba290" +checksum = "0313546c01d59e29be4f09687bcb4fb6690cec931cc3607b6aec7a0e417f4cc6" dependencies = [ "filetime", "libc", - "redox_syscall", "xattr", ] [[package]] -name = "terminal_size" -version = "0.1.15" +name = "termbg" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd2d183bd3fac5f5fe38ddbeb4dc9aec4a39a9d7d59e7491d900302da01cbe1" +checksum = "133c09f40b7a6a10616bb46d2b7d78d50cb8c6c475c84f3c02fe261957d9e0e0" +dependencies = [ + "crossterm", + "thiserror", + "winapi 0.3.9", +] + +[[package]] +name = "terminal_size" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ca8ced750734db02076f44132d802af0b33b09942331f4459dde8636fd2406" dependencies = [ "libc", "winapi 0.3.9", @@ -1325,9 +1458,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" +checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" dependencies = [ "tinyvec_macros", ] @@ -1351,7 +1484,7 @@ dependencies = [ "lazy_static", "libc", "memchr", - "mio", + "mio 0.6.23", "mio-named-pipes", "mio-uds", "num_cpus", @@ -1398,9 +1531,9 @@ dependencies = [ [[package]] name = "tower-service" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" diff --git a/Cargo.toml b/Cargo.toml index 459701f..670ab2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ libc = "0.2" serde = "1.0" serde_derive = "1.0" structopt = "0.3" +termbg = "0.2.0" toml = "0.5" unicode-width = "0.1" diff --git a/README.md b/README.md index 6c95e69..a50f3ce 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ ## Features - Output by the colored and human-readable format + - Automatic theme detection based on terminal background - Keyword search over multi-column - Some additional information which are not supported by `ps` - TCP/UDP port @@ -286,47 +287,47 @@ The complete example of a configuration file can be generated by `--config` opti ```toml [[columns]] kind = "Pid" -style = "BrightYellow" +style = "BrightYellow|Yellow" numeric_search = true nonnumeric_search = false [[columns]] kind = "Username" -style = "BrightGreen" +style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true align = "Right" [style] -header = "BrightWhite" -unit = "BrightWhite" -tree = "BrightWhite" +header = "BrightWhite|Black" +unit = "BrightWhite|Black" +tree = "BrightWhite|Black" [style.by_percentage] -color_000 = "BrightBlue" -color_025 = "BrightGreen" -color_050 = "BrightYellow" -color_075 = "BrightRed" -color_100 = "BrightRed" +color_000 = "BrightBlue|Blue" +color_025 = "BrightGreen|Green" +color_050 = "BrightYellow|Yellow" +color_075 = "BrightRed|Red" +color_100 = "BrightRed|Red" [style.by_state] -color_d = "BrightRed" -color_r = "BrightGreen" -color_s = "BrightBlue" -color_t = "BrightCyan" -color_z = "BrightMagenta" -color_x = "BrightMagenta" -color_k = "BrightYellow" -color_w = "BrightYellow" -color_p = "BrightYellow" +color_d = "BrightRed|Red" +color_r = "BrightGreen|Green" +color_s = "BrightBlue|Blue" +color_t = "BrightCyan|Cyan" +color_z = "BrightMagenta|Magenta" +color_x = "BrightMagenta|Magenta" +color_k = "BrightYellow|Yellow" +color_w = "BrightYellow|Yellow" +color_p = "BrightYellow|Yellow" [style.by_unit] -color_k = "BrightBlue" -color_m = "BrightGreen" -color_g = "BrightYellow" -color_t = "BrightRed" -color_p = "BrightRed" -color_x = "BrightBlue" +color_k = "BrightBlue|Blue" +color_m = "BrightGreen|Green" +color_g = "BrightYellow|Yellow" +color_t = "BrightRed|Red" +color_p = "BrightRed|Red" +color_x = "BrightBlue|Blue" [search] numeric_search = "Exact" @@ -464,42 +465,38 @@ These are the styles for value-aware coloring. For example, if `ByUnit` is chosen, color can be specified for each unit of value ( like `K`, `M`, `G`,,, ). The colors can be configured in `[style.by_unit]` section. -`Color256` can be specified by 0-255 value like below: - -```toml -style = { Color256 = 223 } -``` +Other colors can be configured as the same as `color`. ### `[style]` section `[style]` section defines colors of header, unit and each styles. The available list of color is below. -| Subsection | Key | Value | Default | Description | -| ------------- | --------- | ---------------- | ------------- | -------------------- | -| | header | See `color` list | BrightWhite | Header color | -| | unit | See `color` list | BrightWhite | Unit color | -| | tree | See `color` list | BrightWhite | Tree color | -| by_percentage | color_000 | See `color` list | BrightBlue | Color at 0% - 25% | -| by_percentage | color_025 | See `color` list | BrightGreen | Color at 25% - 50% | -| by_percentage | color_050 | See `color` list | BrightYellow | Color at 50% - 75% | -| by_percentage | color_075 | See `color` list | BrightRed | Color at 75% - 100% | -| by_percentage | color_100 | See `color` list | BrightRed | Color at 100% - | -| by_state | color_d | See `color` list | BrightRed | Color at `D` state | -| by_state | color_r | See `color` list | BrightGreen | Color at `R` state | -| by_state | color_s | See `color` list | BrightBlue | Color at `S` state | -| by_state | color_t | See `color` list | BrightCyan | Color at `T` state | -| by_state | color_z | See `color` list | BrightMagenta | Color at `Z` state | -| by_state | color_x | See `color` list | BrightMagenta | Color at `X` state | -| by_state | color_k | See `color` list | BrightYellow | Color at `K` state | -| by_state | color_w | See `color` list | BrightYellow | Color at `W` state | -| by_state | color_p | See `color` list | BrightYellow | Color at `P` state | -| by_unit | color_k | See `color` list | BrightBlue | Color at unit `K` | -| by_unit | color_m | See `color` list | BrightGreen | Color at unit `M` | -| by_unit | color_g | See `color` list | BrightYellow | Color at unit `G` | -| by_unit | color_t | See `color` list | BrightRed | Color at unit `T` | -| by_unit | color_p | See `color` list | BrightRed | Color at unit `P` | -| by_unit | color_x | See `color` list | BrightBlue | Color at other unit | +| Subsection | Key | Value | Default | Description | +| ------------- | --------- | ---------------- | ---------------------- | -------------------- | +| | header | See `color` list | BrightWhite\|Black | Header color | +| | unit | See `color` list | BrightWhite\|Black | Unit color | +| | tree | See `color` list | BrightWhite\|Black | Tree color | +| by_percentage | color_000 | See `color` list | BrightBlue\|Blue | Color at 0% - 25% | +| by_percentage | color_025 | See `color` list | BrightGreen\|Green | Color at 25% - 50% | +| by_percentage | color_050 | See `color` list | BrightYellow\|Yellow | Color at 50% - 75% | +| by_percentage | color_075 | See `color` list | BrightRed\|Red | Color at 75% - 100% | +| by_percentage | color_100 | See `color` list | BrightRed\|Red | Color at 100% - | +| by_state | color_d | See `color` list | BrightRed\|Red | Color at `D` state | +| by_state | color_r | See `color` list | BrightGreen\|Green | Color at `R` state | +| by_state | color_s | See `color` list | BrightBlue\|Blue | Color at `S` state | +| by_state | color_t | See `color` list | BrightCyan\|Cyan | Color at `T` state | +| by_state | color_z | See `color` list | BrightMagenta\|Magenta | Color at `Z` state | +| by_state | color_x | See `color` list | BrightMagenta\|Magenta | Color at `X` state | +| by_state | color_k | See `color` list | BrightYellow\|Yellow | Color at `K` state | +| by_state | color_w | See `color` list | BrightYellow\|Yellow | Color at `W` state | +| by_state | color_p | See `color` list | BrightYellow\|Yellow | Color at `P` state | +| by_unit | color_k | See `color` list | BrightBlue\|Blue | Color at unit `K` | +| by_unit | color_m | See `color` list | BrightGreen\|Green | Color at unit `M` | +| by_unit | color_g | See `color` list | BrightYellow\|Yellow | Color at unit `G` | +| by_unit | color_t | See `color` list | BrightRed\|Red | Color at unit `T` | +| by_unit | color_p | See `color` list | BrightRed\|Red | Color at unit `P` | +| by_unit | color_x | See `color` list | BrightBlue\|Blue | Color at other unit | #### `color` list @@ -521,10 +518,21 @@ The available list of color is below. - White - Color256 +Colors can be configured by theme through `|`. + +```toml +style = "BrightWhite|Black" # BrightWhite for dark theme and Black for light theme +style = "BrightWhite" # BrightWhite for both theme +``` + +The first color is for dark theme, and the second is for light theme. +If only a color is specified, the color is applied to both theme. + `Color256` can be specified by 0-255 value like below: ```toml -style = { Color256 = 223 } +style = "223|112" # 223 for dark theme and 112 for light theme +style = "223" # 223 for both theme ``` ### `[search]` section diff --git a/config/large.toml b/config/large.toml index 13bd9b9..2084543 100644 --- a/config/large.toml +++ b/config/large.toml @@ -1,20 +1,20 @@ [[columns]] kind = "Pid" -style = "BrightYellow" +style = "BrightYellow|Yellow" numeric_search = true nonnumeric_search = false align = "Left" [[columns]] kind = "User" -style = "BrightGreen" +style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true align = "Left" [[columns]] kind = "Separator" -style = "White" +style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" @@ -28,14 +28,14 @@ align = "Left" [[columns]] kind = "Nice" -style = "BrightMagenta" +style = "BrightMagenta|Magenta" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Tty" -style = "BrightWhite" +style = "BrightWhite|Black" numeric_search = false nonnumeric_search = false align = "Left" @@ -70,7 +70,7 @@ align = "Right" [[columns]] kind = "TcpPort" -style = "BrightCyan" +style = "BrightCyan|Cyan" numeric_search = true nonnumeric_search = false align = "Left" @@ -78,7 +78,7 @@ max_width = 20 [[columns]] kind = "UdpPort" -style = "BrightCyan" +style = "BrightCyan|Cyan" numeric_search = true nonnumeric_search = false align = "Left" @@ -107,76 +107,76 @@ align = "Right" [[columns]] kind = "Separator" -style = "White" +style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "CpuTime" -style = "BrightCyan" +style = "BrightCyan|Cyan" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "StartTime" -style = "BrightMagenta" +style = "BrightMagenta|Magenta" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Docker" -style = "BrightGreen" +style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true align = "Left" [[columns]] kind = "Separator" -style = "White" +style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Command" -style = "BrightWhite" +style = "BrightWhite|Black" numeric_search = false nonnumeric_search = true align = "Left" [style] -header = "BrightWhite" -unit = "BrightWhite" -tree = "BrightWhite" +header = "BrightWhite|Black" +unit = "BrightWhite|Black" +tree = "BrightWhite|Black" [style.by_percentage] -color_000 = "BrightBlue" -color_025 = "BrightGreen" -color_050 = "BrightYellow" -color_075 = "BrightRed" -color_100 = "BrightRed" +color_000 = "BrightBlue|Blue" +color_025 = "BrightGreen|Green" +color_050 = "BrightYellow|Yellow" +color_075 = "BrightRed|Red" +color_100 = "BrightRed|Red" [style.by_state] -color_d = "BrightRed" -color_r = "BrightGreen" -color_s = "BrightBlue" -color_t = "BrightCyan" -color_z = "BrightMagenta" -color_x = "BrightMagenta" -color_k = "BrightYellow" -color_w = "BrightYellow" -color_p = "BrightYellow" +color_d = "BrightRed|Red" +color_r = "BrightGreen|Green" +color_s = "BrightBlue|Blue" +color_t = "BrightCyan|Cyan" +color_z = "BrightMagenta|Magenta" +color_x = "BrightMagenta|Magenta" +color_k = "BrightYellow|Yellow" +color_w = "BrightYellow|Yellow" +color_p = "BrightYellow|Yellow" [style.by_unit] -color_k = "BrightBlue" -color_m = "BrightGreen" -color_g = "BrightYellow" -color_t = "BrightRed" -color_p = "BrightRed" -color_x = "BrightBlue" +color_k = "BrightBlue|Blue" +color_m = "BrightGreen|Green" +color_g = "BrightYellow|Yellow" +color_t = "BrightRed|Red" +color_p = "BrightRed|Red" +color_x = "BrightBlue|Blue" [search] numeric_search = "Exact" diff --git a/config/small.toml b/config/small.toml index 6cef008..e2815e7 100644 --- a/config/small.toml +++ b/config/small.toml @@ -1,27 +1,27 @@ [[columns]] kind = "Pid" -style = "BrightYellow" +style = "BrightYellow|Yellow" numeric_search = true nonnumeric_search = false align = "Left" [[columns]] kind = "User" -style = "BrightGreen" +style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true align = "Left" [[columns]] kind = "Separator" -style = "White" +style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Tty" -style = "BrightWhite" +style = "BrightWhite|Black" numeric_search = false nonnumeric_search = false align = "Left" @@ -42,55 +42,55 @@ align = "Right" [[columns]] kind = "CpuTime" -style = "BrightCyan" +style = "BrightCyan|Cyan" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Separator" -style = "White" +style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Command" -style = "BrightWhite" +style = "BrightWhite|Black" numeric_search = false nonnumeric_search = true align = "Left" [style] -header = "BrightWhite" -unit = "BrightWhite" -tree = "BrightWhite" +header = "BrightWhite|Black" +unit = "BrightWhite|Black" +tree = "BrightWhite|Black" [style.by_percentage] -color_000 = "BrightBlue" -color_025 = "BrightGreen" -color_050 = "BrightYellow" -color_075 = "BrightRed" -color_100 = "BrightRed" +color_000 = "BrightBlue|Blue" +color_025 = "BrightGreen|Green" +color_050 = "BrightYellow|Yellow" +color_075 = "BrightRed|Red" +color_100 = "BrightRed|Red" [style.by_state] -color_d = "BrightRed" -color_r = "BrightGreen" -color_s = "BrightBlue" -color_t = "BrightCyan" -color_z = "BrightMagenta" -color_x = "BrightMagenta" -color_k = "BrightYellow" -color_w = "BrightYellow" -color_p = "BrightYellow" +color_d = "BrightRed|Red" +color_r = "BrightGreen|Green" +color_s = "BrightBlue|Blue" +color_t = "BrightCyan|Cyan" +color_z = "BrightMagenta|Magenta" +color_x = "BrightMagenta|Magenta" +color_k = "BrightYellow|Yellow" +color_w = "BrightYellow|Yellow" +color_p = "BrightYellow|Yellow" [style.by_unit] -color_k = "BrightBlue" -color_m = "BrightGreen" -color_g = "BrightYellow" -color_t = "BrightRed" -color_p = "BrightRed" -color_x = "BrightBlue" +color_k = "BrightBlue|Blue" +color_m = "BrightGreen|Green" +color_g = "BrightYellow|Yellow" +color_t = "BrightRed|Red" +color_p = "BrightRed|Red" +color_x = "BrightBlue|Blue" [search] numeric_search = "Exact" diff --git a/src/config.rs b/src/config.rs index 3643fde..5144b84 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,7 @@ use crate::column::Column; use crate::columns::ConfigColumnKind; use serde_derive::{Deserialize, Serialize}; +use std::str::FromStr; // --------------------------------------------------------------------------------------------------------------------- // Functions for serde defalut @@ -64,8 +65,15 @@ fn default_tree_symbols() -> [String; 5] { ] } -fn default_color_bright_white() -> ConfigColor { - ConfigColor::BrightWhite +fn default_color_by_theme() -> ConfigColorByTheme { + ConfigColorByTheme { + dark: ConfigColor::BrightWhite, + light: ConfigColor::Black, + } +} + +fn default_theme_auto() -> ConfigTheme { + ConfigTheme::Auto } // --------------------------------------------------------------------------------------------------------------------- @@ -105,6 +113,13 @@ pub struct Config { } #[derive(Clone, Debug, Serialize, Deserialize)] +pub enum ConfigTheme { + Auto, + Dark, + Light, +} + +#[derive(Clone, Debug, PartialEq, Eq)] pub enum ConfigColor { BrightBlack, BrightRed, @@ -125,30 +140,146 @@ pub enum ConfigColor { Color256(u8), } -#[derive(Clone, Debug, Serialize, Deserialize)] +fn serialize_color(c: &ConfigColor) -> String { + match c { + ConfigColor::BrightBlack => "BrightBlack".to_string(), + ConfigColor::BrightRed => "BrightRed".to_string(), + ConfigColor::BrightGreen => "BrightGreen".to_string(), + ConfigColor::BrightYellow => "BrightYellow".to_string(), + ConfigColor::BrightBlue => "BrightBlue".to_string(), + ConfigColor::BrightMagenta => "BrightMagenta".to_string(), + ConfigColor::BrightCyan => "BrightCyan".to_string(), + ConfigColor::BrightWhite => "BrightWhite".to_string(), + ConfigColor::Black => "Black".to_string(), + ConfigColor::Red => "Red".to_string(), + ConfigColor::Green => "Green".to_string(), + ConfigColor::Yellow => "Yellow".to_string(), + ConfigColor::Blue => "Blue".to_string(), + ConfigColor::Magenta => "Magenta".to_string(), + ConfigColor::Cyan => "Cyan".to_string(), + ConfigColor::White => "White".to_string(), + ConfigColor::Color256(x) => format!("{}", x), + } +} + +fn deserialize_color(s: &str) -> Option { + match s { + "BrightBlack" => Some(ConfigColor::BrightBlack), + "BrightRed" => Some(ConfigColor::BrightRed), + "BrightGreen" => Some(ConfigColor::BrightGreen), + "BrightYellow" => Some(ConfigColor::BrightYellow), + "BrightBlue" => Some(ConfigColor::BrightBlue), + "BrightMagenta" => Some(ConfigColor::BrightMagenta), + "BrightCyan" => Some(ConfigColor::BrightCyan), + "BrightWhite" => Some(ConfigColor::BrightWhite), + "Black" => Some(ConfigColor::Black), + "Red" => Some(ConfigColor::Red), + "Green" => Some(ConfigColor::Green), + "Yellow" => Some(ConfigColor::Yellow), + "Blue" => Some(ConfigColor::Blue), + "Magenta" => Some(ConfigColor::Magenta), + "Cyan" => Some(ConfigColor::Cyan), + "White" => Some(ConfigColor::White), + s if u8::from_str(s).is_ok() => Some(ConfigColor::Color256(u8::from_str(s).unwrap())), + _ => None, + } +} + +fn serialize_color_by_theme(c: &ConfigColorByTheme) -> String { + let dark = &c.dark; + let light = &c.light; + if dark == light { + serialize_color(dark) + } else { + let dark = serialize_color(dark); + let light = serialize_color(light); + format!("{}|{}", dark, light) + } +} + +fn deserialize_color_by_theme(s: &str) -> Option { + if let Some(i) = s.find("|") { + let (dark, light) = s.split_at(i); + let light = &light[1..]; + let dark = deserialize_color(dark)?; + let light = deserialize_color(light)?; + Some(ConfigColorByTheme { dark, light }) + } else { + let c = deserialize_color(s)?; + Some(ConfigColorByTheme { + dark: c.clone(), + light: c, + }) + } +} + +#[derive(Clone, Debug)] +pub struct ConfigColorByTheme { + pub dark: ConfigColor, + pub light: ConfigColor, +} + +impl serde::Serialize for ConfigColorByTheme { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let s = serialize_color_by_theme(self); + serializer.serialize_str(&s) + } +} + +impl<'de> serde::Deserialize<'de> for ConfigColorByTheme { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + deserialize_color_by_theme(&s).ok_or(serde::de::Error::custom("")) + } +} + +#[derive(Clone, Debug)] pub enum ConfigColumnStyle { - BrightBlack, - BrightRed, - BrightGreen, - BrightYellow, - BrightBlue, - BrightMagenta, - BrightCyan, - BrightWhite, - Black, - Red, - Green, - Yellow, - Blue, - Magenta, - Cyan, - White, - Color256(u8), + Fixed(ConfigColorByTheme), ByPercentage, ByState, ByUnit, } +impl serde::Serialize for ConfigColumnStyle { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let s = match self { + ConfigColumnStyle::ByPercentage => "ByPercentage".to_string(), + ConfigColumnStyle::ByState => "ByState".to_string(), + ConfigColumnStyle::ByUnit => "ByUnit".to_string(), + ConfigColumnStyle::Fixed(c) => serialize_color_by_theme(c), + }; + serializer.serialize_str(&s) + } +} + +impl<'de> serde::Deserialize<'de> for ConfigColumnStyle { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + match s.as_str() { + "ByPercentage" => Ok(ConfigColumnStyle::ByPercentage), + "ByState" => Ok(ConfigColumnStyle::ByState), + "ByUnit" => Ok(ConfigColumnStyle::ByUnit), + s => { + let c = deserialize_color_by_theme(s).ok_or(serde::de::Error::custom(""))?; + Ok(ConfigColumnStyle::Fixed(c)) + } + } + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub enum ConfigColumnAlign { Left, @@ -173,12 +304,12 @@ pub struct ConfigColumn { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigStyle { - #[serde(default = "default_color_bright_white")] - pub header: ConfigColor, - #[serde(default = "default_color_bright_white")] - pub unit: ConfigColor, - #[serde(default = "default_color_bright_white")] - pub tree: ConfigColor, + #[serde(default = "default_color_by_theme")] + pub header: ConfigColorByTheme, + #[serde(default = "default_color_by_theme")] + pub unit: ConfigColorByTheme, + #[serde(default = "default_color_by_theme")] + pub tree: ConfigColorByTheme, #[serde(default)] pub by_percentage: ConfigStyleByPercentage, #[serde(default)] @@ -190,9 +321,9 @@ pub struct ConfigStyle { impl Default for ConfigStyle { fn default() -> Self { ConfigStyle { - header: ConfigColor::BrightWhite, - unit: ConfigColor::BrightWhite, - tree: ConfigColor::BrightWhite, + header: default_color_by_theme(), + unit: default_color_by_theme(), + tree: default_color_by_theme(), by_percentage: Default::default(), by_state: Default::default(), by_unit: Default::default(), @@ -202,73 +333,133 @@ impl Default for ConfigStyle { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigStyleByPercentage { - pub color_000: ConfigColor, - pub color_025: ConfigColor, - pub color_050: ConfigColor, - pub color_075: ConfigColor, - pub color_100: ConfigColor, + pub color_000: ConfigColorByTheme, + pub color_025: ConfigColorByTheme, + pub color_050: ConfigColorByTheme, + pub color_075: ConfigColorByTheme, + pub color_100: ConfigColorByTheme, } impl Default for ConfigStyleByPercentage { fn default() -> Self { ConfigStyleByPercentage { - color_000: ConfigColor::BrightBlue, - color_025: ConfigColor::BrightGreen, - color_050: ConfigColor::BrightYellow, - color_075: ConfigColor::BrightRed, - color_100: ConfigColor::BrightRed, + color_000: ConfigColorByTheme { + dark: ConfigColor::BrightBlue, + light: ConfigColor::Blue, + }, + color_025: ConfigColorByTheme { + dark: ConfigColor::BrightGreen, + light: ConfigColor::Green, + }, + color_050: ConfigColorByTheme { + dark: ConfigColor::BrightYellow, + light: ConfigColor::Yellow, + }, + color_075: ConfigColorByTheme { + dark: ConfigColor::BrightRed, + light: ConfigColor::Red, + }, + color_100: ConfigColorByTheme { + dark: ConfigColor::BrightRed, + light: ConfigColor::Red, + }, } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigStyleByUnit { - pub color_k: ConfigColor, - pub color_m: ConfigColor, - pub color_g: ConfigColor, - pub color_t: ConfigColor, - pub color_p: ConfigColor, - pub color_x: ConfigColor, + pub color_k: ConfigColorByTheme, + pub color_m: ConfigColorByTheme, + pub color_g: ConfigColorByTheme, + pub color_t: ConfigColorByTheme, + pub color_p: ConfigColorByTheme, + pub color_x: ConfigColorByTheme, } impl Default for ConfigStyleByUnit { fn default() -> Self { ConfigStyleByUnit { - color_k: ConfigColor::BrightBlue, - color_m: ConfigColor::BrightGreen, - color_g: ConfigColor::BrightYellow, - color_t: ConfigColor::BrightRed, - color_p: ConfigColor::BrightRed, - color_x: ConfigColor::BrightBlue, + color_k: ConfigColorByTheme { + dark: ConfigColor::BrightBlue, + light: ConfigColor::Blue, + }, + color_m: ConfigColorByTheme { + dark: ConfigColor::BrightGreen, + light: ConfigColor::Green, + }, + color_g: ConfigColorByTheme { + dark: ConfigColor::BrightYellow, + light: ConfigColor::Yellow, + }, + color_t: ConfigColorByTheme { + dark: ConfigColor::BrightRed, + light: ConfigColor::Red, + }, + color_p: ConfigColorByTheme { + dark: ConfigColor::BrightRed, + light: ConfigColor::Red, + }, + color_x: ConfigColorByTheme { + dark: ConfigColor::BrightBlue, + light: ConfigColor::Blue, + }, } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigStyleByState { - pub color_d: ConfigColor, - pub color_r: ConfigColor, - pub color_s: ConfigColor, - pub color_t: ConfigColor, - pub color_z: ConfigColor, - pub color_x: ConfigColor, - pub color_k: ConfigColor, - pub color_w: ConfigColor, - pub color_p: ConfigColor, + pub color_d: ConfigColorByTheme, + pub color_r: ConfigColorByTheme, + pub color_s: ConfigColorByTheme, + pub color_t: ConfigColorByTheme, + pub color_z: ConfigColorByTheme, + pub color_x: ConfigColorByTheme, + pub color_k: ConfigColorByTheme, + pub color_w: ConfigColorByTheme, + pub color_p: ConfigColorByTheme, } impl Default for ConfigStyleByState { fn default() -> Self { ConfigStyleByState { - color_d: ConfigColor::BrightRed, - color_r: ConfigColor::BrightGreen, - color_s: ConfigColor::BrightBlue, - color_t: ConfigColor::BrightCyan, - color_z: ConfigColor::BrightMagenta, - color_x: ConfigColor::BrightMagenta, - color_k: ConfigColor::BrightYellow, - color_w: ConfigColor::BrightYellow, - color_p: ConfigColor::BrightYellow, + color_d: ConfigColorByTheme { + dark: ConfigColor::BrightRed, + light: ConfigColor::Red, + }, + color_r: ConfigColorByTheme { + dark: ConfigColor::BrightGreen, + light: ConfigColor::Green, + }, + color_s: ConfigColorByTheme { + dark: ConfigColor::BrightBlue, + light: ConfigColor::Blue, + }, + color_t: ConfigColorByTheme { + dark: ConfigColor::BrightCyan, + light: ConfigColor::Cyan, + }, + color_z: ConfigColorByTheme { + dark: ConfigColor::BrightMagenta, + light: ConfigColor::Magenta, + }, + color_x: ConfigColorByTheme { + dark: ConfigColor::BrightMagenta, + light: ConfigColor::Magenta, + }, + color_k: ConfigColorByTheme { + dark: ConfigColor::BrightYellow, + light: ConfigColor::Yellow, + }, + color_w: ConfigColorByTheme { + dark: ConfigColor::BrightYellow, + light: ConfigColor::Yellow, + }, + color_p: ConfigColorByTheme { + dark: ConfigColor::BrightYellow, + light: ConfigColor::Yellow, + }, } } } @@ -329,6 +520,8 @@ pub struct ConfigDisplay { pub tree_symbols: [String; 5], #[serde(default = "default_true")] pub abbr_sid: bool, + #[serde(default = "default_theme_auto")] + pub theme: ConfigTheme, } impl Default for ConfigDisplay { @@ -350,6 +543,7 @@ impl Default for ConfigDisplay { String::from("└"), ], abbr_sid: true, + theme: ConfigTheme::Auto, } } } diff --git a/src/main.rs b/src/main.rs index 6daafd6..ecaf585 100644 --- a/src/main.rs +++ b/src/main.rs @@ -132,6 +132,15 @@ pub struct Opt { )] pub color: Option, + /// Theme mode + #[structopt( + long = "theme", + possible_value = "auto", + possible_value = "dark", + possible_value = "light" + )] + pub theme: Option, + /// Pager mode #[structopt( short = "p", @@ -254,6 +263,7 @@ fn run() -> Result<(), Error> { fn run_config() -> Result<(), Error> { let config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); + dbg!(&config); let toml = toml::to_string(&config)?; println!("{}", toml); Ok(()) @@ -326,6 +336,7 @@ mod tests { fn test_run() { let mut config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); config.pager.mode = ConfigPagerMode::Disable; + config.display.theme = ConfigTheme::Dark; let args = vec!["procs"]; let opt = Opt::from_iter(args.iter()); @@ -337,6 +348,7 @@ mod tests { fn test_run_search() { let mut config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); config.pager.mode = ConfigPagerMode::Disable; + config.display.theme = ConfigTheme::Dark; let args = vec!["procs", "root"]; let opt = Opt::from_iter(args.iter()); @@ -392,6 +404,7 @@ mod tests { fn test_run_without_truncate() { let mut config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); config.display.cut_to_terminal = false; + config.display.theme = ConfigTheme::Dark; let args = vec!["procs"]; let opt = Opt::from_iter(args.iter()); @@ -404,6 +417,7 @@ mod tests { fn test_run_insert() { let mut config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); config.pager.mode = ConfigPagerMode::Disable; + config.display.theme = ConfigTheme::Dark; let args = vec!["procs", "--insert", "ppid"]; let opt = Opt::from_iter(args.iter()); @@ -415,6 +429,7 @@ mod tests { fn test_run_sort() { let mut config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); config.pager.mode = ConfigPagerMode::Disable; + config.display.theme = ConfigTheme::Dark; let args = vec!["procs", "--sorta", "cpu"]; let opt = Opt::from_iter(args.iter()); @@ -431,6 +446,7 @@ mod tests { fn test_run_tree() { let mut config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); config.pager.mode = ConfigPagerMode::Disable; + config.display.theme = ConfigTheme::Dark; let args = vec!["procs", "--tree"]; let opt = Opt::from_iter(args.iter()); @@ -442,6 +458,7 @@ mod tests { fn test_run_all() { let mut config: Config = toml::from_str(CONFIG_ALL).unwrap(); config.pager.mode = ConfigPagerMode::Disable; + config.display.theme = ConfigTheme::Dark; let _tcp = std::net::TcpListener::bind("127.0.0.1:10000"); let _udp = std::net::UdpSocket::bind("127.0.0.1:10000"); diff --git a/src/style.rs b/src/style.rs index 217a111..4d1c324 100644 --- a/src/style.rs +++ b/src/style.rs @@ -1,4 +1,4 @@ -use crate::config::{ConfigColor, ConfigColumnStyle, ConfigStyle}; +use crate::config::{ConfigColor, ConfigColorByTheme, ConfigColumnStyle, ConfigStyle, ConfigTheme}; use console::{Style, StyledObject}; use lazy_static::lazy_static; @@ -21,49 +21,75 @@ lazy_static! { static ref WHITE: Style = Style::new().white(); } -fn apply_style_by_state(x: String, s: &ConfigStyle, faded: bool) -> StyledObject { +fn apply_style_by_state( + x: String, + s: &ConfigStyle, + theme: &ConfigTheme, + faded: bool, +) -> StyledObject { match x { - ref x if x.contains('D') => apply_color(x.to_string(), &s.by_state.color_d, faded), - ref x if x.contains('R') => apply_color(x.to_string(), &s.by_state.color_r, faded), - ref x if x.contains('S') => apply_color(x.to_string(), &s.by_state.color_s, faded), - ref x if x.contains('T') => apply_color(x.to_string(), &s.by_state.color_t, faded), - ref x if x.contains('t') => apply_color(x.to_string(), &s.by_state.color_t, faded), - ref x if x.contains('Z') => apply_color(x.to_string(), &s.by_state.color_z, faded), - ref x if x.contains('X') => apply_color(x.to_string(), &s.by_state.color_x, faded), - ref x if x.contains('K') => apply_color(x.to_string(), &s.by_state.color_k, faded), - ref x if x.contains('W') => apply_color(x.to_string(), &s.by_state.color_w, faded), - ref x if x.contains('P') => apply_color(x.to_string(), &s.by_state.color_p, faded), - _ => apply_color(x, &s.by_state.color_x, faded), + ref x if x.contains('D') => apply_color(x.to_string(), &s.by_state.color_d, theme, faded), + ref x if x.contains('R') => apply_color(x.to_string(), &s.by_state.color_r, theme, faded), + ref x if x.contains('S') => apply_color(x.to_string(), &s.by_state.color_s, theme, faded), + ref x if x.contains('T') => apply_color(x.to_string(), &s.by_state.color_t, theme, faded), + ref x if x.contains('t') => apply_color(x.to_string(), &s.by_state.color_t, theme, faded), + ref x if x.contains('Z') => apply_color(x.to_string(), &s.by_state.color_z, theme, faded), + ref x if x.contains('X') => apply_color(x.to_string(), &s.by_state.color_x, theme, faded), + ref x if x.contains('K') => apply_color(x.to_string(), &s.by_state.color_k, theme, faded), + ref x if x.contains('W') => apply_color(x.to_string(), &s.by_state.color_w, theme, faded), + ref x if x.contains('P') => apply_color(x.to_string(), &s.by_state.color_p, theme, faded), + _ => apply_color(x, &s.by_state.color_x, theme, faded), } } -fn apply_style_by_unit(x: String, s: &ConfigStyle, faded: bool) -> StyledObject { +fn apply_style_by_unit( + x: String, + s: &ConfigStyle, + theme: &ConfigTheme, + faded: bool, +) -> StyledObject { match x { - ref x if x.contains('K') => apply_color(x.to_string(), &s.by_unit.color_k, faded), - ref x if x.contains('M') => apply_color(x.to_string(), &s.by_unit.color_m, faded), - ref x if x.contains('G') => apply_color(x.to_string(), &s.by_unit.color_g, faded), - ref x if x.contains('T') => apply_color(x.to_string(), &s.by_unit.color_t, faded), - ref x if x.contains('P') => apply_color(x.to_string(), &s.by_unit.color_p, faded), - _ => apply_color(x, &s.by_unit.color_x, faded), + ref x if x.contains('K') => apply_color(x.to_string(), &s.by_unit.color_k, theme, faded), + ref x if x.contains('M') => apply_color(x.to_string(), &s.by_unit.color_m, theme, faded), + ref x if x.contains('G') => apply_color(x.to_string(), &s.by_unit.color_g, theme, faded), + ref x if x.contains('T') => apply_color(x.to_string(), &s.by_unit.color_t, theme, faded), + ref x if x.contains('P') => apply_color(x.to_string(), &s.by_unit.color_p, theme, faded), + _ => apply_color(x, &s.by_unit.color_x, theme, faded), } } -fn apply_style_by_percentage(x: String, s: &ConfigStyle, faded: bool) -> StyledObject { +fn apply_style_by_percentage( + x: String, + s: &ConfigStyle, + theme: &ConfigTheme, + faded: bool, +) -> StyledObject { let value: f64 = x.trim().parse().unwrap_or(0.0); if value > 100.0 { - apply_color(x, &s.by_percentage.color_100, faded) + apply_color(x, &s.by_percentage.color_100, theme, faded) } else if value > 75.0 { - apply_color(x, &s.by_percentage.color_075, faded) + apply_color(x, &s.by_percentage.color_075, theme, faded) } else if value > 50.0 { - apply_color(x, &s.by_percentage.color_050, faded) + apply_color(x, &s.by_percentage.color_050, theme, faded) } else if value > 25.0 { - apply_color(x, &s.by_percentage.color_025, faded) + apply_color(x, &s.by_percentage.color_025, theme, faded) } else { - apply_color(x, &s.by_percentage.color_000, faded) + apply_color(x, &s.by_percentage.color_000, theme, faded) } } -pub fn apply_color(x: String, c: &ConfigColor, faded: bool) -> StyledObject { +pub fn apply_color( + x: String, + c: &ConfigColorByTheme, + theme: &ConfigTheme, + faded: bool, +) -> StyledObject { + let c = match theme { + ConfigTheme::Dark => &c.dark, + ConfigTheme::Light => &c.light, + _ => unreachable!(), + }; + if faded { match c { ConfigColor::BrightBlack => BLACK.apply_to(x), @@ -111,50 +137,17 @@ pub fn apply_style( x: String, cs: &ConfigColumnStyle, s: &ConfigStyle, + theme: &ConfigTheme, faded: bool, ) -> StyledObject { match cs { - ConfigColumnStyle::BrightBlack => apply_color(x, &ConfigColor::BrightBlack, faded), - ConfigColumnStyle::BrightRed => apply_color(x, &ConfigColor::BrightRed, faded), - ConfigColumnStyle::BrightGreen => apply_color(x, &ConfigColor::BrightGreen, faded), - ConfigColumnStyle::BrightYellow => apply_color(x, &ConfigColor::BrightYellow, faded), - ConfigColumnStyle::BrightBlue => apply_color(x, &ConfigColor::BrightBlue, faded), - ConfigColumnStyle::BrightMagenta => apply_color(x, &ConfigColor::BrightMagenta, faded), - ConfigColumnStyle::BrightCyan => apply_color(x, &ConfigColor::BrightCyan, faded), - ConfigColumnStyle::BrightWhite => apply_color(x, &ConfigColor::BrightWhite, faded), - ConfigColumnStyle::Black => apply_color(x, &ConfigColor::Black, faded), - ConfigColumnStyle::Red => apply_color(x, &ConfigColor::Red, faded), - ConfigColumnStyle::Green => apply_color(x, &ConfigColor::Green, faded), - ConfigColumnStyle::Yellow => apply_color(x, &ConfigColor::Yellow, faded), - ConfigColumnStyle::Blue => apply_color(x, &ConfigColor::Blue, faded), - ConfigColumnStyle::Magenta => apply_color(x, &ConfigColor::Magenta, faded), - ConfigColumnStyle::Cyan => apply_color(x, &ConfigColor::Cyan, faded), - ConfigColumnStyle::White => apply_color(x, &ConfigColor::White, faded), - ConfigColumnStyle::Color256(c) => apply_color(x, &ConfigColor::Color256(*c), faded), - ConfigColumnStyle::ByPercentage => apply_style_by_percentage(x, s, faded), - ConfigColumnStyle::ByState => apply_style_by_state(x, s, faded), - ConfigColumnStyle::ByUnit => apply_style_by_unit(x, s, faded), + ConfigColumnStyle::Fixed(c) => apply_color(x, c, theme, faded), + ConfigColumnStyle::ByPercentage => apply_style_by_percentage(x, s, theme, faded), + ConfigColumnStyle::ByState => apply_style_by_state(x, s, theme, faded), + ConfigColumnStyle::ByUnit => apply_style_by_unit(x, s, theme, faded), } } -pub fn color_to_column_style(c: &ConfigColor) -> ConfigColumnStyle { - match c { - ConfigColor::BrightBlack => ConfigColumnStyle::BrightBlack, - ConfigColor::BrightRed => ConfigColumnStyle::BrightRed, - ConfigColor::BrightGreen => ConfigColumnStyle::BrightGreen, - ConfigColor::BrightYellow => ConfigColumnStyle::BrightYellow, - ConfigColor::BrightBlue => ConfigColumnStyle::BrightBlue, - ConfigColor::BrightMagenta => ConfigColumnStyle::BrightMagenta, - ConfigColor::BrightCyan => ConfigColumnStyle::BrightCyan, - ConfigColor::BrightWhite => ConfigColumnStyle::BrightWhite, - ConfigColor::Black => ConfigColumnStyle::Black, - ConfigColor::Red => ConfigColumnStyle::Red, - ConfigColor::Green => ConfigColumnStyle::Green, - ConfigColor::Yellow => ConfigColumnStyle::Yellow, - ConfigColor::Blue => ConfigColumnStyle::Blue, - ConfigColor::Magenta => ConfigColumnStyle::Magenta, - ConfigColor::Cyan => ConfigColumnStyle::Cyan, - ConfigColor::White => ConfigColumnStyle::White, - ConfigColor::Color256(c) => ConfigColumnStyle::Color256(*c), - } +pub fn color_to_column_style(c: &ConfigColorByTheme) -> ConfigColumnStyle { + ConfigColumnStyle::Fixed(c.clone()) } diff --git a/src/view.rs b/src/view.rs index 26b328b..fc887fe 100644 --- a/src/view.rs +++ b/src/view.rs @@ -305,10 +305,6 @@ impl View { self.term_info.width = std::usize::MAX; } - if use_pager { - View::pager(&config); - } - match (opt.color.as_ref(), &config.display.color_mode) { (Some(x), _) if x == "auto" => { if use_pager && use_terminal { @@ -327,22 +323,51 @@ impl View { _ => (), } + let theme = match (opt.theme.as_ref(), &config.display.theme) { + (Some(x), _) => match x.as_str() { + "auto" => ConfigTheme::Auto, + "dark" => ConfigTheme::Dark, + "light" => ConfigTheme::Light, + _ => unreachable!(), + }, + (_, x) => x.clone(), + }; + let theme = match theme { + ConfigTheme::Auto => { + let timeout = Duration::from_millis(100); + if let Ok(theme) = termbg::theme(timeout) { + match theme { + termbg::Theme::Dark => ConfigTheme::Dark, + termbg::Theme::Light => ConfigTheme::Light, + } + } else { + // If termbg failed, fallback to dark theme + ConfigTheme::Dark + } + } + x => x, + }; + + if use_pager { + View::pager(&config); + } + if !opt.no_header { // Ignore display_* error // `Broken pipe` may occur at pager mode. It can be ignored safely. - let _ = self.display_header(config); - let _ = self.display_unit(&config); + let _ = self.display_header(&config, &theme); + let _ = self.display_unit(&config, &theme); } for pid in &self.visible_pids { let auxiliary = self.auxiliary_pids.contains(pid); - let _ = self.display_content(&config, *pid, auxiliary); + let _ = self.display_content(&config, *pid, &theme, auxiliary); } Ok(()) } - fn display_header(&self, config: &Config) -> Result<(), Error> { + fn display_header(&self, config: &Config, theme: &ConfigTheme) -> Result<(), Error> { let mut row = String::from(""); for (i, c) in self.columns.iter().enumerate() { let order = if i == self.sort_info.idx { @@ -356,6 +381,7 @@ impl View { apply_color( c.column.display_header(&c.align, order, config), &config.style.header, + theme, false ) ); @@ -366,13 +392,18 @@ impl View { Ok(()) } - fn display_unit(&self, config: &Config) -> Result<(), Error> { + fn display_unit(&self, config: &Config, theme: &ConfigTheme) -> Result<(), Error> { let mut row = String::from(""); for c in &self.columns { row = format!( "{} {}", row, - apply_color(c.column.display_unit(&c.align), &config.style.unit, false) + apply_color( + c.column.display_unit(&c.align), + &config.style.unit, + theme, + false + ) ); } row = row.trim_end().to_string(); @@ -381,7 +412,13 @@ impl View { Ok(()) } - fn display_content(&self, config: &Config, pid: i32, auxiliary: bool) -> Result<(), Error> { + fn display_content( + &self, + config: &Config, + pid: i32, + theme: &ConfigTheme, + auxiliary: bool, + ) -> Result<(), Error> { let mut row = String::from(""); for c in &self.columns { row = format!( @@ -391,6 +428,7 @@ impl View { c.column.display_content(pid, &c.align).unwrap(), &c.style, &config.style, + theme, auxiliary ) ); diff --git a/src/watcher.rs b/src/watcher.rs index fd0c0f4..051b0f3 100644 --- a/src/watcher.rs +++ b/src/watcher.rs @@ -67,7 +67,7 @@ impl Watcher { }); } - fn display_header(term_info: &TermInfo, opt: &Opt, interval: u64) -> Result<(), Error> { + fn display_header(term_info: &mut TermInfo, opt: &Opt, interval: u64) -> Result<(), Error> { let header = if opt.tree { format!( " Interval: {}s, Last Updated: {} ( Quit: q or Ctrl-C )", @@ -125,7 +125,7 @@ impl Watcher { if resized { term_info.clear_screen()?; } - Watcher::display_header(&view.term_info, opt, interval)?; + Watcher::display_header(&mut view.term_info, opt, interval)?; view.display(opt, config)?;