Skip to content

Commit

Permalink
[#36] Add new content provider using LSP
Browse files Browse the repository at this point in the history
Uses the LSP to fetch the children of a TU in the project explorer view.

fixes #36
  • Loading branch information
ghentschke committed May 10, 2023
1 parent 0f89dd0 commit 3473fc8
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
package org.eclipse.cdt.lsp.editor.ui.preference;

import java.net.URI;
import java.util.Optional;

import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.lsp.LspPlugin;
import org.eclipse.cdt.lsp.editor.ui.LspEditorUiPlugin;
import org.eclipse.core.expressions.PropertyTester;
Expand All @@ -26,6 +29,7 @@
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.core.runtime.preferences.PreferenceMetadata;
import org.eclipse.lsp4e.outline.SymbolsModel.DocumentSymbolWithFile;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IURIEditorInput;
Expand Down Expand Up @@ -58,6 +62,16 @@ public boolean test(Object receiver, String property, Object[] args, Object expe
}
// When resource == null it's an external file: Check if the file is already opened, if not check the active editor:
return isFileOpenedInLspEditor(editorInput);
} else if (receiver instanceof ITranslationUnit) {
// called to enable the LS based CSymbolsContentProvider:
return Optional.of((ITranslationUnit) receiver)
.map(ITranslationUnit::getCProject)
.map(ICProject::getProject)
.map(LspEditorPreferencesTester::preferLspEditor)
.orElse(Boolean.FALSE);
} else if (receiver instanceof DocumentSymbolWithFile) {
// called to enable the LS based CSymbolsContentProvider:
return true;
}
return false;
}
Expand Down
62 changes: 32 additions & 30 deletions bundles/org.eclipse.cdt.lsp/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,53 +126,55 @@
point="org.eclipse.ui.navigator.navigatorContent">
<navigatorContent
activeByDefault="true"
contentProvider="org.eclipse.cdt.internal.ui.navigator.CNavigatorContentProvider"
contentProvider="org.eclipse.cdt.lsp.ui.navigator.CSymbolsContentProvider"
icon="icons/c.png"
id="org.eclipse.cdt.lsp.navigator.content"
labelProvider="org.eclipse.cdt.internal.ui.navigator.CNavigatorLabelProvider"
name="C/C++ Elements"
priority="high">
labelProvider="org.eclipse.lsp4e.outline.SymbolsLabelProvider"
name="LS Symbols"
priority="normal">
<triggerPoints>
<or>
<instanceof value="org.eclipse.cdt.core.model.ICElement"/>
<instanceof value="org.eclipse.cdt.ui.CElementGrouping"/>
<and>
<instanceof value="org.eclipse.core.resources.IResource"/>
<test
forcePluginActivation="true"
property="org.eclipse.core.resources.projectNature"
value="org.eclipse.cdt.core.cnature"/>
</and>
<instanceof value="org.eclipse.core.resources.IWorkspaceRoot"/>
</or>
<and>
<or>
<instanceof
value="org.eclipse.cdt.core.model.ITranslationUnit">
</instanceof>
<instanceof
value="org.eclipse.lsp4e.outline.SymbolsModel$DocumentSymbolWithFile">
</instanceof></or>
<test
forcePluginActivation="true"
property="org.eclipse.cdt.lsp.server.enable.hasLanguageServer"
value="true">
</test>
</and>
</triggerPoints>
<possibleChildren>
<or>
<instanceof value="org.eclipse.core.resources.IResource"/>
<instanceof value="org.eclipse.cdt.core.model.ICElement"/>
<instanceof value="org.eclipse.cdt.ui.CElementGrouping"/>
<instanceof
value="org.eclipse.lsp4e.outline.SymbolsModel$DocumentSymbolWithFile">
</instanceof>
</or>
</possibleChildren>
<override
policy="InvokeAlwaysRegardlessOfSuppressedExt"
suppressedExtensionId="org.eclipse.ui.navigator.resourceContent"/>
suppressedExtensionId="org.eclipse.cdt.ui.navigator.content"/>
<actionProvider
class="org.eclipse.cdt.lsp.ui.navigator.LspCEditorOpenActionProvider"
class="org.eclipse.cdt.lsp.ui.navigator.CSymbolsOpenActionProvider"
id="org.eclipse.cdt.lsp.navigator.actions.open"
overrides="org.eclipse.ui.navigator.resources.OpenActions"
priority="highest">
priority="normal">
<enablement>
<or>
<instanceof value="org.eclipse.cdt.core.model.ICElement" />
<and>
<instanceof value="org.eclipse.core.resources.IProject"/>
<test
forcePluginActivation="true"
property="org.eclipse.core.resources.projectNature"
value="org.eclipse.cdt.core.cnature"/>
</and>
<instanceof
value="org.eclipse.lsp4e.outline.SymbolsModel$DocumentSymbolWithFile">
</instanceof>
</or>
</enablement>
</actionProvider>
<commonSorter
class="org.eclipse.lsp4e.outline.OutlineSorter"
id="org.eclipse.lsp4e.outline.OutlineSorter">
</commonSorter>
</navigatorContent>
</extension>
<extension
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*******************************************************************************
* Copyright (c) 2023 Bachmann electronic GmbH and others.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Gesa Hentschke (Bachmann electronic GmbH) - initial implementation
*******************************************************************************/

package org.eclipse.cdt.lsp.ui.navigator;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.internal.ui.navigator.CNavigatorContentProvider;
import org.eclipse.cdt.lsp.LspPlugin;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.text.IDocument;
import org.eclipse.lsp4e.LSPEclipseUtils;
import org.eclipse.lsp4e.LanguageServerWrapper;
import org.eclipse.lsp4e.LanguageServers;
import org.eclipse.lsp4e.outline.SymbolsModel;
import org.eclipse.lsp4e.outline.SymbolsModel.DocumentSymbolWithFile;
import org.eclipse.lsp4j.DocumentSymbol;
import org.eclipse.lsp4j.DocumentSymbolParams;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.jsonrpc.messages.Either;



public class CSymbolsContentProvider extends CNavigatorContentProvider {
protected final SymbolsModel symbolsModel = new SymbolsModel();
private volatile CompletableFuture<List<Either<SymbolInformation, DocumentSymbol>>> symbols;

@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public void getPipelinedChildren(Object parent, Set currentChildren) {
if (parent instanceof ITranslationUnit) {
//remove children from other provider first:
currentChildren.clear();
for (Object child : getChildren(parent)) {
if (child != null) {
currentChildren.add(child);
}
}
}
}

@Override
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof DocumentSymbolWithFile) {
return symbolsModel.getChildren(parentElement);
} else if (parentElement instanceof ITranslationUnit) {
try {
return getTranslationUnitChildren((ITranslationUnit) parentElement);
} catch (CModelException e) {
}
}
return NO_CHILDREN;
}

protected Object[] getTranslationUnitChildren(ITranslationUnit unit) throws CModelException {
if (unit.getResource() instanceof IFile) {
refreshTreeContentFromLS((IFile) unit.getResource());
return symbolsModel.getElements();
}
return NO_CHILDREN;
}

protected void refreshTreeContentFromLS(IFile file) {
if (symbols != null) {
symbols.cancel(true);
}

final var params = new DocumentSymbolParams(LSPEclipseUtils.toTextDocumentIdentifier(file.getLocationURI()));

IDocument document = LSPEclipseUtils.getDocument(file);
if (document != null) {
CompletableFuture<Optional<LanguageServerWrapper>> languageServer = LanguageServers.forDocument(document)
.withFilter(capabilities -> LSPEclipseUtils.hasCapability(capabilities.getDocumentSymbolProvider())).computeFirst((w,ls) -> CompletableFuture.completedFuture(w));
try {
symbols = languageServer.get(500, TimeUnit.MILLISECONDS).filter(Objects::nonNull)
.filter(LanguageServerWrapper::isActive)
.map(s -> s.execute(ls -> ls.getTextDocumentService().documentSymbol(params)))
.orElse(CompletableFuture.completedFuture(null));
} catch (TimeoutException | ExecutionException | InterruptedException e) {
LspPlugin.logError(e.getMessage(), e);
symbols = CompletableFuture.completedFuture(null);
if (e instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
}
symbols.thenAcceptAsync(response -> {
symbolsModel.setFile(file);
symbolsModel.update(response);
}).join();
} else {
symbolsModel.setFile(file);
symbolsModel.update(null);
}

}

}
Loading

0 comments on commit 3473fc8

Please sign in to comment.