diff --git a/kclvm/config/src/lib.rs b/kclvm/config/src/lib.rs index edeb16cb9..4856a040b 100644 --- a/kclvm/config/src/lib.rs +++ b/kclvm/config/src/lib.rs @@ -5,6 +5,7 @@ pub mod modfile; pub mod path; pub mod settings; pub mod vfs; +pub mod workfile; #[cfg(test)] pub(crate) mod tests; diff --git a/kclvm/config/src/modfile.rs b/kclvm/config/src/modfile.rs index 3c4bdc81e..27c99dc3e 100644 --- a/kclvm/config/src/modfile.rs +++ b/kclvm/config/src/modfile.rs @@ -15,6 +15,7 @@ use crate::path::ModRelativePath; pub const KCL_MOD_FILE: &str = "kcl.mod"; pub const KCL_MOD_LOCK_FILE: &str = "kcl.mod.lock"; +pub const KCL_WORK_FILE: &str = "kcl.work"; pub const KCL_FILE_SUFFIX: &str = ".k"; pub const KCL_FILE_EXTENSION: &str = "k"; pub const KCL_MOD_PATH_ENV: &str = "${KCL_MOD}"; diff --git a/kclvm/config/src/testdata/a/a.k b/kclvm/config/src/testdata/a/a.k new file mode 100644 index 000000000..e69de29bb diff --git a/kclvm/config/src/testdata/b/b.k b/kclvm/config/src/testdata/b/b.k new file mode 100644 index 000000000..e69de29bb diff --git a/kclvm/config/src/testdata/kcl.work b/kclvm/config/src/testdata/kcl.work new file mode 100644 index 000000000..6e0c727ea --- /dev/null +++ b/kclvm/config/src/testdata/kcl.work @@ -0,0 +1,3 @@ +workspace ./a +workspace ./b +workspace ./c/d \ No newline at end of file diff --git a/kclvm/config/src/workfile.rs b/kclvm/config/src/workfile.rs new file mode 100644 index 000000000..fb09d7a16 --- /dev/null +++ b/kclvm/config/src/workfile.rs @@ -0,0 +1,190 @@ +//! The config for IDE/LSP workspace config file `kcl.work' + +use kclvm_utils::path::PathPrefix; +use serde::{Deserialize, Serialize}; +use std::{ + collections::HashMap, + io::{BufRead, BufReader}, + path::{Path, PathBuf}, +}; + +use crate::modfile::KCL_WORK_FILE; +use anyhow::Result; + +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct WorkFile { + pub workspaces: Vec, + pub failed: HashMap, +} + +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct WorkSpace { + pub content: String, + pub path: String, + pub abs_path: String, +} + +/// Load kcl work file from path +pub fn load_work_file + std::fmt::Debug>(path: P) -> Result { + let file = if path.as_ref().is_dir() { + let file_path = path.as_ref().join(KCL_WORK_FILE); + std::fs::File::open(file_path)? + } else if path.as_ref().is_file() { + std::fs::File::open(&path)? + } else { + return Err(anyhow::anyhow!("kcl.work not found for {:?}", path)); + }; + + let reader = BufReader::new(file); + let mut workfile = WorkFile::default(); + for line in reader.lines() { + if let Ok(line) = line { + let mut directive = line.split_whitespace(); + if let Some(key) = directive.next() { + match key { + "workspace" => { + if let Some(path) = directive.next() { + workfile.workspaces.push(WorkSpace { + content: line.clone(), + path: path.to_string(), + abs_path: "".to_string(), + }); + } + } + _ => { + workfile.failed.insert(line, "Unknown keyword".to_string()); + } + } + } + } + } + Ok(workfile) +} + +impl WorkFile { + pub fn canonicalize(&mut self, root: PathBuf) { + let mut new_workspaces = vec![]; + for workspace in self.workspaces.iter_mut() { + let path = Path::new(&workspace.path); + if !path.is_absolute() { + let filepath = root.join(Path::new(&workspace.path)); + match filepath.canonicalize() { + Ok(path) => new_workspaces.push(WorkSpace { + content: workspace.content.clone(), + path: workspace.path.clone(), + abs_path: path.adjust_canonicalization(), + }), + Err(e) => { + self.failed.insert( + workspace.content.clone(), + format!("path canonicalize failed: {:?}", e), + ); + } + } + } else { + new_workspaces.push(WorkSpace { + content: workspace.content.clone(), + path: workspace.path.clone(), + abs_path: workspace.path.clone(), + }) + }; + } + self.workspaces = new_workspaces; + } +} + +#[cfg(test)] +mod workfile_test { + use std::path::PathBuf; + + use crate::workfile::WorkSpace; + + use super::load_work_file; + #[test] + fn parse_workfile() { + let path = "./src/testdata/"; + let workfile = load_work_file(path).unwrap(); + assert_eq!( + workfile.workspaces, + vec![ + WorkSpace { + content: "workspace ./a".to_string(), + path: "./a".to_string(), + abs_path: "".to_string() + }, + WorkSpace { + content: "workspace ./b".to_string(), + path: "./b".to_string(), + abs_path: "".to_string() + }, + WorkSpace { + content: "workspace ./c/d".to_string(), + path: "./c/d".to_string(), + abs_path: "".to_string() + }, + ] + ); + } + + #[test] + fn parse_workfile1() { + let path = "./src/testdata/kcl.work"; + let workfile = load_work_file(path).unwrap(); + assert_eq!( + workfile.workspaces, + vec![ + WorkSpace { + content: "workspace ./a".to_string(), + path: "./a".to_string(), + abs_path: "".to_string() + }, + WorkSpace { + content: "workspace ./b".to_string(), + path: "./b".to_string(), + abs_path: "".to_string() + }, + WorkSpace { + content: "workspace ./c/d".to_string(), + path: "./c/d".to_string(), + abs_path: "".to_string() + }, + ] + ); + } + + #[test] + fn canonicalize_workfile() { + let path = "./src/testdata/kcl.work"; + let mut workfile = load_work_file(path).unwrap(); + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("testdata"); + let mut a = path.clone(); + a.push("a"); + + let mut b = path.clone(); + b.push("b"); + + let mut cd = path.clone(); + cd.push("c"); + cd.push("d"); + + workfile.canonicalize(path); + assert_eq!( + workfile.workspaces, + vec![ + WorkSpace { + content: "workspace ./a".to_string(), + path: "./a".to_string(), + abs_path: a.to_str().unwrap().to_string(), + }, + WorkSpace { + content: "workspace ./b".to_string(), + path: "./b".to_string(), + abs_path: b.to_str().unwrap().to_string(), + }, + ] + ); + assert!(!workfile.failed.is_empty()); + } +} diff --git a/kclvm/driver/src/lib.rs b/kclvm/driver/src/lib.rs index b6aeec28d..c80022bf6 100644 --- a/kclvm/driver/src/lib.rs +++ b/kclvm/driver/src/lib.rs @@ -11,15 +11,16 @@ use glob::glob; use kclvm_config::{ modfile::{ get_pkg_root, load_mod_file, KCL_FILE_EXTENSION, KCL_FILE_SUFFIX, KCL_MOD_FILE, - KCL_MOD_PATH_ENV, + KCL_MOD_PATH_ENV, KCL_WORK_FILE, }, path::ModRelativePath, settings::{build_settings_pathbuf, DEFAULT_SETTING_FILE}, + workfile::{load_work_file, WorkFile}, }; use kclvm_parser::LoadProgramOptions; use kclvm_utils::path::PathPrefix; -use std::env; use std::iter; +use std::{collections::HashMap, env}; use std::{ collections::HashSet, fs::read_dir, @@ -129,12 +130,16 @@ pub fn canonicalize_input_files( Ok(kcl_paths) } -/// Get compile uint(files and options) from a single file input. +/// Get compile workspace(files and options) from a single file input. /// 1. Lookup entry files in kcl.yaml /// 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(tool: &dyn Toolchain, file: &str, load_pkg: bool) -> CompileUnitOptions { +pub fn lookup_compile_workspace( + tool: &dyn Toolchain, + file: &str, + load_pkg: bool, +) -> CompileUnitOptions { match lookup_compile_unit_path(file) { Ok(CompileUnitPath::SettingFile(dir)) => { let settings_files = lookup_setting_files(&dir); @@ -225,6 +230,91 @@ pub fn lookup_compile_unit(tool: &dyn Toolchain, file: &str, load_pkg: bool) -> } } +pub fn lookup_compile_workspaces( + tool: &dyn Toolchain, + path: &str, + load_pkg: bool, +) -> ( + HashMap, + Option>, +) { + let mut workspaces = HashMap::new(); + match lookup_workspace(path) { + Ok(workspace) => match &workspace { + WorkSpaceKind::WorkFile(work_file_path) => { + if let Ok(mut workfile) = load_work_file(work_file_path) { + let root = work_file_path.parent().unwrap(); + workfile.canonicalize(root.to_path_buf()); + for work in workfile.workspaces { + match lookup_workspace(&work.abs_path) { + Ok(workspace) => { + workspaces.insert( + workspace.clone(), + lookup_compile_workspace(tool, &work.abs_path, load_pkg), + ); + } + Err(_) => {} + } + } + return (workspaces, Some(workfile.failed.clone())); + } + } + WorkSpaceKind::Folder(folder) => { + let mut load_opt = kclvm_parser::LoadProgramOptions::default(); + let metadata = + fill_pkg_maps_for_k_file(tool, path.into(), &mut load_opt).unwrap_or(None); + + if load_pkg { + if folder.is_file() { + if let Ok(files) = get_kcl_files(folder.clone(), false) { + // return (files, Some(load_opt), metadata); + workspaces.insert(workspace, (files, Some(load_opt), metadata)); + return (workspaces, None); + } + } + } + workspaces.insert( + workspace, + (vec![path.to_string()], Some(load_opt), metadata), + ); + } + + WorkSpaceKind::SettingFile(setting_file) => { + workspaces.insert( + workspace.clone(), + lookup_compile_workspace( + tool, + &setting_file.as_path().adjust_canonicalization(), + load_pkg, + ), + ); + } + + WorkSpaceKind::ModFile(mod_file) => { + workspaces.insert( + workspace.clone(), + lookup_compile_workspace( + tool, + &mod_file.as_path().adjust_canonicalization(), + load_pkg, + ), + ); + } + + WorkSpaceKind::File(_) | WorkSpaceKind::NotFound => { + let pathbuf = PathBuf::from(path); + let file_path = pathbuf.as_path(); + if file_path.is_file() { + workspaces.insert(workspace, lookup_compile_workspace(tool, path, load_pkg)); + } + } + }, + Err(_) => {} + } + + (workspaces, None) +} + /// Lookup default setting files e.g. kcl.yaml pub fn lookup_setting_files(dir: &Path) -> Vec { let mut settings = vec![]; @@ -258,6 +348,17 @@ pub enum CompileUnitPath { NotFound, } +/// LSP workspace, will replace CompileUnitPath +#[derive(Debug, PartialEq, Eq, Clone, Hash)] +pub enum WorkSpaceKind { + WorkFile(PathBuf), + ModFile(PathBuf), + SettingFile(PathBuf), + Folder(PathBuf), + File(PathBuf), + NotFound, +} + /// 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 @@ -300,6 +401,44 @@ pub fn lookup_compile_unit_path(file: &str) -> io::Result { Ok(CompileUnitPath::NotFound) } +/// It will replace lookup_compile_unit_path() +pub fn lookup_workspace(path: &str) -> io::Result { + let pathbuf = PathBuf::from(path); + let path = pathbuf.as_path(); + if path.is_dir() { + for entry in read_dir(path)? { + let entry = entry?; + if entry.file_name() == *KCL_WORK_FILE { + return Ok(WorkSpaceKind::WorkFile(entry.path())); + } + } + + for entry in read_dir(path)? { + let entry = entry?; + if entry.file_name() == *KCL_MOD_FILE { + return Ok(WorkSpaceKind::ModFile(entry.path())); + } + } + + for entry in read_dir(path)? { + let entry = entry?; + if entry.file_name() == *DEFAULT_SETTING_FILE { + return Ok(WorkSpaceKind::SettingFile(entry.path())); + } + } + + return Ok(WorkSpaceKind::Folder(PathBuf::from(path))); + } + if path.is_file() { + if let Some(ext) = path.extension() { + if ext.to_str().unwrap() == KCL_FILE_EXTENSION { + return Ok(WorkSpaceKind::File(PathBuf::from(path))); + } + } + } + Ok(WorkSpaceKind::NotFound) +} + /// Get kcl files from path. pub fn get_kcl_files>(path: P, recursively: bool) -> Result> { let mut files = vec![]; diff --git a/kclvm/tools/src/LSP/src/analysis.rs b/kclvm/tools/src/LSP/src/analysis.rs index 8c196598c..f22d08601 100644 --- a/kclvm/tools/src/LSP/src/analysis.rs +++ b/kclvm/tools/src/LSP/src/analysis.rs @@ -1,4 +1,5 @@ use kclvm_ast::ast::Program; +use kclvm_driver::WorkSpaceKind; use kclvm_sema::core::global_state::GlobalState; use parking_lot::RwLock; use ra_ap_vfs::FileId; @@ -10,6 +11,7 @@ pub type DocumentVersion = i32; #[derive(Default)] pub struct Analysis { pub db: Arc>>>>, + pub workspaces: Arc>>>>, } /// AnalysisDatabase holds the result of the compile diff --git a/kclvm/tools/src/LSP/src/state.rs b/kclvm/tools/src/LSP/src/state.rs index 492515bb2..0bf4fa1e3 100644 --- a/kclvm/tools/src/LSP/src/state.rs +++ b/kclvm/tools/src/LSP/src/state.rs @@ -1,12 +1,14 @@ 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::util::{compile, 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_driver::toolchain::{self, Toolchain}; -use kclvm_driver::CompileUnitOptions; +use kclvm_driver::{ + lookup_compile_workspaces, lookup_workspace, CompileUnitOptions, WorkSpaceKind, +}; use kclvm_parser::KCLModuleCache; use kclvm_sema::core::global_state::GlobalState; use kclvm_sema::resolver::scope::KCLScopeCache; @@ -100,6 +102,7 @@ pub(crate) struct LanguageServerSnapshot { pub vfs: Arc>, /// Holds the state of the analysis process pub db: Arc>>>>, + pub workspaces: Arc>>>>, /// Documents that are currently kept in memory from the client pub opened_files: Arc>>, /// request retry time @@ -129,7 +132,7 @@ impl LanguageServerState { Handle { handle, _receiver } }; - let state = LanguageServerState { + let mut state = LanguageServerState { sender, request_queue: ReqQueue::default(), vfs: Arc::new(RwLock::new(Default::default())), @@ -149,6 +152,8 @@ impl LanguageServerState { request_retry: Arc::new(RwLock::new(HashMap::new())), }; + state.init_workspaces(initialize_params.clone()); + let word_index_map = state.word_index_map.clone(); state.thread_pool.execute(move || { if let Err(err) = update_word_index_state(word_index_map, initialize_params, true) { @@ -394,6 +399,7 @@ impl LanguageServerState { entry_cache: self.entry_cache.clone(), tool: self.tool.clone(), request_retry: self.request_retry.clone(), + workspaces: self.analysis.workspaces.clone(), } } @@ -409,6 +415,65 @@ impl LanguageServerState { pub(crate) fn is_completed(&self, request: &lsp_server::Request) -> bool { self.request_queue.incoming.is_completed(&request.id) } + + fn init_workspaces(&mut self, initialize_params: InitializeParams) { + if let Some(workspace_folders) = initialize_params.workspace_folders { + for folder in workspace_folders { + let path = file_path_from_url(&folder.uri).unwrap(); + let tool = Arc::clone(&self.tool); + let (workspaces, failed) = lookup_compile_workspaces(&*tool.read(), &path, true); + + if let Some(failed) = failed { + for (key, err) in failed { + self.log_message(format!("parse kcl.work failed: {}: {}", key, err)); + } + } + + for (workspace, entrys) in workspaces { + self.thread_pool.execute({ + let mut snapshot = self.snapshot(); + let sender = self.task_sender.clone(); + let module_cache = Arc::clone(&self.module_cache); + let scope_cache = Arc::clone(&self.scope_cache); + let entry = Arc::clone(&self.entry_cache); + let tool = Arc::clone(&self.tool); + let gs_cache = Arc::clone(&self.gs_cache); + + let mut files = entrys.0.clone(); + move || { + let (_, compile_res) = compile( + Params { + file: "".to_string(), + module_cache: Some(module_cache), + scope_cache: Some(scope_cache), + vfs: Some(snapshot.vfs), + entry_cache: Some(entry), + tool, + gs_cache: Some(gs_cache), + }, + &mut files, + entrys.1, + ); + let mut workspaces = snapshot.workspaces.write(); + match compile_res { + Ok((prog, gs)) => { + workspaces.insert( + workspace, + Some(Arc::new(AnalysisDatabase { + prog, + gs, + version: -1, + })), + ); + } + Err(err) => {} + } + } + }) + } + } + } + } } pub(crate) fn log_message(message: String, sender: &Sender) -> anyhow::Result<()> { diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/init/folder/a.k b/kclvm/tools/src/LSP/src/test_data/workspace/init/folder/a.k new file mode 100644 index 000000000..e69de29bb diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/init/folder/b.k b/kclvm/tools/src/LSP/src/test_data/workspace/init/folder/b.k new file mode 100644 index 000000000..e69de29bb diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/init/mod/kcl.mod b/kclvm/tools/src/LSP/src/test_data/workspace/init/mod/kcl.mod new file mode 100644 index 000000000..cd1dad592 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/workspace/init/mod/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "mod" +edition = "v0.9.0" +version = "0.0.1" + + diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/init/mod/main.k b/kclvm/tools/src/LSP/src/test_data/workspace/init/mod/main.k new file mode 100644 index 000000000..fa7048e63 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/workspace/init/mod/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/init/work/a/a.k b/kclvm/tools/src/LSP/src/test_data/workspace/init/work/a/a.k new file mode 100644 index 000000000..e69de29bb diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/init/work/b/b.k b/kclvm/tools/src/LSP/src/test_data/workspace/init/work/b/b.k new file mode 100644 index 000000000..e69de29bb diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/init/work/c.k b/kclvm/tools/src/LSP/src/test_data/workspace/init/work/c.k new file mode 100644 index 000000000..e69de29bb diff --git a/kclvm/tools/src/LSP/src/test_data/workspace/init/work/kcl.work b/kclvm/tools/src/LSP/src/test_data/workspace/init/work/kcl.work new file mode 100644 index 000000000..f9f9acf5f --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/workspace/init/work/kcl.work @@ -0,0 +1,3 @@ +workspace ./a +workspace ./b +workspace ./c.k diff --git a/kclvm/tools/src/LSP/src/tests.rs b/kclvm/tools/src/LSP/src/tests.rs index 6a2887f7c..bb7533878 100644 --- a/kclvm/tools/src/LSP/src/tests.rs +++ b/kclvm/tools/src/LSP/src/tests.rs @@ -2,8 +2,10 @@ use crossbeam_channel::after; use crossbeam_channel::select; use indexmap::IndexSet; use kclvm_ast::MAIN_PKG; +use kclvm_config::workfile::WorkSpace; use kclvm_driver::toolchain; use kclvm_driver::toolchain::Metadata; +use kclvm_driver::WorkSpaceKind; use kclvm_sema::core::global_state::GlobalState; use kclvm_sema::resolver::scope::KCLScopeCache; @@ -45,6 +47,7 @@ use serde::Serialize; use std::cell::Cell; use std::cell::RefCell; use std::collections::HashMap; +use std::collections::HashSet; use std::env; use std::path::Path; use std::path::PathBuf; @@ -2258,3 +2261,134 @@ fn compile_unit_test() { .iter() .any(|m| m.filename == file)) } + +#[test] +fn kcl_workspace_init_kclwork_test() { + let tool: crate::state::KCLToolChain = Arc::new(RwLock::new(toolchain::default())); + let tool = Arc::clone(&tool); + + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init"); + + let mut work = root.clone(); + work.push("work"); + + let (workspaces, failed) = + kclvm_driver::lookup_compile_workspaces(&*tool.read(), &work.to_str().unwrap(), true); + + let mut expected = HashSet::new(); + + expected.insert(WorkSpaceKind::Folder( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init") + .join("work") + .join("a"), + )); + + expected.insert(WorkSpaceKind::Folder( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init") + .join("work") + .join("b"), + )); + + expected.insert(WorkSpaceKind::File( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init") + .join("work") + .join("c.k"), + )); + + assert_eq!( + expected, + workspaces.keys().into_iter().map(|w| w.clone()).collect() + ); + + assert!(failed.is_some()); + assert!(failed.unwrap().is_empty()); +} + +#[test] +fn kcl_workspace_init_kclmod_test() { + let tool: crate::state::KCLToolChain = Arc::new(RwLock::new(toolchain::default())); + let tool = Arc::clone(&tool); + + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init"); + + let mut work = root.clone(); + work.push("mod"); + + let (workspaces, failed) = + kclvm_driver::lookup_compile_workspaces(&*tool.read(), &work.to_str().unwrap(), true); + + let mut expected = HashSet::new(); + + expected.insert(WorkSpaceKind::ModFile( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init") + .join("mod") + .join("kcl.mod"), + )); + + assert_eq!( + expected, + workspaces.keys().into_iter().map(|w| w.clone()).collect() + ); + + assert!(failed.is_none()); +} + +#[test] +fn kcl_workspace_init_folder_test() { + let tool: crate::state::KCLToolChain = Arc::new(RwLock::new(toolchain::default())); + let tool = Arc::clone(&tool); + + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init"); + + let mut work = root.clone(); + work.push("folder"); + + let (workspaces, failed) = + kclvm_driver::lookup_compile_workspaces(&*tool.read(), &work.to_str().unwrap(), true); + + let mut expected = HashSet::new(); + + expected.insert(WorkSpaceKind::Folder( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("test_data") + .join("workspace") + .join("init") + .join("folder"), + )); + + assert_eq!( + expected, + workspaces.keys().into_iter().map(|w| w.clone()).collect() + ); + + assert!(failed.is_none()); +} diff --git a/kclvm/tools/src/LSP/src/util.rs b/kclvm/tools/src/LSP/src/util.rs index 973f31c56..27eea25c1 100644 --- a/kclvm/tools/src/LSP/src/util.rs +++ b/kclvm/tools/src/LSP/src/util.rs @@ -9,11 +9,12 @@ use kclvm_ast::pos::ContainsPos; use kclvm_config::modfile::KCL_MOD_FILE; use kclvm_driver::toolchain::Toolchain; use kclvm_driver::{ - lookup_compile_unit, lookup_compile_unit_path, CompileUnitOptions, CompileUnitPath, + lookup_compile_unit_path, lookup_compile_workspace, CompileUnitOptions, CompileUnitPath, }; use kclvm_error::Diagnostic; use kclvm_error::Position as KCLPos; use kclvm_parser::entry::get_dir_files; +use kclvm_parser::LoadProgramOptions; use kclvm_parser::{ entry::get_normalized_k_files_from_paths, load_program, KCLModuleCache, ParseSessionRef, }; @@ -107,7 +108,7 @@ pub(crate) fn lookup_compile_unit_with_cache( if cached_timestamp == ¤t_timestamp { compile_unit.clone() } else { - let res = lookup_compile_unit(tool, file, true); + let res = lookup_compile_workspace(tool, file, true); map.insert( file.to_string(), (res.clone(), Some(current_timestamp)), @@ -116,20 +117,20 @@ pub(crate) fn lookup_compile_unit_with_cache( } } (_, current_timestamp) => { - let res = lookup_compile_unit(tool, file, true); + let res = lookup_compile_workspace(tool, file, true); map.insert(file.to_string(), (res.clone(), current_timestamp)); res } } } None => { - let res = lookup_compile_unit(tool, file, true); + let res = lookup_compile_workspace(tool, file, true); map.insert(file.to_string(), (res.clone(), current_timestamp)); res } } } - None => lookup_compile_unit(tool, file, true), + None => lookup_compile_workspace(tool, file, true), } } @@ -167,6 +168,14 @@ pub(crate) fn compile_with_params( if !files.contains(¶ms.file) { files.push(params.file.clone()); } + compile(params, &mut files, opts) +} + +pub(crate) fn compile( + params: Params, + files: &mut Vec, + opts: Option, +) -> (IndexSet, anyhow::Result<(Program, GlobalState)>) { // Ignore the kcl plugin sematic check. let mut opts = opts.unwrap_or_default(); opts.load_plugins = true; @@ -182,7 +191,7 @@ pub(crate) fn compile_with_params( }; let files: Vec<&str> = files.iter().map(|s| s.as_str()).collect(); // Update opt.k_code_list - if let Some(vfs) = params.vfs { + if let Some(vfs) = ¶ms.vfs { let mut k_code_list = match load_files_code_from_vfs(&files, vfs) { Ok(code_list) => code_list, Err(e) => { @@ -274,7 +283,7 @@ pub(crate) fn apply_document_changes( } } -fn load_files_code_from_vfs(files: &[&str], vfs: KCLVfs) -> anyhow::Result> { +fn load_files_code_from_vfs(files: &[&str], vfs: &KCLVfs) -> anyhow::Result> { let mut res = vec![]; let vfs = &mut vfs.read(); for file in files {