add math as own mode
This commit is contained in:
parent
d0b526fb9d
commit
d08893d545
3 changed files with 93 additions and 121 deletions
|
|
@ -67,6 +67,9 @@ pub enum Mode {
|
|||
|
||||
/// use worf as file browser
|
||||
File,
|
||||
|
||||
/// Use is as calculator
|
||||
Math,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
|
@ -84,6 +87,7 @@ impl FromStr for Mode {
|
|||
"drun" => Ok(Mode::Drun),
|
||||
"dmenu" => Ok(Mode::Dmenu),
|
||||
"file" => Ok(Mode::File),
|
||||
"math" => Ok(Mode::Math),
|
||||
"auto" => Ok(Mode::Auto),
|
||||
_ => Err(ArgsError::InvalidParameter(
|
||||
format!("{s} is not a valid argument show this, see help for details").to_owned(),
|
||||
|
|
|
|||
126
src/lib/mode.rs
126
src/lib/mode.rs
|
|
@ -24,7 +24,7 @@ struct DRunCache {
|
|||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct DRunProvider<T: std::clone::Clone> {
|
||||
struct DRunProvider<T: Clone> {
|
||||
items: Vec<MenuItem<T>>,
|
||||
cache_path: Option<PathBuf>,
|
||||
cache: HashMap<String, i64>,
|
||||
|
|
@ -145,7 +145,7 @@ impl<T: Clone> ItemProvider<T> for DRunProvider<T> {
|
|||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct FileItemProvider<T: std::clone::Clone> {
|
||||
struct FileItemProvider<T: Clone> {
|
||||
last_result: Option<Vec<MenuItem<T>>>,
|
||||
menu_item_data: T,
|
||||
}
|
||||
|
|
@ -276,22 +276,78 @@ impl<T: Clone> ItemProvider<T> for FileItemProvider<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct MathProvider<T: Clone> {
|
||||
menu_item_data: T,
|
||||
}
|
||||
|
||||
impl<T: std::clone::Clone> MathProvider<T> {
|
||||
fn new(menu_item_data: T) -> Self {
|
||||
Self {
|
||||
menu_item_data,
|
||||
}
|
||||
}
|
||||
|
||||
fn contains_math_functions_or_starts_with_number(input: &str) -> bool {
|
||||
// Regex for function names (word boundaries to match whole words)
|
||||
let math_functions = r"\b(sqrt|abs|exp|ln|sin|cos|tan|asin|acos|atan|atan2|sinh|cosh|tanh|asinh|acosh|atanh|floor|ceil|round|signum|min|max|pi|e)\b";
|
||||
|
||||
// Regex for strings that start with a number (including decimals)
|
||||
let starts_with_number = r"^\s*[+-]?(\d+(\.\d*)?|\.\d+)";
|
||||
|
||||
let math_regex = Regex::new(math_functions).unwrap();
|
||||
let number_regex = Regex::new(starts_with_number).unwrap();
|
||||
|
||||
math_regex.is_match(input) || number_regex.is_match(input)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> ItemProvider<T> for MathProvider<T> {
|
||||
fn get_elements(&mut self, search: Option<&str>) -> Vec<MenuItem<T>> {
|
||||
if let Some(search_text) = search {
|
||||
let result = match meval::eval_str(search_text) {
|
||||
Ok(result) => result.to_string(),
|
||||
Err(e) => format!("failed to calculate {e:?}"),
|
||||
};
|
||||
|
||||
let item = MenuItem {
|
||||
label: result,
|
||||
icon_path: None,
|
||||
action: search.map(|s| s.to_string()),
|
||||
sub_elements: vec![],
|
||||
working_dir: None,
|
||||
initial_sort_score: 0,
|
||||
search_sort_score: 0.0,
|
||||
data: Some(self.menu_item_data.clone()),
|
||||
};
|
||||
|
||||
vec![item]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
fn get_sub_elements(&mut self, item: &MenuItem<T>) -> Option<Vec<MenuItem<T>>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
enum AutoRunType {
|
||||
Math,
|
||||
DRun,
|
||||
File,
|
||||
Ssh,
|
||||
WebSearch,
|
||||
Emoji,
|
||||
Run,
|
||||
// Ssh,
|
||||
// WebSearch,
|
||||
// Emoji,
|
||||
// Run,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct AutoItemProvider {
|
||||
drun_provider: DRunProvider<AutoRunType>,
|
||||
file_provider: FileItemProvider<AutoRunType>,
|
||||
last_result: Option<Vec<MenuItem<AutoRunType>>>,
|
||||
math_provider: MathProvider<AutoRunType>,
|
||||
}
|
||||
|
||||
impl AutoItemProvider {
|
||||
|
|
@ -299,55 +355,26 @@ impl AutoItemProvider {
|
|||
AutoItemProvider {
|
||||
drun_provider: DRunProvider::new(AutoRunType::DRun),
|
||||
file_provider: FileItemProvider::new(AutoRunType::File),
|
||||
last_result: None,
|
||||
math_provider: MathProvider::new(AutoRunType::Math),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn contains_math_functions_or_starts_with_number(input: &str) -> bool {
|
||||
// Regex for function names (word boundaries to match whole words)
|
||||
let math_functions = r"\b(sqrt|abs|exp|ln|sin|cos|tan|asin|acos|atan|atan2|sinh|cosh|tanh|asinh|acosh|atanh|floor|ceil|round|signum|min|max|pi|e)\b";
|
||||
|
||||
// Regex for strings that start with a number (including decimals)
|
||||
let starts_with_number = r"^\s*[+-]?(\d+(\.\d*)?|\.\d+)";
|
||||
|
||||
let math_regex = Regex::new(math_functions).unwrap();
|
||||
let number_regex = Regex::new(starts_with_number).unwrap();
|
||||
|
||||
math_regex.is_match(input) || number_regex.is_match(input)
|
||||
}
|
||||
|
||||
impl ItemProvider<AutoRunType> for AutoItemProvider {
|
||||
fn get_elements(&mut self, search_opt: Option<&str>) -> Vec<MenuItem<AutoRunType>> {
|
||||
if let Some(search) = search_opt {
|
||||
let trimmed_search = search.trim();
|
||||
if trimmed_search.is_empty() {
|
||||
self.drun_provider.get_elements(search_opt)
|
||||
} else if contains_math_functions_or_starts_with_number(trimmed_search) {
|
||||
let result = match meval::eval_str(trimmed_search) {
|
||||
Ok(result) => result.to_string(),
|
||||
Err(e) => format!("failed to calculate {e:?}"),
|
||||
};
|
||||
|
||||
let item = MenuItem {
|
||||
label: result,
|
||||
icon_path: None,
|
||||
action: Some(trimmed_search.to_owned()),
|
||||
sub_elements: vec![],
|
||||
working_dir: None,
|
||||
initial_sort_score: 0,
|
||||
search_sort_score: 0.0,
|
||||
data: Some(AutoRunType::Math),
|
||||
};
|
||||
|
||||
return vec![item];
|
||||
} else if MathProvider::<AutoRunType>::contains_math_functions_or_starts_with_number(trimmed_search) {
|
||||
self.math_provider.get_elements(search_opt)
|
||||
} else if trimmed_search.starts_with("$")
|
||||
|| trimmed_search.starts_with("/")
|
||||
|| trimmed_search.starts_with("~")
|
||||
{
|
||||
self.file_provider.get_elements(search_opt)
|
||||
} else {
|
||||
return self.drun_provider.get_elements(search_opt);
|
||||
self.drun_provider.get_elements(search_opt)
|
||||
}
|
||||
} else {
|
||||
self.drun_provider.get_elements(search_opt)
|
||||
|
|
@ -448,6 +475,25 @@ pub fn file(config: &mut Config) -> Result<(), String> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn math(config: &mut Config) -> Result<(), String> {
|
||||
let provider = MathProvider::new("".to_owned());
|
||||
if config.prompt.is_none() {
|
||||
config.prompt = Some("math".to_owned());
|
||||
}
|
||||
|
||||
// todo ues a arc instead of cloning the config
|
||||
let selection_result = gui::show(config.clone(), provider);
|
||||
match selection_result {
|
||||
Ok(_) => {
|
||||
}
|
||||
Err(_) => {
|
||||
log::error!("No item selected");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_drun_cache_and_run<T: Clone>(
|
||||
cache_path: Option<PathBuf>,
|
||||
cache: &mut HashMap<String, i64>,
|
||||
|
|
|
|||
84
src/main.rs
84
src/main.rs
|
|
@ -29,6 +29,9 @@ fn main() -> anyhow::Result<()> {
|
|||
Mode::File => {
|
||||
mode::file(&mut config).map_err(|e| anyhow!(e))?;
|
||||
}
|
||||
Mode::Math => {
|
||||
mode::math(&mut config).map_err(|e| anyhow!(e))?;
|
||||
}
|
||||
Mode::Auto => {
|
||||
mode::auto(&mut config)?;
|
||||
}
|
||||
|
|
@ -39,84 +42,3 @@ fn main() -> anyhow::Result<()> {
|
|||
Err(anyhow!("No mode provided"))
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// fn main() -> anyhow::Result<()> {
|
||||
// env_logger::Builder::new()
|
||||
// // todo change to info as default
|
||||
// .parse_filters(&std::env::var("RUST_LOG").unwrap_or_else(|_| "debug".to_owned()))
|
||||
// .init();
|
||||
// let args = Args::parse();
|
||||
//
|
||||
// let home_dir = std::env::var("HOME")?;
|
||||
// let config_path = args.config.as_ref().map(|c| PathBuf::from(c)).unwrap_or_else(||{
|
||||
// std::env::var("XDG_CONF_HOME")
|
||||
// .map_or(
|
||||
// PathBuf::from(home_dir.clone()).join(".config"),
|
||||
// |xdg_conf_home| PathBuf::from(&xdg_conf_home),
|
||||
// )
|
||||
// .join("wofi")// todo change to ravi
|
||||
// .join("config")
|
||||
// });
|
||||
//
|
||||
// let colors_dir = std::env::var("XDG_CACHE_HOME")
|
||||
// .map_or(
|
||||
// PathBuf::from(home_dir.clone()).join(".cache"),
|
||||
// |xdg_conf_home| PathBuf::from(&xdg_conf_home),
|
||||
// )
|
||||
// .join("wal")
|
||||
// .join("colors");
|
||||
//
|
||||
// let toml_content = fs::read_to_string(config_path)?;
|
||||
// let config: Config = toml::from_str(&toml_content).unwrap_or_default();
|
||||
//
|
||||
//
|
||||
//
|
||||
// gtk4::init()?;
|
||||
//
|
||||
// let application = Application::builder()
|
||||
// .application_id("com.example.FirstGtkApp")
|
||||
// .build();
|
||||
//
|
||||
// application.connect_activate(|app| {
|
||||
// let window = ApplicationWindow::builder()
|
||||
// .application(app)
|
||||
// .title("First GTK Program")
|
||||
// .name("window")
|
||||
// .default_width(config.x.clone().unwrap())
|
||||
// .default_height(config.y.clone().unwrap())
|
||||
// .resizable(false)
|
||||
// .decorated(false)
|
||||
// .build();
|
||||
//
|
||||
//
|
||||
//
|
||||
// // Create a dialog window
|
||||
// let dialog = Dialog::new();
|
||||
// dialog.set_title(Some("Custom Dialog"));
|
||||
// dialog.set_default_size(300, 150);
|
||||
//
|
||||
// // Create a vertical box container for the dialog content
|
||||
// let mut vbox =gtk4:: Box::new(Orientation::Horizontal, 10);
|
||||
//
|
||||
// // Add a label to the dialog
|
||||
// let label = Label::new(Some("This is a custom dialog!"));
|
||||
// vbox.append(&label);
|
||||
//
|
||||
// // Set the dialog content
|
||||
// dialog.set_child(Some(&vbox));
|
||||
//
|
||||
// // Show the dialog
|
||||
// dialog.present();
|
||||
// });
|
||||
//
|
||||
// let empty_array: [&str; 0] = [];;
|
||||
//
|
||||
//
|
||||
// application.run_with_args(&empty_array);
|
||||
//
|
||||
// debug!("merged config result {:#?}", config);
|
||||
//
|
||||
//
|
||||
// Ok(())
|
||||
// }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue