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

feat: Open references if definition result has the same range than clicked offset #533

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/main/java/com/redhat/devtools/lsp4ij/LSPFileSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.redhat.devtools.lsp4ij.features.color.LSPColorSupport;
import com.redhat.devtools.lsp4ij.features.completion.LSPCompletionSupport;
import com.redhat.devtools.lsp4ij.features.declaration.LSPDeclarationSupport;
import com.redhat.devtools.lsp4ij.features.definition.LSPDefinitionSupport;
import com.redhat.devtools.lsp4ij.features.documentLink.LSPDocumentLinkSupport;
import com.redhat.devtools.lsp4ij.features.documentation.LSPHoverSupport;
import com.redhat.devtools.lsp4ij.features.foldingRange.LSPFoldingRangeSupport;
Expand All @@ -43,6 +44,7 @@
public class LSPFileSupport extends UserDataHolderBase implements Disposable {

private static final Key<LSPFileSupport> LSP_FILE_SUPPORT_KEY = Key.create("lsp.file.support");

private final PsiFile file;

private final LSPCodeLensSupport codeLensSupport;
Expand Down Expand Up @@ -75,6 +77,8 @@ public class LSPFileSupport extends UserDataHolderBase implements Disposable {

private final LSPReferenceSupport referenceSupport;

private final LSPDefinitionSupport definitionSupport;

private final LSPDeclarationSupport declarationSupport;

private final LSPTypeDefinitionSupport typeDefinitionSupport;
Expand All @@ -99,6 +103,7 @@ private LSPFileSupport(@NotNull PsiFile file) {
this.implementationSupport = new LSPImplementationSupport(file);
this.referenceSupport = new LSPReferenceSupport(file);
this.declarationSupport = new LSPDeclarationSupport(file);
this.definitionSupport = new LSPDefinitionSupport(file);
this.typeDefinitionSupport = new LSPTypeDefinitionSupport(file);
this.semanticTokensSupport = new LSPSemanticTokensSupport(file);
file.putUserData(LSP_FILE_SUPPORT_KEY, this);
Expand All @@ -123,6 +128,7 @@ public void dispose() {
getCompletionSupport().cancel();
getImplementationSupport().cancel();
getReferenceSupport().cancel();
getDefinitionSupport().cancel();
getDeclarationSupport().cancel();
getTypeDefinitionSupport().cancel();
getSemanticTokensSupport().cancel();
Expand Down Expand Up @@ -270,6 +276,15 @@ public LSPReferenceSupport getReferenceSupport() {
return referenceSupport;
}

/**
* Returns the LSP definition support.
*
* @return the LSP definition support.
*/
public LSPDefinitionSupport getDefinitionSupport() {
return definitionSupport;
}

/**
* Returns the LSP declaration support.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.redhat.devtools.lsp4ij.LSPIJUtils;
import com.redhat.devtools.lsp4ij.LSPRequestConstants;
import com.redhat.devtools.lsp4ij.LanguageServerItem;
import com.redhat.devtools.lsp4ij.LanguageServiceAccessor;
Expand Down Expand Up @@ -61,7 +60,6 @@ protected CompletableFuture<List<Location>> doLoad(LSPDeclarationParams params,
@NotNull Project project,
@NotNull LSPDeclarationParams params,
@NotNull CancellationSupport cancellationSupport) {
var textDocumentIdentifier = LSPIJUtils.toTextDocumentIdentifier(file);
return LanguageServiceAccessor.getInstance(project)
.getLanguageServers(file, LanguageServerItem::isDeclarationSupported)
.thenComposeAsync(languageServers -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*******************************************************************************
* Copyright (c) 2024 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution,
* and is available at https://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Red Hat, Inc. - initial API and definition
******************************************************************************/
package com.redhat.devtools.lsp4ij.features.definition;

import org.eclipse.lsp4j.DefinitionParams;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.TextDocumentIdentifier;

/**
* LSP definition parameters which hosts the offset where definition has been triggered.
*/
public class LSPDefinitionParams extends DefinitionParams {

// Use transient to avoid serializing the fields when GSON will be processed
private transient final int offset;

public LSPDefinitionParams(TextDocumentIdentifier textDocument, Position position, int offset) {
super.setTextDocument(textDocument);
super.setPosition(position);
this.offset = offset;
}

public int getOffset() {
return offset;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*******************************************************************************
* Copyright (c) 2024 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Red Hat, Inc. - initial API and definition
******************************************************************************/
package com.redhat.devtools.lsp4ij.features.definition;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.redhat.devtools.lsp4ij.LSPRequestConstants;
import com.redhat.devtools.lsp4ij.LanguageServerItem;
import com.redhat.devtools.lsp4ij.LanguageServiceAccessor;
import com.redhat.devtools.lsp4ij.features.AbstractLSPDocumentFeatureSupport;
import com.redhat.devtools.lsp4ij.internal.CancellationSupport;
import com.redhat.devtools.lsp4ij.internal.CompletableFutures;
import org.eclipse.lsp4j.Location;
import org.jetbrains.annotations.NotNull;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
* LSP definition support which collect:
*
* <ul>
* <li>textDocument/definition</li>
* </ul>
*/
public class LSPDefinitionSupport extends AbstractLSPDocumentFeatureSupport<LSPDefinitionParams, List<Location>> {

private Integer previousOffset;

public LSPDefinitionSupport(@NotNull PsiFile file) {
super(file);
}

public CompletableFuture<List<Location>> getDefinitions(LSPDefinitionParams params) {
int offset = params.getOffset();
if (previousOffset != null && !previousOffset.equals(offset)) {
super.cancel();
}
previousOffset = offset;
return super.getFeatureData(params);
}

@Override
protected CompletableFuture<List<Location>> doLoad(LSPDefinitionParams params, CancellationSupport cancellationSupport) {
PsiFile file = super.getFile();
return collectTypeDefinitions(file.getVirtualFile(), file.getProject(), params, cancellationSupport);
}

private static @NotNull CompletableFuture<List<Location>> collectTypeDefinitions(@NotNull VirtualFile file,
@NotNull Project project,
@NotNull LSPDefinitionParams params,
@NotNull CancellationSupport cancellationSupport) {
return LanguageServiceAccessor.getInstance(project)
.getLanguageServers(file, LanguageServerItem::isTypeDefinitionSupported)
.thenComposeAsync(languageServers -> {
// Here languageServers is the list of language servers which matches the given file
// and which have definition capability
if (languageServers.isEmpty()) {
return CompletableFuture.completedFuture(null);
}

// Collect list of textDocument/definition future for each language servers
List<CompletableFuture<List<Location>>> definitionsPerServerFutures = languageServers
.stream()
.map(languageServer -> getTypeDefinitionFor(params, languageServer, cancellationSupport))
.toList();

// Merge list of textDocument/definition future in one future which return the list of definition ranges
return CompletableFutures.mergeInOneFuture(definitionsPerServerFutures, cancellationSupport);
});
}

private static CompletableFuture<List<Location>> getTypeDefinitionFor(LSPDefinitionParams params,
LanguageServerItem languageServer,
CancellationSupport cancellationSupport) {
return cancellationSupport.execute(languageServer
.getTextDocumentService()
.definition(params), languageServer, LSPRequestConstants.TEXT_DOCUMENT_DEFINITION)
.thenApplyAsync(locations -> {
if (locations == null) {
// textDocument/definition may return null
return Collections.emptyList();
}
if (locations.isLeft()) {
return locations.getLeft()
.stream()
.map(l -> new Location(l.getUri(), l.getRange()))
.toList();

}
return locations.getRight()
.stream()
.map(l -> new Location(l.getTargetUri(), l.getTargetRange()))
.toList();
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.redhat.devtools.lsp4ij.LSPIJUtils;
import com.redhat.devtools.lsp4ij.LSPRequestConstants;
import com.redhat.devtools.lsp4ij.LanguageServerItem;
import com.redhat.devtools.lsp4ij.LanguageServiceAccessor;
Expand Down Expand Up @@ -61,7 +60,6 @@ protected CompletableFuture<List<Location>> doLoad(LSPImplementationParams param
@NotNull Project project,
@NotNull LSPImplementationParams params,
@NotNull CancellationSupport cancellationSupport) {
var textDocumentIdentifier = LSPIJUtils.toTextDocumentIdentifier(file);
return LanguageServiceAccessor.getInstance(project)
.getLanguageServers(file, LanguageServerItem::isImplementationSupported)
.thenComposeAsync(languageServers -> {
Expand Down
Loading
Loading