From 77151bd1c10fcb16f10b45f4f039fe6aa653bcc9 Mon Sep 17 00:00:00 2001 From: "Aleksey @soar Smyrnov" Date: Wed, 23 Apr 2025 19:49:01 -0600 Subject: [PATCH 1/4] feat: Add history for variables --- src/commands/core/actor.rs | 19 +++++++++++++-- src/env_var.rs | 2 ++ src/filesystem.rs | 49 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/commands/core/actor.rs b/src/commands/core/actor.rs index 5e089e6..67b2b04 100644 --- a/src/commands/core/actor.rs +++ b/src/commands/core/actor.rs @@ -5,6 +5,7 @@ use crate::common::shell::ShellSpawnError; use crate::config::Action; use crate::deser; use crate::env_var; +use crate::filesystem; use crate::finder::structures::{Opts as FinderOpts, SuggestionType}; use crate::prelude::*; use crate::structures::cheat::{Suggestion, VariableMap}; @@ -22,6 +23,7 @@ fn prompt_finder( env_var::remove(env_var::PREVIEW_MAP); let mut extra_preview: Option = None; + let mut variable_history = vec![]; let (suggestions, initial_opts) = if let Some(s) = suggestion { let (suggestion_command, suggestion_opts) = s; @@ -58,7 +60,12 @@ fn prompt_finder( (text, suggestion_opts) } else { - ('\n'.to_string(), &None) + variable_history = filesystem::get_variable_history(variable_name); + if !variable_history.is_empty() { + (variable_history.join("\n"), &None) + } else { + ('\n'.to_string(), &None) + } }; let exe = fs::exe_string(); @@ -131,7 +138,9 @@ fn prompt_finder( }); } - if suggestion.is_none() { + if !variable_history.is_empty() { + opts.suggestion_type = SuggestionType::SingleRecommendation; + } else if suggestion.is_none() { opts.suggestion_type = SuggestionType::Disabled; }; @@ -145,6 +154,12 @@ fn prompt_finder( }) .context("finder was unable to prompt with suggestions")?; + if suggestion.is_none() { + if !variable_history.contains(&output) { + filesystem::save_variable_history(variable_name, &output); + } + } + Ok(output) } diff --git a/src/env_var.rs b/src/env_var.rs index 8097edd..d0a35ab 100644 --- a/src/env_var.rs +++ b/src/env_var.rs @@ -19,6 +19,8 @@ pub const FINDER: &str = "NAVI_FINDER"; pub const CONFIG: &str = "NAVI_CONFIG"; pub const CONFIG_YAML: &str = "NAVI_CONFIG_YAML"; +pub const VARIABLES_HISTORY_FILE: &str = "NAVI_VARIABLES_HISTORY_FILE"; + pub fn parse(varname: &str) -> Option { if let Ok(x) = env::var(varname) { x.parse::().ok() diff --git a/src/filesystem.rs b/src/filesystem.rs index 4d0b4e5..154af32 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -2,12 +2,14 @@ pub use crate::common::fs::{create_dir, exe_string, read_lines, remove_dir}; use crate::env_var; use crate::parser::Parser; use crate::prelude::*; +use std::io::Write; use crate::structures::fetcher; use etcetera::BaseStrategy; use regex::Regex; use std::cell::RefCell; +use std::env; use std::path::MAIN_SEPARATOR; use walkdir::WalkDir; @@ -88,6 +90,53 @@ pub fn cheat_paths(path: Option) -> Result { } } +pub fn variables_history_pathbuf() -> Option { + if let Ok(v) = env::var(env_var::VARIABLES_HISTORY_FILE) { + let pathbuf = PathBuf::from(v); + + if !pathbuf.exists() { + File::create(&pathbuf).unwrap_or_else(|_| panic!("Unable to create file: {}", pathbuf.display())); + } + + Some(pathbuf) + } else { + None + } +} + +pub fn get_variable_history(variable: &str) -> Vec { + if let Some(pathbuf) = variables_history_pathbuf() { + let file = std::fs::File::open(pathbuf).expect("Unable to open history file"); + let reader = std::io::BufReader::new(file); + + reader + .lines() + .filter_map(|line| line.ok()) + .filter_map(|line| { + let parts: Vec<&str> = line.splitn(2, ':').collect(); + if parts.len() == 2 && parts[0] == variable { + Some(parts[1].to_string()) + } else { + None + } + }) + .collect() + } else { + vec![] + } +} + +pub fn save_variable_history(variable: &str, value: &str) { + if let Some(pathbuf) = variables_history_pathbuf() { + let mut file = std::fs::OpenOptions::new() + .append(true) + .create(true) + .open(pathbuf) + .expect("Unable to open history file"); + writeln!(file, "{}:{}", variable, value).expect("Unable to write to history file"); + } +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // // Here are other functions, unrelated to CLI commands (or at least not directly related) From aa2bc4e9aa40176664a30b50fea5cf2f5edebc36 Mon Sep 17 00:00:00 2001 From: "Aleksey @soar Smyrnov" Date: Wed, 23 Apr 2025 19:57:45 -0600 Subject: [PATCH 2/4] fix: Fixes for clippy suggestions --- src/commands/core/actor.rs | 6 ++---- src/filesystem.rs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/commands/core/actor.rs b/src/commands/core/actor.rs index 67b2b04..caee909 100644 --- a/src/commands/core/actor.rs +++ b/src/commands/core/actor.rs @@ -154,10 +154,8 @@ fn prompt_finder( }) .context("finder was unable to prompt with suggestions")?; - if suggestion.is_none() { - if !variable_history.contains(&output) { - filesystem::save_variable_history(variable_name, &output); - } + if suggestion.is_none() && !variable_history.contains(&output) { + filesystem::save_variable_history(variable_name, &output); } Ok(output) diff --git a/src/filesystem.rs b/src/filesystem.rs index 154af32..4b81fcf 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -111,7 +111,7 @@ pub fn get_variable_history(variable: &str) -> Vec { reader .lines() - .filter_map(|line| line.ok()) + .map_while(|line| line.ok()) .filter_map(|line| { let parts: Vec<&str> = line.splitn(2, ':').collect(); if parts.len() == 2 && parts[0] == variable { From c572e01526de3efa08d1da1e43241756941ced22 Mon Sep 17 00:00:00 2001 From: "Aleksey @soar Smyrnov" Date: Wed, 23 Apr 2025 20:27:23 -0600 Subject: [PATCH 3/4] fix: Fix for the case with 1 item in the list --- src/commands/core/actor.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/core/actor.rs b/src/commands/core/actor.rs index caee909..89af96f 100644 --- a/src/commands/core/actor.rs +++ b/src/commands/core/actor.rs @@ -62,6 +62,7 @@ fn prompt_finder( } else { variable_history = filesystem::get_variable_history(variable_name); if !variable_history.is_empty() { + variable_history.insert(0, "".to_string()); (variable_history.join("\n"), &None) } else { ('\n'.to_string(), &None) From 125e1e6c895eb0cd5cd959f4ed947ed851e02859 Mon Sep 17 00:00:00 2001 From: "Aleksey @soar Smyrnov" Date: Tue, 29 Apr 2025 23:28:39 -0600 Subject: [PATCH 4/4] feat: Rename env variable for history file path according to: https://github.com/denisidoro/navi/pull/977#discussion_r2059102393 --- src/env_var.rs | 2 +- src/filesystem.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/env_var.rs b/src/env_var.rs index d0a35ab..525dd57 100644 --- a/src/env_var.rs +++ b/src/env_var.rs @@ -19,7 +19,7 @@ pub const FINDER: &str = "NAVI_FINDER"; pub const CONFIG: &str = "NAVI_CONFIG"; pub const CONFIG_YAML: &str = "NAVI_CONFIG_YAML"; -pub const VARIABLES_HISTORY_FILE: &str = "NAVI_VARIABLES_HISTORY_FILE"; +pub const VAR_HISTORY: &str = "NAVI_VAR_HISTORY"; pub fn parse(varname: &str) -> Option { if let Ok(x) = env::var(varname) { diff --git a/src/filesystem.rs b/src/filesystem.rs index 4b81fcf..2f6fc43 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -91,7 +91,7 @@ pub fn cheat_paths(path: Option) -> Result { } pub fn variables_history_pathbuf() -> Option { - if let Ok(v) = env::var(env_var::VARIABLES_HISTORY_FILE) { + if let Ok(v) = env::var(env_var::VAR_HISTORY) { let pathbuf = PathBuf::from(v); if !pathbuf.exists() {