-
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
Add "Create new symbol '$name'..." code action #1528
Conversation
def createNewFileDialog(directoryUri: Option[URI]): Future[Unit] = { | ||
def createNewFileDialog( | ||
directoryUri: Option[URI], | ||
name: Option[String] |
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've changed this to also accept a name
, so that we can skip the name-picking dialog and just ask for a file kind.
This allows the code action to fully re-use the existing provider's flow, which I think is really nice
|
||
val codeActions = params.getContext().getDiagnostics().asScala.collect { | ||
case d @ ScalacDiagnostic.SymbolNotFound(name) | ||
if d.getRange().encloses(params.getRange()) => |
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 is encloses
and not overlapsWith
, because I don't think it makes sense to show the "Create new..." action when the user has selected a range which contains multiple SymbolNotFound
diagnostics.
def applyCodeAction(codeAction: CodeAction, server: TestingServer): Unit = { | ||
val edit = codeAction.getEdit() | ||
val command = codeAction.getCommand() | ||
if (edit != null) applyWorkspaceEdit(edit) | ||
if (command != null) executeServerCommand(command, 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.
This is now as per the LSP specification: if edit
and command
are both present, first edit
is applied then command
is executed.
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 is an awesome idea!
} | ||
|
||
object CreateNewFile { | ||
val title = "Create new..." |
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.
create new symbol 'NAME'
?
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 thought about adding something like that, but I feel like "symbol" is not very user-friendly (it's very much compiler lingo).
Anything else would require listing out the options ("Create new trait 'NAME'", "Create new class 'NAME'"), but think it would become too heavy.
I feel like "Create new..." is clear when presented in context and it avoids the problem of listing out all the options.
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 agree "symbol" is not ideal but it's used in "rename symbol" and "go to symbol in file" in VS Code so I think it's OK to use it here.
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.
You're right, it's used around, at least in VSCode. I'll make the change
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.
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.
Nice! I think it's a bit more self documenting what this option does with the name. Should we drop the ...
suffix?
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.
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.
Just some minor comments, but I think it's a great idea! Thanks @gabro !
tests/unit/src/test/scala/tests/codeactions/CreateNewFileLspSuite.scala
Outdated
Show resolved
Hide resolved
metals/src/main/scala/scala/meta/internal/metals/NewFilesProvider.scala
Outdated
Show resolved
Hide resolved
s"""|$kind $name { | ||
| | ||
|$indent |
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.
My editor is set to strip out whitespaces on save, so I've been struggling with this.
I think it's much clearer this way, anyway.
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 agree this is clearer. I also have my editor remove trailing whitespace on save, intellij has this enabled by default, so we should not rely on it in our tests
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 also like this as I get a warning in vim about trailing whitespaces all the time ha.
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.
LGTM!
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 is great LGTM
s"""|$kind $name { | ||
| | ||
|$indent |
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 also like this as I get a warning in vim about trailing whitespaces all the time ha.
metals/src/main/scala/scala/meta/internal/metals/codeactions/CreateNewFile.scala
Outdated
Show resolved
Hide resolved
The failed test on Windows looks relevant, but I think it's flaky (especially because it succeeded on Linux and macOS): probably a race condition that caused the diagnostic not to disappear on time.
I'll restart and see whether it fixes itself |
Do you think it would be possible to move cursor into From your gif it seems like you want to be there anyway and I would like to be there too if I created a new class :) (not sure how hard it is though and if it is metals or more editor specific action?) |
@kpbochenek that's absolutely what I would like, and I think it should be possible by working with the range here metals/metals/src/main/scala/scala/meta/internal/metals/NewFilesProvider.scala Lines 192 to 193 in 8141a99
I would do it in a separate issue since it's quite independent from this PR. |
Ok, now the CI is failing for an unrelated test (I've fixed the previous race condition, which was my fault)
Merging |
This PR is a proposal to add a "Create new..." code action which is a quickfix for a "missing symbol" diagnostic.
Previously we would propose to import a symbol (if available) in response to "missing symbol" errors. Now we also propose to create a new class/trait/object
Here's a demo:
As you can see in the demo, this is very useful when sketching down a domain model, which requires creating a bunch of case classes in a top-down fashion.
What do you all think?
(This is currently based on top of #1525, but I'll rebase once it's merged)