Repository: kcl-lang/kcl (language: rust)

Issue:
[WIP] Feat : Support Call Kclvm Cli by C API
<!-- Thank you for contributing to KusionStack!

Note: 

1. With pull requests:

    - Open your pull request against "main"
    - Your pull request should have no more than two commits, if not you should squash them.
    - It should pass all tests in the available continuous integration systems such as GitHub Actions.
    - You should add/modify tests to cover your proposed code changes.
    - If your pull request contains a new feature, please document it on the README.

2. Please create an issue first to describe the problem.

    We recommend that link the issue with the PR in the following question.
    For more info, check https://kusionstack.io/docs/governance/contribute/
-->

#### 1. Does this PR affect any open issues?(Y/N) and add issue references (e.g. "fix #123", "re #123".):

- [ ] N
- [x] Y 
re #125 

#### 2. What is the scope of this PR (e.g. component or file name):

<!-- You can add the scope of this change here. 
-->
        KCLVM/kclvm/spec
        KCLVM/kclvm/src/lib.rs

#### 3. Provide a description of the PR(e.g. more details, effects, motivations or doc link):

<!-- You can choose a brief description here -->
- [ ] Affects user behaviors
- [ ] Contains syntax changes
- [ ] Contains variable changes
- [x] Contains experimental features
- [ ] Performance regression: Consumes more CPU
- [ ] Performance regression: Consumes more Memory
- [ ] Other

<!-- You can add more details here.
-->
    Support user to call kclvm_cli by c_api


#### 4. Are there any breaking changes?(Y/N) and describe the breaking changes(e.g. more details, motivations or doc link):

- [x] N
- [ ] Y 

<!-- You can add more details here.

-->

#### 5. Are there test cases for these changes?(Y/N) select and add more details, references or doc links:

<!-- You can choose a brief description here -->
- [x] Unit test
- [ ] Integration test
- [ ] Benchmark (add benchmark stats below)
- [ ] Manual test (add detailed scripts or steps below)
- [ ] Other

<!-- You can add more details here.
None
-->
KCLVM/kclvm/src/api_test.rs

#### 6. Release note

<!-- compatibility change, improvement, bugfix, and new feature need a release note -->

Please refer to [Release Notes Language Style Guide](https://kusionstack.io/docs/governance/release-policy/) to write a quality release note.

```release-note
None
```



Discussion / hints:
****CLA Assistant Lite bot**** All contributors have signed the CLA  ✍️ ✅
I have read the CLA Document and I hereby sign the CLA
## Pull Request Test Coverage Report for [Build 2744948016](https://coveralls.io/builds/51191024)

* **2** of **5523**   **(0.04%)**  changed or added relevant lines in **6** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage decreased (**-7.6%**) to **51.731%**

---

|  Changes Missing Coverage | Covered Lines | Changed/Added Lines | % |
| :-----|--------------|--------|---: |
| [kclvm/spec/src/main.rs](https://coveralls.io/builds/51191024/source?filename=kclvm%2Fspec%2Fsrc%2Fmain.rs#L2) | 1 | 3 | 33.33%
| [kclvm/spec/src/service/util.rs](https://coveralls.io/builds/51191024/source?filename=kclvm%2Fspec%2Fsrc%2Fservice%2Futil.rs#L2) | 0 | 25 | 0.0%
| [kclvm/spec/src/service/service.rs](https://coveralls.io/builds/51191024/source?filename=kclvm%2Fspec%2Fsrc%2Fservice%2Fservice.rs#L10) | 0 | 109 | 0.0%
| [kclvm/spec/src/service/api.rs](https://coveralls.io/builds/51191024/source?filename=kclvm%2Fspec%2Fsrc%2Fservice%2Fapi.rs#L10) | 0 | 153 | 0.0%
| [kclvm/spec/src/model/gpyrpc.rs](https://coveralls.io/builds/51191024/source?filename=kclvm%2Fspec%2Fsrc%2Fmodel%2Fgpyrpc.rs#L28) | 0 | 5232 | 0.0%
<!-- | **Total:** | **2** | **5523** | **0.04%** | -->


|  Totals | [![Coverage Status](https://coveralls.io/builds/51191024/badge)](https://coveralls.io/builds/51191024) |
| :-- | --: |
| Change from base [Build 2743999583](https://coveralls.io/builds/51186839): |  -7.6% |
| Covered Lines: | 22244 |
| Relevant Lines: | 42999 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Fix patch:
diff --git a/kclvm/ast/src/ast.rs b/kclvm/ast/src/ast.rs
index b021bff62..9dbae2924 100644
--- a/kclvm/ast/src/ast.rs
+++ b/kclvm/ast/src/ast.rs
@@ -413,7 +413,9 @@ impl Into<SerializeProgram> for Program {
 pub struct Program {
     pub root: String,
     pub pkgs: HashMap<String, Vec<String>>,
+    pub pkgs_not_imported: HashMap<String, Vec<String>>,
     pub modules: HashMap<String, Arc<RwLock<Module>>>,
+    pub modules_not_imported: HashMap<String, Arc<RwLock<Module>>>,
 }
 
 impl Program {
@@ -453,7 +455,11 @@ impl Program {
         &self,
         module_path: &str,
     ) -> anyhow::Result<Option<RwLockReadGuard<'_, Module>>> {
-        match self.modules.get(module_path) {
+        match self
+            .modules
+            .get(module_path)
+            .or(self.modules_not_imported.get(module_path))
+        {
             Some(module_ref) => match module_ref.read() {
                 Ok(m) => Ok(Some(m)),
                 Err(_) => Err(anyhow::anyhow!("Failed to acquire module lock")),
@@ -466,7 +472,11 @@ impl Program {
         &self,
         module_path: &str,
     ) -> anyhow::Result<Option<RwLockWriteGuard<'_, Module>>> {
-        match self.modules.get(module_path) {
+        match self
+            .modules
+            .get(module_path)
+            .or(self.modules_not_imported.get(module_path))
+        {
             Some(module_ref) => match module_ref.write() {
                 Ok(m) => Ok(Some(m)),
                 Err(_) => Err(anyhow::anyhow!("Failed to acquire module lock")),
@@ -476,12 +486,19 @@ impl Program {
     }
 
     pub fn get_module_ref(&self, module_path: &str) -> Option<Arc<RwLock<Module>>> {
-        self.modules.get(module_path).cloned()
+        self.modules
+            .get(module_path)
+            .cloned()
+            .or(self.modules_not_imported.get(module_path).cloned())
     }
 
     pub fn get_modules_for_pkg(&self, pkg_name: &str) -> Vec<Arc<RwLock<Module>>> {
         let mut result = Vec::new();
-        if let Some(module_names) = self.pkgs.get(pkg_name) {
+        if let Some(module_names) = self
+            .pkgs
+            .get(pkg_name)
+            .or(self.pkgs_not_imported.get(pkg_name))
+        {
             for module_name in module_names {
                 if let Some(module) = self.get_module_ref(module_name) {
                     result.push(module);
diff --git a/kclvm/driver/src/lib.rs b/kclvm/driver/src/lib.rs
index bbb4c896a..a455e4e3e 100644
--- a/kclvm/driver/src/lib.rs
+++ b/kclvm/driver/src/lib.rs
@@ -146,14 +146,12 @@ pub fn lookup_compile_workspaces(
                 }
             }
             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);
+                let load_opt = kclvm_parser::LoadProgramOptions::default();
+                let metadata = None;
 
                 if load_pkg {
                     if folder.is_dir() {
                         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);
                         }
diff --git a/kclvm/parser/src/lib.rs b/kclvm/parser/src/lib.rs
index d4cdb7c8d..04c707bae 100644
--- a/kclvm/parser/src/lib.rs
+++ b/kclvm/parser/src/lib.rs
@@ -926,7 +926,10 @@ pub fn parse_program(
     opts: &LoadProgramOptions,
 ) -> Result<LoadProgramResult> {
     let compile_entries = get_compile_entries_from_paths(&paths, &opts)?;
-    let workdir = compile_entries.get_root_path().to_string();
+    let workdir = compile_entries
+        .get_root_path()
+        .to_string()
+        .adjust_canonicalization();
     let mut pkgs: HashMap<String, Vec<String>> = HashMap::new();
     let mut new_files = HashSet::new();
     for entry in compile_entries.iter() {
@@ -1004,11 +1007,12 @@ pub fn parse_program(
             }
         }
     }
-
     let program = ast::Program {
         root: workdir,
         pkgs,
+        pkgs_not_imported: HashMap::new(),
         modules,
+        modules_not_imported: HashMap::new(),
     };
 
     Ok(LoadProgramResult {
@@ -1038,9 +1042,13 @@ pub fn load_all_files_under_paths(
             &loader.opts,
         ) {
             Ok(res) => {
+                let diag = sess.1.read().diagnostics.clone();
                 let mut res = res.clone();
                 let k_files_from_import = res.paths.clone();
-                let (k_files_under_path, pkgmap) = get_files_from_path(paths, opts)?;
+                let mut paths = paths.to_vec();
+                paths.push(&res.program.root);
+                let (k_files_under_path, pkgmap) =
+                    get_files_from_path(&res.program.root, &paths, opts)?;
                 loader.pkgmap.extend(pkgmap);
 
                 // Filter unparsed file
@@ -1054,33 +1062,69 @@ pub fn load_all_files_under_paths(
                     }
                 }
 
-                let module_cache = module_cache.unwrap_or_default();
-                let pkgs = &mut res.program.pkgs;
+                let module_cache = loader.module_cache.clone();
+                let pkgs_not_imported = &mut res.program.pkgs_not_imported;
 
                 let mut new_files = HashSet::new();
-
                 // Bfs unparsed and import files
+                loader.parsed_file.extend(unparsed_file.clone());
                 while let Some(file) = unparsed_file.pop_front() {
                     new_files.insert(file.clone());
-                    let deps = parse_file(
-                        sess.clone(),
-                        file,
-                        None,
-                        module_cache.clone(),
-                        pkgs,
-                        &mut loader.pkgmap,
-                        loader.file_graph.clone(),
-                        &loader.opts,
-                    )?;
-                    for dep in deps {
-                        if loader.parsed_file.insert(dep.clone()) {
-                            unparsed_file.push_back(dep.clone());
-                        }
+                    let module_cache_read = module_cache.read();
+                    match &module_cache_read {
+                        Ok(m_cache) => match m_cache.ast_cache.get(file.get_path()) {
+                            Some(_) => continue,
+                            None => {
+                                drop(module_cache_read);
+                                let deps = parse_file(
+                                    sess.clone(),
+                                    file.clone(),
+                                    None,
+                                    module_cache.clone(),
+                                    pkgs_not_imported,
+                                    &mut loader.pkgmap,
+                                    loader.file_graph.clone(),
+                                    &loader.opts,
+                                )?;
+
+                                let m_ref = match module_cache.read() {
+                                    Ok(module_cache) => module_cache
+                                        .ast_cache
+                                        .get(file.get_path())
+                                        .expect(&format!(
+                                            "Module not found in module: {:?}",
+                                            file.get_path()
+                                        ))
+                                        .clone(),
+                                    Err(e) => {
+                                        return Err(anyhow::anyhow!("Parse program failed: {e}"))
+                                    }
+                                };
+
+                                let pkg = loader.pkgmap.get(&file).expect("file not in pkgmap");
+                                let mut m = m_ref.write().unwrap();
+                                fix_rel_import_path_with_file(
+                                    &pkg.pkg_root,
+                                    &mut m,
+                                    &file,
+                                    &loader.pkgmap,
+                                    &loader.opts,
+                                    sess.clone(),
+                                );
+
+                                for dep in deps {
+                                    if loader.parsed_file.insert(dep.clone()) {
+                                        unparsed_file.push_back(dep.clone());
+                                    }
+                                }
+                            }
+                        },
+                        Err(e) => return Err(anyhow::anyhow!("Parse entry failed: {e}")),
                     }
                 }
 
                 // Merge unparsed module into res
-                let modules = &mut res.program.modules;
+                let modules_not_imported = &mut res.program.modules_not_imported;
                 for file in &new_files {
                     let filename = file.get_path().to_str().unwrap().to_string();
                     let m_ref = match module_cache.read() {
@@ -1094,52 +1138,17 @@ pub fn load_all_files_under_paths(
                             .clone(),
                         Err(e) => return Err(anyhow::anyhow!("Parse program failed: {e}")),
                     };
-                    modules.insert(filename.clone(), m_ref);
-                    match pkgs.get_mut(&file.pkg_path) {
+                    modules_not_imported.insert(filename.clone(), m_ref);
+                    match pkgs_not_imported.get_mut(&file.pkg_path) {
                         Some(pkg_modules) => {
                             pkg_modules.push(filename.clone());
                         }
                         None => {
-                            pkgs.insert(file.pkg_path.clone(), vec![filename]);
+                            pkgs_not_imported.insert(file.pkg_path.clone(), vec![filename]);
                         }
                     }
                 }
-
-                // Generate new paths
-                let files = match loader.file_graph.read() {
-                    Ok(file_graph) => {
-                        let files = match file_graph.toposort() {
-                            Ok(files) => files,
-                            Err(_) => file_graph.paths(),
-                        };
-
-                        let file_path_graph = file_graph.file_path_graph().0;
-                        if let Err(cycle) = toposort(&file_path_graph) {
-                            let formatted_cycle = cycle
-                                .iter()
-                                .map(|file| format!("- {}\n", file.to_string_lossy()))
-                                .collect::<String>();
-
-                            sess.1.write().add_error(
-                                ErrorKind::RecursiveLoad,
-                                &[Message {
-                                    range: (Position::dummy_pos(), Position::dummy_pos()),
-                                    style: Style::Line,
-                                    message: format!(
-                                        "Could not compiles due to cyclic import statements\n{}",
-                                        formatted_cycle.trim_end()
-                                    ),
-                                    note: None,
-                                    suggested_replacement: None,
-                                }],
-                            );
-                        }
-                        files
-                    }
-                    Err(e) => return Err(anyhow::anyhow!("Parse program failed: {e}")),
-                };
-
-                res.paths = files.iter().map(|file| file.get_path().clone()).collect();
+                sess.1.write().diagnostics = diag;
                 return Ok(res);
             }
             e => return e,
@@ -1149,6 +1158,7 @@ pub fn load_all_files_under_paths(
 
 /// Get all kcl files under path and dependencies from opts, regardless of whether they are imported or not
 pub fn get_files_from_path(
+    root: &str,
     paths: &[&str],
     opts: Option<LoadProgramOptions>,
 ) -> Result<(HashMap<String, Vec<PathBuf>>, HashMap<PkgFile, Pkg>)> {
@@ -1175,11 +1185,15 @@ pub fn get_files_from_path(
                     .to_str()
                     .unwrap()
                     .to_string();
-                    let fix_path = fix_path
+                    let mut fix_path = fix_path
                         .replace(['/', '\\'], ".")
                         .trim_end_matches('.')
                         .to_string();
 
+                    if fix_path.is_empty() {
+                        fix_path = MAIN_PKG.to_string();
+                    }
+
                     let pkgfile = PkgFile::new(p.clone(), fix_path.clone());
                     pkgmap.insert(
                         pkgfile,
@@ -1203,12 +1217,11 @@ pub fn get_files_from_path(
         if path_buf.is_dir() {
             let all_k_files_under_path = get_kcl_files(path, true)?;
             for f in &all_k_files_under_path {
-                let p = PathBuf::from(f);
-
+                let p = PathBuf::from(f.adjust_canonicalization());
                 let fix_path = p
                     .parent()
                     .unwrap()
-                    .strip_prefix(path_buf.clone())
+                    .strip_prefix(root)
                     .unwrap()
                     .to_str()
                     .unwrap()
diff --git a/kclvm/query/src/query.rs b/kclvm/query/src/query.rs
index f7f926cee..ece300208 100644
--- a/kclvm/query/src/query.rs
+++ b/kclvm/query/src/query.rs
@@ -207,7 +207,7 @@ pub fn get_full_schema_type(
 /// use maplit::hashmap;
 /// use kclvm_ast::MAIN_PKG;
 ///
-/// let work_dir_parent = Path::new(".").join("src").join("test_data").join("get_schema_ty_under_path");
+/// let work_dir_parent = Path::new(env!("CARGO_MANIFEST_DIR")).join("src").join("test_data").join("get_schema_ty_under_path");
 ///
 /// let result = get_full_schema_type_under_path(
 ///     None,
@@ -236,33 +236,8 @@ pub fn get_full_schema_type_under_path(
     schema_name: Option<&str>,
     opts: CompilationOptions,
 ) -> Result<IndexMap<String, Vec<SchemaType>>> {
-    let mut result = IndexMap::new();
     let program_scope = resolve_paths(&opts)?;
-    for (pkg, scope) in &program_scope.scope_map {
-        for (name, o) in &scope.borrow().elems {
-            if o.borrow().ty.is_schema() {
-                let schema_ty = o.borrow().ty.into_schema_type();
-                if opts.get_schema_opts == GetSchemaOption::All
-                    || (opts.get_schema_opts == GetSchemaOption::Definitions
-                        && !schema_ty.is_instance)
-                    || (opts.get_schema_opts == GetSchemaOption::Instances && schema_ty.is_instance)
-                {
-                    // Schema name filter
-                    match schema_name {
-                        Some(schema_name) => {
-                            if schema_name.is_empty() || schema_name == name {
-                                result.entry(pkg.clone()).or_insert(vec![]).push(schema_ty);
-                            }
-                        }
-                        None => {
-                            result.entry(pkg.clone()).or_insert(vec![]).push(schema_ty);
-                        }
-                    }
-                }
-            }
-        }
-    }
-    Ok(result)
+    Ok(filter_pkg_schemas(&program_scope, schema_name, Some(opts)))
 }
 
 fn get_full_schema_type_recursive(schema_ty: SchemaType) -> Result<SchemaType> {
@@ -308,3 +283,50 @@ fn resolve_paths(opts: &CompilationOptions) -> Result<ProgramScope> {
         None,
     ))
 }
+
+pub fn filter_pkg_schemas(
+    program_scope: &ProgramScope,
+    schema_name: Option<&str>,
+    opts: Option<CompilationOptions>,
+) -> IndexMap<String, Vec<SchemaType>> {
+    let mut result = IndexMap::new();
+    for (pkg, scope) in &program_scope.scope_map {
+        for (name, o) in &scope.borrow().elems {
+            if o.borrow().ty.is_schema() {
+                let schema_ty = o.borrow().ty.into_schema_type();
+                if let Some(opts) = &opts {
+                    if opts.get_schema_opts == GetSchemaOption::All
+                        || (opts.get_schema_opts == GetSchemaOption::Definitions
+                            && !schema_ty.is_instance)
+                        || (opts.get_schema_opts == GetSchemaOption::Instances
+                            && schema_ty.is_instance)
+                    {
+                        // Schema name filter
+                        match schema_name {
+                            Some(schema_name) => {
+                                if schema_name.is_empty() || schema_name == name {
+                                    result.entry(pkg.clone()).or_insert(vec![]).push(schema_ty);
+                                }
+                            }
+                            None => {
+                                result.entry(pkg.clone()).or_insert(vec![]).push(schema_ty);
+                            }
+                        }
+                    }
+                } else {
+                    match schema_name {
+                        Some(schema_name) => {
+                            if schema_name.is_empty() || schema_name == name {
+                                result.entry(pkg.clone()).or_insert(vec![]).push(schema_ty);
+                            }
+                        }
+                        None => {
+                            result.entry(pkg.clone()).or_insert(vec![]).push(schema_ty);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    result
+}
diff --git a/kclvm/runner/src/assembler.rs b/kclvm/runner/src/assembler.rs
index 3aff09456..5915fca8e 100644
--- a/kclvm/runner/src/assembler.rs
+++ b/kclvm/runner/src/assembler.rs
@@ -299,6 +299,8 @@ impl KclvmAssembler {
                 root: self.program.root.clone(),
                 pkgs,
                 modules: self.program.modules.clone(),
+                pkgs_not_imported: HashMap::new(),
+                modules_not_imported: HashMap::new(),
             };
             compile_progs.insert(
                 pkgpath,
diff --git a/kclvm/runner/src/lib.rs b/kclvm/runner/src/lib.rs
index 6dbe81f48..934438146 100644
--- a/kclvm/runner/src/lib.rs
+++ b/kclvm/runner/src/lib.rs
@@ -261,6 +261,8 @@ pub fn execute_module(m: Module) -> Result<ExecProgramResult> {
         root: MAIN_PKG.to_string(),
         pkgs,
         modules,
+        pkgs_not_imported: HashMap::new(),
+        modules_not_imported: HashMap::new(),
     };
 
     execute(
diff --git a/kclvm/sema/src/advanced_resolver/mod.rs b/kclvm/sema/src/advanced_resolver/mod.rs
index b38be6dec..b10039cff 100644
--- a/kclvm/sema/src/advanced_resolver/mod.rs
+++ b/kclvm/sema/src/advanced_resolver/mod.rs
@@ -121,66 +121,76 @@ impl<'ctx> AdvancedResolver<'ctx> {
         };
         // Scan all scehma symbol
         for (name, modules) in advanced_resolver.ctx.program.pkgs.iter() {
-            if !advanced_resolver.gs.new_or_invalidate_pkgs.contains(name) {
-                continue;
+            advanced_resolver.scan_schemas(name, modules)?;
+        }
+
+        for (name, modules) in advanced_resolver.ctx.program.pkgs.iter() {
+            advanced_resolver.walk_pkg(name, modules)?;
+        }
+
+        advanced_resolver.gs.build_sema_db();
+        advanced_resolver.gs.new_or_invalidate_pkgs.clear();
+        Ok(())
+    }
+
+    fn scan_schemas(&mut self, name: &String, modules: &Vec<String>) -> anyhow::Result<()> {
+        if !self.gs.new_or_invalidate_pkgs.contains(name) {
+            return Ok(());
+        }
+        self.ctx.current_pkgpath = Some(name.clone());
+        if let Some(pkg_info) = self.gs.get_packages().get_package_info(name) {
+            if modules.is_empty() {
+                return Ok(());
+            }
+            if !self.ctx.scopes.is_empty() {
+                self.ctx.scopes.clear();
             }
-            advanced_resolver.ctx.current_pkgpath = Some(name.clone());
-            if let Some(pkg_info) = advanced_resolver.gs.get_packages().get_package_info(name) {
-                if modules.is_empty() {
-                    continue;
-                }
-                if !advanced_resolver.ctx.scopes.is_empty() {
-                    advanced_resolver.ctx.scopes.clear();
-                }
 
-                advanced_resolver.enter_root_scope(
-                    name.clone(),
-                    pkg_info.pkg_filepath.clone(),
-                    pkg_info.kfile_paths.clone(),
-                );
+            self.enter_root_scope(
+                name.clone(),
+                pkg_info.pkg_filepath.clone(),
+                pkg_info.kfile_paths.clone(),
+            );
 
-                let modules = advanced_resolver.ctx.program.get_modules_for_pkg(name);
-                for module in modules.iter() {
-                    let module = module.read().expect("Failed to acquire module lock");
-                    advanced_resolver.ctx.current_filename = Some(module.filename.clone());
-                    advanced_resolver.walk_module_schemas(&module)?;
-                }
-                advanced_resolver.leave_scope()
+            let modules = self.ctx.program.get_modules_for_pkg(name);
+            for module in modules.iter() {
+                let module = module.read().expect("Failed to acquire module lock");
+                self.ctx.current_filename = Some(module.filename.clone());
+                self.walk_module_schemas(&module)?;
             }
+            self.leave_scope()
         }
+        Ok(())
+    }
 
-        for (name, modules) in advanced_resolver.ctx.program.pkgs.iter() {
-            if !advanced_resolver.gs.new_or_invalidate_pkgs.contains(name) {
-                continue;
+    fn walk_pkg(&mut self, name: &String, modules: &Vec<String>) -> anyhow::Result<()> {
+        if !self.gs.new_or_invalidate_pkgs.contains(name) {
+            return Ok(());
+        }
+        self.ctx.current_pkgpath = Some(name.clone());
+        if let Some(_) = self.gs.get_packages().get_package_info(name) {
+            if modules.is_empty() {
+                return Ok(());
+            }
+            if !self.ctx.scopes.is_empty() {
+                self.ctx.scopes.clear();
             }
-            advanced_resolver.ctx.current_pkgpath = Some(name.clone());
-            if let Some(_) = advanced_resolver.gs.get_packages().get_package_info(name) {
-                if modules.is_empty() {
-                    continue;
-                }
-                if !advanced_resolver.ctx.scopes.is_empty() {
-                    advanced_resolver.ctx.scopes.clear();
-                }
 
-                let scope_ref = advanced_resolver
-                    .gs
-                    .get_scopes_mut()
-                    .get_root_scope(name.to_string())
-                    .unwrap();
+            let scope_ref = self
+                .gs
+                .get_scopes_mut()
+                .get_root_scope(name.to_string())
+                .unwrap();
 
-                advanced_resolver.ctx.scopes.push(scope_ref);
-                let modules = advanced_resolver.ctx.program.get_modules_for_pkg(name);
-                for module in modules.iter() {
-                    let module = module.read().expect("Failed to acquire module lock");
-                    advanced_resolver.ctx.current_filename = Some(module.filename.clone());
-                    advanced_resolver.walk_module(&module)?;
-                }
-                advanced_resolver.leave_scope()
+            self.ctx.scopes.push(scope_ref);
+            let modules = self.ctx.program.get_modules_for_pkg(name);
+            for module in modules.iter() {
+                let module = module.read().expect("Failed to acquire module lock");
+                self.ctx.current_filename = Some(module.filename.clone());
+                self.walk_module(&module)?;
             }
+            self.leave_scope()
         }
-
-        advanced_resolver.gs.build_sema_db();
-        advanced_resolver.gs.new_or_invalidate_pkgs.clear();
         Ok(())
     }
 
diff --git a/kclvm/sema/src/advanced_resolver/node.rs b/kclvm/sema/src/advanced_resolver/node.rs
index b74ac15c6..0d7faf4cc 100644
--- a/kclvm/sema/src/advanced_resolver/node.rs
+++ b/kclvm/sema/src/advanced_resolver/node.rs
@@ -62,7 +62,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'_> {
                         .gs
                         .get_symbols()
                         .get_symbol(schema_symbol)
-                        .ok_or(anyhow!("schema_symbol not found"))?;
+                        .ok_or(anyhow!("schema_symbol not found1"))?;
                     if let Some(schema_ty) = schema_symbol.get_sema_info().ty.clone() {
                         if !unification_stmt.target.node.names.is_empty() {
                             let schema_ty = schema_ty.into_schema_type();
@@ -232,7 +232,10 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'_> {
             .node_ty_map
             .borrow()
             .get(&self.ctx.get_node_key(&schema_stmt.name.id))
-            .ok_or(anyhow!("schema_ty not found"))?
+            .ok_or(anyhow!(
+                "schema_ty not found when walk schema stmt {:?}",
+                schema_stmt
+            ))?
             .clone();
         let schema_symbol = self
             .gs
@@ -875,7 +878,10 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'_> {
             .node_ty_map
             .borrow()
             .get(&self.ctx.get_node_key(&schema_expr.name.id))
-            .ok_or(anyhow!("schema_ty not found"))?
+            .ok_or(anyhow!(
+                "schema_ty not found when walk schema expr {:?}",
+                schema_expr
+            ))?
             .clone();
         match schema_ty.kind {
             TypeKind::Schema(_) => {
diff --git a/kclvm/sema/src/core/symbol.rs b/kclvm/sema/src/core/symbol.rs
index cd14b03c3..0b81521fe 100644
--- a/kclvm/sema/src/core/symbol.rs
+++ b/kclvm/sema/src/core/symbol.rs
@@ -106,6 +106,10 @@ pub enum SymbolHintKind {
 }
 
 impl SymbolData {
+    pub fn get_all_schemas(&self) -> &Arena<SchemaSymbol> {
+        &self.schemas
+    }
+
     pub fn get_package_symbol(&self, id: SymbolRef) -> Option<&PackageSymbol> {
         if matches!(id.get_kind(), SymbolKind::Package) {
             self.packages.get(id.get_id())
diff --git a/kclvm/sema/src/namer/mod.rs b/kclvm/sema/src/namer/mod.rs
index 2303fd663..5c6560672 100644
--- a/kclvm/sema/src/namer/mod.rs
+++ b/kclvm/sema/src/namer/mod.rs
@@ -113,75 +113,74 @@ impl<'ctx> Namer<'ctx> {
             .add_package(namer.ctx.current_package_info.take().unwrap());
 
         for (name, modules) in namer.ctx.program.pkgs.iter() {
-            // new pkgs or invalidate pkg
-            if namer.gs.get_packages().get_package_info(name).is_some()
-                && !namer.gs.new_or_invalidate_pkgs.contains(name)
-            {
-                continue;
-            }
+            namer.walk_pkg(name, modules);
+        }
 
-            // add new pkgs to invalidate pkgs
-            namer.gs.new_or_invalidate_pkgs.insert(name.clone());
-
-            {
-                if modules.is_empty() {
-                    continue;
-                }
-                namer.ctx.value_fully_qualified_name_set.clear();
-                let mut real_path = Path::new(&program.root)
-                    .join(name.replace('.', &std::path::MAIN_SEPARATOR.to_string()))
-                    .to_str()
-                    .unwrap()
-                    .to_string();
-                if name == kclvm_ast::MAIN_PKG {
-                    real_path = program.root.clone()
-                }
-                let pkg_pos = Position {
-                    filename: real_path.clone(),
-                    line: 0,
-                    column: None,
-                };
-
-                let pkg_symbol = PackageSymbol::new(name.clone(), pkg_pos.clone(), pkg_pos);
-                let symbol_ref = namer
-                    .gs
-                    .get_symbols_mut()
-                    .alloc_package_symbol(pkg_symbol, name.to_string());
-                namer.ctx.owner_symbols.push(symbol_ref);
+        namer.define_symbols();
+    }
 
-                namer.ctx.current_package_info =
-                    Some(PackageInfo::new(name.to_string(), real_path, false));
-            }
+    fn walk_pkg(&mut self, name: &String, modules: &Vec<String>) {
+        // new pkgs or invalidate pkg
+        if self.gs.get_packages().get_package_info(name).is_some()
+            && !self.gs.new_or_invalidate_pkgs.contains(name)
+        {
+            return;
+        }
 
-            let modules = namer.ctx.program.get_modules_for_pkg(name);
-            for module in modules.iter() {
-                let module = module.read().expect("Failed to acquire module lock");
-                namer
-                    .ctx
-                    .current_package_info
-                    .as_mut()
-                    .unwrap()
-                    .kfile_paths
-                    .insert(module.filename.clone());
-                namer.ctx.current_module_info =
-                    Some(ModuleInfo::new(module.filename.clone(), name.to_string()));
-                namer.walk_module(&module);
-                namer
-                    .gs
-                    .get_packages_mut()
-                    .add_module_info(namer.ctx.current_module_info.take().unwrap());
-            }
+        // add new pkgs to invalidate pkgs
+        self.gs.new_or_invalidate_pkgs.insert(name.clone());
 
-            namer.ctx.owner_symbols.pop();
-            namer
+        {
+            if modules.is_empty() {
+                return;
+            }
+            self.ctx.value_fully_qualified_name_set.clear();
+            let mut real_path = Path::new(&self.ctx.program.root)
+                .join(name.replace('.', &std::path::MAIN_SEPARATOR.to_string()))
+                .to_str()
+                .unwrap()
+                .to_string();
+            if name == kclvm_ast::MAIN_PKG {
+                real_path = self.ctx.program.root.clone()
+            }
+            let pkg_pos = Position {
+                filename: real_path.clone(),
+                line: 0,
+                column: None,
+            };
+
+            let pkg_symbol = PackageSymbol::new(name.clone(), pkg_pos.clone(), pkg_pos);
+            let symbol_ref = self
                 .gs
-                .get_packages_mut()
-                .add_package(namer.ctx.current_package_info.take().unwrap())
+                .get_symbols_mut()
+                .alloc_package_symbol(pkg_symbol, name.to_string());
+            self.ctx.owner_symbols.push(symbol_ref);
+
+            self.ctx.current_package_info =
+                Some(PackageInfo::new(name.to_string(), real_path, false));
         }
 
-        namer.define_symbols();
+        let modules = self.ctx.program.get_modules_for_pkg(name);
+        for module in modules.iter() {
+            let module = module.read().expect("Failed to acquire module lock");
+            self.ctx
+                .current_package_info
+                .as_mut()
+                .unwrap()
+                .kfile_paths
+                .insert(module.filename.clone());
+            self.ctx.current_module_info =
+                Some(ModuleInfo::new(module.filename.clone(), name.to_string()));
+            self.walk_module(&module);
+            self.gs
+                .get_packages_mut()
+                .add_module_info(self.ctx.current_module_info.take().unwrap());
+        }
 
-        // namer.gs
+        self.ctx.owner_symbols.pop();
+        self.gs
+            .get_packages_mut()
+            .add_package(self.ctx.current_package_info.take().unwrap())
     }
 
     fn init_builtin_symbols(&mut self) {
diff --git a/kclvm/sema/src/resolver/global.rs b/kclvm/sema/src/resolver/global.rs
index 4796a114d..9f5c97adc 100644
--- a/kclvm/sema/src/resolver/global.rs
+++ b/kclvm/sema/src/resolver/global.rs
@@ -27,7 +27,12 @@ impl<'ctx> Resolver<'_> {
     pub(crate) fn init_global_types(&mut self) {
         // 1. Scan all schema and rule type symbols
         let pkgpath = &self.ctx.pkgpath;
-        match self.program.pkgs.get(pkgpath) {
+        match self
+            .program
+            .pkgs
+            .get(pkgpath)
+            .or(self.program.pkgs_not_imported.get(pkgpath))
+        {
             Some(modules) => {
                 // 1. Scan all schema and rule type symbol
                 for module in modules {
diff --git a/kclvm/sema/src/resolver/mod.rs b/kclvm/sema/src/resolver/mod.rs
index 8b318c993..3987f821a 100644
--- a/kclvm/sema/src/resolver/mod.rs
+++ b/kclvm/sema/src/resolver/mod.rs
@@ -73,7 +73,12 @@ impl<'ctx> Resolver<'ctx> {
     pub(crate) fn check(&mut self, pkgpath: &str) {
         self.check_import(pkgpath);
         self.init_global_types();
-        match self.program.pkgs.get(pkgpath) {
+        match self
+            .program
+            .pkgs
+            .get(pkgpath)
+            .or(self.program.pkgs_not_imported.get(pkgpath))
+        {
             Some(modules) => {
                 for module in modules {
                     let module = self
@@ -99,26 +104,29 @@ impl<'ctx> Resolver<'ctx> {
 
     pub(crate) fn check_and_lint_all_pkgs(&mut self) -> ProgramScope {
         self.check(kclvm_ast::MAIN_PKG);
-        for pkg in self.program.pkgs.keys() {
+        self.lint_check_scope_map();
+        let mut handler = self.handler.clone();
+        for diag in &self.linter.handler.diagnostics {
+            handler.diagnostics.insert(diag.clone());
+        }
+
+        for pkg in self.program.pkgs_not_imported.keys() {
             if !self.scope_map.contains_key(pkg) {
                 self.check(pkg);
             }
         }
+
         let mut scope_map = self.scope_map.clone();
         for invalid_pkg_scope in &self.ctx.invalid_pkg_scope {
             scope_map.remove(invalid_pkg_scope);
         }
-        let mut scope = ProgramScope {
+        let scope = ProgramScope {
             scope_map,
             import_names: self.ctx.import_names.clone(),
             node_ty_map: self.node_ty_map.clone(),
-            handler: self.handler.clone(),
+            handler,
             schema_mapping: self.ctx.schema_mapping.clone(),
         };
-        self.lint_check_scope_map();
-        for diag in &self.linter.handler.diagnostics {
-            scope.handler.diagnostics.insert(diag.clone());
-        }
         scope
     }
 }
diff --git a/kclvm/tools/src/LSP/src/analysis.rs b/kclvm/tools/src/LSP/src/analysis.rs
index 3cb60a77f..fbcef2258 100644
--- a/kclvm/tools/src/LSP/src/analysis.rs
+++ b/kclvm/tools/src/LSP/src/analysis.rs
@@ -1,8 +1,8 @@
-use indexmap::IndexSet;
+use indexmap::{IndexMap, IndexSet};
 use kclvm_ast::ast::Program;
 use kclvm_driver::WorkSpaceKind;
 use kclvm_error::Diagnostic;
-use kclvm_sema::core::global_state::GlobalState;
+use kclvm_sema::{core::global_state::GlobalState, ty::SchemaType};
 use parking_lot::RwLock;
 use std::{
     collections::{HashMap, HashSet},
@@ -38,4 +38,5 @@ pub struct AnalysisDatabase {
     pub prog: Program,
     pub gs: GlobalState,
     pub diags: IndexSet<Diagnostic>,
+    pub schema_map: IndexMap<String, Vec<SchemaType>>,
 }
diff --git a/kclvm/tools/src/LSP/src/compile.rs b/kclvm/tools/src/LSP/src/compile.rs
index ed87010f4..3bfc02ff6 100644
--- a/kclvm/tools/src/LSP/src/compile.rs
+++ b/kclvm/tools/src/LSP/src/compile.rs
@@ -1,16 +1,18 @@
-use indexmap::IndexSet;
+use indexmap::{IndexMap, IndexSet};
 use kclvm_ast::ast::Program;
 use kclvm_driver::{lookup_compile_workspace, toolchain};
 use kclvm_error::Diagnostic;
 use kclvm_parser::{
-    entry::get_normalized_k_files_from_paths, load_program, KCLModuleCache, LoadProgramOptions,
-    ParseSessionRef,
+    entry::get_normalized_k_files_from_paths, load_all_files_under_paths, KCLModuleCache,
+    LoadProgramOptions, ParseSessionRef,
 };
+use kclvm_query::query::filter_pkg_schemas;
 use kclvm_sema::{
     advanced_resolver::AdvancedResolver,
     core::global_state::GlobalState,
     namer::Namer,
     resolver::{resolve_program_with_opts, scope::KCLScopeCache},
+    ty::SchemaType,
 };
 use std::collections::HashSet;
 use std::path::PathBuf;
@@ -32,7 +34,10 @@ pub fn compile(
     params: Params,
     files: &mut [String],
     opts: Option<LoadProgramOptions>,
-) -> (IndexSet<Diagnostic>, anyhow::Result<(Program, GlobalState)>) {
+) -> (
+    IndexSet<Diagnostic>,
+    anyhow::Result<(Program, IndexMap<String, Vec<SchemaType>>, GlobalState)>,
+) {
     // Ignore the kcl plugin sematic check.
     let mut opts = opts.unwrap_or_default();
     opts.load_plugins = true;
@@ -92,10 +97,12 @@ pub fn compile(
             }
         }
     }
-    let mut program = match load_program(sess.clone(), &files, Some(opts), params.module_cache) {
-        Ok(r) => r.program,
-        Err(e) => return (diags, Err(anyhow::anyhow!("Parse failed: {:?}", e))),
-    };
+
+    let mut program =
+        match load_all_files_under_paths(sess.clone(), &files, Some(opts), params.module_cache) {
+            Ok(r) => r.program,
+            Err(e) => return (diags, Err(anyhow::anyhow!("Parse failed: {:?}", e))),
+        };
     diags.extend(sess.1.read().diagnostics.clone());
 
     // Resolver
@@ -118,6 +125,7 @@ pub fn compile(
         },
         params.scope_cache.clone(),
     );
+    let schema_map: IndexMap<String, Vec<SchemaType>> = filter_pkg_schemas(&prog_scope, None, None);
     diags.extend(prog_scope.handler.diagnostics);
 
     let mut default = GlobalState::default();
@@ -141,12 +149,16 @@ pub fn compile(
         },
         None => HashSet::new(),
     };
+
+    gs.new_or_invalidate_pkgs
+        .extend(program.pkgs_not_imported.keys().map(|n| n.clone()));
+
     gs.clear_cache();
 
     Namer::find_symbols(&program, gs);
 
     match AdvancedResolver::resolve_program(&program, gs, prog_scope.node_ty_map) {
-        Ok(_) => (diags, Ok((program, gs.clone()))),
+        Ok(_) => (diags, Ok((program, schema_map, gs.clone()))),
         Err(e) => (diags, Err(anyhow::anyhow!("Resolve failed: {:?}", e))),
     }
 }
@@ -156,7 +168,7 @@ pub fn compile_with_params(
     params: Params,
 ) -> (
     IndexSet<kclvm_error::Diagnostic>,
-    anyhow::Result<(Program, GlobalState)>,
+    anyhow::Result<(Program, IndexMap<String, Vec<SchemaType>>, GlobalState)>,
 ) {
     let file = PathBuf::from(params.file.clone().unwrap())
         .canonicalize()
diff --git a/kclvm/tools/src/LSP/src/completion.rs b/kclvm/tools/src/LSP/src/completion.rs
index 70db428d1..83f763f09 100644
--- a/kclvm/tools/src/LSP/src/completion.rs
+++ b/kclvm/tools/src/LSP/src/completion.rs
@@ -16,11 +16,13 @@
 //!     + schema init
 
 use crate::goto_def::{find_def, find_symbol};
-use indexmap::IndexSet;
+use crate::to_lsp::lsp_pos;
+use indexmap::{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, Metadata, Toolchain};
+use kclvm_error::diagnostic::Range;
 use kclvm_parser::get_kcl_files;
 use kclvm_sema::core::global_state::GlobalState;
 use std::io;
@@ -65,6 +67,12 @@ impl From<KCLCompletionItemKind> for CompletionItemKind {
     }
 }
 
+#[derive(Debug, Clone, PartialEq, Hash, Eq, Default)]
+pub struct TextEdit {
+    pub range: Range,
+    pub new_text: String,
+}
+
 /// Abstraction of CompletionItem in KCL
 #[derive(Debug, Clone, PartialEq, Hash, Eq, Default)]
 pub(crate) struct KCLCompletionItem {
@@ -73,6 +81,7 @@ pub(crate) struct KCLCompletionItem {
     pub documentation: Option<String>,
     pub kind: Option<KCLCompletionItemKind>,
     pub insert_text: Option<String>,
+    pub additional_text_edits: Option<Vec<TextEdit>>,
 }
 
 /// Computes completions at the given position.
@@ -83,6 +92,7 @@ pub fn completion(
     gs: &GlobalState,
     tool: &dyn Toolchain,
     metadata: Option<Metadata>,
+    schema_map: &IndexMap<String, Vec<SchemaType>>,
 ) -> Option<lsp_types::CompletionResponse> {
     match trigger_character {
         Some(c) => match c {
@@ -107,6 +117,7 @@ pub fn completion(
                     documentation: None,
                     kind: Some(KCLCompletionItemKind::Module),
                     insert_text: None,
+                    additional_text_edits: None,
                 }));
             }
 
@@ -132,6 +143,7 @@ pub fn completion(
                                                 name,
                                                 &ty.into_func_type(),
                                             )),
+                                            additional_text_edits: None,
                                         },
                                     ));
                                 }
@@ -150,8 +162,13 @@ pub fn completion(
                                     name,
                                     &ty.into_func_type(),
                                 )),
+                                additional_text_edits: None,
                             }
                         }));
+                        // Complete all schema def in gs if in main pkg
+                        if program.get_main_files().contains(&pos.filename) {
+                            completions.extend(unimport_schemas(&pos.filename, gs, schema_map));
+                        }
                     }
                 }
 
@@ -172,7 +189,7 @@ pub fn completion(
                                             ));
                                             // complete schema value
                                             completions.insert(schema_ty_to_value_complete_item(
-                                                &schema_ty,
+                                                &schema_ty, true,
                                             ));
                                         }
                                         SymbolKind::Package => {
@@ -182,6 +199,7 @@ pub fn completion(
                                                 documentation: sema_info.doc.clone(),
                                                 kind: Some(KCLCompletionItemKind::Module),
                                                 insert_text: None,
+                                                additional_text_edits: None,
                                             });
                                         }
                                         _ => {
@@ -197,6 +215,7 @@ pub fn completion(
                                                 documentation: sema_info.doc.clone(),
                                                 kind: type_to_item_kind(ty),
                                                 insert_text: None,
+                                                additional_text_edits: None,
                                             });
                                         }
                                     },
@@ -317,6 +336,7 @@ fn completion_dot(
                                     documentation,
                                     kind,
                                     insert_text,
+                                    additional_text_edits: None,
                                 });
                             }
                             None => {
@@ -326,6 +346,7 @@ fn completion_dot(
                                     documentation: None,
                                     kind: None,
                                     insert_text: None,
+                                    additional_text_edits: None,
                                 });
                             }
                         }
@@ -367,6 +388,7 @@ fn completion_assign(pos: &KCLPos, gs: &GlobalState) -> Option<lsp_types::Comple
                                             kind: Some(KCLCompletionItemKind::Variable),
                                             documentation: sema_info.doc.clone(),
                                             insert_text: Some(format!(" {}", insert_text)),
+                                            additional_text_edits: None,
                                         },
                                     ),
                                 );
@@ -403,6 +425,7 @@ fn completion_newline(
                 documentation: Some(format!("docstring for {}", schema.name.node.clone())),
                 kind: Some(KCLCompletionItemKind::Doc),
                 insert_text: None,
+                additional_text_edits: None,
             });
         }
         return Some(into_completion_items(&completions).into());
@@ -439,6 +462,7 @@ fn completion_newline(
                                                 },
                                                 kind: Some(KCLCompletionItemKind::SchemaAttr),
                                                 insert_text: None,
+                                                additional_text_edits: None,
                                             });
                                         }
                                         _ => {}
@@ -491,6 +515,7 @@ fn completion_import_builtin_pkg() -> IndexSet<KCLCompletionItem> {
             documentation: None,
             kind: Some(KCLCompletionItemKind::Module),
             insert_text: None,
+            additional_text_edits: None,
         })
         .collect()
 }
@@ -521,6 +546,7 @@ fn completion_import_internal_pkg(
                                 documentation: None,
                                 kind: Some(KCLCompletionItemKind::Dir),
                                 insert_text: None,
+                                additional_text_edits: None,
                             });
                         }
                     } else {
@@ -541,6 +567,7 @@ fn completion_import_internal_pkg(
                                             documentation: None,
                                             kind: Some(KCLCompletionItemKind::Module),
                                             insert_text: None,
+                                            additional_text_edits: None,
                                         });
                                     }
                                 }
@@ -565,6 +592,7 @@ fn completion_import_external_pkg(metadata: Option<Metadata>) -> IndexSet<KCLCom
                 documentation: None,
                 kind: Some(KCLCompletionItemKind::Dir),
                 insert_text: None,
+                additional_text_edits: None,
             })
             .collect(),
         None => IndexSet::new(),
@@ -580,13 +608,22 @@ fn completion_import_external_pkg(metadata: Option<Metadata>) -> IndexSet<KCLCom
 /// complete to
 /// ```no_check
 /// #[cfg(not(test))]
-/// p = Person(param1, param2){}<cursor>
+/// import pkg
+/// p = pkg.Person(param1, param2){<cursor>}
 /// ```
-fn schema_ty_to_value_complete_item(schema_ty: &SchemaType) -> KCLCompletionItem {
+fn schema_ty_to_value_complete_item(schema_ty: &SchemaType, has_import: bool) -> KCLCompletionItem {
+    let schema = schema_ty.clone();
     let param = schema_ty.func.params.clone();
+    let pkg_path_last_name = if schema.pkgpath.is_empty() || schema.pkgpath == MAIN_PKG {
+        "".to_string()
+    } else {
+        format!("{}", schema.pkgpath.split('.').last().unwrap())
+    };
+    let need_import = !pkg_path_last_name.is_empty() && !has_import;
+
     let label = format!(
-        "{}{}{}",
-        schema_ty.name.clone(),
+        "{}{}{}{}",
+        schema.name,
         if param.is_empty() {
             "".to_string()
         } else {
@@ -599,26 +636,24 @@ fn schema_ty_to_value_complete_item(schema_ty: &SchemaType) -> KCLCompletionItem
                     .join(", ")
             )
         },
-        "{}"
+        "{}",
+        if need_import {
+            format!("(import {})", schema.pkgpath)
+        } else {
+            "".to_string()
+        },
     );
-    let detail = {
-        let mut details = vec![];
-        let (pkgpath, rest_sign) = schema_ty.schema_ty_signature_str();
-        details.push(format!("{}\n\n{}", pkgpath, rest_sign));
-        details.push("Attributes:".to_string());
-        for (name, attr) in &schema_ty.attrs {
-            details.push(format!(
-                "{}{}: {}",
-                name,
-                if attr.is_optional { "?" } else { "" },
-                attr.ty.ty_str(),
-            ));
-        }
-        details.join("\n")
-    };
+
+    // `pkg_path.schema_name{<cursor>}` or `schema_name{<cursor>}`
     let insert_text = format!(
-        "{}{}{}",
-        schema_ty.name.clone(),
+        "{}{}{}{}{}",
+        pkg_path_last_name,
+        if pkg_path_last_name.is_empty() {
+            ""
+        } else {
+            "."
+        },
+        schema.name,
         if param.is_empty() {
             "".to_string()
         } else {
@@ -632,14 +667,42 @@ fn schema_ty_to_value_complete_item(schema_ty: &SchemaType) -> KCLCompletionItem
                     .join(", ")
             )
         },
-        "{}"
+        "{$0}"
     );
+
+    // insert `import pkg`
+    let additional_text_edits = if need_import {
+        Some(vec![TextEdit {
+            range: (KCLPos::dummy_pos(), KCLPos::dummy_pos()),
+            new_text: format!("import {}\n", schema.pkgpath),
+        }])
+    } else {
+        None
+    };
+
+    let detail = {
+        let mut details = vec![];
+        let (pkgpath, rest_sign) = schema_ty.schema_ty_signature_str();
+        details.push(format!("{}\n\n{}", pkgpath, rest_sign));
+        details.push("Attributes:".to_string());
+        for (name, attr) in &schema_ty.attrs {
+            details.push(format!(
+                "{}{}: {}",
+                name,
+                if attr.is_optional { "?" } else { "" },
+                attr.ty.ty_str(),
+            ));
+        }
+        details.join("\n")
+    };
+
     KCLCompletionItem {
         label,
         detail: Some(detail),
         documentation: Some(schema_ty.doc.clone()),
         kind: Some(KCLCompletionItemKind::Schema),
         insert_text: Some(insert_text),
+        additional_text_edits,
     }
 }
 
@@ -676,6 +739,7 @@ fn schema_ty_to_type_complete_item(schema_ty: &SchemaType) -> KCLCompletionItem
         documentation: Some(schema_ty.doc.clone()),
         kind: Some(KCLCompletionItemKind::Schema),
         insert_text: None,
+        additional_text_edits: None,
     }
 }
 
@@ -709,6 +773,7 @@ fn dot_completion_in_import_stmt(
                         documentation: None,
                         kind: Some(KCLCompletionItemKind::Dir),
                         insert_text: None,
+                        additional_text_edits: None,
                     });
                 } else if path.is_file() {
                     if let Some(extension) = path.extension() {
@@ -725,6 +790,7 @@ fn dot_completion_in_import_stmt(
                                 documentation: None,
                                 kind: Some(KCLCompletionItemKind::File),
                                 insert_text: None,
+                                additional_text_edits: None,
                             });
                         }
                     }
@@ -835,25 +901,71 @@ fn type_to_item_kind(ty: &Type) -> Option<KCLCompletionItemKind> {
 pub(crate) fn into_completion_items(items: &IndexSet<KCLCompletionItem>) -> Vec<CompletionItem> {
     items
         .iter()
-        .map(|item| CompletionItem {
-            label: item.label.clone(),
-            detail: item.detail.clone(),
-            documentation: item
-                .documentation
-                .clone()
-                .map(lsp_types::Documentation::String),
-            kind: item.kind.clone().map(|kind| kind.into()),
-            insert_text: item.insert_text.clone(),
-            insert_text_format: if item.insert_text.is_some() {
-                Some(InsertTextFormat::SNIPPET)
-            } else {
-                None
-            },
-            ..Default::default()
+        .map(|item| {
+            let additional_text_edits = match &item.additional_text_edits {
+                Some(edits) => {
+                    let mut res = vec![];
+                    for edit in edits {
+                        res.push(lsp_types::TextEdit {
+                            range: lsp_types::Range {
+                                start: lsp_pos(&edit.range.0),
+                                end: lsp_pos(&edit.range.1),
+                            },
+                            new_text: edit.new_text.clone(),
+                        })
+                    }
+
+                    Some(res)
+                }
+                None => None,
+            };
+
+            CompletionItem {
+                label: item.label.clone(),
+                detail: item.detail.clone(),
+                documentation: item
+                    .documentation
+                    .clone()
+                    .map(lsp_types::Documentation::String),
+                kind: item.kind.clone().map(|kind| kind.into()),
+                insert_text: item.insert_text.clone(),
+                insert_text_format: if item.insert_text.is_some() {
+                    Some(InsertTextFormat::SNIPPET)
+                } else {
+                    None
+                },
+                additional_text_edits,
+
+                ..Default::default()
+            }
         })
         .collect()
 }
 
+fn unimport_schemas(
+    filename: &str,
+    gs: &GlobalState,
+    schema_map: &IndexMap<String, Vec<SchemaType>>,
+) -> IndexSet<KCLCompletionItem> {
+    let module = gs.get_packages().get_module_info(filename);
+    let mut completions: IndexSet<KCLCompletionItem> = IndexSet::new();
+    for (_, schemas) in schema_map {
+        for schema in schemas {
+            let has_import = match module {
+                Some(m) => m
+                    .get_imports()
+                    .iter()
+                    .any(|(_, info)| info.get_fully_qualified_name() == schema.pkgpath),
+                None => false,
+            };
+            if schema.pkgpath != MAIN_PKG {
+                completions.insert(schema_ty_to_value_complete_item(&schema, has_import));
+            }
+        }
+    }
+    completions
+}
+
 #[cfg(test)]
 mod tests {
     use crate::{
@@ -875,8 +987,8 @@ mod tests {
     #[test]
     #[bench_test]
     fn var_completion_test() {
-        let (file, program, _, gs) =
-            compile_test_file("src/test_data/completion_test/dot/completion.k");
+        let (file, program, _, gs, schema_map) =
+            compile_test_file("src/test_data/completion_test/dot/completion/completion.k");
 
         // test completion for var
         let pos = KCLPos {
@@ -886,7 +998,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let got = completion(None, &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let mut got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -894,8 +1006,22 @@ mod tests {
 
         let mut expected_labels: Vec<String> = vec![
             "", // generate from error recovery of "pkg."
-            "subpkg", "math", "Person", "Person{}", "P", "P{}", "p", "p1", "p2", "p3", "p4",
-            "aaaa", "Config", "Config{}", "n",
+            "subpkg",
+            "math",
+            "Person",
+            "Person1{}",
+            "Person{}",
+            "P",
+            "P{}",
+            "p",
+            "p1",
+            "p2",
+            "p3",
+            "p4",
+            "aaaa",
+            "Config",
+            "Config{}",
+            "n",
         ]
         .iter()
         .map(|s| s.to_string())
@@ -918,7 +1044,7 @@ mod tests {
             column: Some(4),
         };
 
-        let got = completion(None, &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let mut got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -936,8 +1062,8 @@ mod tests {
     #[test]
     #[bench_test]
     fn dot_completion_test() {
-        let (file, program, _, gs) =
-            compile_test_file("src/test_data/completion_test/dot/completion.k");
+        let (file, program, _, gs, schema_map) =
+            compile_test_file("src/test_data/completion_test/dot/completion/completion.k");
 
         // test completion for schema attr
         let pos = KCLPos {
@@ -947,7 +1073,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -963,7 +1089,7 @@ mod tests {
         };
 
         // test completion for str builtin function
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match &got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -994,7 +1120,7 @@ mod tests {
             column: Some(12),
         };
 
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1010,7 +1136,7 @@ mod tests {
             column: Some(12),
         };
 
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1024,7 +1150,7 @@ mod tests {
             line: 19,
             column: Some(5),
         };
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1042,7 +1168,7 @@ mod tests {
             column: Some(4),
         };
 
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1060,7 +1186,7 @@ mod tests {
             column: Some(11),
         };
 
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1076,7 +1202,7 @@ mod tests {
             column: Some(30),
         };
 
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1092,7 +1218,7 @@ mod tests {
     #[test]
     #[bench_test]
     fn dot_completion_test_without_dot() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/without_dot/completion.k");
 
         // test completion for schema attr
@@ -1103,7 +1229,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1119,7 +1245,7 @@ mod tests {
         };
 
         // test completion for str builtin function
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1137,7 +1263,7 @@ mod tests {
             column: Some(12),
         };
 
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1153,7 +1279,7 @@ mod tests {
             column: Some(12),
         };
 
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1167,7 +1293,7 @@ mod tests {
             line: 19,
             column: Some(5),
         };
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match &got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1198,7 +1324,7 @@ mod tests {
             column: Some(4),
         };
 
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match &got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1229,7 +1355,7 @@ mod tests {
             column: Some(11),
         };
 
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1245,7 +1371,7 @@ mod tests {
             column: Some(30),
         };
 
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match &got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1274,7 +1400,7 @@ mod tests {
     #[test]
     #[bench_test]
     fn import_builtin_package() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/import/builtin/builtin_pkg.k");
         let mut items: IndexSet<KCLCompletionItem> = IndexSet::new();
 
@@ -1286,7 +1412,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let got = completion(None, &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let _got_labels: Vec<String> = match &got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1315,6 +1441,7 @@ mod tests {
                 detail: None,
                 documentation: None,
                 insert_text: None,
+                additional_text_edits: None,
             })
             .collect::<IndexSet<KCLCompletionItem>>(),
         );
@@ -1325,7 +1452,7 @@ mod tests {
     #[test]
     #[bench_test]
     fn attr_value_completion() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/assign/completion.k");
 
         let pos = KCLPos {
@@ -1335,7 +1462,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let got = completion(Some(':'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1348,7 +1475,7 @@ mod tests {
             line: 16,
             column: Some(6),
         };
-        let got = completion(Some(':'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1361,7 +1488,7 @@ mod tests {
             line: 18,
             column: Some(6),
         };
-        let got = completion(Some(':'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1374,7 +1501,7 @@ mod tests {
             line: 20,
             column: Some(6),
         };
-        let got = completion(Some(':'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1387,7 +1514,7 @@ mod tests {
             line: 22,
             column: Some(6),
         };
-        let got = completion(Some(':'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1400,7 +1527,7 @@ mod tests {
             line: 24,
             column: Some(6),
         };
-        let got = completion(Some(':'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1413,7 +1540,7 @@ mod tests {
             line: 26,
             column: Some(6),
         };
-        let got = completion(Some(':'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match &got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1435,8 +1562,8 @@ mod tests {
     #[test]
     #[bench_test]
     fn schema_sig_completion() {
-        let (file, program, _, gs) =
-            compile_test_file("src/test_data/completion_test/schema/schema.k");
+        let (file, program, _, gs, schema_map) =
+            compile_test_file("src/test_data/completion_test/schema/schema/schema.k");
 
         let pos = KCLPos {
             filename: file.to_owned(),
@@ -1445,7 +1572,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let mut got = completion(None, &program, &pos, &gs, &tool, None).unwrap();
+        let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         match &mut got {
             CompletionResponse::Array(arr) => {
                 assert_eq!(
@@ -1458,7 +1585,7 @@ mod tests {
                                 .to_string()
                         ),
                         documentation: Some(lsp_types::Documentation::String("".to_string())),
-                        insert_text: Some("Person(${1:b}){}".to_string()),
+                        insert_text: Some("Person(${1:b}){$0}".to_string()),
                         insert_text_format: Some(InsertTextFormat::SNIPPET),
                         ..Default::default()
                     }
@@ -1470,7 +1597,7 @@ mod tests {
 
     #[test]
     fn schema_docstring_newline_completion() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/newline/docstring_newline.k");
 
         let pos = KCLPos {
@@ -1479,7 +1606,8 @@ mod tests {
             column: Some(4),
         };
         let tool = toolchain::default();
-        let mut got = completion(Some('\n'), &program, &pos, &gs, &tool, None).unwrap();
+        let mut got =
+            completion(Some('\n'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         match &mut got {
             CompletionResponse::Array(arr) => {
                 arr.sort_by(|a, b| a.label.cmp(&b.label));
@@ -1500,7 +1628,7 @@ mod tests {
 
     #[test]
     fn str_dot_completion() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/dot/lit_str/lit_str.k");
 
         // test complete str functions when at the end of literal str
@@ -1511,7 +1639,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
 
         match &got {
             CompletionResponse::Array(arr) => {
@@ -1552,7 +1680,7 @@ mod tests {
             column: Some(6),
         };
 
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         let got_labels: Vec<String> = match got {
             CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1566,7 +1694,7 @@ mod tests {
             column: Some(5),
         };
 
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         match got {
             CompletionResponse::Array(arr) => assert!(arr.is_empty()),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1579,7 +1707,7 @@ mod tests {
             column: Some(8),
         };
 
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         match got {
             CompletionResponse::Array(arr) => assert!(arr.is_empty()),
             CompletionResponse::List(_) => panic!("test failed"),
@@ -1590,7 +1718,7 @@ mod tests {
             line: 3,
             column: Some(2),
         };
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         match got {
             CompletionResponse::Array(arr) => {
                 assert!(arr
@@ -1603,7 +1731,7 @@ mod tests {
 
     #[test]
     fn schema_ty_attr_complete() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/dot/schema_ty_attr/schema_ty_attr.k");
 
         let pos = KCLPos {
@@ -1613,7 +1741,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         match got {
             CompletionResponse::Array(arr) => {
                 assert_eq!(
@@ -1632,7 +1760,7 @@ mod tests {
 
     #[test]
     fn schema_end_pos() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/schema/schema_pos/schema_pos.k");
 
         let pos = KCLPos {
@@ -1642,7 +1770,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let got = completion(None, &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         match got {
             CompletionResponse::Array(arr) => {
                 assert_eq!(arr.len(), 4);
@@ -1656,7 +1784,7 @@ mod tests {
 
     #[test]
     fn comment_completion() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/dot/lit_str/lit_str.k");
 
         let pos = KCLPos {
@@ -1666,7 +1794,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
 
         match &got {
             CompletionResponse::Array(arr) => {
@@ -1679,7 +1807,7 @@ mod tests {
     #[test]
     #[bench_test]
     fn missing_expr_completion() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/dot/missing_expr/missing_expr.k");
 
         let pos = KCLPos {
@@ -1689,7 +1817,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         match got {
             CompletionResponse::Array(arr) => {
                 assert_eq!(arr.len(), 2);
@@ -1704,7 +1832,7 @@ mod tests {
     #[test]
     #[bench_test]
     fn check_scope_completion() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/check/check.k");
 
         let pos = KCLPos {
@@ -1714,7 +1842,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let got = completion(Some(':'), &program, &pos, &gs, &tool, None);
+        let got = completion(Some(':'), &program, &pos, &gs, &tool, None, &schema_map);
         assert!(got.is_none());
 
         let pos = KCLPos {
@@ -1723,7 +1851,7 @@ mod tests {
             column: Some(9),
         };
 
-        let got = completion(None, &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         match got {
             CompletionResponse::Array(arr) => {
                 assert_eq!(arr.len(), 3);
@@ -1737,7 +1865,7 @@ mod tests {
     #[test]
     #[bench_test]
     fn join_str_inner_completion() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/dot/lit_str/lit_str.k");
 
         let pos = KCLPos {
@@ -1747,7 +1875,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         match &got {
             CompletionResponse::Array(arr) => {
                 assert!(arr.is_empty())
@@ -1762,7 +1890,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+        let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         match &got {
             CompletionResponse::Array(arr) => {
                 assert!(arr.is_empty())
@@ -1774,8 +1902,8 @@ mod tests {
     #[test]
     #[bench_test]
     fn schema_type_attr_completion() {
-        let (file, program, _, gs) =
-            compile_test_file("src/test_data/completion_test/schema/schema.k");
+        let (file, program, _, gs, schema_map) =
+            compile_test_file("src/test_data/completion_test/schema/schema/schema.k");
 
         let pos = KCLPos {
             filename: file.to_owned(),
@@ -1784,7 +1912,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let mut got = completion(None, &program, &pos, &gs, &tool, None).unwrap();
+        let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         match &mut got {
             CompletionResponse::Array(arr) => {
                 let labels: Vec<String> = arr.iter().map(|item| item.label.clone()).collect();
@@ -1800,7 +1928,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let mut got = completion(None, &program, &pos, &gs, &tool, None).unwrap();
+        let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
         match &mut got {
             CompletionResponse::Array(arr) => {
                 let labels: Vec<String> = arr.iter().map(|item| item.label.clone()).collect();
@@ -1813,7 +1941,7 @@ mod tests {
     #[test]
     #[bench_test]
     fn nested_1_test() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/dot/nested/nested_1/nested_1.k");
 
         let pos = KCLPos {
@@ -1823,7 +1951,7 @@ mod tests {
         };
         let tool = toolchain::default();
 
-        let mut got = completion(None, &program, &pos, &gs, &tool, None).unwrap();
+        let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
 
         match &mut got {
             CompletionResponse::Array(arr) => {
@@ -1837,7 +1965,7 @@ mod tests {
     #[test]
     #[bench_test]
     fn nested_2_test() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/dot/nested/nested_2/nested_2.k");
 
         let pos = KCLPos {
@@ -1848,7 +1976,7 @@ mod tests {
 
         let tool = toolchain::default();
 
-        let mut got = completion(None, &program, &pos, &gs, &tool, None).unwrap();
+        let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
 
         match &mut got {
             CompletionResponse::Array(arr) => {
@@ -1861,7 +1989,7 @@ mod tests {
     #[test]
     #[bench_test]
     fn nested_3_test() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/dot/nested/nested_3/nested_3.k");
 
         let pos = KCLPos {
@@ -1871,7 +1999,7 @@ mod tests {
         };
 
         let tool = toolchain::default();
-        let mut got = completion(None, &program, &pos, &gs, &tool, None).unwrap();
+        let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
 
         match &mut got {
             CompletionResponse::Array(arr) => {
@@ -1885,7 +2013,7 @@ mod tests {
     #[test]
     #[bench_test]
     fn nested_4_test() {
-        let (file, program, _, gs) =
+        let (file, program, _, gs, schema_map) =
             compile_test_file("src/test_data/completion_test/dot/nested/nested_4/nested_4.k");
 
         let pos = KCLPos {
@@ -1896,7 +2024,7 @@ mod tests {
 
         let tool = toolchain::default();
 
-        let mut got = completion(None, &program, &pos, &gs, &tool, None).unwrap();
+        let mut got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
 
         match &mut got {
             CompletionResponse::Array(arr) => {
@@ -1912,7 +2040,7 @@ mod tests {
         ($name:ident, $file:expr, $line:expr, $column: expr, $trigger: expr) => {
             #[test]
             fn $name() {
-                let (file, program, _, gs) = compile_test_file($file);
+                let (file, program, _, gs, schema_map) = compile_test_file($file);
 
                 let pos = KCLPos {
                     filename: file.clone(),
@@ -1921,7 +2049,8 @@ mod tests {
                 };
                 let tool = toolchain::default();
 
-                let mut got = completion($trigger, &program, &pos, &gs, &tool, None).unwrap();
+                let mut got =
+                    completion($trigger, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
 
                 let got_labels = match &mut got {
                     CompletionResponse::Array(arr) => {
@@ -1942,7 +2071,7 @@ mod tests {
         ($name:ident, $file:expr, $line:expr, $column: expr, $trigger: expr) => {
             #[test]
             fn $name() {
-                let (file, program, _, gs) = compile_test_file($file);
+                let (file, program, _, gs, schema_map) = compile_test_file($file);
 
                 let pos = KCLPos {
                     filename: file.clone(),
@@ -1951,7 +2080,8 @@ mod tests {
                 };
                 let tool = toolchain::default();
 
-                let mut got = completion($trigger, &program, &pos, &gs, &tool, None).unwrap();
+                let mut got =
+                    completion($trigger, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
 
                 let got_labels = match &mut got {
                     CompletionResponse::Array(arr) => {
@@ -1984,14 +2114,17 @@ mod tests {
         ($name:ident, $file:expr, $line:expr, $column: expr, $trigger: expr) => {
             #[test]
             fn $name() {
-                let (file, program, _, gs, metadata) = compile_test_file_and_metadata($file);
+                let (file, program, _, gs, metadata, schema_map) =
+                    compile_test_file_and_metadata($file);
                 let pos = KCLPos {
                     filename: file.clone(),
                     line: $line,
                     column: Some($column),
                 };
                 let tool = toolchain::default();
-                let mut got = completion($trigger, &program, &pos, &gs, &tool, metadata).unwrap();
+                let mut got =
+                    completion($trigger, &program, &pos, &gs, &tool, metadata, &schema_map)
+                        .unwrap();
                 let got_labels = match &mut got {
                     CompletionResponse::Array(arr) => {
                         let mut labels: Vec<String> =
@@ -2094,7 +2227,7 @@ mod tests {
 
     completion_label_test_snapshot!(
         schema_attr_in_right,
-        "src/test_data/completion_test/schema/schema.k",
+        "src/test_data/completion_test/schema/schema/schema.k",
         23,
         11,
         None
@@ -2179,4 +2312,12 @@ mod tests {
         23,
         Some('.')
     );
+
+    completion_label_without_builtin_func_test_snapshot!(
+        complete_unimport_schemas,
+        "src/test_data/completion_test/unimport/unimport/main.k",
+        1,
+        1,
+        None
+    );
 }
diff --git a/kclvm/tools/src/LSP/src/document_symbol.rs b/kclvm/tools/src/LSP/src/document_symbol.rs
index 882fb9d45..b2315ce8b 100644
--- a/kclvm/tools/src/LSP/src/document_symbol.rs
+++ b/kclvm/tools/src/LSP/src/document_symbol.rs
@@ -171,7 +171,8 @@ mod tests {
     #[test]
     #[bench_test]
     fn document_symbol_test() {
-        let (file, _, _, gs) = compile_test_file("src/test_data/document_symbol.k");
+        let (file, _, _, gs, _) =
+            compile_test_file("src/test_data/document_symbol/document_symbol.k");
 
         let mut res = document_symbol(file.as_str(), &gs).unwrap();
         let mut expect = vec![];
diff --git a/kclvm/tools/src/LSP/src/find_refs.rs b/kclvm/tools/src/LSP/src/find_refs.rs
index 8d42fb560..68d977e9f 100644
--- a/kclvm/tools/src/LSP/src/find_refs.rs
+++ b/kclvm/tools/src/LSP/src/find_refs.rs
@@ -55,7 +55,7 @@ mod tests {
         ($name:ident, $file:expr, $line:expr, $column: expr) => {
             #[test]
             fn $name() {
-                let (file, _program, _, gs) = compile_test_file($file);
+                let (file, _program, _, gs, _) = compile_test_file($file);
 
                 let pos = KCLPos {
                     filename: file.clone(),
diff --git a/kclvm/tools/src/LSP/src/formatting.rs b/kclvm/tools/src/LSP/src/formatting.rs
index 0b7833af4..4ba39ac09 100644
--- a/kclvm/tools/src/LSP/src/formatting.rs
+++ b/kclvm/tools/src/LSP/src/formatting.rs
@@ -115,7 +115,7 @@ mod tests {
     #[test]
     #[bench_test]
     fn format_range_test() {
-        let (file, _program, _, _gs) = compile_test_file("src/test_data/format/format_range.k");
+        let (file, _program, _, _gs, _) = compile_test_file("src/test_data/format/format_range.k");
         let lsp_range = Range::new(Position::new(0, 0), Position::new(11, 0));
         let text = std::fs::read_to_string(file.clone()).unwrap();
 
diff --git a/kclvm/tools/src/LSP/src/goto_def.rs b/kclvm/tools/src/LSP/src/goto_def.rs
index c04af0109..562f42494 100644
--- a/kclvm/tools/src/LSP/src/goto_def.rs
+++ b/kclvm/tools/src/LSP/src/goto_def.rs
@@ -116,7 +116,7 @@ mod tests {
         ($name:ident, $file:expr, $line:expr, $column: expr) => {
             #[test]
             fn $name() {
-                let (file, _program, _, gs) = compile_test_file($file);
+                let (file, _program, _, gs, _) = compile_test_file($file);
 
                 let pos = KCLPos {
                     filename: file.clone(),
diff --git a/kclvm/tools/src/LSP/src/hover.rs b/kclvm/tools/src/LSP/src/hover.rs
index d0ab05ae5..c69c19b40 100644
--- a/kclvm/tools/src/LSP/src/hover.rs
+++ b/kclvm/tools/src/LSP/src/hover.rs
@@ -263,7 +263,8 @@ 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");
@@ -360,7 +361,7 @@ 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(),
@@ -388,7 +389,7 @@ 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(),
@@ -432,7 +433,7 @@ 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(),
@@ -457,7 +458,7 @@ 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(),
@@ -532,7 +533,7 @@ 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,
@@ -552,7 +553,8 @@ 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,
@@ -572,7 +574,7 @@ 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,
@@ -599,7 +601,7 @@ 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,
@@ -623,7 +625,7 @@ 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,
@@ -643,7 +645,7 @@ 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,
@@ -663,7 +665,7 @@ 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,
@@ -703,7 +705,7 @@ 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,
@@ -731,7 +733,7 @@ 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(),
diff --git a/kclvm/tools/src/LSP/src/inlay_hints.rs b/kclvm/tools/src/LSP/src/inlay_hints.rs
index f9a4817f2..11f8e7da4 100644
--- a/kclvm/tools/src/LSP/src/inlay_hints.rs
+++ b/kclvm/tools/src/LSP/src/inlay_hints.rs
@@ -146,7 +146,7 @@ mod tests {
         ($name:ident, $file:expr) => {
             #[test]
             fn $name() {
-                let (file, _, _, gs) = compile_test_file($file);
+                let (file, _, _, gs, _) = compile_test_file($file);
                 let res = inlay_hints(&file, &gs);
                 insta::assert_snapshot!(format!("{:#?}", res));
             }
diff --git a/kclvm/tools/src/LSP/src/quick_fix.rs b/kclvm/tools/src/LSP/src/quick_fix.rs
index 80020012e..0810c04c2 100644
--- a/kclvm/tools/src/LSP/src/quick_fix.rs
+++ b/kclvm/tools/src/LSP/src/quick_fix.rs
@@ -177,7 +177,12 @@ mod tests {
     fn quick_fix_test() {
         let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
         let test_file = path.clone();
-        let test_file = test_file.join("src").join("test_data").join("quick_fix.k");
+        let test_file = test_file
+            .join("src")
+            .join("test_data")
+            .join("code_action")
+            .join("quick_fix")
+            .join("quick_fix.k");
         let file = test_file.to_str().unwrap();
 
         let diags = compile_with_params(Params {
diff --git a/kclvm/tools/src/LSP/src/request.rs b/kclvm/tools/src/LSP/src/request.rs
index a854ecc46..3e43655a8 100644
--- a/kclvm/tools/src/LSP/src/request.rs
+++ b/kclvm/tools/src/LSP/src/request.rs
@@ -357,6 +357,7 @@ pub(crate) fn handle_completion(
         &db.gs,
         &*snapshot.tool.read(),
         metadata,
+        &db.schema_map,
     );
 
     if res.is_none() {
diff --git a/kclvm/tools/src/LSP/src/semantic_token.rs b/kclvm/tools/src/LSP/src/semantic_token.rs
index 90371bddc..f5b33db61 100644
--- a/kclvm/tools/src/LSP/src/semantic_token.rs
+++ b/kclvm/tools/src/LSP/src/semantic_token.rs
@@ -167,7 +167,7 @@ mod tests {
     #[test]
     #[bench_test]
     fn semantic_tokens_full_test() {
-        let (file, _, _, gs) = compile_test_file("src/test_data/sema_token/sema_token.k");
+        let (file, _, _, gs, _) = compile_test_file("src/test_data/sema_token/sema_token.k");
         let res = semantic_tokens_full(&file, &gs);
         if let Some(tokens) = res {
             match &tokens {
diff --git a/kclvm/tools/src/LSP/src/signature_help.rs b/kclvm/tools/src/LSP/src/signature_help.rs
index b356e9942..a3934db60 100644
--- a/kclvm/tools/src/LSP/src/signature_help.rs
+++ b/kclvm/tools/src/LSP/src/signature_help.rs
@@ -153,7 +153,7 @@ mod tests {
         ($name:ident, $file:expr, $line:expr, $column: expr,  $trigger_character: expr) => {
             #[test]
             fn $name() {
-                let (file, _program, _, gs) = compile_test_file($file);
+                let (file, _program, _, gs, _) = compile_test_file($file);
 
                 let pos = KCLPos {
                     filename: file.clone(),
diff --git a/kclvm/tools/src/LSP/src/state.rs b/kclvm/tools/src/LSP/src/state.rs
index a74ba395b..f94417079 100644
--- a/kclvm/tools/src/LSP/src/state.rs
+++ b/kclvm/tools/src/LSP/src/state.rs
@@ -39,6 +39,7 @@ pub(crate) enum Task {
     Notify(lsp_server::Notification),
     Retry(Request),
     ChangedFile(FileId, ChangeKind),
+    ReOpenFile(FileId, ChangeKind),
 }
 
 #[derive(Debug, Clone)]
@@ -312,7 +313,7 @@ impl LanguageServerState {
                         for (workspace, state) in state_workspaces.iter() {
                             match state {
                                 DBState::Ready(db) => {
-                                    if db.prog.get_module(&filename).unwrap_or(None).is_some() {
+                                    if db.prog.modules.get(&filename).is_some() {
                                         let mut openfiles = self.opened_files.write();
                                         let file_info = openfiles.get_mut(&file.file_id).unwrap();
                                         file_info.workspaces.insert(workspace.clone());
@@ -421,10 +422,16 @@ impl LanguageServerState {
 
                                     self.async_compile(workspace, opts, Some(file.file_id), true);
                                 }
-                                None => self.log_message(format!(
-                                    "Internal Bug: not found any workspace for file {:?}",
-                                    filename
-                                )),
+                                None => {
+                                    self.log_message(format!(
+                                        "Internal Bug: not found any workspace for file {:?}. Try to reload",
+                                        filename
+                                    ));
+
+                                    self.task_sender
+                                        .send(Task::ReOpenFile(file.file_id, ChangeKind::Create))
+                                        .unwrap();
+                                }
                             }
                         }
                     }
@@ -475,6 +482,10 @@ impl LanguageServerState {
                     change_kind,
                 })
             }
+            Task::ReOpenFile(file_id, change_kind) => self.process_changed_file(ChangedFile {
+                file_id,
+                change_kind,
+            }),
         }
         Ok(())
     }
@@ -703,7 +714,7 @@ impl LanguageServerState {
                 }
 
                 match compile_res {
-                    Ok((prog, gs)) => {
+                    Ok((prog, schema_map, gs)) => {
                         let mut workspaces = snapshot.workspaces.write();
                         log_message(
                             format!(
@@ -713,7 +724,7 @@ impl LanguageServerState {
                         );
                         workspaces.insert(
                             workspace.clone(),
-                            DBState::Ready(Arc::new(AnalysisDatabase { prog, gs, diags })),
+                            DBState::Ready(Arc::new(AnalysisDatabase { prog, gs, diags,schema_map })),
                         );
                         drop(workspaces);
                         if temp && changed_file_id.is_some() {


Test patch:
diff --git a/kclvm/parser/src/tests.rs b/kclvm/parser/src/tests.rs
index bcbe17b05..b09c17829 100644
--- a/kclvm/parser/src/tests.rs
+++ b/kclvm/parser/src/tests.rs
@@ -865,6 +865,8 @@ fn parse_all_file_under_path() {
 
     let res = load_all_files_under_paths(sess.clone(), &[main], Some(opt), None).unwrap();
 
-    assert_eq!(res.program.pkgs.keys().len(), 4);
-    assert_eq!(res.paths.len(), 4);
+    assert_eq!(res.program.pkgs.keys().len(), 1);
+    assert_eq!(res.program.pkgs_not_imported.keys().len(), 3);
+
+    assert_eq!(res.paths.len(), 1);
 }
diff --git a/kclvm/runner/src/tests.rs b/kclvm/runner/src/tests.rs
index 22d1f3bf5..8e0f172e2 100644
--- a/kclvm/runner/src/tests.rs
+++ b/kclvm/runner/src/tests.rs
@@ -187,6 +187,8 @@ fn construct_program(module: Module) -> Program {
         root: MAIN_PKG_NAME.to_string(),
         pkgs: pkgs_ast,
         modules,
+        pkgs_not_imported: HashMap::new(),
+        modules_not_imported: HashMap::new(),
     }
 }
 
diff --git a/kclvm/sema/src/resolver/tests.rs b/kclvm/sema/src/resolver/tests.rs
index 3d0240973..88b3d8682 100644
--- a/kclvm/sema/src/resolver/tests.rs
+++ b/kclvm/sema/src/resolver/tests.rs
@@ -30,6 +30,8 @@ pub fn parse_program(filename: &str) -> Result<ast::Program> {
         root: abspath.parent().unwrap().adjust_canonicalization(),
         pkgs: HashMap::new(),
         modules: HashMap::new(),
+        pkgs_not_imported: HashMap::new(),
+        modules_not_imported: HashMap::new(),
     };
 
     let mut module = parse_file_force_errors(abspath.to_str().unwrap(), None)?;
diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__complete_unimport_schemas.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__complete_unimport_schemas.snap
new file mode 100644
index 000000000..2c22b7558
--- /dev/null
+++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__complete_unimport_schemas.snap
@@ -0,0 +1,5 @@
+---
+source: tools/src/LSP/src/completion.rs
+expression: "format! (\"{:?}\", got_labels)"
+---
+["Name{}(import pkg)", "SubPKg{}(import subpkg)"]
diff --git a/kclvm/tools/src/LSP/src/test_data/load_pkg_test.k b/kclvm/tools/src/LSP/src/test_data/code_action/quick_fix/load_pkg_test.k
similarity index 100%
rename from kclvm/tools/src/LSP/src/test_data/load_pkg_test.k
rename to kclvm/tools/src/LSP/src/test_data/code_action/quick_fix/load_pkg_test.k
diff --git a/kclvm/tools/src/LSP/src/test_data/quick_fix.k b/kclvm/tools/src/LSP/src/test_data/code_action/quick_fix/quick_fix.k
similarity index 100%
rename from kclvm/tools/src/LSP/src/test_data/quick_fix.k
rename to kclvm/tools/src/LSP/src/test_data/code_action/quick_fix/quick_fix.k
diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/completion.k
similarity index 100%
rename from kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion.k
rename to kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/completion.k
diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/pkg/file1.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/pkg/file1.k
similarity index 100%
rename from kclvm/tools/src/LSP/src/test_data/completion_test/dot/pkg/file1.k
rename to kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/pkg/file1.k
diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/pkg/file2.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/pkg/file2.k
similarity index 100%
rename from kclvm/tools/src/LSP/src/test_data/completion_test/dot/pkg/file2.k
rename to kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/pkg/file2.k
diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/dot/pkg/subpkg/file1.k b/kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/pkg/subpkg/file1.k
similarity index 100%
rename from kclvm/tools/src/LSP/src/test_data/completion_test/dot/pkg/subpkg/file1.k
rename to kclvm/tools/src/LSP/src/test_data/completion_test/dot/completion/pkg/subpkg/file1.k
diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/schema/schema.k b/kclvm/tools/src/LSP/src/test_data/completion_test/schema/schema/schema.k
similarity index 100%
rename from kclvm/tools/src/LSP/src/test_data/completion_test/schema/schema.k
rename to kclvm/tools/src/LSP/src/test_data/completion_test/schema/schema/schema.k
diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/pkg/kcl.mod b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/pkg/kcl.mod
new file mode 100644
index 000000000..950182eb1
--- /dev/null
+++ b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/pkg/kcl.mod
@@ -0,0 +1,6 @@
+[package]
+name = "pkg"
+edition = "v0.9.0"
+version = "0.0.1"
+
+
diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/pkg/main.k b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/pkg/main.k
new file mode 100644
index 000000000..ac99847b1
--- /dev/null
+++ b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/pkg/main.k
@@ -0,0 +1,2 @@
+schema Name:
+    name: str
\ No newline at end of file
diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/kcl.mod b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/kcl.mod
new file mode 100644
index 000000000..c78a893dd
--- /dev/null
+++ b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/kcl.mod
@@ -0,0 +1,7 @@
+[package]
+name = "unimport"
+edition = "v0.9.0"
+version = "0.0.1"
+
+[dependencies]
+pkg = { path = "../pkg" }
\ No newline at end of file
diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/main.k b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/main.k
new file mode 100644
index 000000000..e69de29bb
diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/subpkg/subpkg.k b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/subpkg/subpkg.k
new file mode 100644
index 000000000..9dfbc5485
--- /dev/null
+++ b/kclvm/tools/src/LSP/src/test_data/completion_test/unimport/unimport/subpkg/subpkg.k
@@ -0,0 +1,2 @@
+schema SubPKg:
+    name: str
\ No newline at end of file
diff --git a/kclvm/tools/src/LSP/src/test_data/diagnostics.k b/kclvm/tools/src/LSP/src/test_data/diagnostics/diagnostics.k
similarity index 100%
rename from kclvm/tools/src/LSP/src/test_data/diagnostics.k
rename to kclvm/tools/src/LSP/src/test_data/diagnostics/diagnostics.k
diff --git a/kclvm/tools/src/LSP/src/test_data/diagnostics/load_pkg_test.k b/kclvm/tools/src/LSP/src/test_data/diagnostics/load_pkg_test.k
new file mode 100644
index 000000000..52fa61550
--- /dev/null
+++ b/kclvm/tools/src/LSP/src/test_data/diagnostics/load_pkg_test.k
@@ -0,0 +1,2 @@
+schema Person:
+    age: int
\ No newline at end of file
diff --git a/kclvm/tools/src/LSP/src/test_data/document_symbol.k b/kclvm/tools/src/LSP/src/test_data/document_symbol/document_symbol.k
similarity index 100%
rename from kclvm/tools/src/LSP/src/test_data/document_symbol.k
rename to kclvm/tools/src/LSP/src/test_data/document_symbol/document_symbol.k
diff --git a/kclvm/tools/src/LSP/src/tests.rs b/kclvm/tools/src/LSP/src/tests.rs
index 6de2d1dd9..d035748ef 100644
--- a/kclvm/tools/src/LSP/src/tests.rs
+++ b/kclvm/tools/src/LSP/src/tests.rs
@@ -1,11 +1,13 @@
 use crossbeam_channel::after;
 use crossbeam_channel::select;
+use indexmap::IndexMap;
 use indexmap::IndexSet;
 use kclvm_driver::lookup_compile_workspace;
 use kclvm_driver::toolchain;
 use kclvm_driver::toolchain::Metadata;
 use kclvm_driver::WorkSpaceKind;
 use kclvm_sema::core::global_state::GlobalState;
+use kclvm_sema::ty::SchemaType;
 use kclvm_utils::path::PathPrefix;
 
 use kclvm_sema::resolver::scope::KCLScopeCache;
@@ -131,7 +133,13 @@ pub(crate) fn compare_goto_res(
 
 pub(crate) fn compile_test_file(
     testfile: &str,
-) -> (String, Program, IndexSet<KCLDiagnostic>, GlobalState) {
+) -> (
+    String,
+    Program,
+    IndexSet<KCLDiagnostic>,
+    GlobalState,
+    IndexMap<String, Vec<SchemaType>>,
+) {
     let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
     let file = path
         .join(testfile)
@@ -148,8 +156,8 @@ pub(crate) fn compile_test_file(
         vfs: Some(KCLVfs::default()),
         gs_cache: Some(KCLGlobalStateCache::default()),
     });
-    let (program, gs) = compile_res.unwrap();
-    (file, program, diags, gs)
+    let (program, schema_map, gs) = compile_res.unwrap();
+    (file, program, diags, gs, schema_map)
 }
 
 pub(crate) fn compile_test_file_and_metadata(
@@ -160,6 +168,7 @@ pub(crate) fn compile_test_file_and_metadata(
     IndexSet<KCLDiagnostic>,
     GlobalState,
     Option<Metadata>,
+    IndexMap<String, Vec<SchemaType>>,
 ) {
     let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
 
@@ -179,9 +188,9 @@ pub(crate) fn compile_test_file_and_metadata(
         vfs: Some(KCLVfs::default()),
         gs_cache: Some(KCLGlobalStateCache::default()),
     });
-    let (program, gs) = compile_res.unwrap();
+    let (program, schema_map, gs) = compile_res.unwrap();
 
-    (file, program, diags, gs, metadata)
+    (file, program, diags, gs, metadata, schema_map)
 }
 
 type Info = (String, (u32, u32, u32, u32), String);
@@ -244,7 +253,7 @@ fn build_lsp_diag(
 fn build_expect_diags() -> Vec<Diagnostic> {
     let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
     let mut test_file = path.clone();
-    test_file.push("src/test_data/diagnostics.k");
+    test_file.push("src/test_data/diagnostics/diagnostics.k");
     let file = test_file.to_str().unwrap();
     let expected_diags: Vec<Diagnostic> = vec![
         build_lsp_diag(
@@ -267,7 +276,7 @@ fn build_expect_diags() -> Vec<Diagnostic> {
         build_lsp_diag(
             (0, 0, 0, 10),
             format!(
-                "Cannot find the module abc from {}/src/test_data/abc",
+                "Cannot find the module abc from {}/src/test_data/diagnostics/abc",
                 path.to_str().unwrap()
             ),
             Some(DiagnosticSeverity::ERROR),
@@ -332,7 +341,7 @@ fn build_expect_diags() -> Vec<Diagnostic> {
 fn diagnostics_test() {
     let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
     let mut test_file = path.clone();
-    test_file.push("src/test_data/diagnostics.k");
+    test_file.push("src/test_data/diagnostics/diagnostics.k");
     let file = test_file.to_str().unwrap();
 
     let diags = compile_with_params(Params {
@@ -350,6 +359,7 @@ fn diagnostics_test() {
         .collect::<Vec<Diagnostic>>();
 
     let expected_diags: Vec<Diagnostic> = build_expect_diags();
+
     for (get, expected) in diagnostics.iter().zip(expected_diags.iter()) {
         assert_eq!(get, expected)
     }
@@ -463,7 +473,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.adjust_canonicalization(),
@@ -525,7 +535,7 @@ fn complete_import_external_file_test() {
         .output()
         .unwrap();
 
-    let (program, gs) = compile_with_params(Params {
+    let (program, schema_map, gs) = compile_with_params(Params {
         file: Some(path.to_string()),
         module_cache: None,
         scope_cache: None,
@@ -541,7 +551,7 @@ fn complete_import_external_file_test() {
         column: Some(11),
     };
     let tool = toolchain::default();
-    let res = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+    let res = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
 
     let got_labels: Vec<String> = match &res {
         CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
@@ -592,7 +602,7 @@ fn goto_import_external_file_test() {
         vfs: Some(KCLVfs::default()),
         gs_cache: Some(KCLGlobalStateCache::default()),
     });
-    let gs = compile_res.unwrap().1;
+    let gs = compile_res.unwrap().2;
 
     assert_eq!(diags.len(), 0);
 
@@ -764,7 +774,7 @@ fn notification_test() {
     let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
     let mut path = root.clone();
 
-    path.push("src/test_data/diagnostics.k");
+    path.push("src/test_data/diagnostics/diagnostics.k");
 
     let path = path.to_str().unwrap();
     let src = std::fs::read_to_string(path).unwrap();
@@ -783,7 +793,7 @@ fn notification_test() {
     );
 
     // Wait for first "textDocument/publishDiagnostics" notification
-    server.wait_for_message_cond(2, &|msg: &Message| match msg {
+    server.wait_for_message_cond(1, &|msg: &Message| match msg {
         Message::Notification(not) => not.method == "textDocument/publishDiagnostics",
         _ => false,
     });
@@ -817,7 +827,7 @@ fn close_file_test() {
     let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
     let mut path = root.clone();
 
-    path.push("src/test_data/diagnostics.k");
+    path.push("src/test_data/diagnostics/diagnostics.k");
 
     let path = path.to_str().unwrap();
     let src = std::fs::read_to_string(path).unwrap();
@@ -1012,6 +1022,7 @@ fn complete_test() {
         .join("test_data")
         .join("completion_test")
         .join("dot")
+        .join("completion")
         .join("completion.k");
 
     let path = path.to_str().unwrap();
@@ -1416,19 +1427,19 @@ fn formatting_unsaved_test() {
 
 #[test]
 fn complete_import_external_file_e2e_test() {
-    let path = PathBuf::from(".")
+    let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
         .join("src")
         .join("test_data")
         .join("completion_test")
         .join("import")
         .join("external")
-        .join("external_1")
+        .join("external_1");
+    let path = root
         .join("main.k")
         .canonicalize()
         .unwrap()
         .display()
         .to_string();
-
     let _ = Command::new("kcl")
         .arg("mod")
         .arg("metadata")
@@ -1448,8 +1459,21 @@ fn complete_import_external_file_e2e_test() {
         )
         .output()
         .unwrap();
+
     let src = std::fs::read_to_string(path.clone()).unwrap();
-    let server = Project {}.server(InitializeParams::default());
+
+    let initialize_params = InitializeParams {
+        workspace_folders: Some(vec![WorkspaceFolder {
+            uri: Url::from_file_path(root.clone()).unwrap(),
+            name: "test".to_string(),
+        }]),
+        ..Default::default()
+    };
+    let server = Project {}.server(initialize_params);
+
+    // FIXME: It takes longer to parse the k8s package on Windows
+    #[cfg(target_os = "windows")]
+    wait_async!(20000);
 
     // Mock open file
     server.notification::<lsp_types::notification::DidOpenTextDocument>(
@@ -1462,6 +1486,7 @@ fn complete_import_external_file_e2e_test() {
             },
         },
     );
+    wait_async!(2000);
 
     let id = server.next_request_id.get();
     server.next_request_id.set(id.wrapping_add(1));
@@ -1615,7 +1640,7 @@ fn konfig_goto_def_test_base() {
         .join("base")
         .join("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: Some(base_path_str.clone()),
         module_cache: None,
         scope_cache: None,
@@ -1747,7 +1772,7 @@ fn konfig_goto_def_test_main() {
         .join("dev")
         .join("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: Some(main_path_str.clone()),
         module_cache: None,
         scope_cache: None,
@@ -1834,7 +1859,7 @@ fn konfig_completion_test_main() {
         .join("dev")
         .join("main.k");
     let main_path_str = main_path.to_str().unwrap().to_string();
-    let (program, gs) = compile_with_params(Params {
+    let (program, schema_map, gs) = compile_with_params(Params {
         file: Some(main_path_str.clone()),
         module_cache: None,
         scope_cache: None,
@@ -1851,7 +1876,7 @@ fn konfig_completion_test_main() {
         column: Some(27),
     };
     let tool = toolchain::default();
-    let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+    let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
     let got_labels: Vec<String> = match got {
         CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
         CompletionResponse::List(_) => panic!("test failed"),
@@ -1870,7 +1895,7 @@ fn konfig_completion_test_main() {
         column: Some(4),
     };
     let tool = toolchain::default();
-    let got = completion(None, &program, &pos, &gs, &tool, None).unwrap();
+    let got = completion(None, &program, &pos, &gs, &tool, None, &schema_map).unwrap();
     let mut got_labels: Vec<String> = match got {
         CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
         CompletionResponse::List(_) => panic!("test failed"),
@@ -1915,7 +1940,7 @@ fn konfig_completion_test_main() {
         column: Some(35),
     };
     let tool = toolchain::default();
-    let got = completion(Some('.'), &program, &pos, &gs, &tool, None).unwrap();
+    let got = completion(Some('.'), &program, &pos, &gs, &tool, None, &schema_map).unwrap();
     let mut got_labels: Vec<String> = match got {
         CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
         CompletionResponse::List(_) => panic!("test failed"),
@@ -1953,7 +1978,7 @@ fn konfig_hover_test_main() {
         .join("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: Some(main_path_str.clone()),
         module_cache: None,
         scope_cache: None,
@@ -2648,17 +2673,14 @@ fn init_workspace_sema_token_test() {
 
 #[test]
 fn pkg_mod_test() {
-    let (_file, _program, diags, _gs) =
+    let (_file, _program, diags, _gs, _) =
         compile_test_file("src/test_data/workspace/pkg_mod_test/test/main.k");
-    for diag in diags.iter().filter(|diag| diag.is_error()) {
-        println!("{:?}", diag);
-    }
     assert_eq!(diags.iter().filter(|diag| diag.is_error()).count(), 0);
 }
 
 #[test]
 fn aug_assign_without_define() {
-    let (_file, _program, diags, _gs) =
+    let (_file, _program, diags, _gs, _) =
         compile_test_file("src/test_data/error_code/aug_assign/aug_assign.k");
     assert_eq!(diags.len(), 1);
 }