Create rust.yml
This commit is contained in:
parent
96ca92e036
commit
43cb14b9e8
6 changed files with 89 additions and 54 deletions
26
.github/workflows/rust.yml
vendored
Normal file
26
.github/workflows/rust.yml
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
name: Rust
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Format
|
||||
run: cargo fmt --check
|
||||
- name: Clippy
|
||||
run: cargo clippy
|
||||
- name: Build
|
||||
run: cargo build --verbose
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
||||
10
src/args.rs
10
src/args.rs
|
|
@ -1,9 +1,8 @@
|
|||
use std::str::FromStr;
|
||||
use clap::Parser;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
|
||||
|
||||
// Define a custom error type using the `thiserror` crate
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ArgsError {
|
||||
|
|
@ -19,7 +18,7 @@ pub enum Mode {
|
|||
Drun,
|
||||
|
||||
/// reads from stdin and displays options which when selected will be output to stdout.
|
||||
Dmenu
|
||||
Dmenu,
|
||||
}
|
||||
|
||||
impl FromStr for Mode {
|
||||
|
|
@ -30,7 +29,9 @@ impl FromStr for Mode {
|
|||
"run" => Ok(Mode::Run),
|
||||
"drun" => Ok(Mode::Drun),
|
||||
"dmenu" => Ok(Mode::Dmenu),
|
||||
_ => Err(ArgsError::InvalidParameter(format!("{s} is not a valid argument show this, see help for details").to_owned()))
|
||||
_ => Err(ArgsError::InvalidParameter(
|
||||
format!("{s} is not a valid argument show this, see help for details").to_owned(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -38,7 +39,6 @@ impl FromStr for Mode {
|
|||
#[derive(Parser, Debug, Deserialize, Serialize)]
|
||||
#[clap(about = "Ravi is a wofi clone written in rust, it aims to be a drop in replacement")]
|
||||
pub struct Args {
|
||||
|
||||
/// Forks the menu so you can close the terminal
|
||||
#[clap(short = 'f', long = "fork")]
|
||||
fork: bool,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use crate::args::Args;
|
||||
use anyhow::anyhow;
|
||||
use gtk4::prelude::ToValue;
|
||||
use merge::Merge;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use crate::args::Args;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Merge, Clone)]
|
||||
pub struct Config {
|
||||
|
|
@ -236,7 +236,6 @@ fn default_password_char() -> Option<String> {
|
|||
Some("*".to_owned())
|
||||
}
|
||||
|
||||
|
||||
pub fn merge_config_with_args(config: &mut Config, args: &Args) -> anyhow::Result<Config> {
|
||||
let args_json = serde_json::to_value(args)?;
|
||||
let mut config_json = serde_json::to_value(config)?;
|
||||
|
|
|
|||
|
|
@ -46,8 +46,7 @@ pub fn default_icon() -> String {
|
|||
}
|
||||
|
||||
fn fetch_icon_from_desktop_file(icon_name: &str) -> Option<String> {
|
||||
find_desktop_files().into_iter()
|
||||
.find_map(|desktop_file| {
|
||||
find_desktop_files().into_iter().find_map(|desktop_file| {
|
||||
desktop_file
|
||||
.get("Desktop Entry")
|
||||
.filter(|desktop_entry| {
|
||||
|
|
@ -154,6 +153,7 @@ pub(crate) fn find_desktop_files() -> Vec<HashMap<String, HashMap<String, Option
|
|||
let mut conf = Ini::new();
|
||||
conf.load(desktop_file.as_path().to_str().unwrap()).ok()
|
||||
})
|
||||
}).collect();
|
||||
})
|
||||
.collect();
|
||||
p
|
||||
}
|
||||
|
|
|
|||
39
src/gui.rs
39
src/gui.rs
|
|
@ -1,22 +1,27 @@
|
|||
use crate::config::Config;
|
||||
use anyhow::Context;
|
||||
use gdk4::Display;
|
||||
use gdk4::gio::File;
|
||||
use gdk4::glib::Propagation;
|
||||
use gdk4::prelude::{Cast, DisplayExt, MonitorExt};
|
||||
use gdk4::Display;
|
||||
use gtk4::prelude::{ApplicationExt, ApplicationExtManual, BoxExt, ButtonExt, EditableExt, EntryExt, FlowBoxChildExt, GtkWindowExt, ListBoxRowExt, NativeExt, WidgetExt};
|
||||
use gtk4::{Align, EventControllerKey, Expander, FlowBox, FlowBoxChild, Label, ListBox, ListBoxRow, PolicyType, ScrolledWindow, SearchEntry, Widget};
|
||||
use gtk4::prelude::{
|
||||
ApplicationExt, ApplicationExtManual, BoxExt, ButtonExt, EditableExt, EntryExt,
|
||||
FlowBoxChildExt, GtkWindowExt, ListBoxRowExt, NativeExt, WidgetExt,
|
||||
};
|
||||
use gtk4::{
|
||||
Align, EventControllerKey, Expander, FlowBox, FlowBoxChild, Label, ListBox, ListBoxRow,
|
||||
PolicyType, ScrolledWindow, SearchEntry, Widget,
|
||||
};
|
||||
use gtk4::{Application, ApplicationWindow, CssProvider, Orientation};
|
||||
use gtk4_layer_shell::{KeyboardMode, LayerShell};
|
||||
use std::process::exit;
|
||||
use anyhow::Context;
|
||||
use log::error;
|
||||
use crate::config::Config;
|
||||
use std::process::exit;
|
||||
|
||||
pub struct EntryElement {
|
||||
pub label: String, // todo support empty label?
|
||||
pub icon_path: Option<String>,
|
||||
pub action: Box<dyn Fn() + Send + 'static>,
|
||||
pub sub_elements: Option<Vec<EntryElement>>,
|
||||
|
||||
}
|
||||
|
||||
pub fn init(config: Config, elements: Vec<EntryElement>) -> anyhow::Result<()> {
|
||||
|
|
@ -33,7 +38,6 @@ pub fn init(config: Config, elements: Vec<EntryElement>) -> anyhow::Result<()> {
|
|||
gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||
);
|
||||
|
||||
|
||||
let display = Display::default().expect("Could not connect to a display");
|
||||
// Apply CSS to the display
|
||||
gtk4::style_context_add_provider_for_display(
|
||||
|
|
@ -43,9 +47,7 @@ pub fn init(config: Config, elements: Vec<EntryElement>) -> anyhow::Result<()> {
|
|||
);
|
||||
|
||||
// No need for application_id unless you want portal support
|
||||
let app = Application::builder()
|
||||
.application_id("ravi")
|
||||
.build();
|
||||
let app = Application::builder().application_id("ravi").build();
|
||||
|
||||
app.connect_activate(move |app| {
|
||||
// Create a toplevel undecorated window
|
||||
|
|
@ -141,8 +143,6 @@ pub fn init(config: Config, elements: Vec<EntryElement>) -> anyhow::Result<()> {
|
|||
|
||||
window.show();
|
||||
|
||||
|
||||
|
||||
// Get the display where the window resides
|
||||
let display = window.display();
|
||||
|
||||
|
|
@ -151,17 +151,22 @@ pub fn init(config: Config, elements: Vec<EntryElement>) -> anyhow::Result<()> {
|
|||
let monitor = display.monitor_at_surface(&surface);
|
||||
if let Some(monitor) = monitor {
|
||||
let geometry = monitor.geometry();
|
||||
if let Some(w) = percent_or_absolute(&config.width.clone().unwrap_or("800".to_owned()), geometry.width()) {
|
||||
if let Some(w) = percent_or_absolute(
|
||||
&config.width.clone().unwrap_or("800".to_owned()),
|
||||
geometry.width(),
|
||||
) {
|
||||
window.set_width_request(w);
|
||||
}
|
||||
if let Some(h) = percent_or_absolute(&config.height.clone().unwrap_or("500".to_owned()), geometry.height()) {
|
||||
if let Some(h) = percent_or_absolute(
|
||||
&config.height.clone().unwrap_or("500".to_owned()),
|
||||
geometry.height(),
|
||||
) {
|
||||
window.set_height_request(h);
|
||||
}
|
||||
} else {
|
||||
error!("failed to get monitor to init window size");
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
let empty_array: [&str; 0] = [];
|
||||
|
|
@ -235,7 +240,7 @@ fn percent_or_absolute(value: &String, base_value: i32) -> Option<i32> {
|
|||
Ok(n) => {
|
||||
let result = ((n as f32 / 100.0) * base_value as f32) as i32;
|
||||
Some(result)
|
||||
},
|
||||
}
|
||||
Err(_) => None,
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
13
src/main.rs
13
src/main.rs
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
use crate::args::{Args, Mode};
|
||||
use crate::config::Config;
|
||||
use crate::desktop::find_desktop_files;
|
||||
use crate::gui::EntryElement;
|
||||
use clap::Parser;
|
||||
use gdk4::prelude::Cast;
|
||||
|
|
@ -18,7 +19,6 @@ use std::os::unix::process::CommandExt;
|
|||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::Arc;
|
||||
use crate::desktop::find_desktop_files;
|
||||
|
||||
mod args;
|
||||
mod config;
|
||||
|
|
@ -68,8 +68,11 @@ fn main() -> anyhow::Result<()> {
|
|||
let mut entries: Vec<EntryElement> = Vec::new();
|
||||
for file in &find_desktop_files() {
|
||||
if let Some(desktop_entry) = file.get("desktop entry") {
|
||||
let icon = desktop_entry.get("icon").and_then(|x| x.as_ref().map(|x| x.to_owned()));
|
||||
let Some(exec) = desktop_entry.get("exec").and_then(|x| x.as_ref().cloned()) else {
|
||||
let icon = desktop_entry
|
||||
.get("icon")
|
||||
.and_then(|x| x.as_ref().map(|x| x.to_owned()));
|
||||
let Some(exec) = desktop_entry.get("exec").and_then(|x| x.as_ref().cloned())
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
@ -87,7 +90,9 @@ fn main() -> anyhow::Result<()> {
|
|||
})
|
||||
};
|
||||
|
||||
let name = desktop_entry.get("name").and_then(|x| x.as_ref().map(|x| x.to_owned()));
|
||||
let name = desktop_entry
|
||||
.get("name")
|
||||
.and_then(|x| x.as_ref().map(|x| x.to_owned()));
|
||||
if let Some(name) = name {
|
||||
entries.push({
|
||||
EntryElement {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue