improve hide/show performance
This commit is contained in:
parent
1cf3e6d3c4
commit
66a708b429
4 changed files with 241 additions and 69 deletions
|
@ -10,6 +10,7 @@ use std::path::PathBuf;
|
|||
use std::process::{Command, Stdio};
|
||||
use std::time::Instant;
|
||||
use std::{env, fs, io};
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
/// Returns a regex with supported image extensions
|
||||
/// # Panics
|
||||
|
@ -279,3 +280,14 @@ pub fn create_file_if_not_exists(path: &PathBuf) -> Result<(), Error> {
|
|||
Err(e) => Err(Error::Io(e.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Check if the given dir entry is an executable
|
||||
pub fn is_executable(entry: &PathBuf) -> bool {
|
||||
if let Ok(metadata) = entry.metadata() {
|
||||
let permissions = metadata.permissions();
|
||||
metadata.is_file() && (permissions.mode() & 0o111 != 0)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::collections::HashMap;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
|
@ -34,8 +35,8 @@ type ArcProvider<T> = Arc<Mutex<dyn ItemProvider<T> + Send>>;
|
|||
type MenuItemSender<T> = Sender<Result<MenuItem<T>, anyhow::Error>>;
|
||||
|
||||
pub trait ItemProvider<T: Clone> {
|
||||
fn get_elements(&mut self, search: Option<&str>) -> Vec<MenuItem<T>>;
|
||||
fn get_sub_elements(&mut self, item: &MenuItem<T>) -> Option<Vec<MenuItem<T>>>;
|
||||
fn get_elements(&mut self, search: Option<&str>) -> (bool, Vec<MenuItem<T>>);
|
||||
fn get_sub_elements(&mut self, item: &MenuItem<T>) -> (bool, Option<Vec<MenuItem<T>>>);
|
||||
}
|
||||
|
||||
impl From<&Anchor> for Edge {
|
||||
|
@ -290,9 +291,12 @@ fn build_ui<T, P>(
|
|||
scroll.set_child(Some(&wrapper_box));
|
||||
|
||||
let wait_for_items = Instant::now();
|
||||
let provider_elements = get_provider_elements.join().unwrap();
|
||||
let (_changed, provider_elements) = get_provider_elements.join().unwrap();
|
||||
log::debug!("got items after {:?}", wait_for_items.elapsed());
|
||||
build_ui_from_menu_items(&ui_elements, &meta, &provider_elements);
|
||||
{
|
||||
let mut lock = ui_elements.menu_rows.lock().unwrap();
|
||||
build_ui_from_menu_items(&ui_elements, &meta, &provider_elements, lock.deref_mut());
|
||||
}
|
||||
|
||||
let items_sort = ArcMenuMap::clone(&ui_elements.menu_rows);
|
||||
ui_elements
|
||||
|
@ -338,7 +342,8 @@ fn build_main_box<T: Clone + 'static>(config: &Config, ui_elements: &Rc<UiElemen
|
|||
fb.grab_focus();
|
||||
fb.invalidate_sort();
|
||||
|
||||
select_first_visible_child(&ui_clone);
|
||||
let lock = ui_clone.menu_rows.lock().unwrap();
|
||||
select_first_visible_child(lock.deref(), &ui_clone.main_box);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -358,10 +363,10 @@ fn build_ui_from_menu_items<T: Clone + 'static>(
|
|||
ui: &Rc<UiElements<T>>,
|
||||
meta: &Rc<MetaData<T>>,
|
||||
items: &Vec<MenuItem<T>>,
|
||||
map: &mut HashMap<FlowBoxChild, MenuItem<T>>,
|
||||
) {
|
||||
let start = Instant::now();
|
||||
{
|
||||
let mut arc_lock = ui.menu_rows.lock().unwrap();
|
||||
let got_lock = Instant::now();
|
||||
|
||||
ui.main_box.unset_sort_func();
|
||||
|
@ -370,13 +375,13 @@ fn build_ui_from_menu_items<T: Clone + 'static>(
|
|||
ui.main_box.remove(&b);
|
||||
drop(b);
|
||||
}
|
||||
arc_lock.clear();
|
||||
map.clear();
|
||||
|
||||
let cleared_box = Instant::now();
|
||||
|
||||
for entry in items {
|
||||
if entry.visible {
|
||||
arc_lock.insert(add_menu_item(ui, meta, entry), (*entry).clone());
|
||||
map.insert(add_menu_item(ui, meta, entry), (*entry).clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,10 +394,6 @@ fn build_ui_from_menu_items<T: Clone + 'static>(
|
|||
created_ui - start
|
||||
);
|
||||
}
|
||||
|
||||
let lic = ArcMenuMap::clone(&ui.menu_rows);
|
||||
ui.main_box
|
||||
.set_sort_func(move |child2, child1| sort_menu_items_by_score(child1, child2, &lic));
|
||||
}
|
||||
|
||||
fn setup_key_event_handler<T: Clone + 'static + Send>(
|
||||
|
@ -416,15 +417,26 @@ fn handle_key_press<T: Clone + 'static>(
|
|||
meta: &Rc<MetaData<T>>,
|
||||
keyboard_key: Key,
|
||||
) -> Propagation {
|
||||
let update_view = |query: &String, items: &mut Vec<MenuItem<T>>| {
|
||||
set_menu_visibility_for_search(query, items, &meta.config);
|
||||
build_ui_from_menu_items(ui, meta, items);
|
||||
select_first_visible_child(ui);
|
||||
let update_view = |query: &String| {
|
||||
let mut lock = ui.menu_rows.lock().unwrap();
|
||||
let mut menus = lock.iter_mut().map(|(s, v)| v).collect::<Vec<_>>();
|
||||
set_menu_visibility_for_search(query, menus.as_mut_slice(), &meta.config);
|
||||
for (fb, item) in lock.iter() {
|
||||
fb.set_visible(item.visible);
|
||||
}
|
||||
|
||||
select_first_visible_child(&*lock, &ui.main_box);
|
||||
};
|
||||
|
||||
let update_view_from_provider = |query: &String| {
|
||||
let mut filtered_list = meta.item_provider.lock().unwrap().get_elements(Some(query));
|
||||
update_view(query, &mut filtered_list);
|
||||
let (changed, filtered_list) = meta.item_provider.lock().unwrap().get_elements(Some(query));
|
||||
if changed {
|
||||
|
||||
let mut lock = ui.menu_rows.lock().unwrap();
|
||||
build_ui_from_menu_items(&ui, &meta, &filtered_list, lock.deref_mut());
|
||||
}
|
||||
|
||||
update_view(query);
|
||||
};
|
||||
|
||||
match keyboard_key {
|
||||
|
@ -461,18 +473,22 @@ fn handle_key_press<T: Clone + 'static>(
|
|||
let lock = ui.menu_rows.lock().unwrap();
|
||||
let menu_item = lock.get(fb);
|
||||
if let Some(menu_item) = menu_item {
|
||||
if let Some(mut new_items) = meta
|
||||
let (changed, items) = meta
|
||||
.item_provider
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get_sub_elements(menu_item)
|
||||
{
|
||||
let query = menu_item.label.clone();
|
||||
drop(lock);
|
||||
.get_sub_elements(menu_item);
|
||||
|
||||
ui.search.set_text(&query);
|
||||
update_view(&query, &mut new_items);
|
||||
let items = items.unwrap_or_default();
|
||||
if changed {
|
||||
let mut lock = ui.menu_rows.lock().unwrap();
|
||||
build_ui_from_menu_items(ui, meta, &items, &mut *lock);
|
||||
}
|
||||
|
||||
let query = menu_item.label.clone();
|
||||
|
||||
ui.search.set_text(&query);
|
||||
update_view(&query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -847,7 +863,7 @@ fn lookup_icon<T: Clone>(menu_item: &MenuItem<T>, config: &Config) -> Option<Ima
|
|||
|
||||
fn set_menu_visibility_for_search<T: Clone>(
|
||||
query: &str,
|
||||
items: &mut [MenuItem<T>],
|
||||
items: &mut [&mut MenuItem<T>],
|
||||
config: &Config,
|
||||
) {
|
||||
{
|
||||
|
@ -906,14 +922,16 @@ fn set_menu_visibility_for_search<T: Clone>(
|
|||
}
|
||||
}
|
||||
|
||||
fn select_first_visible_child<T: Clone>(ui: &UiElements<T>) {
|
||||
let items = ui.menu_rows.lock().unwrap();
|
||||
fn select_first_visible_child<T: Clone>(
|
||||
items: &HashMap<FlowBoxChild, MenuItem<T>>,
|
||||
flow_box: &FlowBox,
|
||||
) {
|
||||
for i in 0..items.len() {
|
||||
let i_32 = i.try_into().unwrap_or(i32::MAX);
|
||||
if let Some(child) = ui.main_box.child_at_index(i_32) {
|
||||
if let Some(child) = flow_box.child_at_index(i_32) {
|
||||
if child.is_visible() {
|
||||
ui.main_box.select_child(&child);
|
||||
break;
|
||||
flow_box.select_child(&child);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
216
src/lib/mode.rs
216
src/lib/mode.rs
|
@ -1,8 +1,5 @@
|
|||
use crate::config::{Config, expand_path};
|
||||
use crate::desktop::{
|
||||
create_file_if_not_exists, find_desktop_files, get_locale_variants, load_cache_file,
|
||||
lookup_name_with_locale, save_cache_file, spawn_fork,
|
||||
};
|
||||
use crate::desktop::{create_file_if_not_exists, find_desktop_files, get_locale_variants, is_executable, load_cache_file, lookup_name_with_locale, save_cache_file, spawn_fork};
|
||||
use crate::gui::{ItemProvider, MenuItem};
|
||||
use crate::{Error, gui};
|
||||
use freedesktop_file_parser::EntryType;
|
||||
|
@ -13,7 +10,7 @@ use std::collections::{HashMap, HashSet};
|
|||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Instant;
|
||||
use std::{fs, io};
|
||||
use std::{env, fs, io};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
struct DRunCache {
|
||||
|
@ -145,19 +142,112 @@ impl<T: Clone + Send + Sync> DRunProvider<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Send + Sync> ItemProvider<T> for DRunProvider<T> {
|
||||
fn get_elements(&mut self, _: Option<&str>) -> Vec<MenuItem<T>> {
|
||||
impl<T: Clone + Send + Sync> ItemProvider<T> for RunProvider<T> {
|
||||
fn get_elements(&mut self, _: Option<&str>) -> (bool, Vec<gui::MenuItem<T>>) {
|
||||
if self.items.is_none() {
|
||||
self.items = Some(self.load().clone());
|
||||
}
|
||||
self.items.clone().unwrap()
|
||||
(false, self.items.clone().unwrap())
|
||||
}
|
||||
|
||||
fn get_sub_elements(&mut self, _: &MenuItem<T>) -> Option<Vec<MenuItem<T>>> {
|
||||
None
|
||||
fn get_sub_elements(&mut self, _: &MenuItem<T>) -> (bool, std::option::Option<Vec<gui::MenuItem<T>>>) {
|
||||
(false, None)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct RunProvider<T: Clone> {
|
||||
items: Option<Vec<MenuItem<T>>>,
|
||||
cache_path: Option<PathBuf>,
|
||||
cache: HashMap<String, i64>,
|
||||
data: T,
|
||||
}
|
||||
|
||||
impl<T: Clone + Send + Sync> RunProvider<T> {
|
||||
fn new(menu_item_data: T) -> Self {
|
||||
let (cache_path, d_run_cache) = load_run_cache();
|
||||
RunProvider {
|
||||
items: None,
|
||||
cache_path,
|
||||
cache: d_run_cache,
|
||||
data: menu_item_data,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
fn load(&self) -> Vec<MenuItem<T>> {
|
||||
let path_var = env::var("PATH").unwrap_or_default();
|
||||
let paths = env::split_paths(&path_var);
|
||||
|
||||
let entries : Vec<_>= paths
|
||||
.filter(|dir| dir.is_dir())
|
||||
.flat_map(|dir| {
|
||||
fs::read_dir(dir)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter_map(Result::ok)
|
||||
.filter_map(|entry| {
|
||||
let path = entry.path();
|
||||
if is_executable(&path) {
|
||||
let label = path
|
||||
.file_name()
|
||||
.and_then(|s| s.to_str())
|
||||
.map(String::from)?;
|
||||
let sort_score = *self.cache.get(&label).unwrap_or(&0) as f64;
|
||||
Some(MenuItem::new(
|
||||
label,
|
||||
None,
|
||||
path.to_str().map(std::string::ToString::to_string),
|
||||
vec![],
|
||||
None,
|
||||
sort_score,
|
||||
None,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
let mut seen_actions = HashSet::new();
|
||||
let mut entries: Vec<MenuItem<T>> = entries
|
||||
.into_iter()
|
||||
.filter(|entry| {
|
||||
if let Some(action) = &entry.action {
|
||||
if let Some(cmd) = action.split('/').last() {
|
||||
seen_actions.insert(cmd.to_string())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
gui::sort_menu_items_alphabetically_honor_initial_score(&mut entries);
|
||||
entries
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Send + Sync> ItemProvider<T> for DRunProvider<T> {
|
||||
fn get_elements(&mut self, _: Option<&str>) -> (bool, Vec<gui::MenuItem<T>>) {
|
||||
if self.items.is_none() {
|
||||
self.items = Some(self.load().clone());
|
||||
}
|
||||
(false, self.items.clone().unwrap())
|
||||
}
|
||||
|
||||
fn get_sub_elements(&mut self, _: &MenuItem<T>) -> (bool, std::option::Option<Vec<gui::MenuItem<T>>>) {
|
||||
(false, None)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
struct FileItemProvider<T: Clone> {
|
||||
last_result: Option<Vec<MenuItem<T>>>,
|
||||
|
@ -213,7 +303,7 @@ impl<T: Clone> FileItemProvider<T> {
|
|||
}
|
||||
|
||||
impl<T: Clone> ItemProvider<T> for FileItemProvider<T> {
|
||||
fn get_elements(&mut self, search: Option<&str>) -> Vec<MenuItem<T>> {
|
||||
fn get_elements(&mut self, search: Option<&str>) -> (bool, Vec<gui::MenuItem<T>>) {
|
||||
let default_path = if let Some(home) = dirs::home_dir() {
|
||||
home.display().to_string()
|
||||
} else {
|
||||
|
@ -230,10 +320,10 @@ impl<T: Clone> ItemProvider<T> for FileItemProvider<T> {
|
|||
|
||||
if !path.exists() {
|
||||
if let Some(last) = &self.last_result {
|
||||
return last.clone();
|
||||
return (false, last.clone());
|
||||
}
|
||||
|
||||
return vec![];
|
||||
return (true, vec![]);
|
||||
}
|
||||
|
||||
if path.is_dir() {
|
||||
|
@ -295,11 +385,11 @@ impl<T: Clone> ItemProvider<T> for FileItemProvider<T> {
|
|||
gui::sort_menu_items_alphabetically_honor_initial_score(&mut items);
|
||||
|
||||
self.last_result = Some(items.clone());
|
||||
items
|
||||
(true, items)
|
||||
}
|
||||
|
||||
fn get_sub_elements(&mut self, _: &MenuItem<T>) -> Option<Vec<MenuItem<T>>> {
|
||||
self.last_result.clone()
|
||||
fn get_sub_elements(&mut self, _: &MenuItem<T>) -> (bool, std::option::Option<Vec<gui::MenuItem<T>>>) {
|
||||
(false, self.last_result.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,12 +434,12 @@ impl<T: Clone> SshProvider<T> {
|
|||
}
|
||||
|
||||
impl<T: Clone> ItemProvider<T> for SshProvider<T> {
|
||||
fn get_elements(&mut self, _: Option<&str>) -> Vec<MenuItem<T>> {
|
||||
self.elements.clone()
|
||||
fn get_elements(&mut self, _: Option<&str>) -> (bool, Vec<gui::MenuItem<T>>) {
|
||||
(false, self.elements.clone())
|
||||
}
|
||||
|
||||
fn get_sub_elements(&mut self, _: &MenuItem<T>) -> Option<Vec<MenuItem<T>>> {
|
||||
None
|
||||
fn get_sub_elements(&mut self, _: &MenuItem<T>) -> (bool, std::option::Option<Vec<gui::MenuItem<T>>>) {
|
||||
(false, None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,7 +476,7 @@ impl<T: Clone> MathProvider<T> {
|
|||
}
|
||||
|
||||
impl<T: Clone> ItemProvider<T> for MathProvider<T> {
|
||||
fn get_elements(&mut self, search: Option<&str>) -> Vec<MenuItem<T>> {
|
||||
fn get_elements(&mut self, search: Option<&str>) -> (bool, Vec<gui::MenuItem<T>>) {
|
||||
if let Some(search_text) = search {
|
||||
let result = match meval::eval_str(search_text) {
|
||||
Ok(result) => result.to_string(),
|
||||
|
@ -404,14 +494,14 @@ impl<T: Clone> ItemProvider<T> for MathProvider<T> {
|
|||
);
|
||||
let mut result = vec![item];
|
||||
result.append(&mut self.elements.clone());
|
||||
result
|
||||
(true, result)
|
||||
} else {
|
||||
self.elements.clone()
|
||||
(false, self.elements.clone())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_sub_elements(&mut self, _: &MenuItem<T>) -> Option<Vec<MenuItem<T>>> {
|
||||
None
|
||||
fn get_sub_elements(&mut self, _: &MenuItem<T>) -> (bool, std::option::Option<Vec<gui::MenuItem<T>>>) {
|
||||
(false, None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -438,12 +528,12 @@ impl DMenuProvider {
|
|||
}
|
||||
|
||||
impl ItemProvider<String> for DMenuProvider {
|
||||
fn get_elements(&mut self, _: Option<&str>) -> Vec<MenuItem<String>> {
|
||||
self.items.clone()
|
||||
fn get_elements(&mut self, _: Option<&str>) -> (bool, Vec<gui::MenuItem<std::string::String>>) {
|
||||
(false, self.items.clone())
|
||||
}
|
||||
|
||||
fn get_sub_elements(&mut self, _: &MenuItem<String>) -> Option<Vec<MenuItem<String>>> {
|
||||
None
|
||||
fn get_sub_elements(&mut self, _: &MenuItem<String>) -> (bool, std::option::Option<Vec<gui::MenuItem<std::string::String>>>) {
|
||||
(false, None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,7 +568,7 @@ impl AutoItemProvider {
|
|||
}
|
||||
|
||||
impl ItemProvider<AutoRunType> for AutoItemProvider {
|
||||
fn get_elements(&mut self, search_opt: Option<&str>) -> Vec<MenuItem<AutoRunType>> {
|
||||
fn get_elements(&mut self, search_opt: Option<&str>) -> (bool, Vec<gui::MenuItem<AutoRunType>>) {
|
||||
if let Some(search) = search_opt {
|
||||
let trimmed_search = search.trim();
|
||||
if trimmed_search.is_empty() {
|
||||
|
@ -496,9 +586,9 @@ impl ItemProvider<AutoRunType> for AutoItemProvider {
|
|||
self.ssh.get_elements(search_opt)
|
||||
} else {
|
||||
// return ssh and drun items
|
||||
let mut drun = self.drun.get_elements(search_opt);
|
||||
drun.append(&mut self.ssh.get_elements(search_opt));
|
||||
drun
|
||||
let (changed, mut drun) = self.drun.get_elements(search_opt);
|
||||
drun.append(&mut self.ssh.get_elements(search_opt).1);
|
||||
(changed, drun)
|
||||
}
|
||||
} else {
|
||||
self.drun.get_elements(search_opt)
|
||||
|
@ -508,8 +598,9 @@ impl ItemProvider<AutoRunType> for AutoItemProvider {
|
|||
fn get_sub_elements(
|
||||
&mut self,
|
||||
item: &MenuItem<AutoRunType>,
|
||||
) -> Option<Vec<MenuItem<AutoRunType>>> {
|
||||
Some(self.get_elements(Some(item.label.as_ref())))
|
||||
) -> (bool, std::option::Option<Vec<gui::MenuItem<AutoRunType>>>) {
|
||||
let (changed, items) = self.get_elements(Some(item.label.as_ref()));
|
||||
(changed, Some(items))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -534,6 +625,27 @@ pub fn d_run(config: &Config) -> Result<(), Error> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Shows the run mode
|
||||
/// # Errors
|
||||
///
|
||||
/// Will return `Err` if it was not able to spawn the process
|
||||
pub fn run(config: &Config) -> Result<(), Error> {
|
||||
let provider = RunProvider::new(String::new());
|
||||
let cache_path = provider.cache_path.clone();
|
||||
let mut cache = provider.cache.clone();
|
||||
|
||||
let selection_result = gui::show(config.clone(), provider, false);
|
||||
match selection_result {
|
||||
Ok(s) => update_run_cache_and_run(cache_path, &mut cache, s)?,
|
||||
Err(_) => {
|
||||
log::error!("No item selected");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
/// Shows the auto mode
|
||||
/// # Errors
|
||||
///
|
||||
|
@ -696,9 +808,39 @@ fn update_drun_cache_and_run<T: Clone>(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
fn update_run_cache_and_run<T: Clone>(
|
||||
cache_path: Option<PathBuf>,
|
||||
cache: &mut HashMap<String, i64>,
|
||||
selection_result: MenuItem<T>,
|
||||
) -> Result<(), Error> {
|
||||
if let Some(cache_path) = cache_path {
|
||||
*cache.entry(selection_result.label).or_insert(0) += 1;
|
||||
if let Err(e) = save_cache_file(&cache_path, cache) {
|
||||
log::warn!("cannot save run cache {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(action) = selection_result.action {
|
||||
spawn_fork(&action, selection_result.working_dir.as_ref())
|
||||
} else {
|
||||
Err(Error::MissingAction)
|
||||
}
|
||||
}
|
||||
|
||||
fn load_d_run_cache() -> (Option<PathBuf>, HashMap<String, i64>) {
|
||||
let cache_path = dirs::cache_dir().map(|x| x.join("worf-drun"));
|
||||
let d_run_cache = {
|
||||
load_cache(cache_path)
|
||||
}
|
||||
|
||||
fn load_run_cache() -> (Option<PathBuf>, HashMap<String, i64>) {
|
||||
let cache_path = dirs::cache_dir().map(|x| x.join("worf-run"));
|
||||
load_cache(cache_path)
|
||||
}
|
||||
|
||||
|
||||
fn load_cache(cache_path: Option<PathBuf>) -> (Option<PathBuf>, HashMap<String, i64>) {
|
||||
let cache = {
|
||||
if let Some(ref cache_path) = cache_path {
|
||||
if let Err(e) = create_file_if_not_exists(cache_path) {
|
||||
log::warn!("No drun cache file and cannot create: {e:?}");
|
||||
|
@ -707,5 +849,5 @@ fn load_d_run_cache() -> (Option<PathBuf>, HashMap<String, i64>) {
|
|||
|
||||
load_cache_file(cache_path.as_ref()).unwrap_or_default()
|
||||
};
|
||||
(cache_path, d_run_cache)
|
||||
(cache_path, cache)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ fn main() -> anyhow::Result<()> {
|
|||
if let Some(show) = &config.show() {
|
||||
match show {
|
||||
Mode::Run => {
|
||||
todo!("run not implemented")
|
||||
mode::run(&config).map_err(|e| anyhow!(e))?;
|
||||
}
|
||||
Mode::Drun => {
|
||||
mode::d_run(&config).map_err(|e| anyhow!(e))?;
|
||||
|
|
Loading…
Add table
Reference in a new issue