From 2b8cc3bd512cff0040815a604027907f65cbe3b7 Mon Sep 17 00:00:00 2001 From: frederik Date: Thu, 29 Aug 2024 22:12:17 +0200 Subject: [PATCH] offline features --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/crate_lookup.rs | 134 +++++++++++++++++++++++++++++++------------- src/lsp.rs | 1 + 4 files changed, 97 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e939ae..6d3d8a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -191,7 +191,7 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cargotom" -version = "0.7.1" +version = "0.8.0" dependencies = [ "clap", "git2", diff --git a/Cargo.toml b/Cargo.toml index 57f3661..a8c0086 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargotom" -version = "0.7.1" +version = "0.8.0" edition = "2021" [dependencies] diff --git a/src/crate_lookup.rs b/src/crate_lookup.rs index b3fb923..dfbc9b7 100644 --- a/src/crate_lookup.rs +++ b/src/crate_lookup.rs @@ -1,13 +1,13 @@ use std::{ + collections::HashMap, fs::{read_dir, read_to_string}, path::{Path, PathBuf}, sync::Arc, time::{Duration, SystemTime, UNIX_EPOCH}, }; -type OfflineCratesData = Option)>)>>>; +type OfflineCratesData = Option>)>)>>>; use reqwest::Client; -use taplo::HashMap; use tokio::{sync::RwLock, time::sleep}; use trie_rs::map::{Trie, TrieBuilder}; @@ -46,7 +46,8 @@ impl CratesIoStorage { fn read_data(path: &Path) -> OfflineCratesData { if let Ok(dir) = read_dir(path.join("index")) { - let mut hm: HashMap)>)>> = HashMap::new(); + let mut hm: HashMap>)>)>> = + HashMap::new(); for file in dir.into_iter().filter_map(|v| v.ok()) { let file = file.path(); let name = file @@ -69,7 +70,8 @@ fn read_data(path: &Path) -> OfflineCratesData { .map(|(key, value)| (normalize_key(&key), (key, value))) { let item = hm.entry(key).or_default(); - item.push(value); + let (a, b) = value; + item.push((a, post_process_value(b))); } } if hm.is_empty() { @@ -87,6 +89,24 @@ fn read_data(path: &Path) -> OfflineCratesData { } } +fn post_process_value(value: Vec<(String, Vec)>) -> Vec<(String, Vec>)> { + let mut out = vec![]; + let mut features = HashMap::new(); + for (version, f) in value { + for feature in f { + let added = feature.starts_with("+"); + let feature = &feature[1..]; + if added { + features.insert(feature.to_string(), Arc::new(feature.to_string())); + } else { + features.remove(feature); + } + } + out.push((version, features.values().cloned().collect::>())) + } + out +} + pub fn shared(t: T) -> Shared { Arc::new(RwLock::new(t)) } @@ -128,8 +148,8 @@ impl CratesIoStorage { ( a.to_string(), None, - b.first() - .map(|(version, features)| version.to_string()) + b.last() + .map(|(version, _)| version.to_string()) .unwrap_or_default(), ) }) @@ -167,7 +187,7 @@ impl CratesIoStorage { Some( versions .iter() - .map(|(versiom, features)| RustVersion::from(versiom.as_str())) + .map(|(versiom, _)| RustVersion::from(versiom.as_str())) .collect::>(), ) } else { @@ -189,43 +209,77 @@ impl CratesIoStorage { } pub async fn get_features_local(&self, name: &str, version: &str) -> Option> { - let version = RustVersion::from(version); - let v = self.versions_cache.read().await; - match v.get(name) { - Some(v) => match v { - InfoCacheEntry::Pending(_) => None, - InfoCacheEntry::Ready(v) => Some( - v.iter() - .find(|v| &v.version == &version) - .map(|b| b.features.clone()) - .unwrap_or_default(), - ), - }, - None => { - //INFO: thats probably fine, bc CratesIoStorage will exist until the lsp is stopped - let cpy = unsafe { (self as *const Self).as_ref() }.unwrap(); - let name = name.to_string(); - tokio::spawn(async move { cpy.versions_features(&name).await }); - None + let ver = RustVersion::from(version); + let lock = self.data.read().await; + if let Some(v) = &*lock { + let search = v.exact_match(normalize_key(name))?; + let (_, versions) = search + .iter() + .find(|v| v.0.to_lowercase() == name.to_lowercase())?; + versions + .iter() + .find(|(version, _)| RustVersion::from(version.as_str()).eq(&ver)) + .map(|v| v.1.iter().map(|v| v.to_string()).collect()) + } else { + let v = self.versions_cache.read().await; + match v.get(name) { + Some(v) => match v { + InfoCacheEntry::Pending(_) => None, + InfoCacheEntry::Ready(v) => Some( + v.iter() + .find(|v| &v.version == &ver) + .map(|b| b.features.clone()) + .unwrap_or_default(), + ), + }, + None => { + //INFO: thats probably fine, bc CratesIoStorage will exist until the lsp is stopped + let cpy = unsafe { (self as *const Self).as_ref() }.unwrap(); + let name = name.to_string(); + tokio::spawn(async move { cpy.versions_features(&name).await }); + None + } } } } - pub async fn get_features(&self, name: &str, version: &str, search: &str) -> Vec { - let search = search.to_lowercase(); - let temp = self.versions_features(name).await.ok(); - temp.and_then(|v| { - v.into_iter() - .find(|v| v.matches_version(version)) - .map(|v| v.features) + pub async fn get_features( + &self, + name: &str, + version: &str, + search: &str, + ) -> Option> { + let search_query = search.to_lowercase(); + let lock = self.data.read().await; + if let Some(v) = &*lock { + let search = v.exact_match(normalize_key(name))?; + let v = RustVersion::from(version); + let (_, versions) = search + .iter() + .find(|v| v.0.to_lowercase() == name.to_lowercase())?; + versions + .iter() + .find(|(version, _)| RustVersion::from(version.as_str()).eq(&v)) .map(|v| { - v.into_iter() - .map(|v| v.to_lowercase()) - .filter(|v| v.starts_with(&search)) - .collect::>() + v.1.iter() + .map(|v| v.to_string()) + .filter(|v| v.starts_with(&search_query)) + .collect() }) - }) - .unwrap_or_default() + } else { + let temp = self.versions_features(name).await.ok(); + temp.and_then(|v| { + v.into_iter() + .find(|v| v.matches_version(version)) + .map(|v| v.features) + .map(|v| { + v.into_iter() + .map(|v| v.to_lowercase()) + .filter(|v| v.starts_with(&search_query)) + .collect::>() + }) + }) + } } pub async fn get_versions(&self, name: &str, version_filter: &str) -> Option> { @@ -238,8 +292,8 @@ impl CratesIoStorage { Some( versions .iter() - .filter(|(version, features)| version.starts_with(version_filter)) - .map(|(version, features)| RustVersion::from(version.as_str())) + .filter(|(version, _)| version.starts_with(version_filter)) + .map(|(version, _)| RustVersion::from(version.as_str())) .collect::>(), ) } else { diff --git a/src/lsp.rs b/src/lsp.rs index 83f5459..3fb8056 100644 --- a/src/lsp.rs +++ b/src/lsp.rs @@ -514,6 +514,7 @@ impl LanguageServer for Backend { value, ) .await + .unwrap_or_default() .into_iter() .map(|v| CompletionItem { label: v.to_string(),