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

Replace slowTask with LSP progress #6144

Merged
merged 12 commits into from
Apr 19, 2024
Merged

Replace slowTask with LSP progress #6144

merged 12 commits into from
Apr 19, 2024

Conversation

kasiaMarek
Copy link
Contributor

@kasiaMarek kasiaMarek commented Feb 20, 2024

resolves: scalameta/metals-feature-requests#374
resolves: #6099
resolves: #6187

@kasiaMarek kasiaMarek changed the title I374 Replace slowTask with LSP progress Feb 20, 2024

connWithTimeout
conn
.withTimeout(60, TimeUnit.SECONDS)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

There doesn't seem to exist a capability for supporting cancel on workDoneProgress.

Copy link
Member

Choose a reason for hiding this comment

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

Could you explain what you mean with this? There should always be a taskStart associated with a progress right, and it would just be attached to that?

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 logic in here was: if client supports slowTask (thus cancel) do not add a timeout to creating connection (user can cancel it), otherwise add timeout. Now we switch to lsp workDoneProgress. Problem is that even if client supports LSP workDoneProgress it doesn't mean they support cancel for workDoneProgress, LSP specification basically says that client can ignore the cancellation option in workDoneProgress if it's not supported. So I decided that the safest option is to always add the timeout.

Copy link
Member

Choose a reason for hiding this comment

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

ahh ok that makes sense. 👍🏼

@@ -36,6 +37,7 @@ class BspConnector(
tables: Tables,
userConfig: () => UserConfiguration,
statusBar: StatusBar,
Copy link
Member

Choose a reason for hiding this comment

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

We don't use this in generateBspConfig anymore so you can remove it there and in here as well.

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 also change to workDoneProgress in ScalaCliBuildTool?

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 might finish too fast for it make much sense but I can do that.


connWithTimeout
conn
.withTimeout(60, TimeUnit.SECONDS)
Copy link
Member

Choose a reason for hiding this comment

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

Could you explain what you mean with this? There should always be a taskStart associated with a progress right, and it would just be attached to that?

Copy link
Member

@jkciesluk jkciesluk left a comment

Choose a reason for hiding this comment

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

It works great, good job!

private class Compilation(
val timer: Timer,
val isNoOp: Boolean,
token: Option[Future[WorkDoneProgress.Token]],
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
token: Option[Future[WorkDoneProgress.Token]],
token: Option[WorkDoneProgress.Token],

could we avoid having a future here? We could probably change startProgress to be generic?

Copy link
Contributor Author

@kasiaMarek kasiaMarek Apr 2, 2024

Choose a reason for hiding this comment

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

It's just to make sure that progress was actually created on client side before we send e.g. end. What I was worried about is if we send end way too fast, before client creates the token for it, so end will be ignored and the progress bar will just be visible forever. I can change this to a Promise if that helps.

We could probably change startProgress to be generic?

I'm not sure I understand.

Copy link
Contributor

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.

I don't remember what I had in mind 😅

Maybe we could have a sealed hierachy instead, soemthing like:

sealed trait Compilation{
  def timer: Timer
  def taskProgress: TaskProgress
}

case class NoopCopilation(
  val timer: Timer,
){
  override def taskProgress: TaskProgress = TaskProgress.empty,
}

case class IncrementalCompilation(  
      val timer: Timer,
      token: Future[WorkDoneProgress.Token],
       taskProgress: TaskProgress
)

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.

I think that after @ckipp01's changes in Bloop we need a noop anymore, Bloop won't send startTask for it anymore.

Copy link
Contributor

Choose a reason for hiding this comment

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

probably not, so maybe we can just do:

case class Compilation(  
      val timer: Timer,
      token: Future[WorkDoneProgress.Token],
      taskProgress: TaskProgress
)

?

Comment on lines 116 to 123
token.map { token =>
val task = taskMap.getOrDefault(token, Task.empty)
task.maybeProgress match {
case Some(progress) =>
progress.update(percentage)
val report = new WorkDoneProgressReport()
report.setPercentage(progress.percentage)
task.additionalMessage.foreach(report.setMessage)
val notification =
messages.Either.forLeft[WorkDoneProgressNotification, Object](
report
)
client.notifyProgress(new ProgressParams(token, notification))
case None =>
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
token.map { token =>
val task = taskMap.getOrDefault(token, Task.empty)
task.maybeProgress match {
case Some(progress) =>
progress.update(percentage)
val report = new WorkDoneProgressReport()
report.setPercentage(progress.percentage)
task.additionalMessage.foreach(report.setMessage)
val notification =
messages.Either.forLeft[WorkDoneProgressNotification, Object](
report
)
client.notifyProgress(new ProgressParams(token, notification))
case None =>
}
token.map(notifyProgress)

?

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.

Looks good! Just two minor comments

private class Compilation(
val timer: Timer,
val isNoOp: Boolean,
token: Option[Future[WorkDoneProgress.Token]],
Copy link
Contributor

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.

I don't remember what I had in mind 😅

Maybe we could have a sealed hierachy instead, soemthing like:

sealed trait Compilation{
  def timer: Timer
  def taskProgress: TaskProgress
}

case class NoopCopilation(
  val timer: Timer,
){
  override def taskProgress: TaskProgress = TaskProgress.empty,
}

case class IncrementalCompilation(  
      val timer: Timer,
      token: Future[WorkDoneProgress.Token],
       taskProgress: TaskProgress
)

what do you think?

@kasiaMarek kasiaMarek merged commit dfa2bfe into scalameta:main Apr 19, 2024
23 of 26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants