Open He1pa opened 4 months ago
ref: https://dpe.org/how-your-monorepo-breaks-the-ide/
In Intellij IDEA we have long-standing assumption that one code file belongs to exactly one module and this module is compiled with a specific dependencies and has a specific compiler version and scpecific libiaries SO you can only really edit it in one context at once even though you would want to do something in multiple context
Reference from gopls's go work
and rust's workspace
in cargo.toml, use an explicit configuration file kcl.work
to define the LSP workspace.
The kcl.work file is line oriented. Each line holds a single directive, made up of a keyword(there is only one keyword workspace
) followed by arguments. For example:
workspace ./a
workspace ./b
workspace ./c/d
Most kcl projects may not need kcl.work. They only work in one workspace and manage the directory structure through kpm.
kcl mod init
- kcl.mod
- kcl.mod.lock
- main.k
LSP workspace is equal to kcl run
in current path
In addition to main.k
, users can also define the compilation entry of the current pkg through the etries
field in kcl.mod
It is almost impossible to maintain the semantic information of hundreds or thousands of workspaces in memory at the same time. Also, in the Konfig repository, users may not care about the code in other projects. Therefore, we need to explicitly use kcl.work to define the active workspace.
In the following project structure:
-- kcl.mod (kcl v0.4.3, it is not the `kcl.mod` in current kpm)
-- base
-- pkg1
-- a.k
-- pkg2
-- prog1
-- base
-- base.k
-- prod
-- kcl.yaml
-- main.k
-- stack.yaml
-- test
-- kcl.yaml
-- main.k
-- stack.yaml
-- project.yaml
-- prog2
-- base
-- base.k
-- prod
-- kcl.yaml
-- main.k
-- stack.yaml
-- test
-- kcl.yaml
-- main.k
-- stack.yaml
-- project.yaml
Assuming that user A maintains prog1, he/she can create a kcl.work
in the root directory and add the following code to kcl.work
workspace ./prog1/prod
workspace ./prog1/test
Functions like rename and find_ref will only work in stack prod and test.
It is generally inadvisable to commit go.work files into version control systems.
We recommend to set kcl.work or kcl.mod in the root directory to set up the workspace. But if not, use the directory of edit file. Search for compilation configuration and compilation entry in the current directory according to the following priority
KCL IDE/LSP workspace
Main Problem
KCL's CLI specifies the compilation entry by inputting a file, files list or a configuration file by argument
-Y
But IDE and LSP dont know what to compile and analyzeCases
Now we are facing several cases
1. Without configuration file
2. kcl.yaml
This pattern appears in the internal, closed-source konfig repository
kcl.yaml
Compile with kcl run -Y kcl.yaml
3.kcl.mod
kcl.mod
Current processing logic
Problem
For case 2 and 3, IDE/LSP will only get the correct project structure when processing
main.k
. But when processingpkg/a.k
, it will be treated as case 1, and pkg will be used as the entry for compile. At this time, the lack of information aboutkcl.mod
andmain.k
will lead to incomplete semantic information, and features such as find_ref and rename will be unavailable.In addition, when we compile with
kcl.mod
as the entry, and then openpkg/a.k
.Aactually, it has been compiled and analyzed. But according to the current logic, it will be recompiled, which will also cause performance loss in IDE.In a workspace, there are multiple entries at the same time. In order to save the status of multiple entries at the same time, LSP will also have performance loss. https://github.com/kcl-lang/kcl/issues/1237
~## Solution~ ~LSP set two modes: SingleEntry and MultiEntry~
~Try to find
kcl.mod
in the IDE workspace~~The logic is consistent with previous to be compatible with the konfig repository. New KCL projects are recommended to use
kcl.mod
~~### LSP Changes~
~Previously, opened/changed a file -> found compile entry -> compile -> update GlobalState~
~After the change, Start LSP -> found compile entry -> compile -> update GlobalState -> update the GlobalState cache according to the changed file~
~### Impact on lsp cache/incremental compilation~
~In the previous design, no matter what the case, the changed files are in the main pkg, and the incremental compilation of resolver/advanced_resolver is based on the premise that the
changed files are in the main pkg
.~~After changing the entry point, it is necessary to reconsider the processing of editing files that are not in the main pkg.~
~For the Parse stage:~ ~The cache is a map of filename -> AST. There is no pkg, so no need to update~
~For the Resolver stage:~ ~Previously, the resolver needed to clear the cache of main_pkg and the affected pkgs. After the change, it is necessary to first query which pkg the file belongs to, analyze the affected pkgs, and clear the cache of these pkgs.~
~For Namer and Advanced Resolver:~ ~Update the pkg that was updated in the resolver stage, no changes are required~
KCL/KPM run
KCL/KPM run also has similar logic when executing, and needs to find the compilation entry and config from the input. The relevant implementation is in https://github.com/kcl-lang/kpm/blob/2c16041e969cd2f7cdaf3af4e4d0cf7d96c67003/pkg/client/run.go#L409
and
There are two kinds of cases related to IDE
This is similar to opening an IDE WorkSpace (but without opening any files), using the current directory(workspace in IDE) as the entry
Ref
Rust Analyzer
Go: