From 8c71eb530712422c173f73ef8f2eb2ef252c0cd9 Mon Sep 17 00:00:00 2001 From: Marc Schreiber Date: Tue, 11 Aug 2020 18:44:25 +0200 Subject: [PATCH] feat: Add Undistract Me Feature (#1019) Often it is handy to get notified when the execution of a command finished. This commit includes notify-rust in order to generate a desktop notification when a command execution finished. --- .github/workflows/workflow.yml | 14 +- Cargo.lock | 243 +++++++++++++++++++++++++++++---- Cargo.toml | 1 + src/configs/cmd_duration.rs | 4 + src/context.rs | 4 + src/modules/cmd_duration.rs | 57 ++++++-- 6 files changed, 283 insertions(+), 40 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index dfc2872d..1b70ac0c 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -27,6 +27,9 @@ jobs: profile: minimal components: rustfmt + - name: Setup | libdbus (ubuntu) + run: sudo apt-get install libdbus-1-dev + - name: Build | Format run: cargo fmt --all -- --check @@ -51,6 +54,10 @@ jobs: target key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + - name: Setup | libdbus (ubuntu) + if: matrix.os == 'ubuntu-latest' + run: sudo apt-get install libdbus-1-dev + - name: Setup | Rust uses: actions-rs/toolchain@v1 with: @@ -108,6 +115,11 @@ jobs: - name: Setup | Checkout uses: actions/checkout@v2 + - name: Setup | libdbus (ubuntu) + if: matrix.os == 'ubuntu-latest' + run: sudo apt-get install libdbus-1-dev + + # Cache files between builds - name: Setup | Cache Cargo uses: actions/cache@v2 with: @@ -132,4 +144,4 @@ jobs: # Run the ignored tests that expect the above setup - name: Build | Test - run: cargo test -- -Z unstable-options --include-ignored + run: cargo test --all-features -- -Z unstable-options --include-ignored diff --git a/Cargo.lock b/Cargo.lock index b9f08166..7d5d45d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,6 +94,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "bitflags" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" + [[package]] name = "bitflags" version = "1.2.1" @@ -111,6 +117,12 @@ dependencies = [ "constant_time_eq", ] +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + [[package]] name = "block-buffer" version = "0.7.3" @@ -187,13 +199,13 @@ dependencies = [ [[package]] name = "clap" -version = "2.33.1" +version = "2.33.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +checksum = "10040cdf04294b565d9e0319955430099ec3813a64c952b86a41200ad714ae48" dependencies = [ "ansi_term 0.11.0", "atty", - "bitflags", + "bitflags 1.2.1", "strsim", "textwrap", "unicode-width", @@ -286,6 +298,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "dbus" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd9e78c210146a1860f897db03412fd5091fd73100778e43ee255cca252cf32" +dependencies = [ + "libc", + "libdbus-sys", +] + [[package]] name = "digest" version = "0.8.1" @@ -295,6 +317,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "dirs" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dirs-next" version = "1.0.1" @@ -330,9 +363,9 @@ checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" [[package]] name = "either" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" [[package]] name = "env_logger" @@ -410,7 +443,7 @@ version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ac22e49b7d886b6802c66662b12609452248b1bc9e87d6d83ecea3db96f557" dependencies = [ - "bitflags", + "bitflags 1.2.1", "libc", "libgit2-sys", "log", @@ -419,9 +452,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34f595585f103464d8d2f6e9864682d74c1601fed5e07d62b1c9058dba8246fb" +checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25" dependencies = [ "autocfg", ] @@ -468,9 +501,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b88cd59ee5f71fea89a62248fc8f387d44400cefe05ef548466d61ced9029a7" +checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9" dependencies = [ "autocfg", "hashbrown", @@ -509,6 +542,15 @@ version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" +[[package]] +name = "libdbus-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc12a3bc971424edbbf7edaf6e5740483444db63aa8e23d3751ff12a30f306f0" +dependencies = [ + "pkg-config", +] + [[package]] name = "libgit2-sys" version = "0.12.9+1.0.1" @@ -548,6 +590,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "mac-notification-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb6b71a9a89cd38b395d994214297447e8e63b1ba5708a9a2b0b1048ceda76" +dependencies = [ + "cc", + "chrono", + "dirs", + "objc-foundation", +] + [[package]] name = "mach" version = "0.2.3" @@ -557,6 +611,15 @@ dependencies = [ "libc", ] +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + [[package]] name = "maplit" version = "1.0.2" @@ -614,7 +677,7 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" dependencies = [ - "bitflags", + "bitflags 1.2.1", "cc", "cfg-if", "libc", @@ -627,12 +690,23 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" dependencies = [ - "bitflags", + "bitflags 1.2.1", "cc", "cfg-if", "libc", ] +[[package]] +name = "notify-rust" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "144acee6a0543dc74893e4b8a33936b5b0a94cc2d4ab024afd0c6daff7afc3c0" +dependencies = [ + "dbus", + "mac-notification-sys", + "winrt-notification", +] + [[package]] name = "ntapi" version = "0.3.4" @@ -671,6 +745,35 @@ dependencies = [ "libc", ] +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + [[package]] name = "once_cell" version = "1.4.0" @@ -698,7 +801,7 @@ version = "0.10.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4" dependencies = [ - "bitflags", + "bitflags 1.2.1", "cfg-if", "foreign-types", "lazy_static", @@ -786,8 +889,8 @@ dependencies = [ "pest", "pest_meta", "proc-macro2", - "quote", - "syn", + "quote 1.0.7", + "syn 1.0.38", ] [[package]] @@ -829,7 +932,7 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" dependencies = [ - "unicode-xid", + "unicode-xid 0.2.1", ] [[package]] @@ -847,6 +950,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "quote" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" + [[package]] name = "quote" version = "1.0.7" @@ -1006,7 +1115,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64808902d7d99f78eaddd2b4e2509713babc3dc3c85ad6f4c447680f3c01e535" dependencies = [ - "bitflags", + "bitflags 1.2.1", "core-foundation 0.7.0", "core-foundation-sys 0.7.0", "libc", @@ -1025,22 +1134,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" +checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" +checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" dependencies = [ "proc-macro2", - "quote", - "syn", + "quote 1.0.7", + "syn 1.0.38", ] [[package]] @@ -1094,6 +1203,7 @@ dependencies = [ "log", "native-tls", "nix 0.18.0", + "notify-rust", "once_cell", "open", "os_info", @@ -1122,8 +1232,8 @@ name = "starship_module_config_derive" version = "0.1.1" dependencies = [ "proc-macro2", - "quote", - "syn", + "quote 1.0.7", + "syn 1.0.38", ] [[package]] @@ -1133,14 +1243,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] -name = "syn" -version = "1.0.36" +name = "strum" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250" +checksum = "4ca6e4730f517e041e547ffe23d29daab8de6b73af4b6ae2a002108169f5e7da" + +[[package]] +name = "strum_macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3384590878eb0cab3b128e844412e2d010821e7e091211b9d87324173ada7db8" +dependencies = [ + "quote 0.3.15", + "syn 0.11.11", +] + +[[package]] +name = "syn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" +dependencies = [ + "quote 0.3.15", + "synom", + "unicode-xid 0.0.4", +] + +[[package]] +name = "syn" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4" dependencies = [ "proc-macro2", - "quote", - "unicode-xid", + "quote 1.0.7", + "unicode-xid 0.2.1", +] + +[[package]] +name = "synom" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +dependencies = [ + "unicode-xid 0.0.4", ] [[package]] @@ -1277,6 +1423,12 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +[[package]] +name = "unicode-xid" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" + [[package]] name = "unicode-xid" version = "0.2.1" @@ -1371,6 +1523,37 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winrt" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e30cba82e22b083dc5a422c2ee77e20dc7927271a0dc981360c57c1453cb48d" +dependencies = [ + "winapi", +] + +[[package]] +name = "winrt-notification" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c31a65da50d792c6f9bd2e3216249566c4fb1d2d34f9b7d2d66d2e93f62a242" +dependencies = [ + "strum", + "strum_macros", + "winapi", + "winrt", + "xml-rs", +] + +[[package]] +name = "xml-rs" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1945e12e16b951721d7976520b0832496ef79c31602c7a29d950de79ba74621" +dependencies = [ + "bitflags 0.9.1", +] + [[package]] name = "yaml-rust" version = "0.4.4" diff --git a/Cargo.toml b/Cargo.toml index 26b2a228..c04678f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ open = "1.4.0" unicode-width = "0.1.8" term_size = "0.3.2" quick-xml = "0.18.1" +notify-rust = { version = "4.0.0", optional = true } # Optional/http: attohttpc = { version = "0.15.0", optional = true, default-features = false, features = ["tls", "form"] } diff --git a/src/configs/cmd_duration.rs b/src/configs/cmd_duration.rs index e7e8c385..7609e9cf 100644 --- a/src/configs/cmd_duration.rs +++ b/src/configs/cmd_duration.rs @@ -9,6 +9,8 @@ pub struct CmdDurationConfig<'a> { pub style: &'a str, pub show_milliseconds: bool, pub disabled: bool, + pub show_notifications: bool, + pub min_time_to_notify: i64, } impl<'a> RootModuleConfig<'a> for CmdDurationConfig<'a> { @@ -19,6 +21,8 @@ impl<'a> RootModuleConfig<'a> for CmdDurationConfig<'a> { show_milliseconds: false, style: "yellow bold", disabled: false, + show_notifications: false, + min_time_to_notify: 45_000, } } } diff --git a/src/context.rs b/src/context.rs index 40b547a7..de7b901d 100644 --- a/src/context.rs +++ b/src/context.rs @@ -198,6 +198,10 @@ impl<'a> Context<'a> { _ => Shell::Unknown, } } + + pub fn get_cmd_duration(&self) -> Option { + self.properties.get("cmd_duration")?.parse::().ok() + } } #[derive(Debug)] diff --git a/src/modules/cmd_duration.rs b/src/modules/cmd_duration.rs index fe1f22b6..8684b0aa 100644 --- a/src/modules/cmd_duration.rs +++ b/src/modules/cmd_duration.rs @@ -11,13 +11,6 @@ pub fn module<'a>(context: &'a Context) -> Option> { let mut module = context.new_module("cmd_duration"); let config: CmdDurationConfig = CmdDurationConfig::try_load(module.config); - let props = &context.properties; - let elapsed = props - .get("cmd_duration") - .unwrap_or(&"invalid_time".into()) - .parse::() - .ok()?; - /* TODO: Once error handling is implemented, warn the user if their config min time is nonsensical */ if config.min_time < 0 { @@ -28,7 +21,10 @@ pub fn module<'a>(context: &'a Context) -> Option> { return None; } - if elapsed < config.min_time as u128 { + let elapsed = context.get_cmd_duration()?; + let config_min = config.min_time as u128; + + if elapsed < config_min { return None; } @@ -53,7 +49,7 @@ pub fn module<'a>(context: &'a Context) -> Option> { } }); - Some(module) + Some(undistract_me(module, &config, elapsed)) } // Render the time into a nice human-readable string @@ -86,6 +82,49 @@ fn render_time_component((component, suffix): (&u128, &&str)) -> String { } } +#[cfg(not(feature = "notify-rust"))] +fn undistract_me<'a, 'b>( + module: Module<'a>, + config: &'b CmdDurationConfig, + _elapsed: u128, +) -> Module<'a> { + if config.show_notifications { + log::debug!("This version of starship was built without notification support."); + } + + module +} + +#[cfg(feature = "notify-rust")] +fn undistract_me<'a, 'b>( + module: Module<'a>, + config: &'b CmdDurationConfig, + elapsed: u128, +) -> Module<'a> { + use ansi_term::{unstyle, ANSIStrings}; + use notify_rust::{Notification, Timeout}; + + if config.show_notifications && config.min_time_to_notify as u128 <= elapsed { + let body = format!( + "Command execution {}", + unstyle(&ANSIStrings(&module.ansi_strings())) + ); + + let mut notification = Notification::new(); + notification + .summary("Command finished") + .body(&body) + .icon("utilities-terminal") + .timeout(Timeout::Milliseconds(750)); + + if let Err(err) = notification.show() { + log::trace!("Cannot show notification: {}", err); + } + } + + module +} + #[cfg(test)] mod tests { use super::*;