You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Integrating with Metals requires several changes in any build to get the full IDE experience (find all references, go to definition, rename, etc). These include:
Adding semanticdb to every project definition and configuring it based on its Scala version. Dealing with semanticdb compiler plugin options such as target and source roots is also necessary.
Disabling -Xfatal-warnings so that warnings turned as errors don't cripple IDE features and enabling -Yrangepos.
Setting bloopExportJarClassifiers to true so that library dependencies have source artifacts that "Go to Definition" can access.
These changes are done per build tool. To support sbt, Metals has an sbt plugin that depends on sbt-bloop and configures the options above. To support Maven and Gradle, we are inlining these modifications in the plugin sources instead.
However, this has several disadvantages. Sbt is the best supported build tool and the "Import Build" experience is still:
Slow. A plugin is added to the global sbt directory which cleans previous caches and forces a new reload every time a build is imported (which affects sbt shells running in users' terminals).
Fragile. Adding a global sbt plugin creates problems around cache cleaning, corrupted settings and conflicts with other sbt plugins.
To those disadvantages, we need to add the complexity of modifying scalac options of build targets in build tools such as Maven and mill, where no easy way to modify the build settings is provided.
Proposed solution
Me and @olafurpg have been working on an proposal to improve on the status quo and provide a better built-in experience, while eliminating the above drawbacks.
The idea is to centralize the modifications required by Metals in bloop itself instead of spreading them across all plugins. The solution will work as follows:
Metals adds the sbt-bloop plugin to project/metals.sbt and gitignores it.
Metals triggers sbt bloopInstall, the whole build is exported.
Metals connects to Bloop via BSP and communicates which semanticdb jars it should use for every supported Scala version.
Bloop will take those semanticdb jars and apply the build target modifications to its in-memory representation. It's important these changes are not written back to the .bloop configuration files, but that instead we create some infrastructure to apply these changes every time there's a change in a configuration file under .bloop/.
Bloop will save the choice for semanticdb artifacts in a workspace settings file under .bloop. Next time that the server is restarted, bloop will detect that setting is set and transform the build targets appropriately. This avoids invalidating compilation caches.
Advantages
A single source of truth, one "unique view" of the build projects. Right now, there are two views, the one generated by Metals and the one generated by a single user bloopInstall.
Works for any build tool, out-of-the-box! Sbt, gradle, maven, mill, fury; all of them are supported.
Simpler than before, Metals can get rid of a bunch of build-tool-specific code.
Fast. sbt-bloop is added in the build by default and caches are not invalidated every time we "Import Build" from VS Code.
Robust, we don't change anything in the build definition so sbt keeps working as before and users don't need to deal with Metals/Bloop errors or conflicts with existing plugins.
Disadvantages
Less modular design. Everything will be now centralized in the bloop server.
Remarks
Comparing performance of bloop and sbt is not as easy as before. People might be comparing wrong timings in performance if they check compilation of bloop after Metals has been connecting and an sbt shell (Bloop would do more job as -Yrangepos and the semanticdb plugin increase compilation time).
This is kind of already happening at the moment when users export the build with Metals and then compile the projects with bloop and sbt independently, but it's worth pointing out again as other solutions could have worked around this problem.
I'm hopeful we can partially address this issue by creating a benchmarking guide and providing benchmark code to compare compilation timings across sbt and bloop (ensuring they use the same scalac options, etc).
Required changes in bloop
These are the concrete changes we would need to add in bloop.
Add a mechanism to persist options per workspace under $WORKSPACE/.bloop/. We can create a new JSON file workspace-settings.bloop.json or workspace-settings.json where we store these options.
Add a generic mechanism to simulate -Xfatal-warnings but without forcing a whole compilation to fail. Compilations with warnings would succeed (we would correctly save the class files) but we would turn warnings into errors and fail with a non-zero exit code. The client will think that the compilation failed indeed, but bloop will instead reuse it and just update the code if the warnings are removed.
Implement a new abstraction to map build targets whenever they are loaded from disk and transform their model. Add the infrastructure to set a transformer whenever Metals connects to it. By default, the identity is used.
/cc @tgodzik This might be of interest to you Tomasz since you've been mostly working on this area and are familiar with the current pain points. What do you think of the proposed solution?
The text was updated successfully, but these errors were encountered:
State of the art
Integrating with Metals requires several changes in any build to get the full IDE experience (find all references, go to definition, rename, etc). These include:
-Xfatal-warnings
so that warnings turned as errors don't cripple IDE features and enabling-Yrangepos
.bloopExportJarClassifiers
totrue
so that library dependencies have source artifacts that "Go to Definition" can access.These changes are done per build tool. To support sbt, Metals has an sbt plugin that depends on
sbt-bloop
and configures the options above. To support Maven and Gradle, we are inlining these modifications in the plugin sources instead.However, this has several disadvantages. Sbt is the best supported build tool and the "Import Build" experience is still:
To those disadvantages, we need to add the complexity of modifying scalac options of build targets in build tools such as Maven and mill, where no easy way to modify the build settings is provided.
Proposed solution
Me and @olafurpg have been working on an proposal to improve on the status quo and provide a better built-in experience, while eliminating the above drawbacks.
The idea is to centralize the modifications required by Metals in bloop itself instead of spreading them across all plugins. The solution will work as follows:
project/metals.sbt
and gitignores it.sbt bloopInstall
, the whole build is exported..bloop/
..bloop
. Next time that the server is restarted, bloop will detect that setting is set and transform the build targets appropriately. This avoids invalidating compilation caches.Advantages
bloopInstall
.sbt-bloop
is added in the build by default and caches are not invalidated every time we "Import Build" from VS Code.Disadvantages
Remarks
Comparing performance of bloop and sbt is not as easy as before. People might be comparing wrong timings in performance if they check compilation of bloop after Metals has been connecting and an sbt shell (Bloop would do more job as
-Yrangepos
and the semanticdb plugin increase compilation time).This is kind of already happening at the moment when users export the build with Metals and then compile the projects with bloop and sbt independently, but it's worth pointing out again as other solutions could have worked around this problem.
I'm hopeful we can partially address this issue by creating a benchmarking guide and providing benchmark code to compare compilation timings across sbt and bloop (ensuring they use the same scalac options, etc).
Required changes in bloop
These are the concrete changes we would need to add in bloop.
$WORKSPACE/.bloop/
. We can create a new JSON fileworkspace-settings.bloop.json
orworkspace-settings.json
where we store these options.-Xfatal-warnings
but without forcing a whole compilation to fail. Compilations with warnings would succeed (we would correctly save the class files) but we would turn warnings into errors and fail with a non-zero exit code. The client will think that the compilation failed indeed, but bloop will instead reuse it and just update the code if the warnings are removed./cc @tgodzik This might be of interest to you Tomasz since you've been mostly working on this area and are familiar with the current pain points. What do you think of the proposed solution?
The text was updated successfully, but these errors were encountered: