diff --git a/src/error.rs b/src/error.rs index 51b6449..746d1aa 100644 --- a/src/error.rs +++ b/src/error.rs @@ -19,8 +19,14 @@ pub struct VersionError { impl VersionError { pub fn new(src: S1, detail: S2) -> Self { - let src = src.to_string(); - let pos = (0, src.len()).into(); + let mut src = src.to_string(); + let mut pos = (0, src.len()).into(); + let clean_src = src.trim_start_matches('^'); + + if let Some((arg_str, arg_pos)) = find_in_args(&clean_src) { + pos = arg_pos; + src = arg_str; + } Self { src, @@ -40,6 +46,13 @@ impl VersionError { pub fn not_installed(src: S) -> Self { Self::new(src, "The version is not installed.") } + + pub fn unsupported(src: S) -> Self { + Self::new( + src, + "This type of version string is not supported with this operation.", + ) + } } #[derive(Debug, Error, Diagnostic)] @@ -132,14 +145,18 @@ pub struct CommandNotFoundError { impl CommandNotFoundError { pub fn new(command: String, args: Vec, path: PathBuf) -> Self { - let pos = (0, command.len()).into(); - let full_command = format!( - "{command} {}", - args.into_iter() - .map(|a| a.into_string().unwrap_or_default()) - .collect::>() - .join(" ") - ); + let (full_command, pos) = find_in_args(&command).unwrap_or_else(|| { + let pos = (0, command.len()).into(); + let full_command = format!( + "{command} {}", + args.into_iter() + .map(|a| a.into_string().unwrap_or_default()) + .collect::>() + .join(" ") + ); + (full_command, pos) + }); + Self { command, full_command, @@ -161,3 +178,11 @@ pub struct MapDirError { #[source] pub caused_by: std::io::Error, } + +pub fn find_in_args(query: &str) -> Option<(String, SourceSpan)> { + let args_string = std::env::args().fold(String::new(), |s, acc| format!("{s} {acc}")); + + args_string + .find(&query) + .map(|index| (args_string, (index, query.len()).into())) +} diff --git a/src/nenv.rs b/src/nenv.rs index c842973..c25c79b 100644 --- a/src/nenv.rs +++ b/src/nenv.rs @@ -64,6 +64,8 @@ impl Nenv { #[tracing::instrument(skip(self))] pub async fn uninstall(&mut self, version: NodeVersion) -> Result<()> { + self.repo.lookup_local_version(&version)?; + if prompt( false, format!( @@ -237,7 +239,8 @@ impl Nenv { async fn get_mapper(&mut self) -> Result { let node_path = self .repo - .get_version_path(&self.active_version)? + .get_version_path(&self.active_version) + .await? .ok_or_else(|| VersionError::not_installed(self.active_version.to_owned()))?; Ok(Mapper::new(node_path)) } diff --git a/src/repository/local_versions.rs b/src/repository/local_versions.rs index d657ff2..c8f6783 100644 --- a/src/repository/local_versions.rs +++ b/src/repository/local_versions.rs @@ -66,18 +66,6 @@ impl InstalledVersions { self.ordered_versions.iter().map(|(v, _)| v).collect() } - pub fn latest(&self) -> Option<&VersionMetadata> { - self.ordered_versions.last().map(|(_, m)| m) - } - - pub fn latest_lts(&self) -> Option<&VersionMetadata> { - self.ordered_versions - .iter() - .filter(|(_, m)| m.lts.is_some()) - .last() - .map(|(_, m)| m) - } - pub fn lts>(&self, lts: S) -> Option<&VersionMetadata> { self.ordered_versions .iter() diff --git a/src/repository/mod.rs b/src/repository/mod.rs index f7d91e2..0e20a5f 100644 --- a/src/repository/mod.rs +++ b/src/repository/mod.rs @@ -149,8 +149,12 @@ impl Repository { /// Returns the path for the given node version #[tracing::instrument(level = "debug", skip(self))] - pub fn get_version_path(&mut self, version: &NodeVersion) -> Result> { - let info = self.lookup_local_version(version)?; + pub async fn get_version_path(&mut self, version: &NodeVersion) -> Result> { + let info = if let Ok(i) = self.lookup_local_version(version) { + i + } else { + self.lookup_remote_version(version).await? + }; let path = build_version_path(&info.version); Ok(if path.exists() { @@ -239,18 +243,13 @@ impl Repository { pub fn lookup_local_version(&self, version_req: &NodeVersion) -> Result<&VersionMetadata> { let versions = &self.installed_versions; let version = match version_req { - NodeVersion::Latest => versions - .latest() - .ok_or_else(|| VersionError::not_installed("latest"))?, - NodeVersion::LatestLts => versions - .latest_lts() - .ok_or_else(|| VersionError::not_installed("lts"))?, NodeVersion::Lts(lts) => versions .lts(lts) .ok_or_else(|| VersionError::unknown_version(lts.to_owned()))?, NodeVersion::Req(req) => versions .fulfilling(req) .ok_or_else(|| VersionError::unfulfillable_version(req.to_owned()))?, + _ => return Err(VersionError::unsupported(version_req.to_owned()).into()), }; Ok(version)