diff --git a/server/src/configuration_set.rs b/server/src/configuration_set.rs index aa0df48..7193959 100644 --- a/server/src/configuration_set.rs +++ b/server/src/configuration_set.rs @@ -3,6 +3,7 @@ use crate::slice_config::{compute_slice_options, ServerConfig, SliceConfig}; use crate::utils::sanitize_path; use std::collections::HashMap; +use std::path::PathBuf; use slicec::slice_options::SliceOptions; use slicec::{ast::Ast, diagnostics::Diagnostic, slice_file::SliceFile}; use slicec::compilation_state::CompilationState; @@ -10,7 +11,7 @@ use slicec::compilation_state::CompilationState; #[derive(Debug, Default)] pub struct CompilationData { pub ast: Ast, - pub files: HashMap, + pub files: HashMap, } // Necessary for using `CompilationData` within async functions. @@ -61,6 +62,9 @@ impl ConfigurationSet { // Process the diagnostics (filter out allowed lints, and update diagnostic levels as necessary). let updated_diagnostics = diagnostics.into_updated(&ast, &files, slice_options); + // Convert the stringified paths returned by `slicec` to actual PathBuf objects. + let files = files.into_iter().map(|(k, v)| (PathBuf::from(k), v)).collect(); + // Store the data we got from compiling, then return the diagnostics so they can be published. self.compilation_data = CompilationData { ast, files }; updated_diagnostics diff --git a/server/src/diagnostic_ext.rs b/server/src/diagnostic_ext.rs index 1b42b23..966769e 100644 --- a/server/src/diagnostic_ext.rs +++ b/server/src/diagnostic_ext.rs @@ -2,7 +2,7 @@ use crate::configuration_set::ConfigurationSet; use crate::session::Session; -use crate::utils::convert_slice_url_to_uri; +use crate::utils::convert_slice_path_to_uri; use crate::{notifications, show_popup}; use slicec::diagnostics::{Diagnostic, DiagnosticLevel, Note}; @@ -27,7 +27,7 @@ pub async fn publish_diagnostics_for_set( .compilation_data .files .keys() - .filter_map(|uri| Some((convert_slice_url_to_uri(uri)?, vec![]))) + .filter_map(|uri| Some((convert_slice_path_to_uri(uri)?, vec![]))) .collect::>>(); // Process the diagnostics and populate the map. @@ -87,7 +87,7 @@ pub fn process_diagnostics( let file = span .expect("If the span was empty, try_into_lsp_diagnostic should have hit the error case") .file; - let uri = convert_slice_url_to_uri(&file)?; + let uri = convert_slice_path_to_uri(file)?; Some((uri, lsp_diagnostic)) } Err(diagnostic) => { @@ -114,8 +114,7 @@ pub async fn clear_diagnostics(client: &Client, configuration_sets: &Mutex Option { let span = note.span.as_ref()?; - let file_path = convert_slice_url_to_uri(&span.file)?; + let file_path = convert_slice_path_to_uri(&span.file)?; let start_position = Position::new((span.start.row - 1) as u32, (span.start.col - 1) as u32); let end_position = Position::new((span.end.row - 1) as u32, (span.end.col - 1) as u32); diff --git a/server/src/main.rs b/server/src/main.rs index 47dc032..4b99c72 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -8,7 +8,7 @@ use crate::session::Session; use crate::slice_config::compute_slice_options; use std::{collections::HashMap, path::Path}; use tower_lsp::{jsonrpc::Error, lsp_types::*, Client, LanguageServer, LspService, Server}; -use utils::{convert_slice_url_to_uri, url_to_sanitized_file_path, FindFile}; +use utils::{convert_slice_path_to_uri, url_to_sanitized_file_path}; mod configuration_set; mod diagnostic_ext; @@ -71,9 +71,9 @@ impl Backend { } } - async fn handle_file_change(&self, file_name: &str) { + async fn handle_file_change(&self, file_path: &Path) { self.client - .log_message(MessageType::INFO, format!("File '{file_name}' changed")) + .log_message(MessageType::INFO, format!("File '{}' changed", file_path.display())) .await; let mut configuration_sets = self.session.configuration_sets.lock().await; @@ -89,7 +89,6 @@ impl Backend { .into_iter() .any(|f| { let key_path = Path::new(&f); - let file_path = Path::new(file_name); key_path == file_path || file_path.starts_with(key_path) }) }) { @@ -101,7 +100,7 @@ impl Backend { set.compilation_data .files .keys() - .filter_map(|uri| convert_slice_url_to_uri(uri)) + .filter_map(convert_slice_path_to_uri) .map(|uri| (uri, vec![])), ); } @@ -189,31 +188,28 @@ impl LanguageServer for Backend { // Find the configuration set that contains the file let configuration_sets = self.session.configuration_sets.lock().await; - let compilation_data = configuration_sets.iter().find_file(&file_path); // Get the definition span and convert it to a GotoDefinitionResponse - compilation_data - .and_then(|data| { - let file = data.files.get(&file_path).expect("mismatch in file name occurred during goto request"); - get_definition_span(file, position) - }) - .and_then(|location| { - let start = Position { - line: (location.start.row - 1) as u32, - character: (location.start.col - 1) as u32, - }; - let end = Position { - line: (location.end.row - 1) as u32, - character: (location.end.col - 1) as u32, - }; - convert_slice_url_to_uri(&location.file).map(|uri| { + Ok(configuration_sets.iter().find_map(|set| { + let files = &set.compilation_data.files; + files + .get(&file_path) + .and_then(|file| get_definition_span(file, position)) + .map(|location| { + let start = Position { + line: (location.start.row - 1) as u32, + character: (location.start.col - 1) as u32, + }; + let end = Position { + line: (location.end.row - 1) as u32, + character: (location.end.col - 1) as u32, + }; GotoDefinitionResponse::Scalar(Location { - uri, + uri: uri.clone(), range: Range::new(start, end), }) }) - }) - .map_or(Ok(None), |resp| Ok(Some(resp))) + })) } async fn hover(&self, params: HoverParams) -> tower_lsp::jsonrpc::Result> { @@ -226,13 +222,12 @@ impl LanguageServer for Backend { // Find the configuration set that contains the file and get the hover info let configuration_sets = self.session.configuration_sets.lock().await; - Ok(configuration_sets - .iter() - .find_file(&file_path) - .and_then(|data| { - let file = data.files.get(&file_path).expect("mismatch in file name occurred during hover request"); - try_into_hover_result(file, position).ok() - })) + Ok(configuration_sets.iter().find_map(|set| { + let files = &set.compilation_data.files; + files + .get(&file_path) + .and_then(|file| try_into_hover_result(file, position).ok()) + })) } async fn did_open(&self, params: DidOpenTextDocumentParams) { diff --git a/server/src/session.rs b/server/src/session.rs index ae65691..274186c 100644 --- a/server/src/session.rs +++ b/server/src/session.rs @@ -3,7 +3,6 @@ use crate::configuration_set::ConfigurationSet; use crate::slice_config::ServerConfig; use crate::utils::{sanitize_path, url_to_sanitized_file_path}; -use std::path::PathBuf; use tokio::sync::{Mutex, RwLock}; use tower_lsp::lsp_types::DidChangeConfigurationParams; @@ -31,7 +30,6 @@ impl Session { let workspace_root_path = params .root_uri .and_then(|uri| url_to_sanitized_file_path(&uri)) - .map(PathBuf::from) .map(|path| path.display().to_string()) .expect("`root_uri` was not sent by the client, or was malformed"); diff --git a/server/src/utils.rs b/server/src/utils.rs index 58e16c9..bc3613d 100644 --- a/server/src/utils.rs +++ b/server/src/utils.rs @@ -1,40 +1,18 @@ // Copyright (c) ZeroC, Inc. -use crate::configuration_set::{CompilationData, ConfigurationSet}; -use std::path::Path; +use std::path::{Path, PathBuf}; use tower_lsp::lsp_types::Url; -// A helper trait that allows us to find a file in an iterator of ConfigurationSet. -pub trait FindFile<'a> { - fn find_file(self, file_name: &str) -> Option<&'a CompilationData>; -} - -impl<'a, I> FindFile<'a> for I -where - I: Iterator, -{ - fn find_file(mut self, file_name: &str) -> Option<&'a CompilationData> { - self.find(|set| { - set.compilation_data.files.keys().any(|f| { - let key_path = Path::new(f); - let file_path = Path::new(file_name); - key_path == file_path || file_path.starts_with(key_path) - }) - }) - .map(|set| &set.compilation_data) - } -} - -// This helper function converts a Url from tower_lsp into a string that can be used to +// This helper function converts a Url from tower_lsp into a path that can be used to // retrieve a file from the compilation state from slicec. -pub fn url_to_sanitized_file_path(url: &Url) -> Option { +pub fn url_to_sanitized_file_path(url: &Url) -> Option { let path = url.to_file_path().ok()?; let path_string = path.to_str()?; - Some(sanitize_path(path_string)) + Some(PathBuf::from(sanitize_path(path_string))) } -pub fn convert_slice_url_to_uri(url: &str) -> Option { - Url::from_file_path(url).ok() +pub fn convert_slice_path_to_uri(path: impl AsRef) -> Option { + Url::from_file_path(path).ok() } #[cfg(target_os = "windows")]