diff --git a/src/file.rs b/src/file.rs index 1ed3ca4106..744d58d3ba 100644 --- a/src/file.rs +++ b/src/file.rs @@ -198,6 +198,17 @@ pub fn replace_path>(path: P) -> PathBuf { } } +pub fn touch_file(file: &Path) -> Result<()> { + if !file.exists() { + create(file)?; + return Ok(()); + } + trace!("touch_file {}", file.display()); + let now = FileTime::now(); + set_file_times(file, now, now) + .wrap_err_with(|| format!("failed to touch file: {}", display_path(file))) +} + pub fn touch_dir(dir: &Path) -> Result<()> { trace!("touch {}", dir.display()); let now = FileTime::now(); diff --git a/src/hint.rs b/src/hint.rs new file mode 100644 index 0000000000..09dbe115a4 --- /dev/null +++ b/src/hint.rs @@ -0,0 +1,59 @@ +use crate::config::SETTINGS; +use crate::dirs; +use once_cell::sync::Lazy; +use std::collections::HashSet; +use std::path::PathBuf; +use std::sync::Mutex; + +#[macro_export] +macro_rules! hint { + ($id:expr, $message:expr, $example_cmd:expr) => {{ + if $crate::hint::should_display_hint($id) { + let _ = $crate::file::touch_file(&$crate::hint::HINTS_DIR.join($id)); + let prefix = console::style("hint") + .dim() + .yellow() + .for_stderr() + .to_string(); + let message = format!($message); + let cmd = console::style($example_cmd).bold().for_stderr(); + info!("{prefix} {message} {cmd}"); + } + }}; +} + +pub static HINTS_DIR: Lazy = Lazy::new(|| dirs::STATE.join("hints")); + +pub static DISPLAYED_HINTS: Lazy>> = Lazy::new(|| { + let mut hints = HashSet::new(); + + for file in xx::file::ls(&*HINTS_DIR).unwrap_or_default() { + if let Some(file_name) = file.file_name().map(|f| f.to_string_lossy()) { + if file_name.starts_with(".") { + continue; + } + hints.insert(file_name.to_string()); + } + } + + Mutex::new(hints) +}); + +pub fn should_display_hint(id: &str) -> bool { + if cfg!(test) || !console::user_attended() || !console::user_attended_stderr() { + return false; + } + if SETTINGS + .disable_hints + .iter() + .any(|hint| hint == id || hint == "*") + { + return false; + } + let displayed_hints = &mut DISPLAYED_HINTS.lock().unwrap(); + if displayed_hints.contains(id) { + return false; + } + displayed_hints.insert(id.to_string()); + true +} diff --git a/src/main.rs b/src/main.rs index 3f2cb41c50..ebe6afefeb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,9 @@ mod test; #[macro_use] mod output; +#[macro_use] +mod hint; + #[macro_use] mod cmd; diff --git a/src/output.rs b/src/output.rs index 8a32dae90e..9712061be6 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,9 +1,5 @@ -use crate::config::SETTINGS; #[cfg(feature = "timings")] use crate::ui::style; -use once_cell::sync::Lazy; -use std::collections::HashSet; -use std::sync::Mutex; #[cfg(test)] #[macro_export] @@ -91,54 +87,6 @@ macro_rules! debug { }}; } -pub fn should_display_hint(id: &str) -> bool { - if cfg!(test) { - return false; - } - if SETTINGS - .disable_hints - .iter() - .any(|hint| hint == id || hint == "*") - { - return false; - } - if !console::user_attended() { - return false; - } - static DISPLAYED_HINTS: Lazy>> = Lazy::new(Default::default); - let displayed_hints = &mut DISPLAYED_HINTS.lock().unwrap(); - if displayed_hints.contains(id) { - return false; - } - displayed_hints.insert(id.to_string()); - true -} - -#[macro_export] -macro_rules! hint { - ($id:expr, $message:expr, $example_cmd:expr) => {{ - if $crate::output::should_display_hint($id) { - let prefix = console::style("hint") - .dim() - .yellow() - .for_stderr() - .to_string(); - let cmd = console::style($example_cmd).bold().for_stderr(); - let disable_single = console::style(format!("mise settings add disable_hints {}", $id)) - .bold() - .for_stderr(); - let disable_all = console::style("mise settings set disable_hints \"*\"") - .bold() - .for_stderr(); - info!("{} {} {}", prefix, format!($message), cmd); - info!( - "{} disable this hint with {} or all with {}", - prefix, disable_single, disable_all - ); - } - }}; -} - #[cfg(not(test))] #[macro_export] macro_rules! info { @@ -149,7 +97,7 @@ macro_rules! info { #[cfg(feature = "timings")] pub fn get_time_diff(module: &str, extra: &str) -> String { - static PREV: Mutex> = Mutex::new(None); + static PREV: std::sync::Mutex> = std::sync::Mutex::new(None); let now = std::time::Instant::now(); if PREV.lock().unwrap().is_none() { *PREV.lock().unwrap() = Some(std::time::Instant::now());