diff --git a/src/main/java/com/redhat/devtools/lsp4ij/client/features/LSPDocumentSymbolFeature.java b/src/main/java/com/redhat/devtools/lsp4ij/client/features/LSPDocumentSymbolFeature.java
index cdd7fa6d2..27f8247b8 100644
--- a/src/main/java/com/redhat/devtools/lsp4ij/client/features/LSPDocumentSymbolFeature.java
+++ b/src/main/java/com/redhat/devtools/lsp4ij/client/features/LSPDocumentSymbolFeature.java
@@ -12,6 +12,8 @@
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.redhat.devtools.lsp4ij.LSPIJUtils;
import com.redhat.devtools.lsp4ij.features.documentSymbol.DocumentSymbolData;
@@ -127,4 +129,10 @@ public boolean canNavigate(@NotNull DocumentSymbol documentSymbol,
var selectionRange = documentSymbol.getSelectionRange();
return selectionRange != null && selectionRange.getStart() != null;
}
+
+ public boolean isSame(@NotNull DocumentSymbolData documentSymbolData,
+ @NotNull PsiElement psiElement) {
+ TextRange textRange = documentSymbolData.getSelectionTextRange() != null ? documentSymbolData.getSelectionTextRange() : documentSymbolData.getTextRange();
+ return textRange.equals(psiElement.getTextRange());
+ }
}
diff --git a/src/main/java/com/redhat/devtools/lsp4ij/features/documentSymbol/DocumentSymbolData.java b/src/main/java/com/redhat/devtools/lsp4ij/features/documentSymbol/DocumentSymbolData.java
index 002b19829..a6b50a648 100644
--- a/src/main/java/com/redhat/devtools/lsp4ij/features/documentSymbol/DocumentSymbolData.java
+++ b/src/main/java/com/redhat/devtools/lsp4ij/features/documentSymbol/DocumentSymbolData.java
@@ -25,6 +25,7 @@
import org.jetbrains.annotations.Nullable;
import javax.swing.Icon;
+import java.util.Objects;
/**
@@ -39,6 +40,7 @@ public class DocumentSymbolData extends FakePsiElement {
private final DocumentSymbolData parent;
private final @NotNull LanguageServerItem languageServer;
private volatile TextRange textRange = null;
+ private volatile TextRange selectionTextRange = null;
private DocumentSymbolData[] cachedChildren;
public DocumentSymbolData(@NotNull DocumentSymbol documentSymbol,
@@ -95,6 +97,21 @@ public TextRange getTextRange() {
return textRange;
}
+ public @Nullable TextRange getSelectionTextRange() {
+ if (documentSymbol.getSelectionRange() == null) {
+ return null;
+ }
+ if (selectionTextRange == null) {
+ synchronized (this) {
+ if (selectionTextRange == null) {
+ Range range = documentSymbol.getSelectionRange();
+ Document document = LSPIJUtils.getDocument(psiFile);
+ this.selectionTextRange = (document != null) ? LSPIJUtils.toTextRange(range, document) : null;
+ }
+ }
+ }
+ return selectionTextRange;
+ }
@Override
public void navigate(boolean requestFocus) {
getClientFeatures().getDocumentSymbolFeature().navigate(documentSymbol, psiFile, requestFocus);
@@ -124,6 +141,26 @@ public boolean canNavigate() {
return cachedChildren;
}
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) {
+ return false;
+ }
+ if (getClass() == o.getClass()) {
+ DocumentSymbolData that = (DocumentSymbolData) o;
+ return Objects.equals(documentSymbol, that.documentSymbol);
+ }
+ if (o instanceof PsiElement psiElement) {
+ return getClientFeatures().getDocumentSymbolFeature().isSame(this, psiElement);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(documentSymbol);
+ }
+
public @NotNull LSPClientFeatures getClientFeatures() {
return languageServer.getClientFeatures();
}
diff --git a/src/main/java/com/redhat/devtools/lsp4ij/features/documentSymbol/LSPDocumentSymbolStructureViewModel.java b/src/main/java/com/redhat/devtools/lsp4ij/features/documentSymbol/LSPDocumentSymbolStructureViewModel.java
index 86e20f01d..2b8ac973f 100644
--- a/src/main/java/com/redhat/devtools/lsp4ij/features/documentSymbol/LSPDocumentSymbolStructureViewModel.java
+++ b/src/main/java/com/redhat/devtools/lsp4ij/features/documentSymbol/LSPDocumentSymbolStructureViewModel.java
@@ -15,10 +15,12 @@
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
import com.intellij.openapi.editor.Editor;
+import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.ArrayUtil;
import com.redhat.devtools.lsp4ij.LSPFileSupport;
import com.redhat.devtools.lsp4ij.client.indexing.ProjectIndexingManager;
+import com.redhat.devtools.lsp4ij.features.semanticTokens.viewProvider.LSPSemanticTokenPsiElement;
import com.redhat.devtools.lsp4ij.internal.PsiFileChangedException;
import org.eclipse.lsp4j.DocumentSymbolParams;
import org.eclipse.lsp4j.TextDocumentIdentifier;
@@ -55,6 +57,12 @@ public boolean isAlwaysLeaf(StructureViewTreeElement element) {
return element.getChildren().length == 0;
}
+ @Override
+ protected Class @NotNull [] getSuitableClasses() {
+ // Any PSI element
+ return new Class[] {PsiElement.class};
+ }
+
@Override
public void dispose() {
super.dispose();
diff --git a/src/main/java/com/redhat/devtools/lsp4ij/features/documentSymbol/LSPStructureViewBuilderProvider.java b/src/main/java/com/redhat/devtools/lsp4ij/features/documentSymbol/LSPStructureViewBuilderProvider.java
new file mode 100644
index 000000000..1d13ad5dd
--- /dev/null
+++ b/src/main/java/com/redhat/devtools/lsp4ij/features/documentSymbol/LSPStructureViewBuilderProvider.java
@@ -0,0 +1,37 @@
+package com.redhat.devtools.lsp4ij.features.documentSymbol;
+
+import com.intellij.ide.structureView.StructureViewBuilder;
+import com.intellij.ide.structureView.StructureViewBuilderProvider;
+import com.intellij.ide.structureView.logical.PhysicalAndLogicalStructureViewBuilder;
+import com.intellij.lang.LanguageStructureViewBuilder;
+import com.intellij.lang.PsiStructureViewFactory;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.impl.AbstractFileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.redhat.devtools.lsp4ij.LanguageServersRegistry;
+import com.redhat.devtools.lsp4ij.client.ExecuteLSPFeatureStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class LSPStructureViewBuilderProvider implements StructureViewBuilderProvider {
+ @Override
+ public @Nullable StructureViewBuilder getStructureViewBuilder(@NotNull FileType fileType, @NotNull VirtualFile file, @NotNull Project project) {
+ if (!(fileType instanceof AbstractFileType)) {
+ return null;
+ }
+ if (!LanguageServersRegistry.getInstance().isFileSupported(file, project)) {
+ // The file is not associated to a language server, don't execute the LSP feature.
+ return null;
+ }
+ PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
+ if (psiFile == null) return null;
+
+ PsiStructureViewFactory factory = LanguageStructureViewBuilder.getInstance().forLanguage(psiFile.getLanguage());
+ if (factory == null) return null;
+ StructureViewBuilder physicalBuilder = factory.getStructureViewBuilder(psiFile);
+ return PhysicalAndLogicalStructureViewBuilder.Companion.wrapPhysicalBuilderIfPossible(physicalBuilder, psiFile);
+ }
+}
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index 0f00684f3..24c1c55c3 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -437,6 +437,10 @@
implementationClass="com.redhat.devtools.lsp4ij.features.documentLink.LSPDocumentLinkDocumentationProvider"/>
+