Skip to content

Commit 859e57b

Browse files
authored
feat: idle support (#27)
* feat: idle support * feat: idle action * fix: clippy * refactor: cleanup
1 parent c0df288 commit 859e57b

File tree

7 files changed

+430
-120
lines changed

7 files changed

+430
-120
lines changed

README.md

Lines changed: 145 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,38 +26,166 @@ Don't forget to give at least a ⭐ if you like this project :D
2626

2727
You can configure state, details and git integration by changing Discord Presence LSP settings. This can be done in <kbd>zed: open settings</kbd> with following configuration:
2828

29-
```json
29+
### Application ID
30+
31+
The `application_id` is required for the rich presence to work. It should be kept as is unless you have a specific reason to change it.
32+
33+
```jsonc
34+
"application_id": "1263505205522337886"
35+
```
36+
37+
### Base Icons URL
38+
39+
The `base_icons_url` is the base URL for all language icons. This URL points to the location where the icons are stored.
40+
41+
```jsonc
42+
"base_icons_url": "https://raw.githubusercontent.com/xhyrom/zed-discord-presence/main/assets/icons/"
43+
```
44+
45+
### State
46+
47+
The `state` option allows you to set the state message displayed in Discord. The placeholder `{filename}` will be replaced with the current file name.
48+
49+
```jsonc
50+
"state": "Working on {filename}"
51+
```
52+
53+
### Details
54+
55+
The `details` option allows you to set the details message displayed in Discord. The placeholder `{workspace}` will be replaced with the current workspace name.
56+
57+
```jsonc
58+
"details": "In {workspace}"
59+
```
60+
61+
### Large Image
62+
63+
The `large_image` option specifies the URL for the large image displayed in Discord. The placeholders `{base_icons_url}` and `{language}` will be replaced accordingly.
64+
65+
```jsonc
66+
"large_image": "{base_icons_url}/{language}.png"
67+
```
68+
69+
### Large Text
70+
71+
The `large_text` option specifies the text displayed when hovering over the large image. The `:u` modifier capitalizes the first letter of the language name.
72+
73+
```jsonc
74+
"large_text": "{language:u}"
75+
```
76+
77+
### Small Image
78+
79+
The `small_image` option specifies the URL for the small image displayed in Discord.
80+
81+
```jsonc
82+
"small_image": "{base_icons_url}/zed.png"
83+
```
84+
85+
### Small Text
86+
87+
The `small_text` option specifies the text displayed when hovering over the small image.
88+
89+
```jsonc
90+
"small_text": "Zed"
91+
```
92+
93+
### Idle Settings
94+
95+
The `idle` settings configure the behavior when you are inactive.
96+
97+
The `timeout` specifies the idle timeout in seconds (300 seconds = 5 minutes).
98+
99+
The `action` determines what happens when you go idle:
100+
101+
- `change_activity` changes the activity to idle with the specified details
102+
- `clear_activity` hides the activity
103+
104+
The `state`, `details`, `large_image`, `large_text`, `small_image`, and `small_text` options specify the messages and images to display when idle.
105+
106+
```jsonc
107+
"idle": {
108+
"timeout": 300,
109+
"action": "change_activity",
110+
"state": "Idling",
111+
"details": "In Zed",
112+
"large_image": "{base_icons_url}/zed.png",
113+
"large_text": "Zed",
114+
"small_image": "{base_icons_url}/idle.png",
115+
"small_text": "Idle"
116+
}
117+
```
118+
119+
### Rules
120+
121+
The `rules` option allows you to disable presence in specific workspaces. The `mode` can be set to `blacklist`
122+
or `whitelist`, and the `paths` array should contain the absolute paths to apply the rule to.
123+
124+
```jsonc
125+
"rules": {
126+
"mode": "blacklist",
127+
"paths": ["absolute path"]
128+
}
129+
```
130+
131+
### Git Integration
132+
133+
The `git_integration` option enables or disables Git integration. When enabled, the extension
134+
will display a button to open the Git repository.
135+
136+
```jsonc
137+
"git_integration": true
138+
```
139+
140+
### Example Configuration
141+
142+
```jsonc
30143
{
31144
"lsp": {
32145
"discord_presence": {
33146
"initialization_options": {
34-
// application id for the rich presence (required, keep it if you don't know what you're doing)
35-
"application_id": "1263505205522337886"
36-
// Base url for all language icons
147+
// Application ID for the rich presence (don't touch it unless you know what you're doing)
148+
"application_id": "1263505205522337886",
149+
// Base URL for all language icons
37150
"base_icons_url": "https://raw.githubusercontent.com/xhyrom/zed-discord-presence/main/assets/icons/",
38151

39152
"state": "Working on {filename}",
40153
"details": "In {workspace}",
41-
// URL for large image
154+
// URL for the large image
42155
"large_image": "{base_icons_url}/{language}.png",
43-
"large_text": "{language:u}", // :u makes first letter upper-case
44-
// URL for small image
156+
"large_text": "{language:u}", // :u capitalizes the first letter
157+
// URL for the small image
45158
"small_image": "{base_icons_url}/zed.png",
46159
"small_text": "Zed",
47160

48-
// Rules - disable presence in some workspaces
161+
// Idle settings - when you're inactive
162+
"idle": {
163+
"timeout": 300, // Idle timeout in seconds (300 seconds = 5 minutes)
164+
165+
// Action to take when idle
166+
// `change_activity` - changes the activity to idle with the following details
167+
// `clear_activity` - clears the activity (hides it)
168+
"action": "change_activity",
169+
170+
"state": "Idling",
171+
"details": "In Zed",
172+
"large_image": "{base_icons_url}/zed.png",
173+
"large_text": "Zed",
174+
"small_image": "{base_icons_url}/idle.png",
175+
"small_text": "Idle",
176+
},
177+
178+
// Rules to disable presence in specific workspaces
49179
"rules": {
50-
"mode": "blacklist", // or whitelist
51-
"paths": [
52-
"absolute path"
53-
]
180+
"mode": "blacklist", // Can also be "whitelist"
181+
"paths": ["absolute path"],
54182
},
55183

56-
"git_integration": true
57-
}
58-
}
59-
}
184+
"git_integration": true,
185+
},
186+
},
187+
},
60188
}
61189
```
62190

63-
You can also use `null` to unset the option. Possible for everything except `base_icons_url`, `rules` and `git_integration`
191+
You can also set any option to `null` to unset it, except for `base_icons_url`, `rules`, and `git_integration`.

lsp/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ edition = "2021"
55

66
[dependencies]
77
discord-rich-presence = "0.2.4"
8-
tokio = { version = "1.37.0", features = ["rt-multi-thread", "io-std", "macros"] }
8+
tokio = { version = "1.37.0", features = ["rt-multi-thread", "io-std", "macros", "time"] }
99
tower-lsp = "0.20.0"
1010
git2 = { version = "0.19.0", default-features = false }
1111
serde_json = { version = "1.0.122", features = ["std"] }

lsp/src/configuration.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,43 @@ impl Rules {
5252
}
5353
}
5454

55+
#[derive(Debug, PartialEq)]
56+
pub enum IdleAction {
57+
ClearActivity, // Clear the activity
58+
ChangeActivity, // Change the activity
59+
}
60+
61+
#[derive(Debug)]
62+
pub struct Idle {
63+
pub timeout: u64, // in seconds
64+
pub action: IdleAction, // what to do when idle
65+
66+
pub state: Option<String>,
67+
pub details: Option<String>,
68+
69+
pub large_image: Option<String>,
70+
pub large_text: Option<String>,
71+
pub small_image: Option<String>,
72+
pub small_text: Option<String>,
73+
}
74+
75+
impl Default for Idle {
76+
fn default() -> Self {
77+
Idle {
78+
timeout: 300,
79+
action: IdleAction::ChangeActivity,
80+
81+
state: Some("Idling".to_string()),
82+
details: Some("In Zed".to_string()),
83+
84+
large_image: Some(String::from("{base_icons_url}/zed.png")),
85+
large_text: Some(String::from("Zed")),
86+
small_image: Some(String::from("{base_icons_url}/idle.png")),
87+
small_text: Some(String::from("Idle")),
88+
}
89+
}
90+
}
91+
5592
#[derive(Debug)]
5693
pub struct Configuration {
5794
pub application_id: String,
@@ -67,6 +104,8 @@ pub struct Configuration {
67104

68105
pub rules: Rules,
69106

107+
pub idle: Idle,
108+
70109
pub git_integration: bool,
71110
}
72111

@@ -104,6 +143,7 @@ impl Configuration {
104143
small_image: Some(String::from("{base_icons_url}/zed.png")),
105144
small_text: Some(String::from("Zed")),
106145
rules: Rules::default(),
146+
idle: Idle::default(),
107147
git_integration: true,
108148
}
109149
}
@@ -141,6 +181,25 @@ impl Configuration {
141181
});
142182
}
143183

184+
if let Some(idle) = options.get("idle") {
185+
self.idle.timeout = idle.get("timeout").and_then(|t| t.as_u64()).unwrap_or(300);
186+
self.idle.action = idle.get("action").and_then(|a| a.as_str()).map_or(
187+
IdleAction::ChangeActivity,
188+
|action| match action {
189+
"clear_activity" => IdleAction::ClearActivity,
190+
"change_activity" => IdleAction::ChangeActivity,
191+
_ => IdleAction::ChangeActivity,
192+
},
193+
);
194+
195+
set_option!(self, idle, state, "state");
196+
set_option!(self, idle, details, "details");
197+
set_option!(self, idle, large_image, "large_image");
198+
set_option!(self, idle, large_text, "large_text");
199+
set_option!(self, idle, small_image, "small_image");
200+
set_option!(self, idle, small_text, "small_text");
201+
}
202+
144203
if let Some(git_integration) = options.get("git_integration") {
145204
self.git_integration = git_integration.as_bool().unwrap_or(true);
146205
}

lsp/src/discord.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,8 @@
1717
* along with this program. If not, see <http://www.gnu.org/licenses/>
1818
*/
1919

20-
use std::{
21-
sync::{Mutex, MutexGuard},
22-
time::{Duration, SystemTime, UNIX_EPOCH},
23-
};
20+
use std::time::{Duration, SystemTime, UNIX_EPOCH};
21+
use tokio::sync::{Mutex, MutexGuard};
2422

2523
use discord_rich_presence::{
2624
activity::{Activity, Assets, Button, Timestamps},
@@ -55,28 +53,35 @@ impl Discord {
5553
self.client = Some(Mutex::new(discord_client));
5654
}
5755

58-
pub fn connect(&self) {
59-
let mut client = self.get_client();
56+
pub async fn connect(&self) {
57+
let mut client = self.get_client().await;
6058
let result = client.connect();
6159
result.unwrap();
6260
}
6361

64-
pub fn kill(&self) {
65-
let mut client = self.get_client();
62+
pub async fn kill(&self) {
63+
let mut client = self.get_client().await;
6664
let result = client.close();
6765
result.unwrap();
6866
}
6967

70-
pub fn get_client(&self) -> MutexGuard<'_, DiscordIpcClient> {
68+
pub async fn get_client(&self) -> MutexGuard<'_, DiscordIpcClient> {
7169
self.client
7270
.as_ref()
7371
.expect("Discord client not initialized")
7472
.lock()
75-
.expect("Failed to lock discord client")
73+
.await
74+
}
75+
76+
pub async fn clear_activity(&self) {
77+
let mut client = self.get_client().await;
78+
client
79+
.clear_activity()
80+
.unwrap_or_else(|_| println!("Failed to clear activity"));
7681
}
7782

7883
#[allow(clippy::too_many_arguments)]
79-
pub fn change_activity(
84+
pub async fn change_activity(
8085
&self,
8186
state: Option<String>,
8287
details: Option<String>,
@@ -86,7 +91,7 @@ impl Discord {
8691
small_text: Option<String>,
8792
git_remote_url: Option<String>,
8893
) {
89-
let mut client = self.get_client();
94+
let mut client = self.get_client().await;
9095
let timestamp: i64 = self.start_timestamp.as_millis() as i64;
9196

9297
let activity = Activity::new()

lsp/src/git.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ fn get_main_remote_url(repository: Repository) -> Option<String> {
3131
return remote.url().map(|url| transform_url(url.to_string()));
3232
}
3333

34-
return match repository.remotes() {
34+
match repository.remotes() {
3535
Ok(remotes) => remotes.get(0).and_then(|name| {
3636
repository
3737
.find_remote(name)
3838
.ok()
3939
.and_then(|remote| remote.url().map(|url| transform_url(url.to_string())))
4040
}),
4141
Err(_) => None,
42-
};
42+
}
4343
}
4444

4545
fn transform_url(url: String) -> String {

0 commit comments

Comments
 (0)