improve config

This commit is contained in:
Alexander Mohr 2025-05-01 17:22:24 +02:00
parent 8cc457dffc
commit 0ca65cae81
4 changed files with 314 additions and 480 deletions

View file

@ -7,7 +7,6 @@ use clap::{Parser, ValueEnum};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use thiserror::Error;
use which::which;
#[derive(Debug)]
pub enum ConfigurationError {
@ -138,64 +137,61 @@ impl FromStr for WrapMode {
#[derive(Debug, Deserialize, Serialize, Clone, Parser)]
#[clap(about = "Worf is a wofi clone written in rust, it aims to be a drop-in replacement")]
#[derive(Default)]
pub struct Config {
/// Forks the menu so you can close the terminal
#[clap(short = 'f', long = "fork")]
pub fork: Option<bool>,
fork: Option<bool>, // todo support fork
/// Selects a config file to use
#[clap(short = 'c', long = "conf")]
pub config: Option<String>,
config: Option<String>,
/// Prints the version and then exits
#[clap(short = 'v', long = "version")]
pub version: Option<bool>,
version: Option<bool>, // todo support or drop
/// Defines the style sheet to be loaded.
/// Defaults to `$XDG_CONF_DIR/worf/style.css`
/// or `$HOME/.config/worf/style.css` if `$XDG_CONF_DIR` is not set.
#[serde(default = "default_style")]
#[clap(long = "style")]
pub style: Option<String>,
style: Option<String>,
/// Defines the mode worf is running in
#[clap(long = "show")]
pub show: Option<Mode>,
show: Option<Mode>,
/// Default width of the window, defaults to 50% of the screen
#[serde(default = "default_width")]
#[clap(long = "width")]
pub width: Option<String>,
width: Option<String>,
/// Default height of the window, defaults to 40% of the screen
#[serde(default = "default_height")]
#[clap(long = "height")]
pub height: Option<String>,
height: Option<String>,
/// Defines which prompt is used. Default is selected 'show'
#[clap(short = 'p', long = "prompt")]
pub prompt: Option<String>,
prompt: Option<String>,
#[clap(short = 'x', long = "xoffset")]
pub xoffset: Option<i32>,
xoffset: Option<i32>,
#[clap(short = 'y', long = "yoffset")]
pub yoffset: Option<i32>,
yoffset: Option<i32>,
/// If true a normal window instead of a layer shell will be used
#[serde(default = "default_normal_window")]
#[clap(short = 'n', long = "normal-window")]
pub normal_window: bool,
normal_window: bool,
/// Set to 'false' to disable images, defaults to true
#[clap(short = 'I', long = "allow-images")]
pub allow_images: Option<bool>,
allow_images: Option<bool>,
#[clap(short = 'm', long = "allow-markup")]
pub allow_markup: Option<bool>,
allow_markup: Option<bool>,
#[clap(short = 'k', long = "cache-file")]
pub cache_file: Option<String>,
cache_file: Option<String>,
/// Defines which terminal to use. defaults to the first one found:
/// * kitty
@ -209,362 +205,146 @@ pub struct Config {
///
/// Must be configured including the needed arguments to launch something
/// i.e. 'kitty -c'
#[serde(default = "default_terminal")]
#[clap(short = 't', long = "term")]
pub term: Option<String>,
term: Option<String>,
#[serde(default = "default_password_char")]
#[clap(short = 'P', long = "password")]
pub password: Option<String>,
password: Option<String>,
#[clap(short = 'e', long = "exec-search")]
pub exec_search: Option<bool>,
exec_search: Option<bool>,
/// Defines whether the scrollbar is visible
#[clap(short = 'b', long = "hide-scroll")]
pub hide_scroll: Option<bool>,
hide_scroll: Option<bool>,
/// Defines the matching method, defaults to contains
#[serde(default = "default_match_method")]
#[clap(short = 'M', long = "matching")]
pub matching: Option<MatchMethod>,
matching: Option<MatchMethod>,
#[clap(short = 'i', long = "insensitive")]
pub insensitive: Option<bool>,
insensitive: Option<bool>,
#[clap(short = 'q', long = "parse-search")]
pub parse_search: Option<bool>,
parse_search: Option<bool>,
/// set where the window is displayed.
/// can be used to anchor a window to an edge by
/// setting top,left for example
#[clap(short = 'l', long = "location", value_delimiter = ',', value_parser = clap::builder::ValueParser::new(Anchor::from_str))]
pub location: Option<Vec<Anchor>>,
#[clap(short = 'l', long = "location", value_delimiter = ',', value_parser = clap::builder::ValueParser::new(Anchor::from_str)
)]
location: Option<Vec<Anchor>>,
#[clap(short = 'a', long = "no-actions")]
pub no_actions: Option<bool>,
no_actions: Option<bool>,
#[clap(short = 'L', long = "lines")]
pub lines: Option<u32>,
lines: Option<u32>,
#[serde(default = "default_columns")]
#[clap(short = 'w', long = "columns")]
pub columns: Option<u32>,
columns: Option<u32>,
#[clap(short = 'O', long = "sort-order")]
pub sort_order: Option<String>,
sort_order: Option<String>,
#[clap(short = 'G', long = "gtk-dark")]
pub gtk_dark: Option<bool>,
gtk_dark: Option<bool>,
#[clap(short = 'Q', long = "search")]
pub search: Option<String>,
search: Option<String>,
#[clap(short = 'o', long = "monitor")]
pub monitor: Option<String>,
monitor: Option<String>,
#[clap(short = 'r', long = "pre-display-cmd")]
pub pre_display_cmd: Option<String>,
pre_display_cmd: Option<String>,
#[serde(default = "default_orientation")]
#[clap(long = "orientation")]
pub orientation: Option<Orientation>,
orientation: Option<Orientation>,
/// Horizontal alignment
#[serde(default = "default_halign")]
#[clap(long = "halign")]
pub halign: Option<Align>,
halign: Option<Align>,
/// Alignment of content
#[serde(default = "default_content_halign")]
#[clap(long = "content-halign")]
pub content_halign: Option<Align>,
content_halign: Option<Align>,
/// Vertical alignment
#[clap(long = "valign")]
pub valign: Option<Align>,
valign: Option<Align>,
pub filter_rate: Option<u32>,
filter_rate: Option<u32>,
/// Defines the image size in pixels
#[serde(default = "default_image_size")]
#[clap(long = "image-size")]
pub image_size: Option<i32>,
image_size: Option<i32>,
pub key_up: Option<String>,
pub key_down: Option<String>,
pub key_left: Option<String>,
pub key_right: Option<String>,
pub key_forward: Option<String>,
pub key_backward: Option<String>,
pub key_submit: Option<String>,
pub key_exit: Option<String>,
pub key_pgup: Option<String>,
pub key_pgdn: Option<String>,
pub key_expand: Option<String>,
pub key_hide_search: Option<String>,
pub key_copy: Option<String>,
key_up: Option<String>,
key_down: Option<String>,
key_left: Option<String>,
key_right: Option<String>,
key_forward: Option<String>,
key_backward: Option<String>,
key_submit: Option<String>,
key_exit: Option<String>,
key_pgup: Option<String>,
key_pgdn: Option<String>,
key_expand: Option<String>,
key_hide_search: Option<String>,
key_copy: Option<String>,
// todo re-add this
// #[serde(flatten)]
// pub key_custom: Option<HashMap<String, String>>,
pub global_coords: Option<bool>,
pub hide_search: Option<bool>,
pub dynamic_lines: Option<bool>,
pub layer: Option<String>,
pub copy_exec: Option<String>,
pub single_click: Option<bool>,
pub pre_display_exec: Option<bool>,
// key_custom: Option<HashMap<String, String>>,
global_coords: Option<bool>,
hide_search: Option<bool>,
dynamic_lines: Option<bool>,
layer: Option<String>,
copy_exec: Option<String>,
single_click: Option<bool>,
pre_display_exec: Option<bool>,
/// Minimum score for a fuzzy search to be shown
#[serde(default = "default_fuzzy_min_score")]
#[clap(long = "fuzzy-min-score")]
pub fuzzy_min_score: Option<f64>,
fuzzy_min_score: Option<f64>,
/// Orientation of items in the row box where items are displayed
#[serde(default = "default_row_box_orientation")]
#[clap(long = "row-box-orientation")]
pub row_bow_orientation: Option<Orientation>,
row_bow_orientation: Option<Orientation>,
// /// Set to to true to wrap text after a given amount of chars
// #[serde(default = "default_text_wrap")]
// #[clap(long = "text-wrap")]
// pub text_wrap: Option<bool>,
//
// /// Defines after how many chars a line is broken over.
// /// Only cuts at spaces.
// #[serde(default = "default_text_wrap_length")]
// #[clap(long = "text-wrap-length")]
// pub text_wrap_length: Option<usize>,
/// Defines how long it takes for the show animation to finish
/// Defaults to 70ms
#[serde(default = "default_show_animation_time")]
#[clap(long = "show-animation-time")]
pub show_animation_time: Option<u64>,
show_animation_time: Option<u64>,
/// Defines how long it takes for the hide animation to finish
/// Defaults to 100ms
#[serde(default = "default_hide_animation_time")]
#[clap(long = "hide-animation-time")]
pub hide_animation_time: Option<u64>,
hide_animation_time: Option<u64>,
#[serde(default = "default_line_wrap")]
#[clap(long = "line-wrap")]
pub line_wrap: Option<WrapMode>,
line_wrap: Option<WrapMode>,
}
impl Default for Config {
fn default() -> Self {
Config {
fork: None,
config: None,
version: None,
style: default_style(),
show: None,
width: default_width(),
height: default_height(),
prompt: None,
xoffset: None,
yoffset: None,
normal_window: default_normal_window(),
allow_images: None,
allow_markup: None,
cache_file: None,
term: None,
password: None,
exec_search: None,
hide_scroll: None,
matching: None,
insensitive: None,
parse_search: None,
location: None,
no_actions: None,
lines: None,
columns: default_columns(),
sort_order: None,
gtk_dark: None,
search: None,
monitor: None,
pre_display_cmd: None,
orientation: default_row_box_orientation(),
halign: default_halign(),
content_halign: default_content_halign(),
valign: None,
filter_rate: None,
image_size: default_image_size(),
key_up: None,
key_down: None,
key_left: None,
key_right: None,
key_forward: None,
key_backward: None,
key_submit: None,
key_exit: None,
key_pgup: None,
key_pgdn: None,
key_expand: None,
key_hide_search: None,
key_copy: None,
//key_custom: None,
line_wrap: default_line_wrap(),
global_coords: None,
hide_search: None,
dynamic_lines: None,
layer: None,
copy_exec: None,
single_click: None,
pre_display_exec: None,
fuzzy_min_score: default_fuzzy_min_score(),
row_bow_orientation: default_row_box_orientation(),
show_animation_time: default_show_animation_time(),
hide_animation_time: default_hide_animation_time(),
impl Config {
#[must_use]
pub fn image_size(&self) -> i32 {
self.image_size.unwrap_or(32)
}
#[must_use]
pub fn match_method(&self) -> MatchMethod {
self.matching.unwrap_or(MatchMethod::Contains)
}
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_show_animation_time() -> Option<u64> {
Some(10)
}
#[must_use]
pub fn fuzzy_min_score(&self) -> f64 {
self.fuzzy_min_score.unwrap_or(0.0)
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_hide_animation_time() -> Option<u64> {
Some(0)
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_row_box_orientation() -> Option<Orientation> {
Some(Orientation::Horizontal)
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_orientation() -> Option<Orientation> {
Some(Orientation::Vertical)
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_halign() -> Option<Align> {
Some(Align::Fill)
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_content_halign() -> Option<Align> {
Some(Align::Fill)
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_columns() -> Option<u32> {
Some(1)
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_normal_window() -> bool {
false
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_line_wrap() -> Option<WrapMode> {
Some(WrapMode::Word)
}
// TODO
// GtkOrientation orientation = config_get_mnemonic(config, "orientation", "vertical", 2, "vertical", "horizontal");
// outer_orientation = config_get_mnemonic(cstoonfig, "orientation", "vertical", 2, "horizontal", "vertical");
// GtkAlign halign = config_get_mnemonic(config, "halign", "fill", 4, "fill", "start", "end", "center");
// content_halign = config_get_mnemonic(config, "content_halign", "fill", 4, "fill", "start", "end", "center");
// char* default_valign = "start";
// if(outer_orientation == GTK_ORIENTATION_HORIZONTAL) {
// default_valign = "center";
// }
// GtkAlign valign = config_get_mnemonic(config, "valign", default_valign, 4, "fill", "start", "end", "center");
// char* prompt = config_get(config, "prompt", mode);
// uint64_t filter_rate = strtol(config_get(config, "filter_rate", "100"), NULL, 10);
// allow_images = strcmp(config_get(config, "allow_images", "false"), "true") == 0;
// allow_markup = strcmp(config_get(config, "allow_markup", "false"), "true") == 0;
// image_size = strtol(config_get(config, "image_size", "32"), NULL, 10);
// cache_file = map_get(config, "cache_file");
// config_dir = map_get(config, "config_dir");
// terminal = map_get(config, "term");
// exec_search = strcmp(config_get(config, "exec_search", "false"), "true") == 0;
// bool hide_scroll = strcmp(config_get(config, "hide_scroll", "false"), "true") == 0;
// matching = config_get_mnemonic(config, "matching", "contains", 3, "contains", "multi-contains", "fuzzy");
// insensitive = strcmp(config_get(config, "insensitive", "false"), "true") == 0;
// parse_search = strcmp(config_get(config, "parse_search", "false"), "true") == 0;
// location = config_get_mnemonic(config, "location", "center", 18,
// "center", "top_left", "top", "top_right", "right", "bottom_right", "bottom", "bottom_left", "left",
// "0", "1", "2", "3", "4", "5", "6", "7", "8");
// no_actions = strcmp(config_get(config, "no_actions", "false"), "true") == 0;
// lines = strtol(config_get(config, "lines", "0"), NULL, 10);
// max_lines = lines;
// columns = strtol(config_get(config, "columns", "1"), NULL, 10);
// sort_order = config_get_mnemonic(config, "sort_order", "default", 2, "default", "alphabetical");
// bool global_coords = strcmp(config_get(config, "global_coords", "false"), "true") == 0;
// hide_search = strcmp(config_get(config, "hide_search", "false"), "true") == 0;
// char* search = map_get(config, "search");
// dynamic_lines = strcmp(config_get(config, "dynamic_lines", "false"), "true") == 0;
// char* monitor = map_get(config, "monitor");
// char* layer = config_get(config, "layer", "top");
// copy_exec = config_get(config, "copy_exec", "wl-copy");
// pre_display_cmd = map_get(config, "pre_display_cmd");
// pre_display_exec = strcmp(config_get(config, "pre_display_exec", "false"), "true") == 0;
// single_click = strcmp(config_get(config, "single_click", "false"), "true") == 0;
//
// keys = map_init_void();
// mods = map_init_void();
//
// map_put_void(mods, "Shift", &shift_mask);
// map_put_void(mods, "Ctrl", &ctrl_mask);
// map_put_void(mods, "Alt", &alt_mask);
//
// key_default = "Up";
// char* key_up = (i == 0) ? "Up" : config_get(config, "key_up", key_default);
// key_default = "Down";
// char* key_down = (i == 0) ? key_default : config_get(config, "key_down", key_default);
// key_default = "Left";
// char* key_left = (i == 0) ? key_default : config_get(config, "key_left", key_default);
// key_default = "Right";
// char* key_right = (i == 0) ? key_default : config_get(config, "key_right", key_default);
// key_default = "Tab";
// char* key_forward = (i == 0) ? key_default : config_get(config, "key_forward", key_default);
// key_default = "Shift-ISO_Left_Tab";
// char* key_backward = (i == 0) ? key_default : config_get(config, "key_backward", key_default);
// key_default = "Return";
// char* key_submit = (i == 0) ? key_default : config_get(config, "key_submit", key_default);
// key_default = "Escape";
// char* key_exit = (i == 0) ? key_default : config_get(config, "key_exit", key_default);
// key_default = "Page_Up";
// char* key_pgup = (i == 0) ? key_default : config_get(config, "key_pgup", key_default);
// key_default = "Page_Down";
// char* key_pgdn = (i == 0) ? key_default : config_get(config, "key_pgdn", key_default);
// key_default = "";
// char* key_expand = (i == 0) ? key_default: config_get(config, "key_expand", key_default);
// key_default = "";
// char* key_hide_search = (i == 0) ? key_default: config_get(config, "key_hide_search", key_default);
// key_default = "Ctrl-c";
// char* key_copy = (i == 0) ? key_default : config_get(config, "key_copy", key_default);
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_style() -> Option<String> {
#[must_use]
pub fn style(&self) -> Option<String> {
style_path(None)
.ok()
.map(|pb| pb.display().to_string())
@ -572,26 +352,104 @@ pub fn default_style() -> Option<String> {
log::error!("no stylesheet found, using system styles");
None
})
}
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_height() -> Option<String> {
Some("40%".to_owned())
}
#[must_use]
pub fn normal_window(&self) -> bool {
self.normal_window
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_width() -> Option<String> {
Some("50%".to_owned())
}
#[must_use]
pub fn location(&self) -> Option<&Vec<Anchor>> {
self.location.as_ref()
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_terminal() -> Option<String> {
#[must_use]
pub fn hide_scroll(&self) -> bool {
self.hide_scroll.unwrap_or(false)
}
#[must_use]
pub fn columns(&self) -> u32 {
self.columns.unwrap_or(1)
}
#[must_use]
pub fn halign(&self) -> Align {
self.halign.unwrap_or(Align::Fill)
}
#[must_use]
pub fn content_halign(&self) -> Align {
self.content_halign.unwrap_or(Align::Fill)
}
#[must_use]
pub fn valign(&self) -> Align {
self.valign.unwrap_or(Align::Center)
}
#[must_use]
pub fn orientation(&self) -> Orientation {
self.orientation.unwrap_or(Orientation::Vertical)
}
#[must_use]
pub fn prompt(&self) -> String {
match &self.prompt {
None => match &self.show {
None => String::new(),
Some(mode) => match mode {
Mode::Run => "run".to_owned(),
Mode::Drun => "drun".to_owned(),
Mode::Dmenu => "dmenu".to_owned(),
Mode::Math => "math".to_owned(),
Mode::File => "file".to_owned(),
Mode::Auto => "auto".to_owned(),
Mode::Ssh => "ssh".to_owned(),
},
},
Some(prompt) => prompt.clone(),
}
}
#[must_use]
pub fn height(&self) -> String {
self.height.clone().unwrap_or("40%".to_owned())
}
#[must_use]
pub fn width(&self) -> String {
self.width.clone().unwrap_or("50%".to_owned())
}
#[must_use]
pub fn show_animation_time(&self) -> u64 {
self.show_animation_time.unwrap_or(10)
}
#[must_use]
pub fn hide_animation_time(&self) -> u64 {
self.hide_animation_time.unwrap_or(10)
}
#[must_use]
pub fn row_bow_orientation(&self) -> Orientation {
self.row_bow_orientation.unwrap_or(Orientation::Horizontal)
}
#[must_use]
pub fn allow_images(&self) -> bool {
self.allow_images.unwrap_or(true)
}
#[must_use]
pub fn line_wrap(&self) -> WrapMode {
self.line_wrap.clone().unwrap_or(WrapMode::None)
}
#[must_use]
pub fn term(&self) -> Option<String> {
self.term.clone().or_else(|| {
let terminals = [
("gnome-terminal", vec!["--"]),
("konsole", vec!["-e"]),
@ -604,47 +462,98 @@ pub fn default_terminal() -> Option<String> {
];
for (term, launch) in &terminals {
if which(term).is_ok() {
return Some(format!("{term} {}", launch.join(" ")));
if which::which(term).is_ok() {
return Some(format!("{} {}", term, launch.join(" ")));
}
}
None
})
}
#[must_use]
pub fn show(&self) -> Option<Mode> {
self.show.clone()
}
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_password_char() -> Option<String> {
Some("*".to_owned())
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_fuzzy_min_length() -> Option<i32> {
Some(10)
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_fuzzy_min_score() -> Option<f64> {
Some(0.0)
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_match_method() -> Option<MatchMethod> {
Some(MatchMethod::Contains)
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_image_size() -> Option<i32> {
Some(32)
}
//
// // TODO
// // GtkOrientation orientation = config_get_mnemonic(config, "orientation", "vertical", 2, "vertical", "horizontal");
// // outer_orientation = config_get_mnemonic(cstoonfig, "orientation", "vertical", 2, "horizontal", "vertical");
// // GtkAlign halign = config_get_mnemonic(config, "halign", "fill", 4, "fill", "start", "end", "center");
// // content_halign = config_get_mnemonic(config, "content_halign", "fill", 4, "fill", "start", "end", "center");
// // char* default_valign = "start";
// // if(outer_orientation == GTK_ORIENTATION_HORIZONTAL) {
// // default_valign = "center";
// // }
// // GtkAlign valign = config_get_mnemonic(config, "valign", default_valign, 4, "fill", "start", "end", "center");
// // char* prompt = config_get(config, "prompt", mode);
// // uint64_t filter_rate = strtol(config_get(config, "filter_rate", "100"), NULL, 10);
// // allow_images = strcmp(config_get(config, "allow_images", "false"), "true") == 0;
// // allow_markup = strcmp(config_get(config, "allow_markup", "false"), "true") == 0;
// // image_size = strtol(config_get(config, "image_size", "32"), NULL, 10);
// // cache_file = map_get(config, "cache_file");
// // config_dir = map_get(config, "config_dir");
// // terminal = map_get(config, "term");
// // exec_search = strcmp(config_get(config, "exec_search", "false"), "true") == 0;
// // bool hide_scroll = strcmp(config_get(config, "hide_scroll", "false"), "true") == 0;
// // matching = config_get_mnemonic(config, "matching", "contains", 3, "contains", "multi-contains", "fuzzy");
// // insensitive = strcmp(config_get(config, "insensitive", "false"), "true") == 0;
// // parse_search = strcmp(config_get(config, "parse_search", "false"), "true") == 0;
// // location = config_get_mnemonic(config, "location", "center", 18,
// // "center", "top_left", "top", "top_right", "right", "bottom_right", "bottom", "bottom_left", "left",
// // "0", "1", "2", "3", "4", "5", "6", "7", "8");
// // no_actions = strcmp(config_get(config, "no_actions", "false"), "true") == 0;
// // lines = strtol(config_get(config, "lines", "0"), NULL, 10);
// // max_lines = lines;
// // columns = strtol(config_get(config, "columns", "1"), NULL, 10);
// // sort_order = config_get_mnemonic(config, "sort_order", "default", 2, "default", "alphabetical");
// // bool global_coords = strcmp(config_get(config, "global_coords", "false"), "true") == 0;
// // hide_search = strcmp(config_get(config, "hide_search", "false"), "true") == 0;
// // char* search = map_get(config, "search");
// // dynamic_lines = strcmp(config_get(config, "dynamic_lines", "false"), "true") == 0;
// // char* monitor = map_get(config, "monitor");
// // char* layer = config_get(config, "layer", "top");
// // copy_exec = config_get(config, "copy_exec", "wl-copy");
// // pre_display_cmd = map_get(config, "pre_display_cmd");
// // pre_display_exec = strcmp(config_get(config, "pre_display_exec", "false"), "true") == 0;
// // single_click = strcmp(config_get(config, "single_click", "false"), "true") == 0;
// //
// // keys = map_init_void();
// // mods = map_init_void();
// //
// // map_put_void(mods, "Shift", &shift_mask);
// // map_put_void(mods, "Ctrl", &ctrl_mask);
// // map_put_void(mods, "Alt", &alt_mask);
// //
// // key_default = "Up";
// // char* key_up = (i == 0) ? "Up" : config_get(config, "key_up", key_default);
// // key_default = "Down";
// // char* key_down = (i == 0) ? key_default : config_get(config, "key_down", key_default);
// // key_default = "Left";
// // char* key_left = (i == 0) ? key_default : config_get(config, "key_left", key_default);
// // key_default = "Right";
// // char* key_right = (i == 0) ? key_default : config_get(config, "key_right", key_default);
// // key_default = "Tab";
// // char* key_forward = (i == 0) ? key_default : config_get(config, "key_forward", key_default);
// // key_default = "Shift-ISO_Left_Tab";
// // char* key_backward = (i == 0) ? key_default : config_get(config, "key_backward", key_default);
// // key_default = "Return";
// // char* key_submit = (i == 0) ? key_default : config_get(config, "key_submit", key_default);
// // key_default = "Escape";
// // char* key_exit = (i == 0) ? key_default : config_get(config, "key_exit", key_default);
// // key_default = "Page_Up";
// // char* key_pgup = (i == 0) ? key_default : config_get(config, "key_pgup", key_default);
// // key_default = "Page_Down";
// // char* key_pgdn = (i == 0) ? key_default : config_get(config, "key_pgdn", key_default);
// // key_default = "";
// // char* key_expand = (i == 0) ? key_default: config_get(config, "key_expand", key_default);
// // key_default = "";
// // char* key_hide_search = (i == 0) ? key_default: config_get(config, "key_hide_search", key_default);
// // key_default = "Ctrl-c";
// // char* key_copy = (i == 0) ? key_default : config_get(config, "key_copy", key_default);
// }
#[must_use]
pub fn parse_args() -> Config {
@ -654,7 +563,7 @@ pub fn parse_args() -> Config {
/// # Errors
///
/// Will return Err when it cannot resolve any path or no style is found
pub fn style_path(full_path: Option<String>) -> Result<PathBuf, anyhow::Error> {
fn style_path(full_path: Option<String>) -> Result<PathBuf, anyhow::Error> {
let alternative_paths = path_alternatives(
vec![dirs::config_dir()],
&PathBuf::from("worf").join("style.css"),
@ -720,24 +629,8 @@ pub fn load_config(args_opt: Option<Config>) -> Result<Config, ConfigurationErro
.map_err(|e| ConfigurationError::Parse(format!("{e}")))?;
if let Some(args) = args_opt {
let mut merge_result = merge_config_with_args(&mut config, &args)
let merge_result = merge_config_with_args(&mut config, &args)
.map_err(|e| ConfigurationError::Parse(format!("{e}")))?;
if merge_result.prompt.is_none() {
match &merge_result.show {
None => {}
Some(mode) => match mode {
Mode::Run => merge_result.prompt = Some("run".to_owned()),
Mode::Drun => merge_result.prompt = Some("drun".to_owned()),
Mode::Dmenu => merge_result.prompt = Some("dmenu".to_owned()),
Mode::Math => merge_result.prompt = Some("math".to_owned()),
Mode::File => merge_result.prompt = Some("file".to_owned()),
Mode::Auto => merge_result.prompt = Some("auto".to_owned()),
Mode::Ssh => merge_result.prompt = Some("ssh".to_owned()),
},
}
}
Ok(merge_result)
} else {
Ok(config)

View file

@ -58,8 +58,8 @@ impl From<config::Orientation> for Orientation {
}
}
impl From<&WrapMode> for NaturalWrapMode {
fn from(value: &WrapMode) -> Self {
impl From<WrapMode> for NaturalWrapMode {
fn from(value: WrapMode) -> Self {
match value {
WrapMode::None => NaturalWrapMode::None,
WrapMode::Word => NaturalWrapMode::Word,
@ -164,7 +164,7 @@ where
P: ItemProvider<T> + 'static + Clone + Send,
{
log::debug!("Starting GUI");
if let Some(ref css) = config.style {
if let Some(ref css) = config.style() {
let provider = CssProvider::new();
let css_file_path = File::for_path(css);
provider.load_from_file(&css_file_path);
@ -246,7 +246,7 @@ fn build_ui<T, P>(
ui_elements.window.set_widget_name("window");
if !config.normal_window {
if !config.normal_window() {
// Initialize the window as a layer
ui_elements.window.init_layer_shell();
ui_elements
@ -260,13 +260,13 @@ fn build_ui<T, P>(
let window_done = Instant::now();
if let Some(location) = config.location.as_ref() {
if let Some(location) = config.location() {
for anchor in location {
ui_elements.window.set_anchor(anchor.into(), true);
}
}
let outer_box = gtk4::Box::new(config.orientation.unwrap().into(), 0);
let outer_box = gtk4::Box::new(config.orientation().into(), 0);
outer_box.set_widget_name("outer-box");
outer_box.append(&ui_elements.search);
ui_elements.window.set_child(Some(&outer_box));
@ -276,7 +276,7 @@ fn build_ui<T, P>(
scroll.set_hexpand(true);
scroll.set_vexpand(true);
if config.hide_scroll.is_some_and(|hs| hs) {
if config.hide_scroll() {
scroll.set_policy(PolicyType::External, PolicyType::External);
}
outer_box.append(&scroll);
@ -321,16 +321,12 @@ fn build_main_box<T: Clone + 'static>(config: &Config, ui_elements: &Rc<UiElemen
.set_selection_mode(gtk4::SelectionMode::Browse);
ui_elements
.main_box
.set_max_children_per_line(config.columns.unwrap());
.set_max_children_per_line(config.columns());
ui_elements.main_box.set_activate_on_single_click(true);
if let Some(halign) = config.halign {
ui_elements.main_box.set_halign(halign.into());
}
if let Some(valign) = config.valign {
ui_elements.main_box.set_valign(valign.into());
}
if config.orientation.unwrap() == config::Orientation::Horizontal {
ui_elements.main_box.set_halign(config.halign().into());
ui_elements.main_box.set_valign(config.valign().into());
if config.orientation() == config::Orientation::Horizontal {
ui_elements.main_box.set_valign(Align::Center);
ui_elements.main_box.set_orientation(Orientation::Vertical);
} else {
@ -350,7 +346,7 @@ fn build_search_entry<T: Clone>(config: &Config, ui_elements: &UiElements<T>) {
ui_elements.search.set_css_classes(&["input"]);
ui_elements
.search
.set_placeholder_text(config.prompt.as_deref());
.set_placeholder_text(Some(config.prompt().as_ref()));
ui_elements.search.set_can_focus(false);
}
@ -533,13 +529,11 @@ fn animate_window_show(config: &Config, window: ApplicationWindow) {
let monitor = display.monitor_at_surface(&surface);
if let Some(monitor) = monitor {
let geometry = monitor.geometry();
let Some(target_width) = percent_or_absolute(config.width.as_ref(), geometry.width())
else {
let Some(target_width) = percent_or_absolute(&config.width(), geometry.width()) else {
return;
};
let Some(target_height) =
percent_or_absolute(config.height.as_ref(), geometry.height())
let Some(target_height) = percent_or_absolute(&config.height(), geometry.height())
else {
return;
};
@ -551,7 +545,7 @@ fn animate_window_show(config: &Config, window: ApplicationWindow) {
let animation_start = Instant::now();
animate_window(
window,
config.show_animation_time.unwrap_or(0),
config.show_animation_time(),
target_height,
target_width,
move || {
@ -568,13 +562,7 @@ where
// todo the target size might not work for higher dpi displays or bigger resolutions
window.set_child(Widget::NONE);
animate_window(
window,
config.hide_animation_time.unwrap_or(0),
10,
10,
on_done_func,
);
animate_window(window, config.hide_animation_time(), 10, 10, on_done_func);
}
fn ease_in_out_cubic(t: f32) -> f32 {
@ -782,23 +770,13 @@ fn create_menu_row<T: Clone + 'static>(
});
row.add_controller(click);
let row_box = gtk4::Box::new(
meta.config
.row_bow_orientation
.unwrap_or(config::Orientation::Horizontal)
.into(),
0,
);
let row_box = gtk4::Box::new(meta.config.row_bow_orientation().into(), 0);
row_box.set_hexpand(true);
row_box.set_vexpand(false);
row_box.set_halign(Align::Fill);
row.set_child(Some(&row_box));
if meta
.config
.allow_images
.is_some_and(|allow_images| allow_images)
{
if meta.config.allow_images() {
if let Some(image) = lookup_icon(element_to_add, &meta.config) {
image.set_widget_name("img");
row_box.append(&image);
@ -806,26 +784,15 @@ fn create_menu_row<T: Clone + 'static>(
}
let label = Label::new(Some(element_to_add.label.as_str()));
let wrap_mode: NaturalWrapMode = if let Some(config_wrap) = &meta.config.line_wrap {
config_wrap.into()
} else {
NaturalWrapMode::Word
};
label.set_natural_wrap_mode(wrap_mode);
label.set_natural_wrap_mode(meta.config.line_wrap().into());
label.set_hexpand(true);
label.set_widget_name("label");
label.set_wrap(true);
row_box.append(&label);
if meta
.config
.content_halign
.is_some_and(|c| c == config::Align::Start)
|| meta
.config
.content_halign
.is_some_and(|c| c == config::Align::Fill)
if meta.config.content_halign().eq(&config::Align::Start)
|| meta.config.content_halign().eq(&config::Align::Fill)
{
label.set_xalign(0.0);
}
@ -851,11 +818,7 @@ fn lookup_icon<T: Clone>(menu_item: &MenuItem<T>, config: &Config) -> Option<Ima
Image::from_icon_name(image_path)
};
image.set_pixel_size(
config
.image_size
.unwrap_or(config::default_image_size().unwrap()),
);
image.set_pixel_size(config.image_size());
Some(image)
} else {
None
@ -886,27 +849,14 @@ fn set_menu_visibility_for_search<T: Clone>(
&menu_item.label.to_lowercase()
);
let matching = if let Some(matching) = &config.matching {
matching
} else {
&config::default_match_method().unwrap()
};
let (search_sort_score, visible) = match matching {
let (search_sort_score, visible) = match config.match_method() {
MatchMethod::Fuzzy => {
let mut score = strsim::jaro_winkler(&query, &menu_item_search);
if score == 0.0 {
score = -1.0;
}
(
score,
score
> config
.fuzzy_min_score
.unwrap_or(config::default_fuzzy_min_score().unwrap_or(0.0))
&& score > 0.0,
)
(score, score > config.fuzzy_min_score() && score > 0.0)
}
MatchMethod::Contains => {
if menu_item_search.contains(&query) {
@ -948,8 +898,7 @@ fn select_first_visible_child<T: Clone>(ui: &UiElements<T>) {
// allowed because truncating is fine, we do no need the precision
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_precision_loss)]
fn percent_or_absolute(value: Option<&String>, base_value: i32) -> Option<i32> {
if let Some(value) = value {
fn percent_or_absolute(value: &str, base_value: i32) -> Option<i32> {
if value.contains('%') {
let value = value.replace('%', "").trim().to_string();
match value.parse::<i32>() {
@ -959,9 +908,6 @@ fn percent_or_absolute(value: Option<&String>, base_value: i32) -> Option<i32> {
} else {
value.parse::<i32>().ok()
}
} else {
None
}
}
/// Sorts menu items in alphabetical order, while maintaining the initial score

View file

@ -533,17 +533,15 @@ pub fn auto(config: &Config) -> Result<(), Error> {
let mut provider = AutoItemProvider::new();
let cache_path = provider.drun.cache_path.clone();
let mut cache = provider.drun.cache.clone();
let mut cfg_clone = config.clone();
loop {
// todo ues a arc instead of cloning the config
let selection_result = gui::show(cfg_clone.clone(), provider.clone(), true);
let selection_result = gui::show(config.clone(), provider.clone(), true);
if let Ok(mut selection_result) = selection_result {
if let Some(data) = &selection_result.data {
match data {
AutoRunType::Math => {
cfg_clone.prompt = Some(selection_result.label.clone());
provider.math.elements.push(selection_result);
}
AutoRunType::DRun => {
@ -603,8 +601,7 @@ fn ssh_launch<T: Clone>(menu_item: &MenuItem<T>, config: &Config) -> Result<(),
action.clone()
} else {
let cmd = config
.term
.clone()
.term()
.map(|s| format!("{s} ssh {}", menu_item.label));
if let Some(cmd) = cmd {
cmd
@ -615,7 +612,7 @@ fn ssh_launch<T: Clone>(menu_item: &MenuItem<T>, config: &Config) -> Result<(),
let cmd = format!(
"{} bash -c \"source ~/.bashrc; {ssh_cmd}\"",
config.term.clone().unwrap_or_default()
config.term().unwrap_or_default()
);
spawn_fork(&cmd, menu_item.working_dir.as_ref())
}
@ -639,14 +636,12 @@ pub fn ssh(config: &Config) -> Result<(), Error> {
/// Shows the math mode
pub fn math(config: &Config) {
let mut cfg_clone = config.clone();
let mut calc: Vec<MenuItem<String>> = vec![];
loop {
let mut provider = MathProvider::new(String::new());
provider.add_elements(&mut calc.clone());
let selection_result = gui::show(cfg_clone.clone(), provider, true);
let selection_result = gui::show(config.clone(), provider, true);
if let Ok(mi) = selection_result {
cfg_clone.prompt = Some(mi.label.clone());
calc.push(mi);
} else {
log::error!("No item selected");

View file

@ -14,7 +14,7 @@ fn main() -> anyhow::Result<()> {
let args = config::parse_args();
let config = config::load_config(Some(args)).map_err(|e| anyhow!(e))?;
if let Some(show) = &config.show {
if let Some(show) = &config.show() {
match show {
Mode::Run => {
todo!("run not implemented")