diff --git a/Cargo.lock b/Cargo.lock index 93ba5c6..1875c5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,6 +73,46 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +[[package]] +name = "clap" +version = "4.5.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + [[package]] name = "colorchoice" version = "1.0.4" @@ -127,11 +167,18 @@ dependencies = [ "wasi", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hl-zed-dc-rpc" version = "0.1.0" dependencies = [ "anyhow", + "clap", "discord-rich-presence", "env_logger", "log", @@ -311,6 +358,12 @@ dependencies = [ "syn", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.104" diff --git a/Cargo.toml b/Cargo.toml index 9957494..672b6d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,4 @@ serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" discord-rich-presence = { git = "https://github.com/vionya/discord-rich-presence" } # git cause errors +clap = { version = "4.5.41", features = ["derive"] } diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 0000000..50780a4 --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,42 @@ +_name="hl-zed-dc-rpc" +pkgname="$_name-git" + +pkgver=r4.30034b9 +pkgrel=1 + +pkgdesc="zed discord rpc for the poor, and only for hyprland (but it like actually works)" +url="https://copeberg.org/virt/$_name" +license=(GPL-3.0) +arch=(x86_64) + +makedepends=('cargo-nightly') +optdepends=('hyprland: this will not do anything without hyprland') + +source=("$_name::git+$url.git") +md5sums=('SKIP') + +pkgver() { + cd $_name + + printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)" +} + +prepare() { + cd $_name + + export RUSTUP_TOOLCHAIN=nightly + cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')" +} + +build() { + cd $_name + + export RUSTUP_TOOLCHAIN=nightly + cargo build --frozen --release +} + +package() { + cd $_name + + install -Dm0755 -t "$pkgdir/usr/bin/" "target/release/$_name" +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..d3ac08b --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# hl-zed-dc-rpc +A discord rich presence for the [Zed Editor](https://zed.dev/) using the [Hyprland](https://hypr.land) IPC to detect running zed instances. Why? Because the [existing extension](https://github.com/xhyrom/zed-discord-presence) is extremely broken. Why you need discord rich presence for your stupid editor in the first place is a completely different question. + +> **IMPORTANT:** This uses the Hyprland IPC to get events for your activity, which means this only works on Hyprland. Yes, this is sketchy af but works suprisingly well. + +## Installation +If you are on Arch, you can build a package with the included [PKGBUILD](./PKGBUILD). + +If you are not on Arch, too bad, you'll have to build yourself: +``` +cargo build --release +``` + +## Usage +The produced executable is a deamon that should run in the background when you have zed and discord open. Start it in your hyprland config: +``` +exec-once = hl-zed-dc-rpc +``` + +The daemon supports a couple of commandline arguments to customize the idle time behaviour: +``` +Usage: hl-zed-dc-rpc [OPTIONS] + +Options: + -i, --idle idle timeout in minutes [default: 10] + -r, --reset-idle whether to reset the elapsed time on idle + -h, --help Print help +``` + +## Credits +The assets shown on Discord, including the application id are blatanly stolen from the [existing extension](https://github.com/xhyrom/zed-discord-presence). Thanks! Also tried to steal some more code but that has largely been refactored to non-resemblance. diff --git a/src/main.rs b/src/main.rs index 6845842..016e33d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use std::{ }; use anyhow::Result; +use clap::Parser; use discord::Discord; use hyprland::{Address, Hyprland}; use language::get_language; @@ -63,10 +64,24 @@ impl ZedInstance { } } +#[derive(Parser)] +#[clap(about)] +#[command(disable_help_subcommand = true)] +pub struct Command { + /// idle timeout in minutes + #[arg(short, long, default_value_t = 10)] + idle: u64, + + /// whether to reset the elapsed time on idle + #[arg(short, long)] + reset_idle: bool, +} + fn main() -> Result<()> { env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); + let args = Command::parse(); - let idle = Duration::from_secs(10 * 60); + let idle = Duration::from_secs(args.idle * 60); let mut discord = Discord::new(APP_ID)?; let mut hyprland = Hyprland::env()?; @@ -97,7 +112,9 @@ fn main() -> Result<()> { debug!("received new hyprland events"); // update anyways if last update has been before idle timeout - let mut changed = Instant::now().duration_since(updated) < idle; + let mut changed = Instant::now().duration_since(updated) > idle; + + println!("{}", Instant::now().duration_since(updated).as_secs()); if let Some(events) = events { for event in events { @@ -108,7 +125,7 @@ fn main() -> Result<()> { instances.insert(address, ZedInstance::new(&title)); true } - hyprland::HyprlandEvent::Active { address } => { + hyprland::HyprlandEvent::Active { address } if address != active => { let changed = if let Some(instance) = instances.get_mut(&active) { instance.focused = SystemTime::now(); true @@ -118,6 +135,14 @@ fn main() -> Result<()> { active = address; + if args.reset_idle + && let Some(instance) = instances.get_mut(&active) + && SystemTime::now().duration_since(instance.focused).expect("time wtf") + > idle + { + instance.started = SystemTime::now(); + } + changed || instances.contains_key(&active) } hyprland::HyprlandEvent::Close { address } => { @@ -164,12 +189,12 @@ fn main() -> Result<()> { let result = if let Some(ref instance) = shown { info!( "setting discord activity to {} in workspace {}", - instance.file.as_ref().map(|s| s.as_str()).unwrap_or(""), + instance.file.as_deref().unwrap_or(""), instance.workspace ); set_activity( &mut discord, - instance.file.as_ref().map(|s| s.as_str()).unwrap_or("nothing"), + instance.file.as_deref().unwrap_or("nothing"), &instance.workspace, instance.started, )