scala-metals in a new workspace defaults to bloop despite .bsp/xyz.json existing
Describe the bug
Previously, if vscode was opened on a freshly cloned workspace with a .bsp/xyz.json, scala-metals would default to using the BSP implementation named in xyz.json. This worked very well. Developers did not need to know anything about the BSP at all. It just worked.
The new behaviour is to default to Bloop. This is a problem, since our projects' builds use neither bloop nor sbt and any attempt to import/auto-generate a bloop project is doomed to failure. Now, developers get confused and start trying to fix the bloop server, not realizing that the problem is that bloop is being invoked in the first place. This situation is made worse by the very undiscoverable nature of the "switch build server" option.
If a project has a .bsp/xyz.json, scala-metals should not default to bloop. The project essentially told scala-metals what is the right BSP to use for that project: xyz. scala-metals no reason to think bloop would work on that project. It should not try.
To Reproduce
Steps to reproduce the behavior:
- Create a git repository
- Add a legal .bsp/xyz.json
- Clone that repository in vscode
- See that scala-metals attempts to start bloop
Expected behavior
scala-metals should default to the BSP specified by the project.
Installation:
- Operating system: macOS + Windows + Linux
- Editor: Visual Studio Code
- Metals version: v1.9.13
Search terms
default BSP implementation .bsp bloop fresh repository vscode scala-metals
I believe metals still should use bloop as its build server by default because bloop is the most stable build server implementation. I think other build tools' BSP features are still "experimental" (even sbt) and changing the default build server may cause a lot of developers trouble.
However, it would be nice if metals-vscode and other plugins have a setting (or any other sharable form) that controls which Build Server default to connect, so that developers can share their configuration on metals.
(Currently, metals store the switch-bsp option in its internal database and not sharable as a file).
Thanks for the report @terpstra.
This was a very conscious choice to make the behavior this way. The main reasons boil down to a few different things.
- sbt > 1.4.x creates a
bsp/sbt.jsonfile no matter what when you started it for the first time. This cause a lot of confusion because Metals would automatically try to connect to it even though there were some version that weren't compatible, there were still some issues being worked out, and there wasn't close to the same feature set yet. Thing like our run/debug code lenses need Bloop to function properly. So we decided that ultimately for a workspace of a "Metals supported build tool", we'd default to Bloop no matter what as long as it provided a better experience for the users. - As mentioned above, this logic should be that if you're not in a workspace that Bloop supports, what you outline should still work as expected. Is it safe to assume that you're using sbt, or are you using another build tool that Metals doesn't support?
https://github.com/scalameta/metals/blob/a5bb60da332a7218f943e10861d25dcf9c364c8c/metals/src/main/scala/scala/meta/internal/bsp/BspConnector.scala#L34-L40
This situation is made worse by the very undiscoverable nature of the "switch build server" option.
So this command should be accessible the same as any other command. We also talked about it in the release notes, it's documented, and we also have a blog post about it. Do you have any ideas how to make this command more discoverable if people are having issues finding it?
I'm open to trying to find a better solution for this situation, but I don't this situation is quite rare. As you said, most people don't want to care about BSP, they just want what works. In the case of all the build tools that we support, most of the time that's Bloop.
- sbt > 1.4.x creates a
bsp/sbt.jsonfile no matter what when you started it for the first time.
That sounds like an sbt bug. If you have to work-around it (rather than fixing it upstream), why not just de-prioritize sbt.json specifically?
Thing like our run/debug code lenses need Bloop to function properly.
Well, those can work for us without bloop, so that argument does not apply to our situation.
So we decided that ultimately for a workspace of a "Metals supported build tool", we'd default to Bloop no matter what as long as it provided a better experience for the users.
I don't understand this. A workspace that includes a .bsp/xyz.json presumably uses xyz to support metals. Why would you suppose that bloop would do a better job? The workspace is telling you it does not, and needs xyz. If bloop were a better choice, the developers would not have created xyz.json, but stuck with the default.
I understand that there was an sbt issue, and bloop can import from sbt build files, but bloop+sbt are not the only build tools out there, and neither of those tools is appropriate for a much larger not-just-local-scala build orchestration problem. Some of our scala is generated by bizarro tools that potentially need to run on license restricted servers.
- As mentioned above, this logic should be that if you're not in a workspace that Bloop supports, what you outline should still work as expected.
How does scala-metals decide that bloop supports a workspace? Can I put something in our workspace to tell scala-metals that bloop is not an option?
Is it safe to assume that you're using sbt, or are you using another build tool that Metals doesn't support?
We're using a different proprietary tool that metals DOES support, because we implemented the BSP specifically to use scala-metals in vscode with our projects.
So this command should be accessible the same as any other command. We also talked about it in the release notes, it's documented
Yes. That's why I found it. But I work on the build at our company, so I know scala-metals and the BSP is what underlies our vscode scala support. Developers who are just working within our framework should not need to know about any of this. Our work-around is we now have 2-3 extra steps in our "how to setup a new developer workspace". Unfortunately, people don't follow directions very reliably.
Do you have any ideas how to make this command more discoverable if people are having issues finding it?
Sure. If you don't want to default to .bsp/xyz.json, just ask the user which BSP to use the moment scala-metals opens a workspace where no explicit choice has been made yet.
I'm open to trying to find a better solution for this situation, but I don't this situation is quite rare. As you said, most people don't want to care about BSP, they just want what works. In the case of all the build tools that we support, most of the time that's Bloop.
- sbt > 1.4.x creates a
bsp/sbt.jsonfile no matter what when you started it for the first time.That sounds like an sbt bug. If you have to work-around it (rather than fixing it upstream), why not just de-prioritize sbt.json specifically?
This assumes that upstream sees it the same way. There are ways to turn this off, but it has to be done locally in a global setting or in your build definition. Seeing that the vast majority of our users are sbt users, it made the most sense for us to default to the majority, and make it possible for the minority. Meaning that for most people, just defaulting to Bloop here isn't an issue, and if they'd like to use another BSP server, then that's no problem.
Thing like our run/debug code lenses need Bloop to function properly.
Well, those can work for us without bloop, so that argument does not apply to our situation.
🤔 I'm curious how this works for you... as we literally check to see if the main BSP connection is Bloop to enable it.
https://github.com/scalameta/metals/blob/a5bb60da332a7218f943e10861d25dcf9c364c8c/metals/src/main/scala/scala/meta/internal/metals/MetalsLanguageServer.scala#L480
So we decided that ultimately for a workspace of a "Metals supported build tool", we'd default to Bloop no matter what as long as it provided a better experience for the users.
I don't understand this. A workspace that includes a .bsp/xyz.json presumably uses xyz to support metals. Why would you suppose that bloop would do a better job? The workspace is telling you it does not, and needs xyz. If bloop were a better choice, the developers would not have created xyz.json, but stuck with the default.
Mainly because as I said, the workspace that have their build definitions written with a build tool that Metals knows, Bloop is almost always the better choice. This is due to how we test, what is widely used, etc. So if your build definition is written with any of the following build tools we default to Bloop because we have it tested. Again, this is a case of favoring the majority of users to provide the best experience possible for the average Metals user.
I understand that there was an sbt issue, and bloop can import from sbt build files, but bloop+sbt are not the only build tools out there, and neither of those tools is appropriate for a much larger not-just-local-scala build orchestration problem. Some of our scala is generated by bizarro tools that potentially need to run on license restricted servers.
Absolutely, that's why we have the ability for the user to switch BSP servers if they choose to.
- As mentioned above, this logic should be that if you're not in a workspace that Bloop supports, what you outline should still work as expected.
Some of our scala is generated by bizarro tools that potentially need to run on license restricted servers.
It should seem obvious, but the vast majority of tools will favor the common over "bizarro" tools. That's sort of a no brainer that out of the box a tool would support for example the most common setup vs bizarro.
How does scala-metals decide that bloop supports a workspace? Can I put something in our workspace to tell scala-metals that bloop is not an option?
Metals checks to see if the root workspace holds any of the common build files for the build tools outlined here. If so, there is Bloop support for those build definitions, so we default to Bloop.
Is it safe to assume that you're using sbt, or are you using another build tool that Metals doesn't support?
We're using a different proprietary tool that metals DOES support, because we implemented the BSP specifically to use scala-metals in vscode with our projects.
To clarify, I meant does Metals advertise support for it, have tests for that build tool, and documentation about it. I'm assuming that you mean no since it's a proprietary tool. If I may ask, what are you build files named? I'm assuming they have the same name as one of the other supported tools, since if it didn't, it should still pick up .bsp/custom-tool.json.
So this command should be accessible the same as any other command. We also talked about it in the release notes, it's documented
Yes. That's why I found it. But I work on the build at our company, so I know scala-metals and the BSP is what underlies our vscode scala support. Developers who are just working within our framework should not need to know about any of this. Our work-around is we now have 2-3 extra steps in our "how to setup a new developer workspace". Unfortunately, people don't follow directions very reliably.
Do you have any ideas how to make this command more discoverable if people are having issues finding it?
Sure. If you don't want to default to .bsp/xyz.json, just ask the user which BSP to use the moment scala-metals opens a workspace where no explicit choice has been made yet.
As you just mentioned up above, a lot of users are unfamiliar with BSP, so such a prompt is bound to cause confusion. We decided in this case it was better to default to Bloop if it's a supported build tool.
I'm open to trying to find a better solution for this situation, but I don't this situation is quite rare. As you said, most people don't want to care about BSP, they just want what works. In the case of all the build tools that we support, most of the time that's Bloop.
I'll re-iterate what I have written here. I'm more than happy to try to solve this is a good way, but please understand that we'll also defer to the most commonly used setup for an average user than a setup that treats a bizarro or proprietary tool as equal. There isn't currently a way to force Metals to use a specific build server apart from making a choice, but again, I'm open to explore what could be done in your case, but we'll have to think a bit about it since I don't believe we'll be changing the default to Bloop for build spaces that have build files that we recognize and support. Maybe there is a way to differentiate your build file from whicherver tool Metals seems to think it is? In that way we may be able to make the checks stricter so that it doesn't think your workspace is a supported one when it first starts, and therefore would default to what's in the .bsp/.
If some of that info is proprietary and you don't want to share on here, I understand. Feel free to DM me on Gitter or Discord.
How does scala-metals decide that bloop supports a workspace? Can I put something in our workspace to tell scala-metals that bloop is not an option?
Metals checks to see if the root workspace holds any of the common build files for the build tools outlined here. If so, there is Bloop support for those build definitions, so we default to Bloop.
I think I've found the answer. There's a project/build.properties file that lingers on in our workspace.
I think I've found the answer. There's a project/build.properties file that lingers on in our workspace.
If this file isn't necessary, in theory you should be able to remove it, and then the old behavior of it default to .bsp/custom.json should work. There were tons of changes made to BSP discovery related things in the last couple releases, so if something seems to not work as expected, let us know.
That file is obsolete. When I delete it, everything works properly on a fresh clone. -.-
I thought scala-metals was assuming that every repository supports bloop. Now I see it had evidence to justify that incorrect assumption. Oddly, when I select 'switch build server', it still lists Bloop as an option, though.
So, I have a solution for our situation. Thank you for explaining. Also, thank you for scala-metals! It has been rock-solid in my experience. We're moving our whole organization to vscode specifically because of "remote - ssh" and scala metals. For our situation, those are the 1-2 IDE punch. All the other useful vscode plugins are just gravy.
I still think it's not wise for scala-metals to override the explicit directive of a project's maintainers. However, this issue no longer affects my organization. I could imagine a situation, though, where an organization uses sbt/bloop for a feature-reduced flow, but uses xyz for their production flow. So this complaint may rise again down the road.
Thing like our run/debug code lenses need Bloop to function properly.
Well, those can work for us without bloop, so that argument does not apply to our situation.
🤔 I'm curious how this works for you... as we literally check to see if the main BSP connection is Bloop to enable it.
I said "can" work, not "do" work. ;-) I am actively working on integrating our test suite into vscode. Right now you still have to run them by hand. I was wondering why when I reported scalaTestClasses to metals, nothing happened. Now I know why.
I'm not really convinced that a 'code lens' is right for us, anyway. What I really want is a per-directory test-result scoreboard. The JUnit "Test Explorer" seems like a better fit for us. Does anything like this already exist for scala, or even better, scalatest?
If you don't want to default to .bsp/xyz.json, just ask the user which BSP to use the moment scala-metals opens a workspace where no explicit choice has been made yet.
As you just mentioned up above, a lot of users are unfamiliar with BSP, so such a prompt is bound to cause confusion. We decided in this case it was better to default to Bloop if it's a supported build tool.
To turn it around: users are only faced with this prompt in the unusual situation that a .bsp/xyz.json exists. Those are also exactly the set of users who are likely to be negatively impacted by the wrong choice. The question could also be phrased in a way that clarifies the situation:
"We've detected that your workspace supports a custom build tool (xyz), due to the existence of .bsp/xyz.json. However, your workspace also contains build.sbt, which suggests it is an SBT build best supported by the bloop build tool. Please select which tool is the right one to compile this project: xyz bloop. You can prevent this question from appearing for other users by deleting either .bsp/xyz.json or build.sbt at your discretion."
If you had that message, it would also have spared you the support cost of this issue report, since I would have immediately deleted project/build.properties.
To turn it around: users are only faced with this prompt in the unusual situation that a .bsp/xyz.json exists.
The thing is is that this isn't an unusual situation. Literally every Scala developer using sbt > 1.4.0 would hit on this. So it's much easier to not field questions from a massive amount of developers using sbt, even with a clear message, than answering the one offs in very very specific scenarios, like yours. Often what we think are clear messages are soaked with assumptions, so it's just never that clear.
Oddly, when I select 'switch build server', it still lists Bloop as an option, though.
I think I see the issue for this actually and I went ahead and created #2424 about it. Should be a simple fix.
So, I have a solution for our situation.
Glad to hear it.
All in all, I understand your concerns. In reality we have a very opinionated way that we follow BSP discovery. This is done simply to provide the best experience to most people. If we fully followed BSP discovery, then your situation wouldn't have been an issue, but at the cost of confusing a massive amount of developers, by showing them prompts about BSP. In this situation, we favor the smooth ride for the majority of users. That a choice I feel pretty strongly about, and I don't want to speak for the other maintainers, but I believe they do as well.
I'm going to go ahead and close this because I believe I've addressed everything, but feel free to let us know if you have any other issues apart from the feature request created (https://github.com/scalameta/metals-feature-requests/issues/183) and the issue I created #2424.
One last suggestion: if you really insist on defaulting to bloop, if bloop fails to initialize (missing .bloop or nothing it can import), you could present the switch build server option at that time, if there are alternatives and no explicit choice has been made yet.
Should this issue be re-opened in the light of https://github.com/scalameta/metals/discussions/4505#discussioncomment-3933786?
We can reopen it since I think I was outvoted on this issue :(
Is that still the opinion that we should treat the build server in .bsp as the default instead of Bloop or should we rather simply add a setting for choosing the default build server as requested here: https://github.com/scalameta/metals-feature-requests/issues/358.
Actually reading the original issue again, this shouldn't be a problem anymore. Currently all custom .bsp/xyz.json will be discovered as "build tools", so if sbt is also found in the workspace the user will be explicitly asked which "build tool" (sbt or custom bsp) they want to use.