mirror of
https://github.com/imgurbot12/rmenu.git
synced 2025-01-12 23:36:29 +01:00
feat: support more dynamic configuration via env & xdg
This commit is contained in:
parent
aa1b2f6db9
commit
188f542ffb
5 changed files with 91 additions and 66 deletions
67
README.md
67
README.md
|
@ -1,5 +1,4 @@
|
||||||
RMenu
|
## RMenu
|
||||||
------
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
TODO: improve documentation:
|
TODO: improve documentation:
|
||||||
|
@ -11,14 +10,22 @@ Another customizable Application-Launcher written in Rust
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* Blazingly Fast 🔥
|
- Blazingly Fast 🔥
|
||||||
* Simple and Easy to Use
|
- Simple and Easy to Use
|
||||||
* Customizable (Configuration and CSS-Styling)
|
- Customizable (Configuration and CSS-Styling)
|
||||||
* Plugin Support
|
- Plugin Support
|
||||||
* Dmenu-Like Stdin Menu Generation
|
- Dmenu-Like Stdin Menu Generation
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
|
Install Dependencies (Ubuntu)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install pkg-config libglib2.0-dev libghc-gi-gdk-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev libwebkit2gtk-4.1-dev libnm-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Compile and Install Binaries/Config-Files
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ make install
|
$ make install
|
||||||
```
|
```
|
||||||
|
@ -33,13 +40,13 @@ $ rmenu --help
|
||||||
|
|
||||||
RMenu Comes with a few default plugins.
|
RMenu Comes with a few default plugins.
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
| :-------: | ------------------------------------------------------- |
|
| :-------: | ------------------------------------------------------- |
|
||||||
| run | Execute a program in $PATH |
|
| run | Execute a program in $PATH |
|
||||||
| drun | Run a Configured Free-Desktop Application |
|
| drun | Run a Configured Free-Desktop Application |
|
||||||
| audio | Select and Set-Default PulseAudio Sink using `pactl` |
|
| audio | Select and Set-Default PulseAudio Sink using `pactl` |
|
||||||
| network | Wi-Fi Login/Connection Tool using Network-Manager |
|
| network | Wi-Fi Login/Connection Tool using Network-Manager |
|
||||||
| window | Simple Window Switcher (Currently Only Support Sway) |
|
| window | Simple Window Switcher (Currently Only Support Sway) |
|
||||||
| powermenu | Simple Power/Logout Tool (Currently Only Supports Sway) |
|
| powermenu | Simple Power/Logout Tool (Currently Only Supports Sway) |
|
||||||
|
|
||||||
Run a plugin by passing the `-r` flag like one of the following:
|
Run a plugin by passing the `-r` flag like one of the following:
|
||||||
|
@ -56,16 +63,16 @@ Or even run plugins in combination if you'd like:
|
||||||
$ rmenu -r run -r drun
|
$ rmenu -r run -r drun
|
||||||
```
|
```
|
||||||
|
|
||||||
Custom Menus can also be passed much like Dmenu by passing items via
|
Custom Menus can also be passed much like Dmenu by passing items via an input.
|
||||||
an input. The schema follows a standard as defined in [rmenu-plugin](./rmenu-plugin)
|
The schema follows a standard as defined in [rmenu-plugin](./rmenu-plugin)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ generate-my-menu.sh > input.json
|
$ generate-my-menu.sh > input.json
|
||||||
$ rmenu -i input.json
|
$ rmenu -i input.json
|
||||||
```
|
```
|
||||||
|
|
||||||
When neither a plugin nor an input are specified, rmenu defaults to
|
When neither a plugin nor an input are specified, rmenu defaults to reading from
|
||||||
reading from stdin.
|
stdin.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ generate-my-menu.sh | rmenu
|
$ generate-my-menu.sh | rmenu
|
||||||
|
@ -73,20 +80,23 @@ $ generate-my-menu.sh | rmenu
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
Customize RMenu Behavior and Appearal in a [single config](./rmenu/public/config.yaml)
|
Customize RMenu Behavior and Appearal in a
|
||||||
|
[single config](./rmenu/public/config.yaml)
|
||||||
|
|
||||||
Customize the entire app's appearance with CSS. A few [Example Themes](./themes/)
|
Customize the entire app's appearance with CSS. A few
|
||||||
are available as reference. To try them out use: `rmenu --css <my-css-theme>`
|
[Example Themes](./themes/) are available as reference. To try them out use:
|
||||||
or move the css file to `$HOME/.config/rmenu/style.css`
|
`rmenu --css <my-css-theme>` or move the css file to
|
||||||
|
`$HOME/.config/rmenu/style.css`
|
||||||
|
|
||||||
### Scripting
|
### Scripting
|
||||||
|
|
||||||
RMenu plugins and imports communicate using JSON messages defined in `rmenu-plugin`.
|
RMenu plugins and imports communicate using JSON messages defined in
|
||||||
Writing JSON in shell is painful, so rmenu provides another cli-tool to help build
|
`rmenu-plugin`. Writing JSON in shell is painful, so rmenu provides another
|
||||||
messages quickly and easily while still retaining the flexibility of JSON.
|
cli-tool to help build messages quickly and easily while still retaining the
|
||||||
|
flexibility of JSON.
|
||||||
|
|
||||||
After Installing. Use the following command, and look at [other-plugins](./other-plugins)
|
After Installing. Use the following command, and look at
|
||||||
for example uses.
|
[other-plugins](./other-plugins) for example uses.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rmenu-build --help
|
$ rmenu-build --help
|
||||||
|
@ -95,16 +105,21 @@ $ rmenu-build --help
|
||||||
### Example Screenshots
|
### Example Screenshots
|
||||||
|
|
||||||
#### Launchpad
|
#### Launchpad
|
||||||
|
|
||||||
![launchpad](./screenshots/launchpad.png)
|
![launchpad](./screenshots/launchpad.png)
|
||||||
|
|
||||||
#### Nord
|
#### Nord
|
||||||
|
|
||||||
![nord](./screenshots/nord.png)
|
![nord](./screenshots/nord.png)
|
||||||
|
|
||||||
#### Dark
|
#### Dark
|
||||||
|
|
||||||
![dark](./screenshots/dark.png)
|
![dark](./screenshots/dark.png)
|
||||||
|
|
||||||
#### Solarized
|
#### Solarized
|
||||||
|
|
||||||
![solzarized](./screenshots/solarized.png)
|
![solzarized](./screenshots/solarized.png)
|
||||||
|
|
||||||
#### PowerMenu
|
#### PowerMenu
|
||||||
|
|
||||||
![powermenu](./screenshots/powermenu.png)
|
![powermenu](./screenshots/powermenu.png)
|
||||||
|
|
|
@ -7,7 +7,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cached = "0.44.0"
|
cached = "0.44.0"
|
||||||
clap = { version = "4.3.15", features = ["derive"] }
|
clap = { version = "4.3.15", features = ["derive", "env"] }
|
||||||
dioxus = "0.4.3"
|
dioxus = "0.4.3"
|
||||||
dioxus-desktop = "0.4.3"
|
dioxus-desktop = "0.4.3"
|
||||||
dioxus-html = "0.4.3"
|
dioxus-html = "0.4.3"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader, Read};
|
use std::io::{BufRead, BufReader, Read};
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::process::{Command, ExitStatus, Stdio};
|
use std::process::{Command, ExitStatus, Stdio};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::{fmt::Display, fs::read_to_string};
|
use std::{fmt::Display, fs::read_to_string};
|
||||||
|
@ -9,7 +10,7 @@ use rmenu_plugin::{Entry, Message};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::config::{cfg_replace, Config, Keybind};
|
use crate::config::{cfg_replace, Config, Keybind};
|
||||||
use crate::{DEFAULT_CONFIG, DEFAULT_CSS};
|
use crate::{CONFIG_DIR, DEFAULT_CONFIG, DEFAULT_THEME};
|
||||||
|
|
||||||
/// Allowed Formats for Entry Ingestion
|
/// Allowed Formats for Entry Ingestion
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -52,18 +53,18 @@ pub struct Args {
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
run: Vec<String>,
|
run: Vec<String>,
|
||||||
/// Override default configuration path
|
/// Override default configuration path
|
||||||
#[arg(short, long)]
|
#[arg(short, long, env = "RMENU_CONFIG")]
|
||||||
config: Option<String>,
|
config: Option<PathBuf>,
|
||||||
/// Override base css theme styling
|
/// Override base css theme styling
|
||||||
#[arg(long, default_value_t=String::from(DEFAULT_CSS))]
|
#[arg(long, env = "RMENU_THEME")]
|
||||||
theme: String,
|
theme: Option<PathBuf>,
|
||||||
/// Include additional css settings
|
/// Include additional css settings
|
||||||
#[arg(long)]
|
#[arg(long, env = "RMENU_CSS")]
|
||||||
css: Option<String>,
|
css: Option<PathBuf>,
|
||||||
|
|
||||||
// root config settings
|
// root config settings
|
||||||
/// Override terminal command
|
/// Override terminal command
|
||||||
#[arg(long)]
|
#[arg(long, env = "RMENU_TERMINAL")]
|
||||||
terminal: Option<String>,
|
terminal: Option<String>,
|
||||||
/// Number of results to include for each page
|
/// Number of results to include for each page
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
|
@ -178,15 +179,18 @@ pub enum RMenuError {
|
||||||
pub type Result<T> = std::result::Result<T, RMenuError>;
|
pub type Result<T> = std::result::Result<T, RMenuError>;
|
||||||
|
|
||||||
impl Args {
|
impl Args {
|
||||||
|
/// Find Configuration Path
|
||||||
|
pub fn find_config(&self) -> PathBuf {
|
||||||
|
self.config.clone().unwrap_or_else(|| {
|
||||||
|
let cfgdir = std::env::var("XDG_CONFIG_DIR").unwrap_or_else(|_| CONFIG_DIR.to_string());
|
||||||
|
PathBuf::from(cfgdir).join(DEFAULT_CONFIG)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Load Configuration File
|
/// Load Configuration File
|
||||||
pub fn get_config(&self) -> Result<Config> {
|
pub fn get_config(&self, path: &PathBuf) -> Result<Config> {
|
||||||
// read configuration
|
let path = path.to_string_lossy().to_string();
|
||||||
let path = self
|
let path = shellexpand::tilde(&path).to_string();
|
||||||
.config
|
|
||||||
.as_ref()
|
|
||||||
.map(|v| v.as_str())
|
|
||||||
.unwrap_or(DEFAULT_CONFIG);
|
|
||||||
let path = shellexpand::tilde(path).to_string();
|
|
||||||
let config: Config = match read_to_string(path) {
|
let config: Config = match read_to_string(path) {
|
||||||
Ok(content) => serde_yaml::from_str(&content),
|
Ok(content) => serde_yaml::from_str(&content),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -236,23 +240,30 @@ impl Args {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load CSS Theme or Default
|
/// Load CSS Theme or Default
|
||||||
pub fn get_theme(&self) -> String {
|
pub fn get_theme(&self, cfgdir: &PathBuf) -> String {
|
||||||
let path = shellexpand::tilde(&self.theme).to_string();
|
let theme = self.theme.clone().or(Some(cfgdir.join(DEFAULT_THEME)));
|
||||||
match read_to_string(&path) {
|
if let Some(theme) = theme {
|
||||||
Ok(css) => css,
|
let path = theme.to_string_lossy().to_string();
|
||||||
Err(err) => {
|
let path = shellexpand::tilde(&path).to_string();
|
||||||
log::error!("Failed to load CSS: {err:?}");
|
match read_to_string(&path) {
|
||||||
String::new()
|
Ok(css) => return css,
|
||||||
|
Err(err) => log::error!("Failed to load CSS: {err:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
String::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load Additional CSS or Default
|
/// Load Additional CSS or Default
|
||||||
pub fn get_css(&self, c: &Config) -> String {
|
pub fn get_css(&self, c: &Config) -> String {
|
||||||
if let Some(css) = self.css.as_ref().or(c.css.as_ref()) {
|
let css = self
|
||||||
let path = shellexpand::tilde(&css).to_string();
|
.css
|
||||||
|
.clone()
|
||||||
|
.or(c.css.as_ref().map(|s| PathBuf::from(s)));
|
||||||
|
if let Some(css) = css {
|
||||||
|
let path = css.to_string_lossy().to_string();
|
||||||
|
let path = shellexpand::tilde(&path).to_string();
|
||||||
match read_to_string(&path) {
|
match read_to_string(&path) {
|
||||||
Ok(theme) => return theme,
|
Ok(css) => return css,
|
||||||
Err(err) => log::error!("Failed to load Theme: {err:?}"),
|
Err(err) => log::error!("Failed to load Theme: {err:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
//! RMENU Configuration Implementations
|
//! RMENU Configuration Implementations
|
||||||
use heck::AsPascalCase;
|
|
||||||
use rmenu_plugin::Options;
|
|
||||||
use serde::{de::Error, Deserialize};
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
@ -10,6 +7,9 @@ use dioxus_desktop::tao::{
|
||||||
window::Fullscreen,
|
window::Fullscreen,
|
||||||
};
|
};
|
||||||
use dioxus_html::input_data::keyboard_types::{Code, Modifiers};
|
use dioxus_html::input_data::keyboard_types::{Code, Modifiers};
|
||||||
|
use heck::AsPascalCase;
|
||||||
|
use rmenu_plugin::Options;
|
||||||
|
use serde::{de::Error, Deserialize};
|
||||||
|
|
||||||
// parse supported modifiers from string
|
// parse supported modifiers from string
|
||||||
fn mod_from_str(s: &str) -> Option<Modifiers> {
|
fn mod_from_str(s: &str) -> Option<Modifiers> {
|
||||||
|
|
|
@ -11,8 +11,8 @@ use clap::Parser;
|
||||||
use rmenu_plugin::{self_exe, Entry};
|
use rmenu_plugin::{self_exe, Entry};
|
||||||
|
|
||||||
static CONFIG_DIR: &'static str = "~/.config/rmenu/";
|
static CONFIG_DIR: &'static str = "~/.config/rmenu/";
|
||||||
static DEFAULT_CSS: &'static str = "~/.config/rmenu/style.css";
|
static DEFAULT_THEME: &'static str = "style.css";
|
||||||
static DEFAULT_CONFIG: &'static str = "~/.config/rmenu/config.yaml";
|
static DEFAULT_CONFIG: &'static str = "config.yaml";
|
||||||
static DEFAULT_CSS_CONTENT: &'static str = include_str!("../public/default.css");
|
static DEFAULT_CSS_CONTENT: &'static str = include_str!("../public/default.css");
|
||||||
|
|
||||||
/// Application State for GUI
|
/// Application State for GUI
|
||||||
|
@ -43,10 +43,9 @@ fn main() -> cli::Result<()> {
|
||||||
|
|
||||||
// parse cli and retrieve values for app
|
// parse cli and retrieve values for app
|
||||||
let mut cli = cli::Args::parse();
|
let mut cli = cli::Args::parse();
|
||||||
let mut config = cli.get_config()?;
|
let mut cfgpath = cli.find_config();
|
||||||
|
let mut config = cli.get_config(&cfgpath)?;
|
||||||
let entries = cli.get_entries(&mut config)?;
|
let entries = cli.get_entries(&mut config)?;
|
||||||
let css = cli.get_css(&config);
|
|
||||||
let theme = cli.get_theme();
|
|
||||||
|
|
||||||
// update config based on cli-settings and entries
|
// update config based on cli-settings and entries
|
||||||
config = cli.update_config(config);
|
config = cli.update_config(config);
|
||||||
|
@ -56,11 +55,11 @@ fn main() -> cli::Result<()> {
|
||||||
.any(|e| e.icon.is_some() || e.icon_alt.is_some());
|
.any(|e| e.icon.is_some() || e.icon_alt.is_some());
|
||||||
config.use_comments = config.use_comments && entries.iter().any(|e| e.comment.is_some());
|
config.use_comments = config.use_comments && entries.iter().any(|e| e.comment.is_some());
|
||||||
|
|
||||||
// change directory to config folder
|
// retrieve cfgdir and get theme/css
|
||||||
let cfgdir = shellexpand::tilde(CONFIG_DIR).to_string();
|
cfgpath.pop();
|
||||||
if let Err(err) = std::env::set_current_dir(&cfgdir) {
|
let cfgdir = cfgpath;
|
||||||
log::error!("failed to change directory: {err:?}");
|
let theme = cli.get_theme(&cfgdir);
|
||||||
}
|
let css = cli.get_css(&config);
|
||||||
|
|
||||||
// genrate app context and run gui
|
// genrate app context and run gui
|
||||||
gui::run(App {
|
gui::run(App {
|
||||||
|
|
Loading…
Reference in a new issue