-
Notifications
You must be signed in to change notification settings - Fork 411
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
Avoid validating all opened workingcopies when didChange a document #2587
Avoid validating all opened workingcopies when didChange a document #2587
Conversation
This 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.
@testforstephen @jdneo you may want to take a look at redhat-developer/vscode-java#2982 (comment)
A related issue - #279 |
We understand the reason behind validating all open working copies. However, the concern is that the disadvantages outweigh the benefits. I believe you should notice similar user complaint that the more you use it, the slower the extension gets. This should be one reason for that. Let’s consider this issue from another perspective. If the related file Test2.java is not open, renaming test2 to test in Test.java will not automatically fix the compilation errors in Test2.java. This means that validating all working copies cannot guarantee that all potential errors introduced by current changes will be immediately revealed. In contrast, when editing a Java file in Eclipse, only the current file is immediately validated, not other working copies.
validatingcopy.mp4
validatingcopy1.mp4 |
@testforstephen Agree. cc @fbricon @rgrunber |
So I found an issue with this PR: if you use a code action that creates a missing class, once the new class has been created, then file being edited still shows an error, until the next validation trigger. Same issue with code action creating a missing method. |
@fbricon One possible solution is to append a WDYT? |
Here is a patch code that can solve the code action diagnostics issue when creating missing class. You can test it by applying the git diff code on the current PR. However, I think it would be clearer to use a separate PR for the new issue. diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CodeActionHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CodeActionHandler.java
index 0c353e8e..b3e48fce 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CodeActionHandler.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CodeActionHandler.java
@@ -46,6 +46,7 @@ import org.eclipse.jdt.ls.core.internal.corrections.InnovationContext;
import org.eclipse.jdt.ls.core.internal.corrections.QuickFixProcessor;
import org.eclipse.jdt.ls.core.internal.corrections.RefactorProcessor;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.ChangeCorrectionProposal;
+import org.eclipse.jdt.ls.core.internal.corrections.proposals.NewCUProposal;
import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager;
import org.eclipse.jdt.ls.core.internal.preferences.Preferences;
import org.eclipse.jdt.ls.core.internal.text.correction.AssignToVariableAssistCommandProposal;
@@ -198,7 +199,7 @@ public class CodeActionHandler {
}
try {
for (ChangeCorrectionProposal proposal : proposals) {
- Optional<Either<Command, CodeAction>> codeActionFromProposal = getCodeActionFromProposal(proposal, params.getContext());
+ Optional<Either<Command, CodeAction>> codeActionFromProposal = getCodeActionFromProposal(params.getTextDocument().getUri(), proposal, params.getContext());
if (codeActionFromProposal.isPresent() && !codeActions.contains(codeActionFromProposal.get())) {
codeActions.add(codeActionFromProposal.get());
}
@@ -256,7 +257,7 @@ public class CodeActionHandler {
}
}
- private Optional<Either<Command, CodeAction>> getCodeActionFromProposal(ChangeCorrectionProposal proposal, CodeActionContext context) throws CoreException {
+ private Optional<Either<Command, CodeAction>> getCodeActionFromProposal(String uri, ChangeCorrectionProposal proposal, CodeActionContext context) throws CoreException {
String name = proposal.getName();
Command command = null;
@@ -281,6 +282,12 @@ public class CodeActionHandler {
CodeAction codeAction = new CodeAction(name);
codeAction.setKind(proposal.getKind());
if (command == null) { // lazy resolve the edit.
+ if (proposal instanceof NewCUProposal) {
+ codeAction.setCommand(new Command("refresh Diagnostics", "java.project.refreshDiagnostics", Arrays.asList(
+ uri, "thisFile", false
+ )));
+ }
+
// The relevance is in descending order while CodeActionComparator sorts in ascending order
codeAction.setData(new CodeActionData(proposal, -proposal.getRelevance()));
} else {
|
I'm not fond at all about this solution, as it puts the burden on clients to implement/call a new refresh command |
BTW that patch doesn't take care of a code action modifying a different file to implement new/missing methods. |
|
This refresh command is an existing delegate command on server side, no extra client effort for this.
The patch is just a demo that we have a different solution to fix the code action problem. We can apply similar logic to cover other code action cases. |
Thanks for sharing more history. However, I’m concerned that validating all open buffers on each editing would have a negative impact on the performance that outweighs the benefits. If you have any suggestions on how to improve it and make it more client-friendly, I’m open to hearing them. |
Let me clarify a little bit, the command If we agree the solution to fix the code action diagnostic, i can create a new PR for it. Anything further to improve in this PR? |
....jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/BaseDocumentLifeCycleHandler.java
Outdated
Show resolved
Hide resolved
9da77d5
to
3c6b133
Compare
Hi @puremourning @mfussenegger, We are discussing the CodeAction spec, and support returning a TextEdit and a command (such as java.project.refreshDiagnostics in the CodeAction response. The jdtls provides this refreshDiagnostics command as a workspace/executeCommand command. VS Code supports this workspace command well. How about other clients? Do they support this server side workspace command for code action response? |
If I understand correctly, you are going to return an We have a TODO: fixits = []
for code_action in code_actions:
if 'edit' in code_action:
# TODO: Start supporting a mix of WorkspaceEdits and Commands
# once there's a need for such
assert 'command' not in code_action
# This is a WorkspaceEdit literal
fixits.append( self.CodeActionLiteralToFixIt( request_data,
code_action ) )
continue
# Either a CodeAction or a Command
assert 'command' in code_action |
Yes, we intend to return both as the spec allows AND, not just OR.
|
@puremourning I opened an issue ycm-core/ycmd#1692 (Support a mix of edit and command in the code action response) since ycmd implementation is inconsistent with the LSP spec. |
3c6b133
to
e372e23
Compare
…lidate all buffers during document lifecycle job
The latest PR adds a client flag ‘validateAllOpenBuffersOnDidChange’ to control whether to check all open buffers for errors during didChange event. The default value is true, so all clients will keep the old behavior unless they explicitly set the flag to false. I also created another PR #2664 to address the issue of inconsistent diagnostics with code action. In VS Code, we will set the flag to false for performance reasons. In my experiment, opening 40 test cases with guava project and typing any code took more than 5 seconds to run a validation on all buffers. This is too slow. |
test this please |
40s with or without this PR? |
Rather than a custom capability can it be a workspace configuration? That avoids client code changes and lets the user decide rather than the client author. |
I tested it with 40 Java files opened in the editor, and edited one Java file with more than 2000 lines of code. The diagnostics job reports errors much faster with this PR. Without this PR, it takes 8 seconds to finish the diagnostics job and report errors. With this PR, it only takes 700 milliseconds to report errors. |
…o control whether to validate all open buffers
@puremourning Done. Changed to a workspace setting |
Sorry I had missed the notification. Neovim LSP supports handling workspace edit and commands within code actions.
Does a save still update all open buffers? |
No, saving a file will not revalidate all open buffers. But it will trigger an auto-build job to recompile the affected files and update their diagnostics. This PR is to discuss the diagnostics strategy for unsaved changes that occur during editing. |
Both the PR description section #2587 (comment) and the wiki https://github.com/eclipse/eclipse.jdt.ls/wiki/Running-the-JAVA-LS-server-from-the-command-line have been updated to explain how clients can use this setting. |
So I tried this out with my client and one thing that would be nice is a way to "force" jdt to revalidate a specific buffer. That way I can trigger a revalidation of a file which was open, but not visible in the editor, but that's now visible. This makes the results for the user smoother as it doesn't lead to stale diagnostics, like in the below example: https://asciinema.org/a/zBzR2IGroIuN5XFF0YpTa31iL Ideally I could (from the client) force a refresh of diagnostic for the file on the right when I put my cursor into that window (in vim terms, visit the buffer). I did try just sending didClose followed immediately by didOpen whenever visiting the buffer, but this was too slow and caused things like semantic tokens requests to fail randomly. |
Wait I just remembered that the whole reason you pinged me on this was because of the custom "refreshDiagnostics" command! #2587 (comment) Let me see if I can abuse that for this purpose. |
This PR introduces a workspace setting
java.edit.validateAllOpenBuffersOnChanges
that allows users to choose the diagnostics strategy for unsaved changes when editing a Java file.