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

Display build target info #3380

Merged
merged 2 commits into from
Feb 7, 2022

Conversation

Arthurm1
Copy link
Contributor

This is an alternative to #3077 which I think I'll ditch in favour of this.

Instead of webview it uses metalsdecode: and virtual docs. The benefits are that it should be able to be supported in the same way across different clients (vscode, vim, sublime). It also means that multiple build target views can be open at once. The downside is that it loses the navigation to other build targets and to jars.

You can open a uri with the format metalsDecode:file:///workspacePath/buildTargetName.metals-buildtarget in the same way as other metalsDecode types work and Metals will hand you back the text describing that build target.
You can fire off target-info-display command and Metals will use the QuickPick functionality to offer a list of target names.

There's a textmate grammar file for highlighting the build target file.

@ckipp01 @ayoub-benali I've kind of assumed that since you have the metalsDecode functionality in Vim/Sublime that this will be easy to add?

This is rebased off the Java PR #2520 as it sets up all the javacoptions so there's no point reviewing til that's merged.

metals-1639750923059.mp4

@GavinRay97
Copy link
Contributor

This is really cool + useful, thank you 👀

@ayoub-benali
Copy link
Contributor

Cool feature 🎉 and yes I shouldn't be too difficult to add

@ckipp01
Copy link
Member

ckipp01 commented Dec 21, 2021

Same from me on the nvim-metals side. This should be easy to add 👍🏼

Copy link
Contributor

@tgodzik tgodzik left a comment

Choose a reason for hiding this comment

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

Great work! Finally I will not have to go manually into .bloop files 😅

And probably this would be much easier for sbt server than before. Left some questions and we should probably rebase.

class BuildTargetInfo(buildTargets: BuildTargets) {

def buildTargetDetails(targetName: String): String = {
buildTargets.allCommon
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like we need to rebase on recent main? We renamed allCommon from what I remember.

val padding = " " * (maxFilenameSize - filename.size)
val status = if (f.toFile.exists) {
if (f.toFile().isDirectory())
" "
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we make it a value? The same length is used underneath I think? And maybe do soemthing like " " * 5 ?

@@ -33,7 +34,8 @@ class ClasspathTreeView[Value, Key](
viewId,
rootUri,
title + s" (${toplevels().size})",
collapseState = MetalsTreeItemCollapseState.collapsed
collapseState = MetalsTreeItemCollapseState.collapsed,
contextValue = "root"
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need the new contextValue ? This should be documented in tree view protocol https://scalameta.org/metals/docs/integrations/tree-view-protocol if we add it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's so VSCode can show a context menu only on projects, not libraries, in the treeview. If you're ok with that then I'll add some docs

Copy link
Contributor

Choose a reason for hiding this comment

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

Would we be able to do it in VS Code only? I would rather avoid changing it if it's not needed for any other extensions. @ckipp01 what do you think?

Or maybe, we could make it general and add command filed instead something like:

"comand" :  { "id" : "show-target", args: [] }

what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The Display Build Target command works from VSCode. This was just an extra way of doing it - i.e. right click on a project in the Metals TreeView and get the info. I'm cool with removing that if you'd prefer not to change the treeview API

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that is a cool option to have it under right click, just wondering if we can make the API change less VS Code reliant. I am also worried that with this change we will need to update all the clients.

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, let me take a look if we can do it without the added parameter

Copy link
Member

Choose a reason for hiding this comment

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

If at all possible I think we should avoid baking in VS Code specific stuff to the actual protocol itself. The more we do that the harder it becomes to work around for all other clients. I don't really understand the full context behind this to be honest. I don't know what a context menu is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ContextValue is gone. The context menu allows you to right-click on a project in the treeview and get a menu up to allow you to call Display the Build Target info directly on the project/target, instead of running the Display Build Target command and getting a list of project/targets up. Just a different way of getting to view project info

@ckipp01
Copy link
Member

ckipp01 commented Jan 31, 2022

@ckipp01 @ayoub-benali I've kind of assumed that since you have the metalsDecode functionality in Vim/Sublime that this will be easy to add?

Yup, the handling of just the raw text would be fine. Although I honestly think this would be a killer feature to return to the editor in a structured manner instead of just text. I know for myself this was actually what I proposed in #2479 but kind of got shot down. If the client can have access to this info, it unlocks a ton of stuff they can do with it. So the text is great, but I'd honestly love this as JSON.

Copy link
Member

@ckipp01 ckipp01 left a comment

Choose a reason for hiding this comment

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

I think we have a lot of duplication in here with already existing stuff that things like BuildTarget already gives is. Is it possible to maybe slim down all the extra classes that are added here and to instead use the existing ones?

targetId: BuildTargetIdentifier
): Option[String] = {
extractTargetDetail(targetId).map(detail => {
val info = ListBuffer[String]()
Copy link
Member

Choose a reason for hiding this comment

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

Sort of a nit, but you could also just use a string builder here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With StringBuilder I think I'd need to add newlines everywhere

if (detail.common.tags.nonEmpty) {
info += ""
info += "Tags"
detail.common.tags.foreach(f => info += s" $f")
Copy link
Member

Choose a reason for hiding this comment

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

Can we replace all the usages of f with more meaning names.

languageIds: List[String],
dependencies: List[String],
dependentTargets: List[String],
capabilities: List[(String, Boolean)],
Copy link
Member

Choose a reason for hiding this comment

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

It'd be nicer if this could be a List[BuildTargetCapability]. Then we could also avoid the ._2 shenanigans up above.

Copy link
Member

Choose a reason for hiding this comment

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

Actually thinking about this, there seems to be a lot of redundancy in here. Are all of these classes actually needed. For example we could also just use BuildTargetCapabilities from BSP for this couldn't we? Same with almost all of this stuff in here. This is very close to the actual BuildTarget interface.

else
path
}
if (classPath.nonEmpty) {
Copy link
Member

Choose a reason for hiding this comment

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

I'm recommend breaking this up a bit. We have 3 nested ifs in here that can be tricky to follow. Breaking those out to functions might make this easier to read.

Comment on lines 259 to 264
var capabilities = List.empty[(String, Boolean)]
capabilities ::= ("Debug", target.capabilities.getCanDebug)
capabilities ::= ("Test", target.capabilities.getCanTest)
capabilities ::= ("Run", target.capabilities.getCanRun)
capabilities ::= ("Compile", target.capabilities.getCanCompile)
capabilities
Copy link
Member

Choose a reason for hiding this comment

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

Lets avoid the var here. We can just create a list and add these when we create the list like one :: two :: three :: nil and just return that. Although again as I stated above, we should avoid a tuple here, and even avoid the extra class if we can.

@tgodzik tgodzik added the affects clients Use this if you are adding a new setting or making a change that will affect clients. label Jan 31, 2022
@Arthurm1 Arthurm1 force-pushed the virtual_display_build_target branch 2 times, most recently from f40ec08 to 41d2438 Compare January 31, 2022 19:36
@Arthurm1
Copy link
Contributor Author

@ckipp01 @ayoub-benali I've kind of assumed that since you have the metalsDecode functionality in Vim/Sublime that this will be easy to add?

Yup, the handling of just the raw text would be fine. Although I honestly think this would be a killer feature to return to the editor in a structured manner instead of just text. I know for myself this was actually what I proposed in #2479 but kind of got shot down. If the client can have access to this info, it unlocks a ton of stuff they can do with it. So the text is great, but I'd honestly love this as JSON.

From what I can see you want the client to be able to interact with the build server e.g. query targets or run a mainclass?

Instead of creating multiple commands for whatever the client wants from the underlying build server, how about creating a generic pass this command to BSP command and get Metals to send back the BSP json results. Then the client can call whatever BSP stuff it wants without having to special case each requirement in Metals.

@Arthurm1
Copy link
Contributor Author

@tgodzik I don't understand the ScalaFix error here. Can you help?

@tgodzik
Copy link
Contributor

tgodzik commented Feb 1, 2022

@tgodzik I don't understand the ScalaFix error here. Can you help?

It doesn't seem related. I will rerun.

@Arthurm1
Copy link
Contributor Author

Arthurm1 commented Feb 1, 2022

@tgodzik InsertInferredTypeLspSuite.match-bind fails sometimes but has nothing to do with this.

It seems to fail because in inferTypeTitle a different match occurs...

Here's the code snippet...

    pattern.parent
          .collect {
            case Pat.Typed(_, _) => None
            case Pat.Bind(lhs, _) if lhs != pattern => Some(insertTypeToPattern)
            case _: Pat.Bind => None
            case vl: Defn.Val if vl.decltpe.isEmpty => Some(insertType)
            case vr: Defn.Var if vr.decltpe.isEmpty => Some(insertType)
            case _: Pat | _: Enumerator => Some(insertTypeToPattern)
          }
          .getOrElse(None)

Sometimes the test enters...
case Pat.Bind(lhs, _) if lhs != pattern => Some(insertTypeToPattern)
Sometimes it enters...
case _: Pat.Bind => None

One passes, the other fails. I don't know why this randomly happens as I have no idea what this code is supposed to do. It's fairly easy to reproduce the failure when you run the whole
InsertInferredTypeLspSuite suite but if you just run InsertInferredTypeLspSuite-match-bind it always passes.

@tgodzik
Copy link
Contributor

tgodzik commented Feb 1, 2022

@tgodzik InsertInferredTypeLspSuite.match-bind fails sometimes but has nothing to do with this.

It seems to fail because in inferTypeTitle a different match occurs...

Sometimes the test enters... case Pat.Bind(lhs, _) if lhs != pattern => Some(insertTypeToPattern) Sometimes it enters... case _: Pat.Bind => None

One passes, the other fails. I don't know why this randomly happens as I have no idea what this code is supposed to do. It's fairly easy to reproduce the failure when you run the whole InsertInferredTypeLspSuite suite but if you just run InsertInferredTypeLspSuite-match-bind it always passes.

Och, I've seen this happen before, but couldn't reproduce it.

@tgodzik
Copy link
Contributor

tgodzik commented Feb 1, 2022

I will take a look!

@Arthurm1
Copy link
Contributor Author

Arthurm1 commented Feb 4, 2022

@tgodzik I think this is ready to merge.

Copy link
Contributor

@tgodzik tgodzik left a comment

Choose a reason for hiding this comment

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

LGTM!

@tgodzik tgodzik merged commit c86af49 into scalameta:main Feb 7, 2022
@Arthurm1 Arthurm1 deleted the virtual_display_build_target branch February 7, 2022 13:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
affects clients Use this if you are adding a new setting or making a change that will affect clients.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants