Skip to content

Commit

Permalink
feat: lsp workspace. 1. delete db and use workspace to store compile …
Browse files Browse the repository at this point in the history
…result. 2.Initialize the global workspace when starting lsp. For file changes, update the workspace for files in the global workspace and create a temporary workspace for files not in the global workspace (compatible with old versions, consistent with previous behavior). 3.Publish Diag globally, not only in the currently opened file

Signed-off-by: he1pa <18012015693@163.com>
  • Loading branch information
He1pa committed Aug 22, 2024
1 parent 7edd84f commit fc768a0
Show file tree
Hide file tree
Showing 12 changed files with 399 additions and 258 deletions.
2 changes: 1 addition & 1 deletion kclvm/driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use kclvm_config::{
},
path::ModRelativePath,
settings::{build_settings_pathbuf, DEFAULT_SETTING_FILE},
workfile::load_work_file,
workfile::{load_work_file, WorkFile},
};
use kclvm_parser::LoadProgramOptions;
use kclvm_utils::path::PathPrefix;
Expand Down
38 changes: 31 additions & 7 deletions kclvm/parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,14 @@ pub fn load_program(
Loader::new(sess, paths, opts, module_cache).load_main()
}

pub type KCLModuleCache = Arc<RwLock<IndexMap<String, ast::Module>>>;
pub type KCLModuleCache = Arc<RwLock<ModuleCache>>;

#[derive(Default, Debug)]
pub struct ModuleCache {
pub ast_cache: IndexMap<String, ast::Module>,
/// Invalid modules and new code, equivalent to paths and k_code_list. The difference is that paths is in the main package.
pub invalidate_module: HashMap<String, Option<String>>,
}
struct Loader {
sess: ParseSessionRef,
paths: Vec<String>,
Expand All @@ -320,7 +327,7 @@ impl Loader {
sess: ParseSessionRef,
paths: &[&str],
opts: Option<LoadProgramOptions>,
module_cache: Option<Arc<RwLock<IndexMap<String, ast::Module>>>>,
module_cache: Option<KCLModuleCache>,
) -> Self {
Self {
sess,
Expand Down Expand Up @@ -350,15 +357,30 @@ impl Loader {
for entry in compile_entries.iter() {
let k_files = entry.get_k_files();
let maybe_k_codes = entry.get_k_codes();
// Load main package.
// update main pkg ast cache
for (i, filename) in k_files.iter().enumerate() {
let m = parse_file_with_session(
self.sess.clone(),
filename,
maybe_k_codes[i].clone(),
)?;
let mut module_cache_ref = module_cache.write().unwrap();
module_cache_ref.insert(filename.clone(), m.clone());
module_cache_ref
.ast_cache
.insert(filename.clone(), m.clone());
}
// update invalidate module ast cache
let mut module_cache_ref = module_cache.write().unwrap();
let invalidate_module = module_cache_ref.invalidate_module.clone();
module_cache_ref.invalidate_module.clear();
drop(module_cache_ref);

for (filename, code) in invalidate_module.iter() {
let m = parse_file_with_session(self.sess.clone(), filename, code.clone())?;
let mut module_cache_ref = module_cache.write().unwrap();
module_cache_ref
.ast_cache
.insert(filename.clone(), m.clone());
}
}
}
Expand All @@ -370,7 +392,7 @@ impl Loader {
for (i, filename) in k_files.iter().enumerate() {
let mut m = if let Some(module_cache) = self.module_cache.as_ref() {
let module_cache_ref = module_cache.read().unwrap();
module_cache_ref.get(filename).unwrap().clone()
module_cache_ref.ast_cache.get(filename).unwrap().clone()
} else {
parse_file_with_session(self.sess.clone(), filename, maybe_k_codes[i].clone())?
};
Expand Down Expand Up @@ -619,13 +641,15 @@ impl Loader {
for filename in k_files {
let mut m = if let Some(module_cache) = self.module_cache.as_ref() {
let module_cache_ref = module_cache.read().unwrap();
if let Some(module) = module_cache_ref.get(&filename) {
if let Some(module) = module_cache_ref.ast_cache.get(&filename) {
module.clone()
} else {
let m = parse_file_with_session(self.sess.clone(), &filename, None)?;
drop(module_cache_ref);
let mut module_cache_ref = module_cache.write().unwrap();
module_cache_ref.insert(filename.clone(), m.clone());
module_cache_ref
.ast_cache
.insert(filename.clone(), m.clone());
m
}
} else {
Expand Down
4 changes: 3 additions & 1 deletion kclvm/sema/src/resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,14 @@ pub fn resolve_program_with_opts(
cached_scope.invalidate_pkgs.clear();
cached_scope.update(program);
resolver.scope_map = cached_scope.scope_map.clone();
resolver.scope_map.remove(kclvm_ast::MAIN_PKG);
resolver.node_ty_map = Rc::new(RefCell::new(cached_scope.node_ty_map.clone()));
resolver.ctx.schema_mapping = cached_scope.schema_mapping.clone();
cached_scope
.invalidate_pkgs
.insert(kclvm_ast::MAIN_PKG.to_string());
for pkg in &cached_scope.invalidate_pkgs {
resolver.scope_map.remove(pkg);
}
}
}
let scope = resolver.check_and_lint(kclvm_ast::MAIN_PKG);
Expand Down
17 changes: 13 additions & 4 deletions kclvm/tools/src/LSP/src/analysis.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
use indexmap::IndexSet;
use kclvm_ast::ast::Program;
use kclvm_driver::WorkSpaceKind;
use kclvm_error::Diagnostic;
use kclvm_sema::core::global_state::GlobalState;
use parking_lot::RwLock;
use ra_ap_vfs::FileId;
use std::{collections::HashMap, sync::Arc};
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};

pub type DocumentVersion = i32;

#[derive(Default, Clone)]
pub struct OpenFileInfo {
pub version: DocumentVersion,
pub workspaces: HashSet<WorkSpaceKind>,
}

/// Analysis holds the analysis mapping (FileId -> AnalysisDatabase)
#[derive(Default)]
pub struct Analysis {
pub db: Arc<RwLock<HashMap<FileId, Option<Arc<AnalysisDatabase>>>>>,
pub workspaces: Arc<RwLock<HashMap<WorkSpaceKind, Option<Arc<AnalysisDatabase>>>>>,
}

Expand All @@ -19,5 +28,5 @@ pub struct Analysis {
pub struct AnalysisDatabase {
pub prog: Program,
pub gs: GlobalState,
pub version: DocumentVersion,
pub diags: IndexSet<Diagnostic>,
}
4 changes: 0 additions & 4 deletions kclvm/tools/src/LSP/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ pub(crate) enum LSPError {
Retry,
FileIdNotFound(VfsPath),
AnalysisDatabaseNotFound(VfsPath),
DocumentVersionNotFound(VfsPath),
}

impl fmt::Display for LSPError {
Expand All @@ -25,9 +24,6 @@ impl fmt::Display for LSPError {
"Internal bug: Path {path} analysisDatabase not found, maybe compile failed"
)
}
LSPError::DocumentVersionNotFound(path) => {
write!(f, "Internal bug: {path} document version not found")
}
}
}
}
Expand Down
29 changes: 20 additions & 9 deletions kclvm/tools/src/LSP/src/notification.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use kclvm_config::{modfile::KCL_MOD_FILE, settings::DEFAULT_SETTING_FILE};
use kclvm_config::{
modfile::{KCL_MOD_FILE, KCL_WORK_FILE},
settings::DEFAULT_SETTING_FILE,
};
use lsp_types::notification::{
Cancel, DidChangeTextDocument, DidChangeWatchedFiles, DidCloseTextDocument,
DidOpenTextDocument, DidSaveTextDocument,
};
use std::path::Path;
use std::{collections::HashSet, path::Path};

use crate::{
analysis::OpenFileInfo,
dispatcher::NotificationDispatcher,
from_lsp,
state::LanguageServerState,
Expand Down Expand Up @@ -52,9 +56,13 @@ impl LanguageServerState {
);

if let Some(id) = self.vfs.read().file_id(&path.into()) {
self.opened_files
.write()
.insert(id, params.text_document.version);
self.opened_files.write().insert(
id,
OpenFileInfo {
version: params.text_document.version,
workspaces: HashSet::new(),
},
);
}
Ok(())
}
Expand Down Expand Up @@ -97,9 +105,11 @@ impl LanguageServerState {
let old_text = text.clone();
apply_document_changes(&mut text, content_changes);
vfs.set_file_contents(path.into(), Some(text.clone().into_bytes()));
self.opened_files
.write()
.insert(file_id, text_document.version);
let mut opened_files = self.opened_files.write();
let file_info = opened_files.get_mut(&file_id).unwrap();
file_info.version = text_document.version;
drop(opened_files);

// Update word index
let old_word_index = build_word_index_with_content(&old_text, &text_document.uri, true);
let new_word_index = build_word_index_with_content(&text, &text_document.uri, true);
Expand Down Expand Up @@ -147,11 +157,12 @@ impl LanguageServerState {
self.loader.handle.invalidate(path.clone());
if KCL_CONFIG_FILE.contains(&path.file_name().unwrap().to_str().unwrap()) {
self.entry_cache.write().clear();
self.init_workspaces();
}
}

Ok(())
}
}

const KCL_CONFIG_FILE: [&str; 2] = [DEFAULT_SETTING_FILE, KCL_MOD_FILE];
const KCL_CONFIG_FILE: [&str; 3] = [DEFAULT_SETTING_FILE, KCL_MOD_FILE, KCL_WORK_FILE];
4 changes: 2 additions & 2 deletions kclvm/tools/src/LSP/src/quick_fix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ mod tests {
use super::quick_fix;
use crate::{
state::KCLVfs,
to_lsp::kcl_diag_to_lsp_diags,
to_lsp::kcl_diag_to_lsp_diags_by_file,
util::{compile_with_params, Params},
};

Expand All @@ -196,7 +196,7 @@ mod tests {

let diagnostics = diags
.iter()
.flat_map(|diag| kcl_diag_to_lsp_diags(diag, file))
.flat_map(|diag| kcl_diag_to_lsp_diags_by_file(diag, file))
.collect::<Vec<Diagnostic>>();

let uri = Url::from_file_path(file).unwrap();
Expand Down
Loading

0 comments on commit fc768a0

Please sign in to comment.