Skip to content
Merged
27 changes: 17 additions & 10 deletions src/aqua/aqua_registry_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,28 +116,35 @@ fn fetch_latest_repo(repo: &Git) -> Result<()> {
Ok(())
}

/// Search aqua packages by tool name, returning "owner/name" IDs
/// where the name part is similar to the query.
pub fn aqua_suggest(query: &str) -> Vec<String> {
use std::collections::HashMap;
struct AquaSuggestionsCache {
name_to_ids: HashMap<&'static str, Vec<&'static str>>,
names: Vec<&'static str>,
}

static AQUA_SUGGESTIONS_CACHE: Lazy<AquaSuggestionsCache> = Lazy::new(|| {
let ids = aqua_registry::package_ids();
// Build a map from tool name to full IDs for O(1) lookup
let mut name_to_ids: HashMap<&str, Vec<&str>> = HashMap::new();
for id in &ids {
let mut name_to_ids: HashMap<&'static str, Vec<&'static str>> = HashMap::new();
for id in ids {
if let Some((_, name)) = id.rsplit_once('/') {
name_to_ids.entry(name).or_default().push(id);
}
}
let names: Vec<&str> = name_to_ids.keys().copied().collect();
let names = name_to_ids.keys().copied().collect();
AquaSuggestionsCache { name_to_ids, names }
});

/// Search aqua packages by tool name, returning "owner/name" IDs
/// where the name part is similar to the query.
pub fn aqua_suggest(query: &str) -> Vec<String> {
let cache = &*AQUA_SUGGESTIONS_CACHE;

// Use a higher threshold (0.8) to avoid noisy suggestions
let similar_names = xx::suggest::similar_n_with_threshold(query, &names, 5, 0.8);
let similar_names = xx::suggest::similar_n_with_threshold(query, &cache.names, 5, 0.8);

// Map back to full IDs
let mut results = Vec::new();
for matched_name in &similar_names {
if let Some(full_ids) = name_to_ids.get(matched_name.as_str()) {
if let Some(full_ids) = cache.name_to_ids.get(matched_name.as_str()) {
for full_id in full_ids {
results.push(full_id.to_string());
if results.len() >= 5 {
Expand Down
2 changes: 1 addition & 1 deletion src/cli/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ impl Install {
.map(|t| format!(" mise use {t}"))
.collect();
warn!(
"{tool_list} installed but not activated — {} not in a mise.toml config file.\nTo install and activate, run:\n{}",
"{tool_list} installed but not activated — {} not in any config file.\nTo install and activate, run:\n{}",
if inactive_tools.len() == 1 {
"it is"
} else {
Expand Down
9 changes: 9 additions & 0 deletions src/toolset/tool_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::{collections::BTreeMap, sync::Arc};
use crate::backend::ABackend;
use crate::cli::args::BackendArg;
use crate::config::Config;
use crate::env;
#[cfg(windows)]
use crate::file;
use crate::hash::hash_to_str;
Expand Down Expand Up @@ -247,6 +248,14 @@ impl ToolVersion {
return build(v.clone());
}
}
// In prefer-offline mode (hook-env, activate, exec), skip remote version
// fetching for fully-qualified versions (e.g. "2.3.2") that aren't installed.
// Prefix versions like "2" still need remote resolution to find e.g. "2.1.0".
if env::PREFER_OFFLINE.load(std::sync::atomic::Ordering::Relaxed)
&& v.matches('.').count() >= 2
{
return build(v);
}
// First try with date filter (common case)
let matches = backend
.list_versions_matching_with_opts(config, &v, opts.before_date)
Expand Down
Loading