Skip to content

Commit 4ef05f7

Browse files
committed
feat: Add powermenu plugin
1 parent d2017f2 commit 4ef05f7

File tree

9 files changed

+437
-0
lines changed

9 files changed

+437
-0
lines changed

Cargo.lock

Lines changed: 33 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ members = [
1010
"plugins/rink",
1111
"plugins/shell",
1212
"plugins/kidex",
13+
"plugins/powermenu",
1314
"plugins/translate",
1415
"plugins/randr",
1516
"plugins/stdin",

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ The flake provides multiple packages:
8888
- **applications** - the applications plugin
8989
- **dictionary** - the dictionary plugin
9090
- **kidex** - the kidex plugin
91+
- **powermenu** - the powermenu plugin
9192
- **randr** - the randr plugin
9293
- **rink** - the rink plugin
9394
- **shell** - the shell plugin
@@ -207,6 +208,8 @@ list of plugins in this repository is as follows:
207208
- Quickly translate text.
208209
- [Kidex](plugins/kidex/README.md)
209210
- File search provided by [Kidex](https://github.com/Kirottu/kidex).
211+
- [Powermenu](/plugins/powermenu/README.md)
212+
- System power menu actions: lock, log out, power off, etc.
210213
- [Randr](plugins/randr/README.md)
211214
- Rotate and resize; quickly change monitor configurations on the fly.
212215
- TODO: Only supports Hyprland, needs support for other compositors.

flake.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
applications = mkPlugin "applications";
5757
dictionary = mkPlugin "dictionary";
5858
kidex = mkPlugin "kidex";
59+
powermenu = mkPlugin "powermenu";
5960
randr = mkPlugin "randr";
6061
rink = mkPlugin "rink";
6162
shell = mkPlugin "shell";

plugins/powermenu/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "powermenu"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
crate-type = ["cdylib"]
8+
9+
[dependencies]
10+
anyrun-plugin = { path = "../../anyrun-plugin" }
11+
abi_stable = "0.11.1"
12+
serde = { version = "1.0.204", features = ["derive"] }
13+
ron = "0.8.1"
14+
num_enum = "0.7.3"
15+
fuzzy-matcher = "0.3.7"

plugins/powermenu/README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Powermenu
2+
3+
A plugin to lock, logout, power off your machine, etc.
4+
5+
## Usage
6+
7+
Search for one of the following actions: lock, logout, power off, reboot, suspend, hibernate.
8+
Select the action.
9+
If prompted, confirm it.
10+
11+
## Configuration
12+
13+
```ron
14+
// <Anyrun config dir>/powermenu.ron
15+
Config(
16+
lock: (
17+
command: "loginctl lock-session",
18+
confirm: false,
19+
),
20+
logout: (
21+
command: "loginctl terminate-user $USER",
22+
confirm: true,
23+
),
24+
poweroff: (
25+
command: "systemctl -i poweroff",
26+
confirm: true,
27+
),
28+
reboot: (
29+
command: "systemctl -i reboot",
30+
confirm: true,
31+
),
32+
suspend: (
33+
command: "systemctl -i suspend",
34+
confirm: false,
35+
),
36+
hibernate: (
37+
command: "systemctl -i hibernate",
38+
confirm: false,
39+
),
40+
)
41+
```

plugins/powermenu/src/actions.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
use abi_stable::std_types::ROption;
2+
use anyrun_plugin::Match;
3+
use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
4+
use num_enum::{IntoPrimitive, TryFromPrimitive};
5+
6+
#[derive(Clone, Copy, IntoPrimitive, TryFromPrimitive)]
7+
#[repr(u64)]
8+
pub enum PowerAction {
9+
Lock,
10+
Logout,
11+
Poweroff,
12+
Reboot,
13+
Suspend,
14+
Hibernate,
15+
}
16+
17+
impl PowerAction {
18+
const VALUES: [Self; 6] = [
19+
Self::Lock,
20+
Self::Logout,
21+
Self::Poweroff,
22+
Self::Reboot,
23+
Self::Suspend,
24+
Self::Hibernate,
25+
];
26+
27+
pub const fn get_title(&self) -> &str {
28+
match self {
29+
Self::Lock => "Lock",
30+
Self::Logout => "Log out",
31+
Self::Poweroff => "Power off",
32+
Self::Reboot => "Reboot",
33+
Self::Suspend => "Suspend",
34+
Self::Hibernate => "Hibernate",
35+
}
36+
}
37+
pub const fn get_description(&self) -> &str {
38+
match self {
39+
Self::Lock => "Lock the session screen",
40+
Self::Logout => "Terminate the session",
41+
Self::Poweroff => "Shut down the system",
42+
Self::Reboot => "Restart the system",
43+
Self::Suspend => "Suspend the system to RAM",
44+
Self::Hibernate => "Suspend the system to disk",
45+
}
46+
}
47+
48+
pub const fn get_icon_name(&self) -> &str {
49+
match self {
50+
Self::Lock => "system-lock-screen",
51+
Self::Logout => "system-log-out",
52+
Self::Poweroff => "system-shutdown",
53+
Self::Reboot => "system-reboot",
54+
Self::Suspend => "system-suspend",
55+
Self::Hibernate => "system-suspend-hibernate",
56+
}
57+
}
58+
59+
pub fn as_match(self) -> Match {
60+
Match {
61+
title: self.get_title().into(),
62+
icon: ROption::RSome(self.get_icon_name().into()),
63+
use_pango: false,
64+
description: ROption::RSome(self.get_description().into()),
65+
id: ROption::RSome(self.into()),
66+
}
67+
}
68+
69+
pub fn get_fuzzy_matching_values(phrase: &str) -> impl Iterator<Item = Self> {
70+
let fuzzy_matcher = SkimMatcherV2::default().ignore_case();
71+
let mut matches_with_scores = Self::VALUES
72+
.into_iter()
73+
.filter_map(|action| {
74+
action
75+
.get_fuzzy_score(&fuzzy_matcher, phrase)
76+
.map(|score| (action, score))
77+
})
78+
.collect::<Vec<_>>();
79+
matches_with_scores.sort_by_key(|(_action, score)| *score);
80+
matches_with_scores
81+
.into_iter()
82+
.map(|(action, _score)| action)
83+
}
84+
85+
fn get_fuzzy_score(self, matcher: &impl FuzzyMatcher, phrase: &str) -> Option<i64> {
86+
matcher
87+
.fuzzy_match(self.get_title(), phrase)
88+
.max(matcher.fuzzy_match(self.get_description(), phrase))
89+
}
90+
}
91+
92+
#[derive(PartialEq, Eq, IntoPrimitive, TryFromPrimitive)]
93+
#[repr(u64)]
94+
pub enum ConfirmAction {
95+
Confirm,
96+
Cancel,
97+
}
98+
99+
impl ConfirmAction {
100+
pub fn is_confirmed(&self) -> bool {
101+
*self == Self::Confirm
102+
}
103+
}

plugins/powermenu/src/config.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use serde::Deserialize;
2+
3+
use crate::actions::PowerAction;
4+
5+
#[derive(Deserialize, Default)]
6+
pub struct PowerActionConfig {
7+
pub command: String,
8+
pub confirm: bool,
9+
}
10+
11+
#[derive(Deserialize)]
12+
pub struct Config {
13+
#[serde(default = "Config::default_lock_config")]
14+
lock: PowerActionConfig,
15+
#[serde(default = "Config::default_logout_config")]
16+
logout: PowerActionConfig,
17+
#[serde(default = "Config::default_poweroff_config")]
18+
poweroff: PowerActionConfig,
19+
#[serde(default = "Config::default_reboot_config")]
20+
reboot: PowerActionConfig,
21+
#[serde(default = "Config::default_suspend_config")]
22+
suspend: PowerActionConfig,
23+
#[serde(default = "Config::default_hibernate_config")]
24+
hibernate: PowerActionConfig,
25+
}
26+
27+
impl Config {
28+
fn default_lock_config() -> PowerActionConfig {
29+
PowerActionConfig {
30+
command: String::from("loginctl lock-session"),
31+
confirm: false,
32+
}
33+
}
34+
35+
fn default_logout_config() -> PowerActionConfig {
36+
PowerActionConfig {
37+
command: String::from("loginctl terminate-user $USER"),
38+
confirm: true,
39+
}
40+
}
41+
42+
fn default_poweroff_config() -> PowerActionConfig {
43+
PowerActionConfig {
44+
command: String::from("systemctl -i poweroff"),
45+
confirm: true,
46+
}
47+
}
48+
49+
fn default_reboot_config() -> PowerActionConfig {
50+
PowerActionConfig {
51+
command: String::from("systemctl -i reboot"),
52+
confirm: true,
53+
}
54+
}
55+
56+
fn default_suspend_config() -> PowerActionConfig {
57+
PowerActionConfig {
58+
command: String::from("systemctl -i suspend"),
59+
confirm: false,
60+
}
61+
}
62+
63+
fn default_hibernate_config() -> PowerActionConfig {
64+
PowerActionConfig {
65+
command: String::from("systemctl -i hibernate"),
66+
confirm: false,
67+
}
68+
}
69+
70+
pub const fn get_action_config(&self, action: PowerAction) -> &PowerActionConfig {
71+
match action {
72+
PowerAction::Lock => &self.lock,
73+
PowerAction::Logout => &self.logout,
74+
PowerAction::Poweroff => &self.poweroff,
75+
PowerAction::Reboot => &self.reboot,
76+
PowerAction::Suspend => &self.suspend,
77+
PowerAction::Hibernate => &self.hibernate,
78+
}
79+
}
80+
}
81+
82+
impl Default for Config {
83+
fn default() -> Self {
84+
Self {
85+
lock: Self::default_lock_config(),
86+
logout: Self::default_logout_config(),
87+
poweroff: Self::default_poweroff_config(),
88+
reboot: Self::default_reboot_config(),
89+
suspend: Self::default_suspend_config(),
90+
hibernate: Self::default_hibernate_config(),
91+
}
92+
}
93+
}

0 commit comments

Comments
 (0)