Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support the SBT extension in BSP import #6553

Merged
merged 8 commits into from Jul 5, 2021

Conversation

retronym
Copy link
Member

@retronym retronym commented Jun 18, 2021

This enables code assist in the .sbt and project/*.scala files in IntelliJ (pending merge of the related PR to intelli-scala).

Other IDEs that support BSP import could also take advantage of this; scala-metals has a ticket to add support: scalameta/metals-feature-requests#143

To disable this feature (e.g. if using an IDE version that does not yet support the sbt extension in the BSP protocl, set ThisBuild / bspSbtEnabled := false.

Fixes #5953

Requires: JetBrains/intellij-scala#593

@adpi2
Copy link
Member

adpi2 commented Jun 18, 2021

Looks very promising so far. Thank you @retronym for taking care of this!

@retronym
Copy link
Member Author

retronym commented Jun 22, 2021

I should get back to this later today, thanks for the review comments so far.

The corresponding change to IntelliJ is just about ready to land: JetBrains/intellij-scala#593

@retronym
Copy link
Member Author

This one is ready for another round of review. I'll try to address attaching SBT source JARs to the project in a followup PR.

@retronym retronym marked this pull request as ready for review June 23, 2021 22:02
This enables code assist in the .sbt and project/*.scala files
in IntelliJ and any other IDEs that implement this extension.
  - Restore old type of `bspWorkspace` key for backwards compat.
    Instead, introduce `bspFullWorkspace` that includes the
    SBT targets
  - Log a warning if the client requests, e.g. `scalaMainClasses`
    for a SBT target
  - Refactor the code that creates the SBT build targets so it
    doesn't depend on `sbtFullWorkspace`.
  - Add a setting `bspSbtEnabled` to let the user opt-opt of
    SBT target export (e.g. to compensate for a client that does
    not yet support them)
@retronym retronym force-pushed the topic/bsp-sbt-target branch 6 times, most recently from 89ae692 to 1dd9cf1 Compare June 28, 2021 01:27
Copy link
Member

@eed3si9n eed3si9n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but I yield the detail review to Adrien.

eed3si9n
eed3si9n previously approved these changes Jun 28, 2021
Copy link
Member

@eed3si9n eed3si9n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but I yield the detail review to Adrien.

Comment on lines 150 to 155
// Not a constructor parameter to avoid a binary incompatibility
private[this] var _buildSources: BuildSources = BuildSources.Empty
private[sbt] def setBuildSourcesData(data: BuildSources): PluginData = {
_buildSources = data; this
}
private[sbt] def buildSourcesData: BuildSources = _buildSources
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eed3si9n Is it really necessary to preserve the binary compatibility of PluginData? How bad would it be to break it in sbt 1.6?

I am asking this because I also want to add more parameters in it for #6566.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The breakage is just for the constructor, copy, and apply factory methods, not for consumers of the data. I think it is highly unlikely to break existing plugins.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really necessary to preserve the binary compatibility of PluginData? How bad would it be to break it in sbt 1.6?

We maintain binary compatibility for the purpose of maintaining plugin compatibility, so I think PluginData would be ok to break, but ultimately we the only way to quantify this would be to release a milestone and test it using Community Build. If none of the existing builds break, then we should be ok.

Copy link
Member

@adpi2 adpi2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 2 comments below should be addressed before merging. Otherwise I would suggest to update the test here:

test("workspace/buildTargets") { _ =>
svr.sendJsonRpc(
"""{ "jsonrpc": "2.0", "id": "16", "method": "workspace/buildTargets", "params": {} }"""
)
assert(processing("workspace/buildTargets"))
assert {
svr.waitForString(10.seconds) { s =>
(s contains """"id":"16"""") &&
(s contains """"displayName":"util"""")
}
}
}

and to add a new test for the sources of the build.sbt target.

main/src/main/scala/sbt/internal/Load.scala Outdated Show resolved Hide resolved
@retronym
Copy link
Member Author

Update: I'm currently trying to extend the BSP test. Having some difficulty there as one of my new tests for sources (sbt build) works in isolation but not after the exising test for normal sources. Haven't figured out the crosstalk yet.

Copy link
Member

@adpi2 adpi2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just pushed a small fix for the new buildTarget/resources request. Otherwise it looks good to me as it is.
I tried in Metals and most of the things (goto definitions and code completions) are already working out-of-the-box. That's cool!

@retronym
Copy link
Member Author

retronym commented Jul 1, 2021

@eed3si9n Are you happy with this one now, in particular deeming PluginData creation/copying as sbt-internal and excluded from MiMa?

@retronym
Copy link
Member Author

retronym commented Jul 1, 2021

There was a scalacheck test failure in one of the test runs, not related to this PR, but maybe worth looking into:

[info] - sbt.ParseKey.An unspecified project axis resolves to the current project: Falsified after 4341 passed tests
[info] > StructureKeyMask(Env:
[info]     Tasks:
[info]     aa (delegates: )
[info] Build file:///aaaaaaa/#a :
[info]     Project a
[info]       Delegates:
[info]         
[info]       Configurations:
[info]         A
[info]     Project b
[info]       Delegates:
[info]         
[info]       Configurations:
[info]         A
[info]     Project aa
[info]       Delegates:
[info]         
[info]       Configurations:
[info]         A
[info] current: ProjectRef(file:///aaaaaaa/#a,a)
[info] Settings:
[info] 	Global / <key>
[info] 	   aa
[info] All keys:
[info] 	aa,ScopedKey(Scope(Select(BuildRef(file:///aaaaaaa/#a)), Select(ConfigKey(A)), Select(aa), Zero),aa),ScopeMask(false,false,true,false))
[info] > === Not Equal ===
[info] > --- lhs ---
[info] > Select(ConfigKey(A))
[info] > --- rhs ---
[info] > Zero
[info] > === Not Equal ===
[info] > --- lhs ---
[info] > Select(ProjectRef(file:///aaaaaaa/#a,aa))
[info] > --- rhs ---
[info] > Select(ProjectRef(file:///aaaaaaa/#a,a))
[info] > parsed subproject: Select(ProjectRef(file:///aaaaaaa/#a,aa))
[info] > current subproject: ProjectRef(file:///aaaaaaa/#a,a)
[info] > Key: {file:///aaaaaaa/#a} / A / aa / aa
[info] > Mask: ScopeMask(false,false,true,false)
[info] > Key string: 'aa / aa'
[info] > Parsed: Right(ProjectRef(uri("file:///aaaaaaa/#a"), "aa") / aa)
[info] > Structure: Env:
[info]     Tasks:
[info]     aa (delegates: )
[info] Build file:///aaaaaaa/#a :
[info]     Project a
[info]       Delegates:
[info]         
[info]       Configurations:
[info]         A
[info]     Project b
[info]       Delegates:
[info]         
[info]       Configurations:
[info]         A
[info]     Project aa
[info]       Delegates:
[info]         
[info]       Configurations:
[info]         A
[info] current: ProjectRef(file:///aaaaaaa/#a,a)
[info] Settings:
[info] 	Global / <key>
[info] 	   aa
[info] All keys:
[info] 	aa

@eed3si9n
Copy link
Member

eed3si9n commented Jul 1, 2021

@retronym I'm guessing it's a known ambiguity when we have subproject named aa and a task key aa, aa / aa can be interpreted as "aa task in aa project", not "aa task scoped to aa task in current subproject", and thus "An unspecified project axis resolves to the current project" gets falsified. I probably should try to filter that out of the test.

I'm fine with PluginData. I guess the question is if we should call this a 1.6.0 feature or 1.5.x. We can publish 1.6.0-M1, run Community Build, and then back port it to 1.5.x if it passes?

@retronym
Copy link
Member Author

retronym commented Jul 2, 2021

I did a GitHub code search for "plugindata language:scala", filtered out files with package sbt, and didn't spot any usages of the changed methods.

$ gh api --paginate -X GET search/code -f q='language:scala plugindata' -q ".items[] | .url" > /tmp/urls.txt
$ for url in $(cat /tmp/urls.txt); do echo $url; code=$(gh api $url  -q ".content" | base64 --decode); echo $code | grep 'package sbt' || echo $code; done | tee /tmp/code.txt

Not a perfect method, but I think it is likely safe enough for 1.5.x. @adpi2 mentioned that he also has a followup change to add extra data to PluginData.

@eed3si9n
Copy link
Member

eed3si9n commented Jul 5, 2021

ok. We can merge it now, and see.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

BSP: support sbt extension
3 participants