Skip to content

Commit

Permalink
Add content filtering to outline view based on SymbolKind (fix issue #…
Browse files Browse the repository at this point in the history
  • Loading branch information
travkin79 authored Aug 13, 2024
1 parent 9d6b137 commit a240416
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 10 deletions.
21 changes: 21 additions & 0 deletions org.eclipse.lsp4e/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,27 @@
</visibleWhen>
</command>
</menuContribution>
<menuContribution
allPopups="false"
locationURI="menu:org.eclipse.ui.views.ContentOutline">
<menu
id="org.eclipse.lsp4e.outline.hideMenu"
label="Hide...">
<visibleWhen>
<reference
definitionId="org.eclipse.lsp4e.activePartHasCNFOutlinePage">
</reference>
</visibleWhen>
</menu>
</menuContribution>
<menuContribution
allPopups="false"
locationURI="menu:org.eclipse.lsp4e.outline.hideMenu">
<dynamic
class="org.eclipse.lsp4e.outline.OutlineViewHideSymbolKindMenuContributor"
id="org.eclipse.lsp4e.filters.dynamic">
</dynamic>
</menuContribution>
<menuContribution
allPopups="true"
locationURI="popup:org.eclipse.ui.genericeditor.source.menu?after=additions">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public class CNFOutlinePage implements IContentOutlinePage, ILabelProviderListen
public static final String LINK_WITH_EDITOR_PREFERENCE = ID + ".linkWithEditor"; //$NON-NLS-1$
public static final String SHOW_KIND_PREFERENCE = ID + ".showKind"; //$NON-NLS-1$
public static final String SORT_OUTLINE_PREFERENCE = ID + ".sortOutline"; //$NON-NLS-1$
public static final String HIDE_DOCUMENT_SYMBOL_KIND_PREFERENCE_PREFIX = ID + ".hide"; //$NON-NLS-1$

private CommonViewer outlineViewer = lateNonNull();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Mickael Istria (Red Hat Inc.) - initial implementation
* Lucas Bullen (Red Hat Inc.) - Bug 508472 - Outline to provide "Link with Editor"
* - Bug 517428 - Requests sent before initialization
* Mickael Istria (Red Hat Inc.) - initial implementation
* Lucas Bullen (Red Hat Inc.) - Bug 508472 - Outline to provide "Link with Editor"
* - Bug 517428 - Requests sent before initialization
* Dietrich Travkin (Solunar GmbH) - Issue 254 - Add outline view contents filtering
*******************************************************************************/
package org.eclipse.lsp4e.outline;

Expand All @@ -31,6 +32,9 @@
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand All @@ -53,10 +57,12 @@
import org.eclipse.lsp4e.LanguageServerPlugin;
import org.eclipse.lsp4e.LanguageServerWrapper;
import org.eclipse.lsp4e.internal.CancellationUtil;
import org.eclipse.lsp4e.outline.SymbolsModel.DocumentSymbolWithURI;
import org.eclipse.lsp4e.ui.UI;
import org.eclipse.lsp4j.DocumentSymbol;
import org.eclipse.lsp4j.DocumentSymbolParams;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.SymbolKind;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.eclipse.ui.IMemento;
Expand Down Expand Up @@ -139,6 +145,34 @@ public void documentAboutToBeChanged(DocumentEvent event) {
public void documentChanged(DocumentEvent event) {
refreshTreeContentFromLS();
}

}

private final class PreferencesChangedOutlineUpdater implements IPreferenceChangeListener, IOutlineUpdater {

@Override
public void install() {
IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(LanguageServerPlugin.PLUGIN_ID);
preferences.addPreferenceChangeListener(this);
}

@Override
public void uninstall() {
IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(LanguageServerPlugin.PLUGIN_ID);
preferences.removePreferenceChangeListener(this);
}

@Override
public void preferenceChange(PreferenceChangeEvent event) {
if (viewer != null
&& event.getKey().startsWith(CNFOutlinePage.HIDE_DOCUMENT_SYMBOL_KIND_PREFERENCE_PREFIX)) {
viewer.getControl().getDisplay().asyncExec(() -> {
if(!viewer.getTree().isDisposed()) {
viewer.refresh();
}
});
}
}
}

private final class ReconcilerOutlineUpdater extends AbstractReconciler implements IOutlineUpdater {
Expand Down Expand Up @@ -225,17 +259,20 @@ public void resourceChanged(IResourceChangeEvent event) {
private final boolean refreshOnResourceChanged;
private boolean isQuickOutline;
private @Nullable IOutlineUpdater outlineUpdater;
private IOutlineUpdater preferencesDependantOutlineUpdater;

public LSSymbolsContentProvider() {
this(false);
}

public LSSymbolsContentProvider(boolean refreshOnResourceChanged) {
this.refreshOnResourceChanged = refreshOnResourceChanged;
preferencesDependantOutlineUpdater = new PreferencesChangedOutlineUpdater();
}

@Override
public void init(@NonNullByDefault({}) ICommonContentExtensionSite aConfig) {
preferencesDependantOutlineUpdater.install();
}

@Override
Expand Down Expand Up @@ -281,18 +318,39 @@ private IOutlineUpdater createOutlineUpdater() {

@Override
public Object[] getElements(@Nullable Object inputElement) {
if (this.symbols != null && !this.symbols.isDone()) {
if (symbols != null && !symbols.isDone()) {
return new Object[] { new PendingUpdateAdapter() };
}
if (this.lastError != null && symbolsModel.getElements().length == 0) {
if (lastError != null && symbolsModel.getElements().length == 0) {
return new Object[] { "An error occured, see log for details" }; //$NON-NLS-1$
}
return symbolsModel.getElements();
return Arrays.stream(symbolsModel.getElements())
.filter(element -> !hideElement(element))
.toArray(Object[]::new);
}

@Override
public Object[] getChildren(Object parentElement) {
return symbolsModel.getChildren(parentElement);
return Arrays.stream(symbolsModel.getChildren(parentElement))
.filter(element -> !hideElement(element))
.toArray(Object[]::new);
}

private boolean hideElement(Object element) {
SymbolKind kind = null;

if (element instanceof DocumentSymbol documentSymbol) {
kind = documentSymbol.getKind();
} else if (element instanceof DocumentSymbolWithURI documentSymbolWithURI) {
kind = documentSymbolWithURI.symbol.getKind();
} else if (element instanceof SymbolInformation symbolInformation) {
kind = symbolInformation.getKind();
}

if (kind != null) {
return OutlineViewHideSymbolKindMenuContributor.isHideSymbolKind(kind);
}
return false;
}

@Override
Expand Down Expand Up @@ -342,10 +400,12 @@ protected void refreshTreeContentFromLS() {
TreePath[] initialSelection = ((ITreeSelection) viewer.getSelection()).getPaths();
viewer.refresh();
if (expandedElements.length > 0) {
viewer.setExpandedTreePaths(Arrays.stream(expandedElements).map(symbolsModel::toUpdatedSymbol)
.filter(Objects::nonNull).toArray(TreePath[]::new));
viewer.setExpandedTreePaths(Arrays.stream(expandedElements)
.map(symbolsModel::toUpdatedSymbol)
.filter(Objects::nonNull).toArray(TreePath[]::new));
viewer.setSelection(new TreeSelection(Arrays.stream(initialSelection)
.map(symbolsModel::toUpdatedSymbol).filter(Objects::nonNull).toArray(TreePath[]::new)));
.map(symbolsModel::toUpdatedSymbol)
.filter(Objects::nonNull).toArray(TreePath[]::new)));
} else {
viewer.expandToLevel(EXPAND_ROOT_LEVEL);
}
Expand Down Expand Up @@ -376,6 +436,7 @@ public void dispose() {
if (outlineUpdater != null) {
outlineUpdater.uninstall();
}
preferencesDependantOutlineUpdater.uninstall();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*******************************************************************************
* Copyright (c) 2024 Advantest Europe GmbH. All rights reserved.
* 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:
* Dietrich Travkin (Solunar GmbH) - initial implementation of outline contents filtering (issue #254)
*******************************************************************************/
package org.eclipse.lsp4e.outline;

import java.util.Arrays;
import java.util.Comparator;

import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.lsp4e.LanguageServerPlugin;
import org.eclipse.lsp4e.ui.LSPImages;
import org.eclipse.lsp4j.SymbolKind;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.actions.CompoundContributionItem;

public class OutlineViewHideSymbolKindMenuContributor extends CompoundContributionItem {

@Override
protected IContributionItem[] getContributionItems() {
return Arrays.stream(SymbolKind.values())
.sorted(new Comparator<SymbolKind>() {

@Override
public int compare(SymbolKind sk1, SymbolKind sk2) {
return sk1.name().compareTo(sk2.name());
}

})
.map(kind -> createHideSymbolKindContributionItem(kind))
.toArray(IContributionItem[]::new);
}

private IContributionItem createHideSymbolKindContributionItem(SymbolKind kind) {
return new ActionContributionItem(new HideSymbolKindAction(kind));
}

static boolean isHideSymbolKind(SymbolKind kind) {
IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(LanguageServerPlugin.PLUGIN_ID);
return preferences.getBoolean(CNFOutlinePage.HIDE_DOCUMENT_SYMBOL_KIND_PREFERENCE_PREFIX + kind.name(), false);
}

static boolean toggleHideSymbolKind(SymbolKind kind) {
IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(LanguageServerPlugin.PLUGIN_ID);
boolean oldValue = isHideSymbolKind(kind);

preferences.putBoolean(CNFOutlinePage.HIDE_DOCUMENT_SYMBOL_KIND_PREFERENCE_PREFIX + kind.name(), !oldValue);

return !oldValue;
}

private static class HideSymbolKindAction extends Action {
private final SymbolKind kind;

HideSymbolKindAction(SymbolKind kind) {
super(kind.name(), IAction.AS_CHECK_BOX);
this.kind = kind;
setChecked(isHideSymbolKind(kind));

Image img = LSPImages.imageFromSymbolKind(kind);
if (img != null) {
setImageDescriptor(ImageDescriptor.createFromImage(img));
}
}

@Override
public void run() {
boolean checkedState = toggleHideSymbolKind(kind);
setChecked(checkedState);
}

}

}

0 comments on commit a240416

Please sign in to comment.