-
Notifications
You must be signed in to change notification settings - Fork 327
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
Reworked Bloop connection and Tree View #1677
Conversation
@nilskp I changed the TreeView to make it more explicit that the commands are clickable and add two more useful commands. Will this be helpful? |
345ae6a
to
1d7362d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some notes on what I changed and why. Overall, I think we need the improvements here to help with the issues we are having in Bloop. In the meantime, I am also trying to help with those issues in Bloop.
@ckipp01 Could you maybe take a look at this from the coc-metals perspective? Not sure if a lot of changes will be need or whether I should do something differently.
@@ -96,13 +98,15 @@ final class BloopServers( | |||
serverStarted | |||
) | |||
|
|||
val finished = Promise[Unit]() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This promise is used to determine whether the launcher is finished.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then maybe it could be called: launched
instead of finished
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
finished
is updated when the launcher finishes and not when it launches, so I think this is better.
@@ -70,14 +72,21 @@ final class BspServers( | |||
s"${details.getName} input stream" | |||
) | |||
|
|||
val finished = Promise[Unit]() | |||
Future { | |||
process.waitFor() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not 100% sure about this solution, need to test it with another BSP server.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a test for it in Bill Suite, seems to work pretty well.
)(implicit ec: ExecutionContextExecutorService) | ||
extends Cancelable { | ||
|
||
@volatile private var connection = Future.successful(initialConnection) | ||
connection.foreach { conn => conn.onConnectionFinished(reconnect) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This uses the promise from the launcher to reconnect when the connection is finished.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand the logic here, what is the difference between this and the logic below?
connection.foreach { conn => conn.onConnectionFinished(reconnect) } | |
initialConnection.onConnectionFinished(reconnect) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
onConnectionFinished
is coming from the process or the launcher to say that the connection is finished. onReconnection
is used to later reindex the workspace.
The alternative is to do it in the MetalsLanguageServer and just do a full reconnect, but then it will be less seamless for the user.
LauncherConnection stoped -> BuildServerConnection.reconnect -> MetalsLanguageServer.indexWorkspace
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a bit better than a full reconnect, because we will not lose any requests to the build server.
def onReconnection( | ||
index: BuildServerConnection => Future[Unit] | ||
): Unit = { | ||
onReconnection.set(index) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to reindex the workspace and this is to make sure that we will only try to reindex once we finished the indexing at least once.
case response if response == Messages.DisconnectedServer.notNow => | ||
notification.dismiss(5, TimeUnit.MINUTES) | ||
connection | ||
if (config.askToReconnect) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depends now on the user configuration.
conn.onConnectionFinished(reconnect) | ||
conn | ||
} | ||
connection.foreach(_ => onReconnection.get()(this)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we actually specify that we want to reindex.
@@ -66,6 +66,26 @@ final class Compilations( | |||
cascadeBatch.cancelCurrentRequest() | |||
} | |||
|
|||
def recompile(): Future[Unit] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used to fully recompile a workspace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the fully
part is more important, then maybe it should be called compileAll
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to recompileAll
) | ||
scribe.error(message, e) | ||
BuildChange.Failed | ||
.flatMap(compileAllOpen) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved compiling after recover, since this caused to disconnect the build server if anything happened during the compilation.
val result = connectToNewBuildServer(build) | ||
build.onReconnection { reconnected => | ||
connectToNewBuildServer(reconnected) | ||
.flatMap(compileAllOpen) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also compile, which will effectively just move all the old artifacts to the new BSP directory.
TreeViewNode( | ||
viewId = "commands", | ||
nodeUri = s"metals://command/${command.id}", | ||
label = command.title, | ||
command = MetalsCommand( | ||
command.title, | ||
command.id, | ||
"metals." + command.id, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Somehow this didn't work with the new command, since the ones declared all have the metals.
prefix
This might not be needed, but I haven't been able to make the new command work otherwise.
I think we could also just use an echo command for all server commands here.
2c870e8
to
aabc8e3
Compare
metals/src/main/scala/scala/meta/internal/metals/MetalsServerConfig.scala
Show resolved
Hide resolved
metals/src/main/scala/scala/meta/internal/metals/ServerCommands.scala
Outdated
Show resolved
Hide resolved
First try shows the |
Seems to be an issue with shutting down currently. The connection might get automatically reestablised 😅 Will fix it tomorrow. |
Project just changed the name, so maybe we can adjust the names of views too? MetalsCompile should be empty unless we are compiling anything. |
caa9aac
to
e2c4358
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really excited to see this PR! I believe it will be a big improvements in troubleshooting errors when Metals is behaving weirdly. A few notes on the names, I haven't reviewed the code.
Should "Recompile workspace" be called "Clean compile workspace" instead?
Should we use the sync icon 🔄 for "Import build" for consistency with IntelliJ "Refresh project"? We can use something like a stop icon ⏹️ for "Restart build server" instead.
Can we move "Restart build server" to the bottom of the command list in the tree view?
(brainstorming, maybe for a separate PR) I wonder if we should have some form of "Clean import build" which removes .bloop/
before importing the build 🤔 I worry however that we end up having too many troubleshooting commands and users blindly run them all.
I was thinking about it, but recompile seemed to be clear that we are redoing the whole compilation. I can change don't feel strongly about it
Good idea! I wasn't really sure about those two.
Sure!
Honestly, I have never needed to do that myself. Either clean compile or restart server should help with most situations. There is no need to remove the .json files in .bloop ever, so the only thing we need to do is remove the compile artifacts, which the clean compile should do. |
e2c4358
to
86dce71
Compare
@olafurpg I updated the icons for import and restart server. I used The image in the description got updated too. Btw. you can actually easily look for icons in https://microsoft.github.io/vscode-codicons/dist/codicon.html And they are quite easy to modify in |
86dce71
to
db17161
Compare
@@ -75,6 +76,12 @@ class MetalsTreeViewProvider( | |||
languageClient.metalsTreeViewDidChange( | |||
TreeViewDidChangeParams( | |||
Array( | |||
TreeViewNode( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sort of nitpicky, but I'm trying to debug what is going on with coc-metals
with the branch, and one things I noticed is that this is technically against the spec that we have published. In the TreeViewNode
class, viewId
and lable
aren't marked as @Nullable
, and in the spec it's the same thing. I'm getting an undefined
that I'm trying to chase down, and I'm sure it's coming from here, but this is the sort of thing that could cause it and confuse someone since there should be somewhat of a guarantee that there is a label
here. The same for the other two TreeViewNode
's below this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added TreeViewNode.empty that sets both the id and label.
TreeViewNode( | ||
Compile, | ||
"metals://ongoing-compilations", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ckipp01 Maybe this part is a problem with the undefined
? I hoped the node is discovered by id, but maybe we check something else in vim? This is the only big change, the rest is just moving things around
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I found the issue. The TVP panel in coc-metals was sort of built with the assumption that apart from the initial view it was never empty. Now that things have been shifted around the the compilations view will return an empty array just isn't accounted for. So I need to adjust the logic for this since I have logic built-in to find the offset of node to update, which is wrong now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, cool. Thanks for taking a look at it!
@@ -96,13 +98,15 @@ final class BloopServers( | |||
serverStarted | |||
) | |||
|
|||
val finished = Promise[Unit]() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then maybe it could be called: launched
instead of finished
?
/** Run build/shutdown procedure */ | ||
def shutdown(): Future[Unit] = connection.map { conn => | ||
try { | ||
isShuttingDown.set(true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
by using compareAndSet(false, true
you could guarantee here that the method will be called exactly once, hence making it idempotent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea! Fixed it!
@@ -66,6 +66,26 @@ final class Compilations( | |||
cascadeBatch.cancelCurrentRequest() | |||
} | |||
|
|||
def recompile(): Future[Unit] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the fully
part is more important, then maybe it should be called compileAll
?
} | ||
_ = { | ||
treeView.init() | ||
def compileAllOpen: BuildChange => Future[BuildChange] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could be compileOpenFiles
at first I was not 100% if it meant open files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed to compileAllOpenFiles
e1444fe
to
079c8f7
Compare
…estart-build commands to it. Also, make reconnection work better by: - reconnecting as soon as the build server is disconnected - making reconnection automatic unless the user specifically asks for it not to be - moving compilation outside the initial build server connection - longer running compilations would then produce invalid exceptions
079c8f7
to
3875129
Compare
Previously, we would only reconnect if the user asked for it and often this would not show up quickly.
Now, we make the reconnection work better by:
metals.ask-to-reconnect=true
Also in this PR:
The reworked tree view would look like this:
I am also thinking of: