-
Notifications
You must be signed in to change notification settings - Fork 27
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
feat: Text document selection range support (issue 651) #669
feat: Text document selection range support (issue 651) #669
Conversation
…red into the IDE's extendWordSelectionHandler EP.
@@ -14,6 +14,7 @@ The [LSPClientFeatures](https://github.com/redhat-developer/lsp4ij/blob/main/src | |||
- [LSP documentSymbol feature](#lsp-documentSymbol-feature) |
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 recommend that you hide whitespace differences because I ran several of the existing files through the Java formatter against the project's code style and it resulted in minor whitespace changes.
@@ -1105,6 +1140,7 @@ public void setServerCapabilities(@NotNull ServerCapabilities serverCapabilities | |||
|
|||
@Nullable | |||
public TextDocumentServerCapabilityRegistry<? extends TextDocumentRegistrationOptions> getCapabilityRegistry(String method) { | |||
// TODO: Can these be changed to else/if? Or can this be changed to switch? |
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 don't know how often this methods gets called, but it looks like it can be changed to either if ... else if ... else if ...
or ideally switch (method)
to make it more efficient. I'm happy to do that as part of these changes if you'd like.
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 method is called when language server is starting and receive some registerCapability (you can see those LSP trace in the LSP console (do a search with registerCapability). If you want update it, let's go.
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.
Thanks so much to have done this horrible change!
src/main/java/com/redhat/devtools/lsp4ij/features/selectionRange/LSPSelectionRangeSupport.java
Outdated
Show resolved
Hide resolved
...ain/java/com/redhat/devtools/lsp4ij/features/selectionRange/LSPBasicWordSelectionFilter.java
Outdated
Show resolved
Hide resolved
src/main/java/com/redhat/devtools/lsp4ij/features/selectionRange/LSPSelectionRangeSupport.java
Outdated
Show resolved
Hide resolved
Wow again an impressive PR. Let me some times to give yiu detailled review. |
@SCWells72 it would be nice also to update the LSPSupport markdown to enable the selectiinRange and add a detailled info about implementation and a little demo with some expl1nation line shortcut to use. I could do that if you wish. |
I'll update |
I've added a demo to |
} | ||
|
||
// Only if textDocument/selectionRange is supported for the file | ||
return LSPFileSupport.getSupport(file).getSelectionRangeSupport() != null; |
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 check is every time not null. You need to check if there is a language server which support selectionrange:
// Check if the file can support the feature
return LanguageServiceAccessor.getInstance(project)
.hasAny(file.getVirtualFile(), ls -> ls.getClientFeatures().getSelectionRangeFeature().isSelectionRangeSupported(file)));
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.
Please see what I've done in the latest commit. I looked for something that does what the new method isSupported(PsiFile, Predicate<LSPClientFeatures>)
is doing but couldn't find anything quite like it. If something does exist, please let me know and I'll migrate to it; if not, perhaps that method should be moved somewhere more common for future needs? If so, where? LanguageServerAccessor
? LSP4IJUtils
? ???
} | ||
|
||
// textDocument/selectionRanges has been collected correctly, create list of IJ SelectionDescriptor from LSP SelectionRange list | ||
return selectionRangesFuture.getNow(null); |
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.
It seems method should never return null, replace with:
return selectionRangesFuture.getNow(Colletions.emptyList());
docs/LSPSupport.md
Outdated
### Selection range | ||
|
||
[textDocument/selectionRange](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_selectionRange) is implemented with | ||
the `extendWordSelectionHandler` extension point and used via the IDE's **Extend Selection** and **Shrink Selection** actions. |
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.
Please add shortcut sample in () to execute those actions.
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.
Sorry, but what does "in ()" mean? Is there already a list of supported keyboard shortcuts for LSP4IJ-integrated actions?
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 wanted to say add (Ctrl+W) / (Ctrl+Shift+W)
…sting/better way to perform dry run enablement like I'm doing here. If so, I'll migrate to it; if not, perhaps isSupported() should be moved to a common location.
if (LSPRequestConstants.TEXT_DOCUMENT_CODE_ACTION.equals(method)) { | ||
// register 'textDocument/codeAction' capability | ||
return getCodeActionFeature().getCodeActionCapabilityRegistry(); | ||
if (method == null) { |
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 the result of changing this to use switch
which should use a jump table instead of having to evaluate each and every condition. Note that the project formatter is responsible for deciding which case
labels are single-line vs. multi-line here.
} | ||
|
||
// TODO: This seems so incredibly boiler-plate that it should already exist somewhere common | ||
private static boolean isSupported(@NotNull PsiFile file, |
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.
Is there not already something that does this in an encapsulated manner like this? If not, should this be moved into a common location?
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.
The short answer is https://github.com/redhat-developer/lsp4ij/pull/669/files#r1877498632
Here a detailled explanation: when you need to check that an IJ feature is enabled (ex : to enable/disable Implementations menu item, selectionrange like you need for your PR) it MUST be very fast otherwise IJ will freeze.
You must never wait for starting language servers which can takes some times (some language servers can take 15sec to start it), so IJ could freeze during 15 sec.
Using document matcher requires to open a read action. In Ij Quarkus we use that to associate our Quarkus Language server to Java files only when the project have some Java class in the classpath.
Using hasAny is very fast. It checks:
- if there is one or more language server which are associated to the file
- if there is one language server has thecapability but ONLY when language server is started.
It means that if you execute Ctrl+W and language servers is starting, the action will be disable but I think it is better to loose the Ctrl+W feature and avoid freezing IJ.
} | ||
|
||
// Only if textDocument/selectionRange is supported for the file | ||
return isSupported(file, LSPClientFeatures::getSelectionRangeFeature); |
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.
Remove your isSupported method with
Project project = file.getProject();
if (project.isDisposed()) {
return false;
}
// Only if textDocument/selectionRange is supported for the file
return LanguageServiceAccessor.getInstance(project)
.hasAny(file.getVirtualFile(), ls -> ls.getClientFeatures().getSelectionRangeFeature().isSelectionRangeSupported(file));
} | ||
|
||
// TODO: This seems so incredibly boiler-plate that it should already exist somewhere common | ||
private static boolean isSupported(@NotNull PsiFile file, |
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.
Please remove this method
/** | ||
* Selection range tests by emulating LSP 'textDocument/selectionRange' responses from the typescript-language-server. | ||
*/ | ||
public class TypeScriptSelectionRangeTest extends LSPSelectionRangeFixtureTestCase { |
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.
Thanks so much to have written tests, that's great!
New PR for this work opened as #678. |
This PR integrates the LSP
textDocument/selectionRange
feature into the IDE'sextendWordSelectionHandler
EP that provides the Extend/Shrink Selection actions (which are among my absolute favorites in the IDE). Note that it does not yet include unit tests, but I do plan to add them once I know that there's interest in moving forward with it.Here's an example of it working in TypeScript:
and here it is in CSS:
I'll add a few notes on things that I know will likely warrant further discussion.