diff --git a/kclvm/driver/src/kpm.rs b/kclvm/driver/src/kpm.rs deleted file mode 100644 index 2bba1a9d3..000000000 --- a/kclvm/driver/src/kpm.rs +++ /dev/null @@ -1,281 +0,0 @@ -use crate::{kcl, lookup_the_nearest_file_dir}; -use anyhow::{bail, Result}; -use kclvm_config::modfile::KCL_MOD_FILE; -use kclvm_parser::LoadProgramOptions; -use notify::{RecursiveMode, Watcher}; -use serde::{Deserialize, Serialize}; -use std::marker::Send; -use std::{ - collections::HashMap, - fs::File, - io::Write, - path::PathBuf, - process::Command, - sync::{mpsc::channel, Arc, Mutex}, -}; - -/// Searches for the nearest kcl.mod directory containing the given file and fills the compilation options -/// with metadata of dependent packages. -/// -/// # Arguments -/// -/// * `k_file_path` - Path to the K file for which metadata is needed. -/// * `opts` - Mutable reference to the compilation options to fill. -/// -/// # Returns -/// -/// * `Result<()>` - Empty result if successful, error otherwise. -pub(crate) fn fill_pkg_maps_for_k_file( - k_file_path: PathBuf, - opts: &mut LoadProgramOptions, -) -> Result<()> { - match lookup_the_nearest_file_dir(k_file_path, KCL_MOD_FILE) { - Some(mod_dir) => { - let metadata = fetch_metadata(mod_dir.canonicalize()?)?; - let maps: HashMap = metadata - .packages - .into_iter() - .map(|(pname, pkg)| (pname, pkg.manifest_path.display().to_string())) - .collect(); - opts.package_maps.extend(maps); - } - None => return Ok(()), - }; - - Ok(()) -} - -/// Trait for writing messages to a file. -pub trait Writer { - fn write_message(&mut self, message: &str) -> Result<()>; -} - -impl Writer for File { - /// Writes a message to the file followed by a newline. - /// - /// # Arguments - /// - /// * `message` - The message to write. - /// - /// # Returns - /// - /// * `Result<()>` - Empty result if successful, error otherwise. - fn write_message(&mut self, message: &str) -> Result<()> { - writeln!(self, "{}", message)?; - Ok(()) - } -} - -/// Watches for modifications in the kcl.mod file within the given directory and updates dependencies accordingly. -/// -/// # Arguments -/// -/// * `directory` - The directory containing the kcl.mod file to watch. -/// * `writer` - The writer for outputting log messages. -/// -/// # Returns -/// -/// * `Result<()>` - Empty result if successful, error otherwise. -pub fn watch_kcl_mod(directory: PathBuf, writer: W) -> Result<()> { - let writer = Arc::new(Mutex::new(writer)); // Wrap writer in Arc> for thread safety - let (sender, receiver) = channel(); - let writer_clone = Arc::clone(&writer); // Create a clone of writer for the closure - - let mut watcher = notify::recommended_watcher(move |res| { - if let Err(err) = sender.send(res) { - let mut writer = writer_clone.lock().unwrap(); // Lock the mutex before using writer - writer - .write_message(&format!("Error sending event to channel: {:?}", err)) - .ok(); - } - })?; - - watcher.watch(&directory, RecursiveMode::NonRecursive)?; - - loop { - match receiver.recv() { - Ok(event) => { - match event { - Ok(event) => match event.kind { - notify::event::EventKind::Modify(modify_kind) => { - if let notify::event::ModifyKind::Data(data_change) = modify_kind { - if data_change == notify::event::DataChange::Content { - let mut writer = writer.lock().unwrap(); // Lock the mutex before using writer - writer.write_message("kcl.mod file content modified. Updating dependencies...").ok(); - update_dependencies(directory.clone())?; - } - } - } - _ => {} - }, - Err(err) => { - let mut writer = writer.lock().unwrap(); // Lock the mutex before using writer - writer - .write_message(&format!("Watcher error: {:?}", err)) - .ok(); - } - } - } - Err(e) => { - let mut writer = writer.lock().unwrap(); // Lock the mutex before using writer - writer - .write_message(&format!("Receiver error: {:?}", e)) - .ok(); - } - } - } -} - -impl Writer for Arc> -where - W: Writer, -{ - /// Writes a message using the wrapped writer. - /// - /// # Arguments - /// - /// * `message` - The message to write. - /// - /// # Returns - /// - /// * `Result<()>` - Empty result if successful, error otherwise. - fn write_message(&mut self, message: &str) -> Result<()> { - self.lock().unwrap().write_message(message) - } -} - -/// Tracks changes in the kcl.mod file within the given working directory and watches for updates. -/// -/// # Arguments -/// -/// * `work_dir` - The working directory where the kcl.mod file is located. -/// -/// # Returns -/// -/// * `Result<()>` - Empty result if successful, error otherwise. -pub fn kcl_mod_file_track(work_dir: PathBuf, writer: W) -> Result<()> -where - W: Writer + Send + 'static, -{ - let writer = Arc::new(Mutex::new(writer)); // Wrap writer in Arc> for thread safety - - let directory = match lookup_the_nearest_file_dir(work_dir.clone(), KCL_MOD_FILE) { - Some(mod_dir) => mod_dir, - None => { - let mut writer = writer.lock().unwrap(); // Lock the writer - writer.write_message(&format!( - "Manifest file '{}' not found in directory hierarchy", - KCL_MOD_FILE - ))?; - return Ok(()); - } - }; - - if let Err(err) = watch_kcl_mod(directory, Arc::clone(&writer)) { - let mut writer = writer.lock().unwrap(); // Lock the writer - writer.write_message(&format!("Error watching kcl.mod file: {:?}", err))?; - } - Ok(()) -} - -#[derive(Deserialize, Serialize, Default, Debug, Clone)] - -/// [`Metadata`] is the metadata of the current KCL module, -/// currently only the mapping between the name and path of the external dependent package is included. -pub struct Metadata { - pub packages: HashMap, -} - -/// Structure representing a package. -#[derive(Clone, Debug, Serialize, Deserialize)] -/// [`Package`] is a kcl package. -pub struct Package { - /// Name as given in the `kcl.mod` - pub name: String, - /// Path containing the `kcl.mod` - pub manifest_path: PathBuf, -} - -impl Metadata { - /// Parses metadata from a string. - /// - /// # Arguments - /// - /// * `data` - The string containing metadata. - /// - /// # Returns - /// - /// * `Result` - Metadata if successful, error otherwise. - fn parse(data: String) -> Result { - let meta = serde_json::from_str(data.as_ref())?; - Ok(meta) - } -} - -/// Fetches metadata of packages from the kcl.mod file within the given directory. -/// -/// # Arguments -/// -/// * `manifest_path` - The path to the directory containing the kcl.mod file. -/// -/// # Returns -/// -/// * `Result` - Metadata if successful, error otherwise. -pub fn fetch_metadata(manifest_path: PathBuf) -> Result { - match Command::new(kcl()) - .arg("mod") - .arg("metadata") - .current_dir(manifest_path) - .output() - { - Ok(output) => { - if !output.status.success() { - bail!( - "fetch metadata failed with error: {}", - String::from_utf8_lossy(&output.stderr) - ); - } - Ok(Metadata::parse( - String::from_utf8_lossy(&output.stdout).to_string(), - )?) - } - Err(err) => bail!("fetch metadata failed with error: {}", err), - } -} - -/// Updates dependencies for the kcl.mod file within the given directory. -/// -/// # Arguments -/// -/// * `work_dir` - The working directory containing the kcl.mod file. -/// -/// # Returns -/// -/// * `Result<()>` - Empty result if successful, error otherwise. -pub fn update_dependencies(work_dir: PathBuf) -> Result<()> { - match lookup_the_nearest_file_dir(work_dir.clone(), KCL_MOD_FILE) { - Some(mod_dir) => { - match Command::new(kcl()) - .arg("mod") - .arg("update") - .current_dir(mod_dir) - .output() - { - Ok(output) => { - if !output.status.success() { - bail!( - "update failed with error: {}", - String::from_utf8_lossy(&output.stderr) - ); - } - Ok(()) - } - Err(err) => bail!("update failed with error: {}", err), - } - } - None => bail!( - "Manifest file '{}' not found in directory hierarchy", - KCL_MOD_FILE - ), - } -} diff --git a/kclvm/driver/src/lib.rs b/kclvm/driver/src/lib.rs index d8bee4063..3ef432cf9 100644 --- a/kclvm/driver/src/lib.rs +++ b/kclvm/driver/src/lib.rs @@ -1,7 +1,6 @@ use anyhow::Result; pub mod arguments; -pub mod kpm; -pub const DEFAULT_PROJECT_FILE: &str = "project.yaml"; +pub mod toolchain; #[cfg(test)] mod tests; @@ -16,8 +15,7 @@ use kclvm_config::{ settings::{build_settings_pathbuf, DEFAULT_SETTING_FILE}, }; use kclvm_parser::LoadProgramOptions; -use kclvm_utils::{path::PathPrefix, pkgpath::rm_external_pkg_name}; -use kpm::{fetch_metadata, fill_pkg_maps_for_k_file}; +use kclvm_utils::path::PathPrefix; use std::env; use std::iter; use std::{ @@ -26,6 +24,7 @@ use std::{ io::{self, ErrorKind}, path::{Path, PathBuf}, }; +use toolchain::{fill_pkg_maps_for_k_file, Toolchain}; use walkdir::WalkDir; /// Expand the single file pattern to a list of files. @@ -133,12 +132,9 @@ pub fn canonicalize_input_files( /// 2. Lookup entry files in kcl.mod /// 3. If not found, consider the path or folder where the file is /// located as the compilation entry point -pub fn lookup_compile_unit( - file: &str, - load_pkg: bool, -) -> (Vec, Option) { +pub fn lookup_compile_unit(tool: &dyn Toolchain, file: &str, load_pkg: bool) -> CompileUnitOptions { match lookup_compile_unit_path(file) { - Ok(CompileUnit::SettingFile(dir)) => { + Ok(CompileUnitPath::SettingFile(dir)) => { let settings_files = lookup_setting_files(&dir); let files = if settings_files.is_empty() { vec![file] @@ -164,7 +160,7 @@ pub fn lookup_compile_unit( match canonicalize_input_files(&files, work_dir, true) { Ok(kcl_paths) => { // 1. find the kcl.mod path - let _ = fill_pkg_maps_for_k_file(file.into(), &mut load_opt); + let _ = fill_pkg_maps_for_k_file(tool, file.into(), &mut load_opt); (kcl_paths, Some(load_opt)) } Err(_) => (vec![file.to_string()], None), @@ -173,18 +169,15 @@ pub fn lookup_compile_unit( Err(_) => (vec![file.to_string()], None), } } - Ok(CompileUnit::ModFile(dir)) => match load_mod_file(&dir) { + Ok(CompileUnitPath::ModFile(dir)) => match load_mod_file(&dir) { Ok(mod_file) => { let mut load_opt = kclvm_parser::LoadProgramOptions::default(); - let _ = fill_pkg_maps_for_k_file(file.into(), &mut load_opt); + let _ = fill_pkg_maps_for_k_file(tool, file.into(), &mut load_opt); if let Some(files) = mod_file.get_entries() { let work_dir = dir.to_string_lossy().to_string(); load_opt.work_dir = work_dir.clone(); match canonicalize_input_files(&files, work_dir, true) { - Ok(kcl_paths) => { - let _ = fill_pkg_maps_for_k_file(file.into(), &mut load_opt); - (kcl_paths, Some(load_opt)) - } + Ok(kcl_paths) => (kcl_paths, Some(load_opt)), Err(_) => (vec![file.to_string()], None), } } else { @@ -205,9 +198,9 @@ pub fn lookup_compile_unit( } Err(_) => (vec![file.to_string()], None), }, - Ok(CompileUnit::NotFound) | Err(_) => { + Ok(CompileUnitPath::NotFound) | Err(_) => { let mut load_opt = kclvm_parser::LoadProgramOptions::default(); - let _ = fill_pkg_maps_for_k_file(file.into(), &mut load_opt); + let _ = fill_pkg_maps_for_k_file(tool, file.into(), &mut load_opt); if load_pkg { let path = Path::new(file); @@ -248,10 +241,12 @@ fn lookup_kcl_yaml(dir: &Path) -> io::Result { } } -/// CompileUnit is the kcl program default entries that are defined +pub type CompileUnitOptions = (Vec, Option); + +/// CompileUnitPath is the kcl program default entries that are defined /// in the config files. #[derive(Debug, PartialEq, Eq, Clone)] -pub enum CompileUnit { +pub enum CompileUnitPath { SettingFile(PathBuf), ModFile(PathBuf), NotFound, @@ -260,8 +255,9 @@ pub enum CompileUnit { /// For the KCL project, some definitions may be introduced through multi-file /// compilation (kcl.yaml). This function is used to start from a single file and try /// to find a `compile unit` that contains all definitions -/// Given a file path, search for the nearest "kcl.yaml" file or the nearest "project.yaml" file. +/// Given a file path, search for the nearest "kcl.yaml" file or the nearest "kcl.mod" file. /// If a "kcl.yaml" file is found, return the path of the directory containing the file. +/// If a "kcl.mod" file is found, return the path of the directory containing the file. /// If none of these files are found, return an error indicating that the files were not found. /// /// Example: @@ -278,7 +274,7 @@ pub enum CompileUnit { /// /// If the input file is project/prod/main.k or project/test/main.k, it will return /// Path("project/prod") or Path("project/test") -pub fn lookup_compile_unit_path(file: &str) -> io::Result { +pub fn lookup_compile_unit_path(file: &str) -> io::Result { let path = PathBuf::from(file); let current_dir_path = path.as_path().parent().unwrap(); let entries = read_dir(current_dir_path)?; @@ -288,12 +284,14 @@ pub fn lookup_compile_unit_path(file: &str) -> io::Result { if entry.file_name() == *DEFAULT_SETTING_FILE { // If find "kcl.yaml", the input file is in a compile stack, return the // path of this compile stack - return Ok(CompileUnit::SettingFile(PathBuf::from(current_dir_path))); + return Ok(CompileUnitPath::SettingFile(PathBuf::from( + current_dir_path, + ))); } else if entry.file_name() == *KCL_MOD_FILE { - return Ok(CompileUnit::ModFile(PathBuf::from(current_dir_path))); + return Ok(CompileUnitPath::ModFile(PathBuf::from(current_dir_path))); } } - Ok(CompileUnit::NotFound) + Ok(CompileUnitPath::NotFound) } /// Get kcl files from path. @@ -458,35 +456,3 @@ fn probe(path: PathBuf) -> Option { .chain(with_extension) .find(|it| it.is_file()) } - -/// [`get_real_path_from_external`] will ask for the local path for [`pkg_name`] with subdir [`pkgpath`]. -/// If the external package, whose [`pkg_name`] is 'my_package', is stored in '\user\my_package_v0.0.1'. -/// The [`pkgpath`] is 'my_package.examples.apps'. -/// -/// [`get_real_path_from_external`] will return '\user\my_package_v0.0.1\examples\apps' -/// -/// # Note -/// [`get_real_path_from_external`] is just a method for calculating a path, it doesn't check whether a path exists. -pub fn get_real_path_from_external( - pkg_name: &str, - pkgpath: &str, - current_pkg_path: PathBuf, -) -> PathBuf { - let mut real_path = PathBuf::new(); - let pkg_root = fetch_metadata(current_pkg_path) - .map(|metadata| { - metadata - .packages - .get(pkg_name) - .map_or(PathBuf::new(), |pkg| pkg.manifest_path.clone()) - }) - .unwrap_or_else(|_| PathBuf::new()); - real_path = real_path.join(pkg_root); - - let pkgpath = match rm_external_pkg_name(pkgpath) { - Ok(path) => path, - Err(_) => String::new(), - }; - pkgpath.split('.').for_each(|s| real_path.push(s)); - real_path -} diff --git a/kclvm/driver/src/tests.rs b/kclvm/driver/src/tests.rs index d98d30c8c..2ecf2d855 100644 --- a/kclvm/driver/src/tests.rs +++ b/kclvm/driver/src/tests.rs @@ -7,9 +7,10 @@ use kclvm_parser::LoadProgramOptions; use walkdir::WalkDir; use crate::arguments::parse_key_value_pair; -use crate::kpm::{fetch_metadata, fill_pkg_maps_for_k_file, update_dependencies}; -use crate::lookup_the_nearest_file_dir; +use crate::toolchain::fill_pkg_maps_for_k_file; +use crate::toolchain::Toolchain; use crate::{canonicalize_input_files, expand_input_files, get_pkg_list}; +use crate::{lookup_the_nearest_file_dir, toolchain}; #[test] fn test_canonicalize_input_files() { @@ -199,7 +200,7 @@ fn test_fill_pkg_maps_for_k_file_with_line() { let mut opts = LoadProgramOptions::default(); assert_eq!(format!("{:?}", opts.package_maps), "{}"); - let res = fill_pkg_maps_for_k_file(main_pkg_path.clone(), &mut opts); + let res = fill_pkg_maps_for_k_file(&toolchain::default(), main_pkg_path.clone(), &mut opts); assert!(res.is_ok()); let pkg_maps = opts.package_maps.clone(); @@ -241,7 +242,7 @@ fn test_fill_pkg_maps_for_k_file() { let mut opts = LoadProgramOptions::default(); assert_eq!(format!("{:?}", opts.package_maps), "{}"); - let res = fill_pkg_maps_for_k_file(path.clone(), &mut opts); + let res = fill_pkg_maps_for_k_file(&toolchain::default(), path.clone(), &mut opts); assert!(res.is_ok()); let vendor_home = get_vendor_home(); @@ -316,7 +317,8 @@ fn test_fetch_metadata() { ); let vendor_home = get_vendor_home(); - let metadata = fetch_metadata(path.clone()); + let tool = toolchain::default(); + let metadata = tool.fetch_metadata(path.clone()); // Show more information when the test fails. println!("{:?}", metadata); assert!(metadata.is_ok()); @@ -346,7 +348,8 @@ fn test_fetch_metadata() { #[test] fn test_fetch_metadata_invalid() { let result = panic::catch_unwind(|| { - let result = fetch_metadata("invalid_path".to_string().into()); + let tool = toolchain::default(); + let result = tool.fetch_metadata("invalid_path".to_string().into()); match result { Ok(_) => { panic!("The method should not return Ok") @@ -378,7 +381,8 @@ fn test_update_dependencies() { .join("test_data") .join("kpm_update"); - let update_mod = update_dependencies(path.clone()); + let tool = toolchain::default(); + let update_mod = tool.update_dependencies(path.clone()); // Show more information when the test fails. println!("{:?}", update_mod); assert!(update_mod.is_ok()); diff --git a/kclvm/driver/src/toolchain.rs b/kclvm/driver/src/toolchain.rs new file mode 100644 index 000000000..c753bd297 --- /dev/null +++ b/kclvm/driver/src/toolchain.rs @@ -0,0 +1,203 @@ +use crate::{kcl, lookup_the_nearest_file_dir}; +use anyhow::{bail, Result}; +use kclvm_config::modfile::KCL_MOD_FILE; +use kclvm_parser::LoadProgramOptions; +use kclvm_utils::pkgpath::rm_external_pkg_name; +use serde::{Deserialize, Serialize}; +use std::ffi::OsStr; +use std::{collections::HashMap, path::PathBuf, process::Command}; + +/// `Toolchain` is a trait that outlines a standard set of operations that must be +/// implemented for a KCL module (mod), typically involving fetching metadata from, +/// and updating dependencies within, a specified path. +pub trait Toolchain: Send + Sync { + /// Fetches the metadata from the given manifest file path. + /// + /// The `manifest_path` parameter is generic over P, meaning it can be any type that + /// implements the `AsRef` trait. It is commonly a reference to a file path or a type + /// that can be converted into a file path reference, such as `String` or `PathBuf`. + /// + /// The return type `Result` indicates that this method will either return an + /// instance of `Metadata` or an error. + /// + /// # Parameters + /// + /// * `manifest_path` - A reference to the path of the manifest file, expected to be a type + /// that can be converted into a reference to a filesystem path. + fn fetch_metadata(&self, manifest_path: PathBuf) -> Result; + + /// Updates the dependencies as defined within the given manifest file path. + /// + /// The `manifest_path` parameter is generic over P, just like in the `fetch_metadata` method, + /// and is used to specify the location of the manifest file. + /// + /// The return type `Result<()>` indicates that this method will execute without returning a + /// value upon success but may return an error. + /// + /// # Parameters + /// + /// * `manifest_path` - A reference to the path of the manifest file, expected to be a type + /// that can be converted into a reference to a filesystem path. + fn update_dependencies(&self, manifest_path: PathBuf) -> Result<()>; +} + +#[derive(Debug, Clone)] +pub struct CommandToolchain> { + path: S, +} + +impl Default for CommandToolchain { + fn default() -> Self { + Self { path: kcl() } + } +} + +impl + Send + Sync> Toolchain for CommandToolchain { + fn fetch_metadata(&self, manifest_path: PathBuf) -> Result { + match Command::new(&self.path) + .arg("mod") + .arg("metadata") + .current_dir(manifest_path) + .output() + { + Ok(output) => { + if !output.status.success() { + bail!( + "fetch metadata failed with error: {}", + String::from_utf8_lossy(&output.stderr) + ); + } + Ok(Metadata::parse( + String::from_utf8_lossy(&output.stdout).to_string(), + )?) + } + Err(err) => bail!("fetch metadata failed with error: {}", err), + } + } + + fn update_dependencies(&self, manifest_path: PathBuf) -> Result<()> { + match Command::new(&self.path) + .arg("mod") + .arg("update") + .current_dir(manifest_path) + .output() + { + Ok(output) => { + if !output.status.success() { + bail!( + "update failed with error: {}", + String::from_utf8_lossy(&output.stderr) + ); + } + Ok(()) + } + Err(err) => bail!("update failed with error: {}", err), + } + } +} + +#[derive(Deserialize, Serialize, Default, Debug, Clone)] + +/// [`Metadata`] is the metadata of the current KCL module, +/// currently only the mapping between the name and path of the external dependent package is included. +pub struct Metadata { + pub packages: HashMap, +} + +/// Structure representing a package. +#[derive(Clone, Debug, Serialize, Deserialize)] +/// [`Package`] is a kcl package. +pub struct Package { + /// Name as given in the `kcl.mod` + pub name: String, + /// Path containing the `kcl.mod` + pub manifest_path: PathBuf, +} + +impl Metadata { + /// Parses metadata from a string. + /// + /// # Arguments + /// + /// * `data` - The string containing metadata. + /// + /// # Returns + /// + /// * `Result` - Metadata if successful, error otherwise. + fn parse(data: String) -> Result { + let meta = serde_json::from_str(data.as_ref())?; + Ok(meta) + } +} + +/// [`default`] returns the default toolchain. +#[inline] +pub fn default() -> impl Toolchain { + CommandToolchain::default() +} + +/// Searches for the nearest kcl.mod directory containing the given file and fills the compilation options +/// with metadata of dependent packages. +/// +/// # Arguments +/// +/// * `k_file_path` - Path to the K file for which metadata is needed. +/// * `opts` - Mutable reference to the compilation options to fill. +/// +/// # Returns +/// +/// * `Result<()>` - Empty result if successful, error otherwise. +pub(crate) fn fill_pkg_maps_for_k_file( + tool: &dyn Toolchain, + k_file_path: PathBuf, + opts: &mut LoadProgramOptions, +) -> Result<()> { + match lookup_the_nearest_file_dir(k_file_path, KCL_MOD_FILE) { + Some(mod_dir) => { + let metadata = tool.fetch_metadata(mod_dir.canonicalize()?)?; + let maps: HashMap = metadata + .packages + .into_iter() + .map(|(name, pkg)| (name, pkg.manifest_path.display().to_string())) + .collect(); + opts.package_maps.extend(maps); + } + None => return Ok(()), + }; + + Ok(()) +} + +/// [`get_real_path_from_external`] will ask for the local path for [`pkg_name`] with subdir [`pkgpath`]. +/// If the external package, whose [`pkg_name`] is 'my_package', is stored in '\user\my_package_v0.0.1'. +/// The [`pkgpath`] is 'my_package.examples.apps'. +/// +/// [`get_real_path_from_external`] will return '\user\my_package_v0.0.1\examples\apps' +/// +/// # Note +/// [`get_real_path_from_external`] is just a method for calculating a path, it doesn't check whether a path exists. +pub fn get_real_path_from_external( + tool: &dyn Toolchain, + pkg_name: &str, + pkgpath: &str, + current_pkg_path: PathBuf, +) -> PathBuf { + let mut real_path = PathBuf::new(); + let pkg_root = tool + .fetch_metadata(current_pkg_path) + .map(|metadata| { + metadata + .packages + .get(pkg_name) + .map_or(PathBuf::new(), |pkg| pkg.manifest_path.clone()) + }) + .unwrap_or_else(|_| PathBuf::new()); + real_path = real_path.join(pkg_root); + + let pkgpath = match rm_external_pkg_name(pkgpath) { + Ok(path) => path, + Err(_) => String::new(), + }; + pkgpath.split('.').for_each(|s| real_path.push(s)); + real_path +} diff --git a/kclvm/tools/src/LSP/src/analysis.rs b/kclvm/tools/src/LSP/src/analysis.rs index d700ca845..eafa3e67a 100644 --- a/kclvm/tools/src/LSP/src/analysis.rs +++ b/kclvm/tools/src/LSP/src/analysis.rs @@ -1,9 +1,21 @@ -use crate::db::AnalysisDatabase; +use kclvm_ast::ast::Program; +use kclvm_sema::core::global_state::GlobalState; use parking_lot::RwLock; use ra_ap_vfs::FileId; use std::{collections::HashMap, sync::Arc}; +pub type DocumentVersion = i32; + +/// Analysis holds the analysis mapping (FileId -> AnalysisDatabase) #[derive(Default)] pub struct Analysis { pub db: Arc>>>, } + +/// AnalysisDatabase holds the result of the compile +#[derive(Default, Clone)] +pub struct AnalysisDatabase { + pub prog: Program, + pub gs: GlobalState, + pub version: DocumentVersion, +} diff --git a/kclvm/tools/src/LSP/src/completion.rs b/kclvm/tools/src/LSP/src/completion.rs index 29bf3aa71..7abfd17e5 100644 --- a/kclvm/tools/src/LSP/src/completion.rs +++ b/kclvm/tools/src/LSP/src/completion.rs @@ -18,14 +18,14 @@ use std::io; use std::{fs, path::Path}; -use crate::goto_def::find_def_with_gs; +use crate::goto_def::find_def; use indexmap::IndexSet; use kclvm_ast::ast::{self, ImportStmt, Program, Stmt}; use kclvm_ast::MAIN_PKG; use kclvm_config::modfile::KCL_FILE_EXTENSION; +use kclvm_driver::toolchain::{get_real_path_from_external, Toolchain}; use kclvm_sema::core::global_state::GlobalState; -use kclvm_driver::get_real_path_from_external; use kclvm_error::Position as KCLPos; use kclvm_sema::builtin::{BUILTIN_FUNCTIONS, STANDARD_SYSTEM_MODULES}; use kclvm_sema::core::package::ModuleInfo; @@ -79,10 +79,11 @@ pub(crate) fn completion( program: &Program, pos: &KCLPos, gs: &GlobalState, + tool: &dyn Toolchain, ) -> Option { match trigger_character { Some(c) => match c { - '.' => completion_dot(program, pos, gs), + '.' => completion_dot(program, pos, gs, tool), '=' | ':' => completion_assign(pos, gs), '\n' => completion_newline(program, pos, gs), _ => None, @@ -214,6 +215,7 @@ fn completion_dot( program: &Program, pos: &KCLPos, gs: &GlobalState, + tool: &dyn Toolchain, ) -> Option { let mut items: IndexSet = IndexSet::new(); @@ -226,7 +228,7 @@ fn completion_dot( if let Some(stmt) = program.pos_to_stmt(&pre_pos) { match stmt.node { - Stmt::Import(stmt) => return completion_import(&stmt, pos, program), + Stmt::Import(stmt) => return completion_import(&stmt, pos, program, tool), _ => { let (expr, _) = inner_most_expr_in_stmt(&stmt.node, pos, None); if let Some(node) = expr { @@ -243,9 +245,9 @@ fn completion_dot( } // look_up_exact_symbol - let mut def = find_def_with_gs(&pre_pos, gs, true); + let mut def = find_def(&pre_pos, gs, true); if def.is_none() { - def = find_def_with_gs(pos, gs, false); + def = find_def(pos, gs, false); } match def { @@ -322,7 +324,7 @@ fn completion_dot( /// Now, just completion for schema attr value fn completion_assign(pos: &KCLPos, gs: &GlobalState) -> Option { let mut items = IndexSet::new(); - if let Some(symbol_ref) = find_def_with_gs(pos, gs, false) { + if let Some(symbol_ref) = find_def(pos, gs, false) { if let Some(symbol) = gs.get_symbols().get_symbol(symbol_ref) { if let Some(def) = symbol.get_definition() { match def.get_kind() { @@ -570,6 +572,7 @@ fn completion_import( stmt: &ImportStmt, _pos: &KCLPos, program: &Program, + tool: &dyn Toolchain, ) -> Option { let mut items: IndexSet = IndexSet::new(); let pkgpath = &stmt.path.node; @@ -577,7 +580,7 @@ fn completion_import( Path::new(&program.root).join(pkgpath.replace('.', std::path::MAIN_SEPARATOR_STR)); if !real_path.exists() { real_path = - get_real_path_from_external(&stmt.pkg_name, pkgpath, program.root.clone().into()); + get_real_path_from_external(tool, &stmt.pkg_name, pkgpath, program.root.clone().into()); } if real_path.is_dir() { if let Ok(entries) = fs::read_dir(real_path) { @@ -734,6 +737,7 @@ pub(crate) fn into_completion_items(items: &IndexSet) -> Vec< #[cfg(test)] mod tests { use indexmap::IndexSet; + use kclvm_driver::toolchain; use kclvm_error::Position as KCLPos; use kclvm_sema::builtin::{BUILTIN_FUNCTIONS, MATH_FUNCTION_TYPES, STRING_MEMBER_FUNCTIONS}; use lsp_types::{CompletionItem, CompletionItemKind, CompletionResponse, InsertTextFormat}; @@ -760,7 +764,8 @@ mod tests { column: Some(1), }; - let got = completion(None, &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(None, &program, &pos, &gs, &tool).unwrap(); let mut got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -792,7 +797,7 @@ mod tests { column: Some(4), }; - let got = completion(None, &program, &pos, &gs).unwrap(); + let got = completion(None, &program, &pos, &gs, &tool).unwrap(); let mut got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -820,7 +825,8 @@ mod tests { column: Some(7), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -836,7 +842,7 @@ mod tests { }; // test completion for str builtin function - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match &got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -867,7 +873,7 @@ mod tests { column: Some(12), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -883,7 +889,7 @@ mod tests { column: Some(12), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -897,7 +903,7 @@ mod tests { line: 19, column: Some(5), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -915,7 +921,7 @@ mod tests { column: Some(4), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -933,7 +939,7 @@ mod tests { column: Some(11), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -956,7 +962,8 @@ mod tests { column: Some(7), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -972,7 +979,7 @@ mod tests { }; // test completion for str builtin function - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -990,7 +997,7 @@ mod tests { column: Some(12), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1006,7 +1013,7 @@ mod tests { column: Some(12), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1020,7 +1027,7 @@ mod tests { line: 19, column: Some(5), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match &got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1051,7 +1058,7 @@ mod tests { column: Some(4), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match &got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1082,7 +1089,7 @@ mod tests { column: Some(11), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1106,7 +1113,8 @@ mod tests { column: Some(8), }; - let got = completion(None, &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(None, &program, &pos, &gs, &tool).unwrap(); let _got_labels: Vec = match &got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1153,7 +1161,8 @@ mod tests { column: Some(6), }; - let got = completion(Some(':'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(Some(':'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1166,7 +1175,7 @@ mod tests { line: 16, column: Some(6), }; - let got = completion(Some(':'), &program, &pos, &gs).unwrap(); + let got = completion(Some(':'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1179,7 +1188,7 @@ mod tests { line: 18, column: Some(6), }; - let got = completion(Some(':'), &program, &pos, &gs).unwrap(); + let got = completion(Some(':'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1192,7 +1201,7 @@ mod tests { line: 20, column: Some(6), }; - let got = completion(Some(':'), &program, &pos, &gs).unwrap(); + let got = completion(Some(':'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1205,7 +1214,7 @@ mod tests { line: 22, column: Some(6), }; - let got = completion(Some(':'), &program, &pos, &gs).unwrap(); + let got = completion(Some(':'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1218,7 +1227,7 @@ mod tests { line: 24, column: Some(6), }; - let got = completion(Some(':'), &program, &pos, &gs).unwrap(); + let got = completion(Some(':'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1231,7 +1240,7 @@ mod tests { line: 26, column: Some(6), }; - let got = completion(Some(':'), &program, &pos, &gs).unwrap(); + let got = completion(Some(':'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1252,7 +1261,8 @@ mod tests { column: Some(5), }; - let mut got = completion(None, &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let mut got = completion(None, &program, &pos, &gs, &tool).unwrap(); match &mut got { CompletionResponse::Array(arr) => { assert_eq!( @@ -1286,7 +1296,8 @@ mod tests { column: Some(4), }; - let mut got = completion(Some('\n'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let mut got = completion(Some('\n'), &program, &pos, &gs, &tool).unwrap(); match &mut got { CompletionResponse::Array(arr) => { arr.sort_by(|a, b| a.label.cmp(&b.label)); @@ -1310,7 +1321,7 @@ mod tests { line: 5, column: Some(4), }; - let got = completion(Some('\n'), &program, &pos, &gs).unwrap(); + let got = completion(Some('\n'), &program, &pos, &gs, &tool).unwrap(); match got { CompletionResponse::Array(arr) => { assert!(arr.is_empty()) @@ -1329,8 +1340,8 @@ mod tests { line: 3, column: Some(4), }; - - let mut got = completion(Some('\n'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let mut got = completion(Some('\n'), &program, &pos, &gs, &tool).unwrap(); match &mut got { CompletionResponse::Array(arr) => { arr.sort_by(|a, b| a.label.cmp(&b.label)); @@ -1361,7 +1372,8 @@ mod tests { column: Some(10), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); match &got { CompletionResponse::Array(arr) => { @@ -1402,7 +1414,7 @@ mod tests { column: Some(6), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1416,7 +1428,7 @@ mod tests { column: Some(5), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); match got { CompletionResponse::Array(arr) => assert!(arr.is_empty()), CompletionResponse::List(_) => panic!("test failed"), @@ -1429,7 +1441,7 @@ mod tests { column: Some(8), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); match got { CompletionResponse::Array(arr) => assert!(arr.is_empty()), CompletionResponse::List(_) => panic!("test failed"), @@ -1440,7 +1452,7 @@ mod tests { line: 3, column: Some(2), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); match got { CompletionResponse::Array(arr) => { assert!(arr @@ -1462,7 +1474,8 @@ mod tests { column: Some(2), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); match got { CompletionResponse::Array(arr) => { assert_eq!( @@ -1490,7 +1503,8 @@ mod tests { column: Some(16), }; - let got = completion(None, &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(None, &program, &pos, &gs, &tool).unwrap(); match got { CompletionResponse::Array(arr) => { assert_eq!(arr.len(), 4); @@ -1513,7 +1527,8 @@ mod tests { column: Some(4), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); match &got { CompletionResponse::Array(arr) => { @@ -1535,7 +1550,8 @@ mod tests { column: Some(16), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); match got { CompletionResponse::Array(arr) => { assert_eq!(arr.len(), 2); @@ -1559,7 +1575,8 @@ mod tests { column: Some(10), }; - let got = completion(Some(':'), &program, &pos, &gs); + let tool = toolchain::default(); + let got = completion(Some(':'), &program, &pos, &gs, &tool); assert!(got.is_none()); let pos = KCLPos { @@ -1568,7 +1585,7 @@ mod tests { column: Some(9), }; - let got = completion(None, &program, &pos, &gs).unwrap(); + let got = completion(None, &program, &pos, &gs, &tool).unwrap(); match got { CompletionResponse::Array(arr) => { assert_eq!(arr.len(), 3); @@ -1591,7 +1608,8 @@ mod tests { column: Some(28), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); match &got { CompletionResponse::Array(arr) => { assert!(arr.is_empty()) @@ -1605,7 +1623,8 @@ mod tests { column: Some(27), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); match &got { CompletionResponse::Array(arr) => { assert!(arr.is_empty()) @@ -1626,7 +1645,8 @@ mod tests { column: Some(15), }; - let mut got = completion(None, &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let mut got = completion(None, &program, &pos, &gs, &tool).unwrap(); match &mut got { CompletionResponse::Array(arr) => { let labels: Vec = arr.iter().map(|item| item.label.clone()).collect(); @@ -1641,7 +1661,8 @@ mod tests { column: Some(21), }; - let mut got = completion(None, &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let mut got = completion(None, &program, &pos, &gs, &tool).unwrap(); match &mut got { CompletionResponse::Array(arr) => { let labels: Vec = arr.iter().map(|item| item.label.clone()).collect(); diff --git a/kclvm/tools/src/LSP/src/config.rs b/kclvm/tools/src/LSP/src/config.rs deleted file mode 100644 index 7364a0316..000000000 --- a/kclvm/tools/src/LSP/src/config.rs +++ /dev/null @@ -1,3 +0,0 @@ -/// The configuration used by the language server. -#[derive(Debug, Clone, Default)] -pub struct Config {} diff --git a/kclvm/tools/src/LSP/src/db.rs b/kclvm/tools/src/LSP/src/db.rs deleted file mode 100644 index e816d9f14..000000000 --- a/kclvm/tools/src/LSP/src/db.rs +++ /dev/null @@ -1,14 +0,0 @@ -use indexmap::IndexSet; -use kclvm_ast::ast::Program; -use kclvm_error::Diagnostic; -use kclvm_sema::core::global_state::GlobalState; - -pub type DocumentVersion = i32; -/// Holds the result of the compile -#[derive(Default, Clone)] -pub struct AnalysisDatabase { - pub prog: Program, - pub diags: IndexSet, - pub gs: GlobalState, - pub version: DocumentVersion, -} diff --git a/kclvm/tools/src/LSP/src/find_refs.rs b/kclvm/tools/src/LSP/src/find_refs.rs index 2b3472e4e..54279ed36 100644 --- a/kclvm/tools/src/LSP/src/find_refs.rs +++ b/kclvm/tools/src/LSP/src/find_refs.rs @@ -1,21 +1,23 @@ +use std::sync::Arc; + use crate::from_lsp::{file_path_from_url, kcl_pos}; -use crate::goto_def::{find_def_with_gs, goto_definition_with_gs}; +use crate::goto_def::{find_def, goto_def}; use crate::to_lsp::lsp_location; use crate::util::{compile_with_params, Params}; -use crate::state::{KCLCompileUnitCache, KCLVfs, KCLWordIndexMap}; +use crate::state::{KCLEntryCache, KCLVfs, KCLWordIndexMap}; use anyhow::Result; -use kclvm_ast::ast::Program; +use kclvm_driver::toolchain; use kclvm_error::Position as KCLPos; use kclvm_parser::KCLModuleCache; use kclvm_sema::core::global_state::GlobalState; use kclvm_sema::resolver::scope::KCLScopeCache; use lsp_types::Location; +use parking_lot::lock_api::RwLock; const FIND_REFS_LIMIT: usize = 20; pub(crate) fn find_refs Result<(), anyhow::Error>>( - _program: &Program, kcl_pos: &KCLPos, include_declaration: bool, word_index_map: KCLWordIndexMap, @@ -24,9 +26,9 @@ pub(crate) fn find_refs Result<(), anyhow::Error>>( gs: &GlobalState, module_cache: Option, scope_cache: Option, - compile_unit_cache: Option, + entry_cache: Option, ) -> Result, String> { - let def = find_def_with_gs(kcl_pos, gs, true); + let def = find_def(kcl_pos, gs, true); match def { Some(def_ref) => match gs.get_symbols().get_symbol(def_ref) { Some(obj) => { @@ -43,7 +45,7 @@ pub(crate) fn find_refs Result<(), anyhow::Error>>( logger, module_cache, scope_cache, - compile_unit_cache, + entry_cache, )) } else { Err(format!("Invalid file path: {0}", start.filename)) @@ -69,7 +71,7 @@ pub(crate) fn find_refs_from_def Result<(), anyhow::Error>>( logger: F, module_cache: Option, scope_cache: Option, - compile_unit_cache: Option, + entry_cache: Option, ) -> Vec { let mut ref_locations = vec![]; for word_index in (*word_index_map.write()).values_mut() { @@ -95,17 +97,16 @@ pub(crate) fn find_refs_from_def Result<(), anyhow::Error>>( module_cache: module_cache.clone(), scope_cache: scope_cache.clone(), vfs: vfs.clone(), - compile_unit_cache: compile_unit_cache.clone(), + entry_cache: entry_cache.clone(), + tool: Arc::new(RwLock::new(toolchain::default())), }) { - Ok((prog, _, gs)) => { + Ok((_, _, gs)) => { let ref_pos = kcl_pos(&file_path, ref_loc.range.start); if *ref_loc == def_loc && !include_declaration { return false; } // find def from the ref_pos - if let Some(real_def) = - goto_definition_with_gs(&prog, &ref_pos, &gs) - { + if let Some(real_def) = goto_def(&ref_pos, &gs) { match real_def { lsp_types::GotoDefinitionResponse::Scalar( real_def_loc, diff --git a/kclvm/tools/src/LSP/src/from_lsp.rs b/kclvm/tools/src/LSP/src/from_lsp.rs index 8a8b28da3..8f129b0aa 100644 --- a/kclvm/tools/src/LSP/src/from_lsp.rs +++ b/kclvm/tools/src/LSP/src/from_lsp.rs @@ -54,7 +54,7 @@ pub(crate) fn file_path_from_url(url: &Url) -> anyhow::Result { .ok() .and_then(|path| { path.to_str() - .map(|p| kclvm_utils::path::convert_windows_drive_letter(p)) + .map(kclvm_utils::path::convert_windows_drive_letter) }) .ok_or_else(|| anyhow::anyhow!("can't convert url to file path: {}", url)) } diff --git a/kclvm/tools/src/LSP/src/goto_def.rs b/kclvm/tools/src/LSP/src/goto_def.rs index 93e8c235c..79c69031b 100644 --- a/kclvm/tools/src/LSP/src/goto_def.rs +++ b/kclvm/tools/src/LSP/src/goto_def.rs @@ -9,20 +9,18 @@ use crate::to_lsp::lsp_location; use indexmap::IndexSet; -use kclvm_ast::ast::Program; use kclvm_error::Position as KCLPos; use kclvm_sema::core::global_state::GlobalState; use kclvm_sema::core::symbol::SymbolRef; use lsp_types::GotoDefinitionResponse; // Navigates to the definition of an identifier. -pub(crate) fn goto_definition_with_gs( - _program: &Program, +pub(crate) fn goto_def( kcl_pos: &KCLPos, gs: &GlobalState, ) -> Option { let mut res = IndexSet::new(); - let def = find_def_with_gs(kcl_pos, gs, true); + let def = find_def(kcl_pos, gs, true); match def { Some(def_ref) => match gs.get_symbols().get_symbol(def_ref) { Some(def) => match def_ref.get_kind() { @@ -48,11 +46,7 @@ pub(crate) fn goto_definition_with_gs( positions_to_goto_def_resp(&res) } -pub(crate) fn find_def_with_gs( - kcl_pos: &KCLPos, - gs: &GlobalState, - exact: bool, -) -> Option { +pub(crate) fn find_def(kcl_pos: &KCLPos, gs: &GlobalState, exact: bool) -> Option { if exact { match gs.look_up_exact_symbol(kcl_pos) { Some(symbol_ref) => match gs.get_symbols().get_symbol(symbol_ref) { @@ -97,7 +91,7 @@ fn positions_to_goto_def_resp( #[cfg(test)] mod tests { - use super::goto_definition_with_gs; + use super::goto_def; use crate::{ from_lsp::file_path_from_url, tests::{compare_goto_res, compile_test_file}, @@ -111,14 +105,14 @@ mod tests { #[bench_test] fn goto_import_pkg_test() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let pos = KCLPos { filename: file, line: 1, column: Some(10), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); let mut expected_files = IndexSet::new(); let path_str = path.to_str().unwrap(); @@ -148,7 +142,7 @@ mod tests { fn goto_import_file_test() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); @@ -159,7 +153,7 @@ mod tests { line: 2, column: Some(10), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); match res.unwrap() { lsp_types::GotoDefinitionResponse::Scalar(loc) => { let got_path = file_path_from_url(&loc.uri).unwrap(); @@ -176,7 +170,7 @@ mod tests { fn goto_pkg_prefix_def_test() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); // test goto pkg prefix def: p = pkg.Person { <- pkg let pos = KCLPos { @@ -184,7 +178,7 @@ mod tests { line: 4, column: Some(7), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); let mut expected_files = IndexSet::new(); let path_str = path.to_str().unwrap(); let test_files = [ @@ -213,7 +207,7 @@ mod tests { fn goto_schema_def_test() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); @@ -225,7 +219,7 @@ mod tests { column: Some(11), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res( res, (&expected_path.to_str().unwrap().to_string(), 0, 7, 0, 13), @@ -237,7 +231,7 @@ mod tests { fn goto_var_def_in_config_and_config_if_test() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); @@ -247,7 +241,7 @@ mod tests { line: 67, column: Some(36), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 65, 11, 65, 14)); let pos = KCLPos { @@ -256,7 +250,7 @@ mod tests { column: Some(44), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 65, 16, 65, 21)); let pos = KCLPos { filename: file.clone(), @@ -264,7 +258,7 @@ mod tests { column: Some(11), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 69, 6, 69, 10)); let pos = KCLPos { filename: file.clone(), @@ -272,7 +266,7 @@ mod tests { column: Some(10), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 69, 6, 69, 10)); } @@ -281,7 +275,7 @@ mod tests { fn goto_var_def_in_dict_comp_test() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); @@ -292,7 +286,7 @@ mod tests { column: Some(68), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 76, 143, 76, 145)); let pos = KCLPos { @@ -301,7 +295,7 @@ mod tests { column: Some(61), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 76, 143, 76, 145)); } @@ -310,7 +304,7 @@ mod tests { fn goto_schema_attr_def_test() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); @@ -322,7 +316,7 @@ mod tests { column: Some(7), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res( res, (&expected_path.to_str().unwrap().to_string(), 4, 4, 4, 8), @@ -334,7 +328,7 @@ mod tests { fn goto_schema_attr_def_test1() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/goto_def.k"); @@ -346,7 +340,7 @@ mod tests { column: Some(12), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res( res, (&expected_path.to_str().unwrap().to_string(), 18, 4, 18, 8), @@ -358,7 +352,7 @@ mod tests { fn test_goto_identifier_names() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/goto_def.k"); @@ -370,7 +364,7 @@ mod tests { column: Some(5), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res( res, (&expected_path.to_str().unwrap().to_string(), 23, 0, 23, 2), @@ -383,7 +377,7 @@ mod tests { column: Some(8), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res( res, (&expected_path.to_str().unwrap().to_string(), 21, 1, 21, 2), @@ -396,7 +390,7 @@ mod tests { column: Some(12), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res( res, (&expected_path.to_str().unwrap().to_string(), 18, 4, 18, 8), @@ -406,7 +400,7 @@ mod tests { #[test] #[bench_test] fn goto_identifier_def_test() { - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); // test goto identifier definition: p1 = p let pos = KCLPos { @@ -415,7 +409,7 @@ mod tests { column: Some(6), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 3, 0, 3, 1)); } @@ -424,7 +418,7 @@ mod tests { fn goto_assign_type_test() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); @@ -436,7 +430,7 @@ mod tests { column: Some(17), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 33, 7, 33, 15)); } @@ -446,7 +440,7 @@ mod tests { // test goto schema attr type definition: p1: pkg.Person let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); @@ -457,7 +451,7 @@ mod tests { column: Some(15), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res( res, (&expected_path.to_str().unwrap().to_string(), 0, 7, 0, 13), @@ -470,7 +464,7 @@ mod tests { // test goto schema attr type definition: p2: [pkg.Person] let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); @@ -480,7 +474,7 @@ mod tests { line: 13, column: Some(15), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res( res, (&expected_path.to_str().unwrap().to_string(), 0, 7, 0, 13), @@ -493,7 +487,7 @@ mod tests { // test goto schema attr type definition: p3: {str: pkg.Person} let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); @@ -503,7 +497,7 @@ mod tests { line: 14, column: Some(22), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res( res, (&expected_path.to_str().unwrap().to_string(), 0, 7, 0, 13), @@ -516,7 +510,7 @@ mod tests { // test goto schema attr type definition(Person): p4: pkg.Person | pkg.Person1 let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); @@ -527,7 +521,7 @@ mod tests { column: Some(17), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res( res, (&expected_path.to_str().unwrap().to_string(), 0, 7, 0, 13), @@ -540,7 +534,7 @@ mod tests { // test goto schema attr type definition(Person1): p4: pkg.Person | pkg.Person1 let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/pkg/schema_def1.k"); @@ -550,7 +544,7 @@ mod tests { line: 15, column: Some(28), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res( res, (&expected_path.to_str().unwrap().to_string(), 0, 7, 0, 14), @@ -562,7 +556,7 @@ mod tests { fn goto_local_var_def_test() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); @@ -574,7 +568,7 @@ mod tests { column: Some(11), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 43, 4, 43, 9)); let pos = KCLPos { @@ -583,7 +577,7 @@ mod tests { column: Some(11), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 43, 4, 43, 9)); let pos = KCLPos { @@ -592,14 +586,14 @@ mod tests { column: Some(11), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 43, 4, 43, 9)); } #[test] #[bench_test] fn complex_select_goto_def() { - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let pos = KCLPos { filename: file.clone(), @@ -607,14 +601,14 @@ mod tests { column: Some(22), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 43, 4, 43, 9)); } #[test] #[bench_test] fn schema_attribute_def_goto_def() { - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let pos = KCLPos { filename: file.clone(), @@ -622,14 +616,14 @@ mod tests { column: Some(5), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 18, 4, 18, 8)); } #[test] #[bench_test] fn config_desuger_def_goto_def() { - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let pos = KCLPos { filename: file.clone(), @@ -637,14 +631,14 @@ mod tests { column: Some(9), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 18, 4, 18, 8)); } #[test] #[bench_test] fn lambda_param_goto_def() { - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let pos = KCLPos { filename: file.clone(), @@ -652,7 +646,7 @@ mod tests { column: Some(4), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 84, 14, 84, 15)); let pos = KCLPos { @@ -661,14 +655,14 @@ mod tests { column: Some(8), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 84, 22, 84, 23)); } #[test] #[bench_test] fn list_if_expr_test() { - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let pos = KCLPos { filename: file.clone(), @@ -676,14 +670,14 @@ mod tests { column: Some(8), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 88, 0, 88, 1)); } #[test] #[bench_test] fn lambda_local_var_test() { - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let pos = KCLPos { filename: file.clone(), @@ -691,7 +685,7 @@ mod tests { column: Some(9), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); compare_goto_res(res, (&file, 94, 11, 94, 12)); } } diff --git a/kclvm/tools/src/LSP/src/hover.rs b/kclvm/tools/src/LSP/src/hover.rs index a0574a8af..0da531847 100644 --- a/kclvm/tools/src/LSP/src/hover.rs +++ b/kclvm/tools/src/LSP/src/hover.rs @@ -1,4 +1,3 @@ -use kclvm_ast::ast::Program; use kclvm_error::Position as KCLPos; use kclvm_sema::{ builtin::BUILTIN_DECORATORS, @@ -7,7 +6,7 @@ use kclvm_sema::{ }; use lsp_types::{Hover, HoverContents, MarkedString}; -use crate::goto_def::find_def_with_gs; +use crate::goto_def::find_def; enum MarkedStringType { String, @@ -16,13 +15,9 @@ enum MarkedStringType { /// Returns a short text describing element at position. /// Specifically, the doc for schema and schema attr(todo) -pub(crate) fn hover( - _program: &Program, - kcl_pos: &KCLPos, - gs: &GlobalState, -) -> Option { +pub(crate) fn hover(kcl_pos: &KCLPos, gs: &GlobalState) -> Option { let mut docs: Vec<(String, MarkedStringType)> = vec![]; - let def = find_def_with_gs(kcl_pos, gs, true); + let def = find_def(kcl_pos, gs, true); match def { Some(def_ref) => match gs.get_symbols().get_symbol(def_ref) { Some(obj) => match def_ref.get_kind() { @@ -32,10 +27,10 @@ pub(crate) fn hover( // Schema Definition hover // ``` // pkg + // ---------------- // schema Foo(Base)[param: type]: - // ----------------- - // attr1: type - // attr2? type + // attr1: type + // attr2? type // ----------------- // doc // ``` @@ -244,7 +239,7 @@ mod tests { fn schema_doc_hover_test() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_test/goto_def.k"); let mut expected_path = path; expected_path.push("src/test_data/goto_def_test/pkg/schema_def.k"); @@ -255,7 +250,7 @@ mod tests { line: 4, column: Some(11), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Array(vec) => { if let MarkedString::String(s) = vec[0].clone() { @@ -282,7 +277,7 @@ mod tests { line: 5, column: Some(7), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Scalar(marked_string) => { if let MarkedString::LanguageString(s) = marked_string { @@ -341,14 +336,14 @@ mod tests { #[test] #[bench_test] fn schema_doc_hover_test1() { - let (file, program, _, gs) = compile_test_file("src/test_data/hover_test/hover.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/hover_test/hover.k"); let pos = KCLPos { filename: file.clone(), line: 16, column: Some(8), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Array(vec) => { @@ -369,14 +364,14 @@ mod tests { #[test] #[bench_test] fn schema_attr_hover_test() { - let (file, program, _, gs) = compile_test_file("src/test_data/hover_test/hover.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/hover_test/hover.k"); let pos = KCLPos { filename: file.clone(), line: 17, column: Some(7), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Array(vec) => { @@ -395,7 +390,7 @@ mod tests { line: 18, column: Some(7), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Array(vec) => { @@ -413,14 +408,14 @@ mod tests { #[test] #[bench_test] fn lambda_doc_hover_test() { - let (file, program, _, gs) = compile_test_file("src/test_data/hover_test/lambda.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/hover_test/lambda.k"); let pos = KCLPos { filename: file.clone(), line: 1, column: Some(1), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Array(vec) => { @@ -438,14 +433,14 @@ mod tests { #[test] #[bench_test] fn func_def_hover() { - let (file, program, _, gs) = compile_test_file("src/test_data/hover_test/hover.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/hover_test/hover.k"); let pos = KCLPos { filename: file.clone(), line: 22, column: Some(18), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Array(vec) => { @@ -468,7 +463,7 @@ mod tests { line: 23, column: Some(14), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Array(vec) => { @@ -491,7 +486,7 @@ mod tests { line: 25, column: Some(4), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Array(vec) => { @@ -510,13 +505,13 @@ mod tests { #[test] #[bench_test] fn complex_select_hover() { - let (file, program, _, gs) = compile_test_file("src/test_data/hover_test/fib.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/hover_test/fib.k"); let pos = KCLPos { filename: file.clone(), line: 14, column: Some(22), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Scalar(marked_string) => { if let MarkedString::LanguageString(s) = marked_string { @@ -530,13 +525,13 @@ mod tests { #[test] #[bench_test] fn assignment_ty_in_lambda_hover() { - let (file, program, _, gs) = compile_test_file("src/test_data/hover_test/ty_in_lambda.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/hover_test/ty_in_lambda.k"); let pos = KCLPos { filename: file.clone(), line: 3, column: Some(8), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Scalar(marked_string) => { if let MarkedString::LanguageString(s) = marked_string { @@ -550,13 +545,13 @@ mod tests { #[test] #[bench_test] fn str_var_func_hover() { - let (file, program, _, gs) = compile_test_file("src/test_data/hover_test/hover.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/hover_test/hover.k"); let pos = KCLPos { filename: file.clone(), line: 28, column: Some(12), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Array(vec) => { assert_eq!(vec.len(), 3); @@ -577,13 +572,13 @@ mod tests { #[test] #[bench_test] fn import_pkg_hover() { - let (file, program, _, gs) = compile_test_file("src/test_data/hover_test/import_pkg.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/hover_test/import_pkg.k"); let pos = KCLPos { filename: file.clone(), line: 3, column: Some(7), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Array(vec) => { assert_eq!(vec.len(), 2); @@ -601,13 +596,13 @@ mod tests { #[test] #[bench_test] fn expr_after_config_if_hover() { - let (file, program, _, gs) = compile_test_file("src/test_data/hover_test/hover.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/hover_test/hover.k"); let pos = KCLPos { filename: file.clone(), line: 41, column: Some(13), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Scalar(marked_string) => { if let MarkedString::LanguageString(s) = marked_string { @@ -621,13 +616,13 @@ mod tests { #[test] #[bench_test] fn schema_scope_variable_hover() { - let (file, program, _, gs) = compile_test_file("src/test_data/hover_test/fib.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/hover_test/fib.k"); let pos = KCLPos { filename: file.clone(), line: 3, column: Some(11), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Scalar(marked_string) => { if let MarkedString::LanguageString(s) = marked_string { @@ -641,13 +636,13 @@ mod tests { #[test] #[bench_test] fn decorator_hover() { - let (file, program, _, gs) = compile_test_file("src/test_data/hover_test/decorator.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/hover_test/decorator.k"); let pos = KCLPos { filename: file.clone(), line: 1, column: Some(1), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); let expect_content = vec![ MarkedString::LanguageString(LanguageString { language: "KCL".to_string(), @@ -669,7 +664,7 @@ mod tests { line: 3, column: Some(8), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Array(vec) => { assert_eq!(vec, expect_content); @@ -681,13 +676,13 @@ mod tests { #[test] #[bench_test] fn inherit_schema_attr_hover() { - let (file, program, _, gs) = compile_test_file("src/test_data/hover_test/inherit.k"); + let (file, _program, _, gs) = compile_test_file("src/test_data/hover_test/inherit.k"); let pos = KCLPos { filename: file.clone(), line: 5, column: Some(9), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); let expect_content = vec![ MarkedString::String("__main__".to_string()), @@ -708,14 +703,14 @@ mod tests { #[test] #[bench_test] fn dict_key_in_schema() { - let (file, program, _, gs) = + let (file, _program, _, gs) = compile_test_file("src/test_data/hover_test/dict_key_in_schema/dict_key_in_schema.k"); let pos = KCLPos { filename: file.clone(), line: 5, column: Some(5), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Scalar(marked_string) => { @@ -731,7 +726,7 @@ mod tests { line: 9, column: Some(5), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); let expected = lsp_types::HoverContents::Scalar(MarkedString::LanguageString(LanguageString { language: "KCL".to_string(), @@ -744,7 +739,7 @@ mod tests { line: 13, column: Some(5), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); let expected = lsp_types::HoverContents::Scalar(MarkedString::LanguageString(LanguageString { language: "KCL".to_string(), diff --git a/kclvm/tools/src/LSP/src/lib.rs b/kclvm/tools/src/LSP/src/lib.rs index a67f1f53a..01cac1fd1 100644 --- a/kclvm/tools/src/LSP/src/lib.rs +++ b/kclvm/tools/src/LSP/src/lib.rs @@ -1,8 +1,6 @@ mod analysis; mod capabilities; mod completion; -mod config; -mod db; mod dispatcher; mod document_symbol; mod error; diff --git a/kclvm/tools/src/LSP/src/main.rs b/kclvm/tools/src/LSP/src/main.rs index 9a8e8aeeb..4ff88e992 100644 --- a/kclvm/tools/src/LSP/src/main.rs +++ b/kclvm/tools/src/LSP/src/main.rs @@ -1,12 +1,9 @@ use crate::main_loop::main_loop; -use config::Config; use main_loop::app; mod analysis; mod capabilities; mod completion; -mod config; -mod db; mod dispatcher; mod document_symbol; mod error; @@ -82,8 +79,7 @@ fn run_server() -> anyhow::Result<()> { .map_err(|_| anyhow::anyhow!("Initialize result error"))?; connection.initialize_finish(initialize_id, initialize_result)?; - let config = Config::default(); - main_loop(connection, config, initialize_params)?; + main_loop(connection, initialize_params)?; io_threads.join()?; Ok(()) } diff --git a/kclvm/tools/src/LSP/src/main_loop.rs b/kclvm/tools/src/LSP/src/main_loop.rs index b0f8b16c1..272e639e2 100644 --- a/kclvm/tools/src/LSP/src/main_loop.rs +++ b/kclvm/tools/src/LSP/src/main_loop.rs @@ -1,4 +1,3 @@ -use crate::config::Config; use crate::state::LanguageServerState; use clap::Command; use lsp_server::Connection; @@ -8,10 +7,9 @@ use lsp_types::InitializeParams; /// Runs the main loop of the language server. This will receive requests and handle them. pub(crate) fn main_loop( connection: Connection, - config: Config, initialize_params: InitializeParams, ) -> anyhow::Result<()> { - LanguageServerState::new(connection.sender, config, initialize_params).run(connection.receiver) + LanguageServerState::new(connection.sender, initialize_params).run(connection.receiver) } #[allow(dead_code)] diff --git a/kclvm/tools/src/LSP/src/notification.rs b/kclvm/tools/src/LSP/src/notification.rs index ac14cc72d..d553022fc 100644 --- a/kclvm/tools/src/LSP/src/notification.rs +++ b/kclvm/tools/src/LSP/src/notification.rs @@ -144,7 +144,7 @@ impl LanguageServerState { let path = from_lsp::abs_path(&change.uri)?; self.loader.handle.invalidate(path.clone()); if KCL_CONFIG_FILE.contains(&path.file_name().unwrap().to_str().unwrap()) { - self.compile_unit_cache.write().clear(); + self.entry_cache.write().clear(); } } @@ -152,4 +152,4 @@ impl LanguageServerState { } } -const KCL_CONFIG_FILE: [&'static str; 2] = [DEFAULT_SETTING_FILE, KCL_MOD_FILE]; +const KCL_CONFIG_FILE: [&str; 2] = [DEFAULT_SETTING_FILE, KCL_MOD_FILE]; diff --git a/kclvm/tools/src/LSP/src/quick_fix.rs b/kclvm/tools/src/LSP/src/quick_fix.rs index ea2e5cf28..c535c5026 100644 --- a/kclvm/tools/src/LSP/src/quick_fix.rs +++ b/kclvm/tools/src/LSP/src/quick_fix.rs @@ -6,7 +6,7 @@ use lsp_types::{ }; use serde_json::Value; -pub(crate) fn quick_fix(uri: &Url, diags: &Vec) -> Vec { +pub(crate) fn quick_fix(uri: &Url, diags: &[Diagnostic]) -> Vec { let mut code_actions: Vec = vec![]; for diag in diags { if let Some(code) = &diag.code { @@ -128,12 +128,14 @@ pub(crate) fn convert_code_to_kcl_diag_id(code: &NumberOrString) -> Option Ok(Some(locations)), Err(msg) => { @@ -308,7 +306,13 @@ pub(crate) fn handle_completion( let db = snapshot.get_db(&path.clone().into())?; - let res = completion(completion_trigger_character, &db.prog, &kcl_pos, &db.gs); + let res = completion( + completion_trigger_character, + &db.prog, + &kcl_pos, + &db.gs, + &*snapshot.tool.read(), + ); if res.is_none() { log_message("Completion item not found".to_string(), &sender)?; @@ -329,7 +333,7 @@ pub(crate) fn handle_hover( } let db = snapshot.get_db(&path.clone().into())?; let kcl_pos = kcl_pos(&file, params.text_document_position_params.position); - let res = hover::hover(&db.prog, &kcl_pos, &db.gs); + let res = hover::hover(&kcl_pos, &db.gs); if res.is_none() { log_message("Hover definition not found".to_string(), &sender)?; } @@ -379,7 +383,6 @@ pub(crate) fn handle_rename( let kcl_pos = kcl_pos(&file, params.text_document_position.position); let log = |msg: String| log_message(msg, &sender); let references = find_refs( - &db.prog, &kcl_pos, true, snapshot.word_index_map.clone(), @@ -388,7 +391,7 @@ pub(crate) fn handle_rename( &db.gs, Some(snapshot.module_cache), Some(snapshot.scope_cache), - Some(snapshot.compile_unit_cache), + Some(snapshot.entry_cache), ); match references { Result::Ok(locations) => { diff --git a/kclvm/tools/src/LSP/src/state.rs b/kclvm/tools/src/LSP/src/state.rs index 8d9b26655..379e15d46 100644 --- a/kclvm/tools/src/LSP/src/state.rs +++ b/kclvm/tools/src/LSP/src/state.rs @@ -1,13 +1,13 @@ -use crate::analysis::Analysis; -use crate::config::Config; -use crate::db::{AnalysisDatabase, DocumentVersion}; +use crate::analysis::{Analysis, AnalysisDatabase, DocumentVersion}; use crate::from_lsp::file_path_from_url; use crate::to_lsp::{kcl_diag_to_lsp_diags, url}; use crate::util::{compile_with_params, get_file_name, to_json, Params}; use crate::word_index::build_word_index; use anyhow::Result; use crossbeam_channel::{select, unbounded, Receiver, Sender}; -use kclvm_parser::{KCLModuleCache, LoadProgramOptions}; +use kclvm_driver::toolchain::{self, Toolchain}; +use kclvm_driver::CompileUnitOptions; +use kclvm_parser::KCLModuleCache; use kclvm_sema::resolver::scope::KCLScopeCache; use lsp_server::{ReqQueue, Request, Response}; use lsp_types::Url; @@ -47,55 +47,41 @@ pub(crate) struct Handle { pub(crate) type KCLVfs = Arc>; pub(crate) type KCLWordIndexMap = Arc>>>>; -pub(crate) type KCLCompileUnitCache = - Arc, Option)>>>; +pub(crate) type KCLEntryCache = Arc>>; +pub(crate) type KCLToolChain = Arc>; /// State for the language server pub(crate) struct LanguageServerState { /// Channel to send language server messages to the client pub(crate) sender: Sender, - /// The request queue keeps track of all incoming and outgoing requests. pub(crate) request_queue: lsp_server::ReqQueue<(String, Instant), RequestHandler>, - - /// The configuration passed by the client - pub _config: Config, - /// Thread pool for async execution pub thread_pool: threadpool::ThreadPool, - /// Channel to send tasks to from background operations pub task_sender: Sender, - /// Channel to receive tasks on from background operations pub task_receiver: Receiver, - - /// The virtual filesystem that holds all the file contents - pub vfs: KCLVfs, - /// True if the client requested that we shut down pub shutdown_requested: bool, - + /// The virtual filesystem that holds all the file contents + pub vfs: KCLVfs, /// Holds the state of the analysis process pub analysis: Analysis, - /// Documents that are currently kept in memory from the client pub opened_files: Arc>>, - /// The VFS loader pub loader: Handle, Receiver>, - /// The word index map pub word_index_map: KCLWordIndexMap, - /// KCL parse cache pub module_cache: KCLModuleCache, - /// KCL resolver cache pub scope_cache: KCLScopeCache, - /// KCL compile unit cache cache - pub compile_unit_cache: KCLCompileUnitCache, + pub entry_cache: KCLEntryCache, + /// Toolchain is used to provider KCL tool features for the language server. + pub tool: KCLToolChain, } /// A snapshot of the state of the language server @@ -114,16 +100,14 @@ pub(crate) struct LanguageServerSnapshot { /// KCL resolver cache pub scope_cache: KCLScopeCache, /// KCL compile unit cache cache - pub compile_unit_cache: KCLCompileUnitCache, + pub entry_cache: KCLEntryCache, + /// Toolchain is used to provider KCL tool features for the language server. + pub tool: KCLToolChain, } #[allow(unused)] impl LanguageServerState { - pub fn new( - sender: Sender, - config: Config, - initialize_params: InitializeParams, - ) -> Self { + pub fn new(sender: Sender, initialize_params: InitializeParams) -> Self { let (task_sender, task_receiver) = unbounded::(); let loader = { @@ -137,7 +121,6 @@ impl LanguageServerState { let state = LanguageServerState { sender, request_queue: ReqQueue::default(), - _config: config, vfs: Arc::new(RwLock::new(Default::default())), thread_pool: threadpool::ThreadPool::default(), task_sender: task_sender.clone(), @@ -149,7 +132,8 @@ impl LanguageServerState { loader, module_cache: KCLModuleCache::default(), scope_cache: KCLScopeCache::default(), - compile_unit_cache: KCLCompileUnitCache::default(), + entry_cache: KCLEntryCache::default(), + tool: Arc::new(RwLock::new(toolchain::default())), }; let word_index_map = state.word_index_map.clone(); @@ -237,7 +221,8 @@ impl LanguageServerState { let sender = self.task_sender.clone(); let module_cache = Arc::clone(&self.module_cache); let scope_cache = Arc::clone(&self.scope_cache); - let compile_unit_cache = Arc::clone(&self.compile_unit_cache); + let entry = Arc::clone(&self.entry_cache); + let tool = Arc::clone(&self.tool); move || match url(&snapshot, file.file_id) { Ok(uri) => { let version = @@ -248,7 +233,8 @@ impl LanguageServerState { module_cache: Some(module_cache), scope_cache: Some(scope_cache), vfs: Some(snapshot.vfs), - compile_unit_cache: Some(compile_unit_cache), + entry_cache: Some(entry), + tool, }) { Ok((prog, diags, gs)) => { let current_version = snapshot @@ -264,7 +250,6 @@ impl LanguageServerState { file.file_id, Arc::new(AnalysisDatabase { prog, - diags: diags.clone(), gs, version, }), @@ -316,8 +301,8 @@ impl LanguageServerState { } }); } - Err(_) => { - self.log_message(format!("{:?} not found", file.file_id)); + Err(err) => { + self.log_message(format!("{:?} not found: {}", file.file_id, err)); } } } @@ -383,7 +368,8 @@ impl LanguageServerState { word_index_map: self.word_index_map.clone(), module_cache: self.module_cache.clone(), scope_cache: self.scope_cache.clone(), - compile_unit_cache: self.compile_unit_cache.clone(), + entry_cache: self.entry_cache.clone(), + tool: self.tool.clone(), } } diff --git a/kclvm/tools/src/LSP/src/tests.rs b/kclvm/tools/src/LSP/src/tests.rs index f55d05173..98e528599 100644 --- a/kclvm/tools/src/LSP/src/tests.rs +++ b/kclvm/tools/src/LSP/src/tests.rs @@ -2,6 +2,7 @@ use crossbeam_channel::after; use crossbeam_channel::select; use indexmap::IndexSet; use kclvm_ast::MAIN_PKG; +use kclvm_driver::toolchain; use kclvm_sema::core::global_state::GlobalState; use kclvm_sema::resolver::scope::KCLScopeCache; @@ -38,6 +39,7 @@ use lsp_types::Url; use lsp_types::WorkspaceEdit; use lsp_types::WorkspaceFolder; +use parking_lot::lock_api::RwLock; use serde::Serialize; use std::cell::Cell; use std::cell::RefCell; @@ -69,16 +71,15 @@ use proc_macro_crate::bench_test; use lsp_server::{Connection, Message, Notification, Request}; use crate::completion::completion; -use crate::config::Config; use crate::from_lsp::file_path_from_url; -use crate::goto_def::goto_definition_with_gs; +use crate::goto_def::goto_def; use crate::hover::hover; use crate::main_loop::main_loop; -use crate::state::KCLCompileUnitCache; +use crate::state::KCLEntryCache; use crate::state::KCLVfs; use crate::to_lsp::kcl_diag_to_lsp_diags; -use crate::util::compile_unit_with_cache; +use crate::util::lookup_compile_unit_with_cache; use crate::util::to_json; use crate::util::{apply_document_changes, compile_with_params, Params}; @@ -131,7 +132,8 @@ pub(crate) fn compile_test_file( module_cache: Some(KCLModuleCache::default()), scope_cache: Some(KCLScopeCache::default()), vfs: Some(KCLVfs::default()), - compile_unit_cache: Some(KCLCompileUnitCache::default()), + entry_cache: Some(KCLEntryCache::default()), + tool: Arc::new(RwLock::new(toolchain::default())), }) .unwrap(); (file, program, diags, gs) @@ -293,7 +295,8 @@ fn diagnostics_test() { module_cache: None, scope_cache: None, vfs: Some(KCLVfs::default()), - compile_unit_cache: Some(KCLCompileUnitCache::default()), + entry_cache: Some(KCLEntryCache::default()), + tool: Arc::new(RwLock::new(toolchain::default())), }) .unwrap(); @@ -416,7 +419,7 @@ fn test_lsp_with_kcl_mod_in_order() { fn goto_import_pkg_with_line_test() { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let (file, program, _, gs) = + let (file, _program, _, gs) = compile_test_file("src/test_data/goto_def_with_line_test/main_pkg/main.k"); let pos = KCLPos { filename: file, @@ -424,7 +427,7 @@ fn goto_import_pkg_with_line_test() { column: Some(27), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); match res.unwrap() { lsp_types::GotoDefinitionResponse::Scalar(loc) => { @@ -480,7 +483,8 @@ fn complete_import_external_file_test() { module_cache: None, scope_cache: None, vfs: Some(KCLVfs::default()), - compile_unit_cache: Some(KCLCompileUnitCache::default()), + entry_cache: Some(KCLEntryCache::default()), + tool: Arc::new(RwLock::new(toolchain::default())), }) .unwrap(); @@ -489,7 +493,8 @@ fn complete_import_external_file_test() { line: 1, column: Some(11), }; - let res = completion(Some('.'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let res = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match &res { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), @@ -533,12 +538,13 @@ fn goto_import_external_file_test() { .output() .unwrap(); - let (program, diags, gs) = compile_with_params(Params { + let (_program, diags, gs) = compile_with_params(Params { file: path.to_string(), module_cache: None, scope_cache: None, vfs: Some(KCLVfs::default()), - compile_unit_cache: Some(KCLCompileUnitCache::default()), + entry_cache: Some(KCLEntryCache::default()), + tool: Arc::new(RwLock::new(toolchain::default())), }) .unwrap(); @@ -550,7 +556,7 @@ fn goto_import_external_file_test() { line: 1, column: Some(57), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); assert!(res.is_some()); } @@ -563,8 +569,7 @@ pub struct Project {} impl Project { /// Instantiates a language server for this project. pub fn server(self, initialize_params: InitializeParams) -> Server { - let config = Config::default(); - Server::new(config, initialize_params) + Server::new(initialize_params) } } @@ -579,11 +584,11 @@ pub struct Server { impl Server { /// Constructs and initializes a new `Server` - pub fn new(config: Config, initialize_params: InitializeParams) -> Self { + pub fn new(initialize_params: InitializeParams) -> Self { let (connection, client) = Connection::memory(); let worker = std::thread::spawn(move || { - main_loop(connection, config, initialize_params).unwrap(); + main_loop(connection, initialize_params).unwrap(); }); Self { @@ -889,29 +894,30 @@ fn cancel_test() { } #[test] -fn compile_unit_cache_test() { +fn entry_test() { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let mut path = root.clone(); path.push("src/test_data/compile_unit/b.k"); let path = path.to_str().unwrap(); - let compile_unit_cache = KCLCompileUnitCache::default(); + let tool = toolchain::default(); + let entry = KCLEntryCache::default(); let start = Instant::now(); - let _ = compile_unit_with_cache(&Some(Arc::clone(&compile_unit_cache)), &path.to_string()); + let _ = lookup_compile_unit_with_cache(&tool, &Some(Arc::clone(&entry)), path); - assert!(compile_unit_cache.read().get(&path.to_string()).is_some()); + assert!(entry.read().get(&path.to_string()).is_some()); let first_compile_time = start.elapsed(); let start = Instant::now(); - let _ = compile_unit_with_cache(&Some(compile_unit_cache), &path.to_string()); + let _ = lookup_compile_unit_with_cache(&tool, &Some(entry), path); let second_compile_time = start.elapsed(); assert!(first_compile_time > second_compile_time); } #[test] -fn compile_unit_cache_e2e_test() { +fn entry_e2e_test() { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let mut path = root.clone(); let mut kcl_yaml = root.clone(); @@ -1387,12 +1393,13 @@ fn konfig_goto_def_test_base() { let mut base_path = konfig_path.clone(); base_path.push("appops/nginx-example/base/base.k"); let base_path_str = base_path.to_str().unwrap().to_string(); - let (program, _, gs) = compile_with_params(Params { + let (_program, _, gs) = compile_with_params(Params { file: base_path_str.clone(), module_cache: None, scope_cache: None, vfs: Some(KCLVfs::default()), - compile_unit_cache: Some(KCLCompileUnitCache::default()), + entry_cache: Some(KCLEntryCache::default()), + tool: Arc::new(RwLock::new(toolchain::default())), }) .unwrap(); @@ -1402,7 +1409,7 @@ fn konfig_goto_def_test_base() { line: 7, column: Some(30), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); let mut expected_path = konfig_path.clone(); expected_path.push("base/pkg/kusion_models/kube/frontend/server.k"); compare_goto_res( @@ -1416,7 +1423,7 @@ fn konfig_goto_def_test_base() { line: 9, column: Some(32), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); let mut expected_path = konfig_path.clone(); expected_path.push("base/pkg/kusion_models/kube/frontend/container/container.k"); compare_goto_res( @@ -1430,7 +1437,7 @@ fn konfig_goto_def_test_base() { line: 9, column: Some(9), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); let mut expected_path = konfig_path.clone(); expected_path.push("base/pkg/kusion_models/kube/frontend/server.k"); compare_goto_res( @@ -1450,7 +1457,7 @@ fn konfig_goto_def_test_base() { line: 10, column: Some(10), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); let mut expected_path = konfig_path.clone(); expected_path.push("base/pkg/kusion_models/kube/frontend/container/container.k"); compare_goto_res( @@ -1464,7 +1471,7 @@ fn konfig_goto_def_test_base() { line: 2, column: Some(49), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); let mut expected_path = konfig_path.clone(); expected_path.push("base/pkg/kusion_models/kube/frontend/service/service.k"); compare_goto_res( @@ -1479,12 +1486,13 @@ fn konfig_goto_def_test_main() { let mut main_path = konfig_path.clone(); main_path.push("appops/nginx-example/dev/main.k"); let main_path_str = main_path.to_str().unwrap().to_string(); - let (program, _, gs) = compile_with_params(Params { + let (_program, _, gs) = compile_with_params(Params { file: main_path_str.clone(), module_cache: None, scope_cache: None, vfs: Some(KCLVfs::default()), - compile_unit_cache: Some(KCLCompileUnitCache::default()), + entry_cache: Some(KCLEntryCache::default()), + tool: Arc::new(RwLock::new(toolchain::default())), }) .unwrap(); @@ -1494,7 +1502,7 @@ fn konfig_goto_def_test_main() { line: 6, column: Some(31), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); let mut expected_path = konfig_path.clone(); expected_path.push("base/pkg/kusion_models/kube/frontend/server.k"); compare_goto_res( @@ -1508,7 +1516,7 @@ fn konfig_goto_def_test_main() { line: 7, column: Some(14), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); let mut expected_path = konfig_path.clone(); expected_path.push("base/pkg/kusion_models/kube/frontend/server.k"); compare_goto_res( @@ -1528,7 +1536,7 @@ fn konfig_goto_def_test_main() { line: 2, column: Some(61), }; - let res = goto_definition_with_gs(&program, &pos, &gs); + let res = goto_def(&pos, &gs); let mut expected_path = konfig_path.clone(); expected_path.push("base/pkg/kusion_models/kube/templates/resource.k"); compare_goto_res( @@ -1548,7 +1556,8 @@ fn konfig_completion_test_main() { module_cache: None, scope_cache: None, vfs: Some(KCLVfs::default()), - compile_unit_cache: Some(KCLCompileUnitCache::default()), + entry_cache: Some(KCLEntryCache::default()), + tool: Arc::new(RwLock::new(toolchain::default())), }) .unwrap(); @@ -1558,7 +1567,8 @@ fn konfig_completion_test_main() { line: 6, column: Some(27), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1576,7 +1586,8 @@ fn konfig_completion_test_main() { line: 7, column: Some(4), }; - let got = completion(None, &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(None, &program, &pos, &gs, &tool).unwrap(); let mut got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1620,7 +1631,8 @@ fn konfig_completion_test_main() { line: 1, column: Some(35), }; - let got = completion(Some('.'), &program, &pos, &gs).unwrap(); + let tool = toolchain::default(); + let got = completion(Some('.'), &program, &pos, &gs, &tool).unwrap(); let mut got_labels: Vec = match got { CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(), CompletionResponse::List(_) => panic!("test failed"), @@ -1653,12 +1665,13 @@ fn konfig_hover_test_main() { let mut main_path = konfig_path.clone(); main_path.push("appops/nginx-example/dev/main.k"); let main_path_str = main_path.to_str().unwrap().to_string(); - let (program, _, gs) = compile_with_params(Params { + let (_program, _, gs) = compile_with_params(Params { file: main_path_str.clone(), module_cache: None, scope_cache: None, vfs: Some(KCLVfs::default()), - compile_unit_cache: Some(KCLCompileUnitCache::default()), + entry_cache: Some(KCLEntryCache::default()), + tool: Arc::new(RwLock::new(toolchain::default())), }) .unwrap(); @@ -1668,7 +1681,7 @@ fn konfig_hover_test_main() { line: 6, column: Some(32), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { HoverContents::Array(arr) => { let expect: Vec = vec![ @@ -1690,7 +1703,7 @@ fn konfig_hover_test_main() { line: 7, column: Some(15), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { HoverContents::Array(arr) => { let expect: Vec = vec![ @@ -1713,7 +1726,7 @@ fn konfig_hover_test_main() { line: 6, column: Some(3), }; - let got = hover(&program, &pos, &gs).unwrap(); + let got = hover(&pos, &gs).unwrap(); match got.contents { HoverContents::Scalar(s) => { assert_eq!( @@ -2091,7 +2104,8 @@ fn compile_unit_test() { module_cache: None, scope_cache: None, vfs: Some(KCLVfs::default()), - compile_unit_cache: Some(KCLCompileUnitCache::default()), + entry_cache: Some(KCLEntryCache::default()), + tool: Arc::new(RwLock::new(toolchain::default())), }) .unwrap(); // b.k is not contained in kcl.yaml but need to be contained in main pkg diff --git a/kclvm/tools/src/LSP/src/util.rs b/kclvm/tools/src/LSP/src/util.rs index ea0dba533..fc73bd476 100644 --- a/kclvm/tools/src/LSP/src/util.rs +++ b/kclvm/tools/src/LSP/src/util.rs @@ -6,11 +6,12 @@ use kclvm_ast::ast::{ use kclvm_ast::node_ref; use kclvm_ast::pos::ContainsPos; -use kclvm_driver::lookup_compile_unit; +use kclvm_driver::toolchain::Toolchain; +use kclvm_driver::{lookup_compile_unit, CompileUnitOptions}; use kclvm_error::Diagnostic; use kclvm_error::Position as KCLPos; use kclvm_parser::entry::get_dir_files; -use kclvm_parser::{load_program, KCLModuleCache, LoadProgramOptions, ParseSessionRef}; +use kclvm_parser::{load_program, KCLModuleCache, ParseSessionRef}; use kclvm_sema::advanced_resolver::AdvancedResolver; use kclvm_sema::core::global_state::GlobalState; use kclvm_sema::namer::Namer; @@ -19,7 +20,7 @@ use kclvm_sema::resolver::resolve_program_with_opts; use kclvm_sema::resolver::scope::KCLScopeCache; use crate::from_lsp; -use crate::state::{KCLCompileUnitCache, KCLVfs}; +use crate::state::{KCLEntryCache, KCLToolChain, KCLVfs}; use lsp_types::Url; use parking_lot::RwLockReadGuard; use ra_ap_vfs::{FileId, Vfs}; @@ -63,27 +64,29 @@ pub(crate) struct Params { pub file: String, pub module_cache: Option, pub scope_cache: Option, + pub entry_cache: Option, pub vfs: Option, - pub compile_unit_cache: Option, + pub tool: KCLToolChain, } -pub(crate) fn compile_unit_with_cache( - compile_unit_cache: &Option, +pub(crate) fn lookup_compile_unit_with_cache( + tool: &dyn Toolchain, + entry_map: &Option, file: &str, -) -> (Vec, Option) { - match compile_unit_cache { +) -> CompileUnitOptions { + match entry_map { Some(cache) => { let mut map = cache.write(); match map.get(file) { Some(compile_unit) => compile_unit.clone(), None => { - let res = lookup_compile_unit(file, true); + let res = lookup_compile_unit(tool, file, true); map.insert(file.to_string(), res.clone()); res } } } - None => lookup_compile_unit(file, true), + None => lookup_compile_unit(tool, file, true), } } @@ -91,7 +94,8 @@ pub(crate) fn compile_with_params( params: Params, ) -> anyhow::Result<(Program, IndexSet, GlobalState)> { // Lookup compile unit (kcl.mod or kcl.yaml) from the entry file. - let (mut files, opt) = compile_unit_with_cache(¶ms.compile_unit_cache, ¶ms.file); + let (mut files, opt) = + lookup_compile_unit_with_cache(&*params.tool.read(), ¶ms.entry_cache, ¶ms.file); if !files.contains(¶ms.file) { files.push(params.file.clone()); @@ -129,7 +133,7 @@ pub(crate) fn compile_with_params( let diags = sess.1.borrow().diagnostics.clone(); Ok((program, diags, gs)) }) { - Ok(res) => return res, + Ok(res) => res, Err(e) => Err(anyhow::anyhow!("Compile failed: {:?}", e)), } }