mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
RUBY-12492 Supported aliases in file structure
Also org.jetbrains.yaml.structureView package was refactored
This commit is contained in:
@@ -40,6 +40,9 @@ YamlScalarType.error.scalar.value=Scalar value expected
|
||||
YamlIntegerType.error.integer.value=Integer value expected
|
||||
YamlNumberType.error.numeric.value=Numeric value expected
|
||||
|
||||
YAMLStructureViewDocument.element.name=YAML document
|
||||
YAMLStructureViewSequenceItem.element.name=Sequence Item
|
||||
|
||||
YAMLParser.invalid.header.symbols=Invalid block scalar header
|
||||
YAMLParser.multiple.anchors=Multiple anchors are not permitted
|
||||
YAMLParser.multiple.tags=Multiple tags are not permitted
|
||||
@@ -47,6 +50,9 @@ YAMLParser.multiple.tags=Multiple tags are not permitted
|
||||
YAMLAnchorRenameProcessor.lost.alias=Alias will refer to another anchor
|
||||
YAMLAnchorRenameProcessor.reuse=Anchor already has the same name
|
||||
|
||||
YAMLAliasResolveNodeProvider.action.name=Show aliased sub-trees
|
||||
YAMLAliasResolveNodeProvider.action.description=Resolve aliases and show referenced values in the structure
|
||||
|
||||
inspections.group.name=YAML
|
||||
inspections.unresolved.alias.name=Unresolved alias
|
||||
inspections.unresolved.alias.message=Can''t resolve alias {0}
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.structureView;
|
||||
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeUi;
|
||||
import com.intellij.ide.util.treeView.NodeDescriptorProvidingKey;
|
||||
import com.intellij.ide.util.treeView.TreeAnchorizer;
|
||||
import com.intellij.navigation.ItemPresentation;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* File structure popup work with unique values (see {@link StructureViewTreeElement#getValue()}).
|
||||
* If it is needed to show the same PSI element several times then each occurrence of such psi should be wrapped to some unique object.
|
||||
* This class perform this task.
|
||||
* <p/>
|
||||
* This class could be moved to some common platform package if it will be needed for somebody else.
|
||||
* The implementation of this class is based on {@link PsiTreeElementBase} implementation (copy-pasted and modified).
|
||||
*/
|
||||
abstract class DuplicatedPsiTreeElementBase<T extends PsiElement & Navigatable> implements StructureViewTreeElement,
|
||||
ItemPresentation,
|
||||
NodeDescriptorProvidingKey {
|
||||
@NotNull
|
||||
private final StoredData<T> myValue;
|
||||
|
||||
/** @param details is used to distinguish different occurrences of the same PSI element */
|
||||
protected DuplicatedPsiTreeElementBase(@NotNull T psiElement, @NotNull String details) {
|
||||
myValue = new StoredData<>(psiElement, details);
|
||||
}
|
||||
|
||||
/** @return stored psi element */
|
||||
@NotNull
|
||||
public final T getElement() {
|
||||
return getValue().getElement();
|
||||
}
|
||||
|
||||
/** @return additional information which is used to distinguish different occurrences of the same PSI element */
|
||||
@NotNull
|
||||
public final String getDetails() {
|
||||
return getValue().getDetails();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract Collection<StructureViewTreeElement> getChildrenBase();
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ItemPresentation getPresentation() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object getKey() {
|
||||
return String.valueOf(getElement());
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
@NotNull
|
||||
@Override
|
||||
public final StoredData<T> getValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getElement().toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public final StructureViewTreeElement[] getChildren() {
|
||||
return AbstractTreeUi.calculateYieldingToWriteAction(this::doGetChildren);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StructureViewTreeElement[] doGetChildren() {
|
||||
return PsiTreeElementBase.mergeWithExtensions(getElement(), getChildrenBase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void navigate(boolean requestFocus) {
|
||||
getElement().navigate(requestFocus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNavigate() {
|
||||
return getElement().canNavigate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNavigateToSource() {
|
||||
return canNavigate();
|
||||
}
|
||||
|
||||
@Contract(value = "null -> false", pure = true)
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final DuplicatedPsiTreeElementBase that = (DuplicatedPsiTreeElementBase)o;
|
||||
|
||||
return getValue().equals(that.getValue());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return getValue().hashCode();
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** This class is a wrapper over PSI element with additional information */
|
||||
private static class StoredData<T extends Navigatable> implements Navigatable {
|
||||
@NotNull
|
||||
private final Object myAnchor;
|
||||
@NotNull
|
||||
private final String myDetails;
|
||||
|
||||
public StoredData(@NotNull T element, @NotNull String details) {
|
||||
myAnchor = TreeAnchorizer.getService().createAnchor(element);
|
||||
myDetails = details;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public T getElement() {
|
||||
@SuppressWarnings("unchecked")
|
||||
T element = (T)TreeAnchorizer.getService().retrieveElement(myAnchor);
|
||||
assert element != null;
|
||||
return element;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getDetails() {
|
||||
return myDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void navigate(boolean requestFocus) {
|
||||
getElement().navigate(requestFocus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNavigate() {
|
||||
return getElement().canNavigate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNavigateToSource() {
|
||||
return getElement().canNavigateToSource();
|
||||
}
|
||||
|
||||
@Contract(value = "null -> false", pure = true)
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
StoredData<?> data = (StoredData<?>)o;
|
||||
return Objects.equals(getElement(), data.getElement()) &&
|
||||
Objects.equals(getDetails(), data.getDetails());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getElement(), getDetails());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.structureView;
|
||||
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
import com.intellij.ide.util.ActionShortcutProvider;
|
||||
import com.intellij.ide.util.FileStructureNodeProvider;
|
||||
import com.intellij.ide.util.treeView.smartTree.ActionPresentation;
|
||||
import com.intellij.ide.util.treeView.smartTree.ActionPresentationData;
|
||||
import com.intellij.ide.util.treeView.smartTree.TreeElement;
|
||||
import com.intellij.openapi.actionSystem.Shortcut;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.yaml.YAMLBundle;
|
||||
import org.jetbrains.yaml.psi.*;
|
||||
import org.jetbrains.yaml.resolve.YAMLAliasReference;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public class YAMLAliasResolveNodeProvider implements FileStructureNodeProvider<StructureViewTreeElement>, ActionShortcutProvider {
|
||||
@NonNls public static final String ID = "YAML_SHOW_RESOLVED_ALIAS_VALUES";
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getCheckBoxText() {
|
||||
return YAMLBundle.message("YAMLAliasResolveNodeProvider.action.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Shortcut[] getShortcut() {
|
||||
throw new IncorrectOperationException("see getActionIdForShortcut()");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getActionIdForShortcut() {
|
||||
return "FileStructurePopup";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<StructureViewTreeElement> provideNodes(@NotNull TreeElement node) {
|
||||
if (!(node instanceof DuplicatedPsiTreeElementBase)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
DuplicatedPsiTreeElementBase yamlNode = (DuplicatedPsiTreeElementBase)node;
|
||||
PsiElement psiElem = yamlNode.getElement();
|
||||
YAMLPsiElement yamlElem = psiElem instanceof YAMLPsiElement ? (YAMLPsiElement)psiElem : null;
|
||||
YAMLValue value = getContainedValue(yamlElem);
|
||||
if (!(value instanceof YAMLAlias)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return YAMLStructureViewFactory.createChildrenViewTreeElements(resolveAlias((YAMLAlias)value), yamlNode.getDetails());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ActionPresentation getPresentation() {
|
||||
return new ActionPresentationData(YAMLBundle.message("YAMLAliasResolveNodeProvider.action.name"),
|
||||
YAMLBundle.message("YAMLAliasResolveNodeProvider.action.description"),
|
||||
YAMLStructureViewFactory.ALIAS_ICON);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static YAMLValue resolveAlias(@NotNull YAMLAlias alias) {
|
||||
YAMLAliasReference ref = alias.getReference();
|
||||
YAMLAnchor anchor = ref == null ? null : ref.resolve();
|
||||
return anchor != null ? anchor.getMarkedValue() : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Contract("null -> null")
|
||||
private static YAMLValue getContainedValue(@Nullable YAMLPsiElement element) {
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
Ref<YAMLValue> result = Ref.create();
|
||||
element.accept(new YamlPsiElementVisitor() {
|
||||
@Override
|
||||
public void visitKeyValue(@NotNull YAMLKeyValue keyValue) {
|
||||
result.set(keyValue.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSequenceItem(@NotNull YAMLSequenceItem sequenceItem) {
|
||||
result.set(sequenceItem.getValue());
|
||||
}
|
||||
});
|
||||
return result.get();
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package org.jetbrains.yaml.structureView;
|
||||
|
||||
import com.intellij.ide.structureView.StructureViewModel;
|
||||
import com.intellij.ide.structureView.StructureViewModelBase;
|
||||
import com.intellij.ide.structureView.TreeBasedStructureViewBuilder;
|
||||
import com.intellij.ide.util.treeView.smartTree.Sorter;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.yaml.psi.YAMLDocument;
|
||||
import org.jetbrains.yaml.psi.YAMLFile;
|
||||
import org.jetbrains.yaml.psi.YAMLKeyValue;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
*/
|
||||
public class YAMLStructureViewBuilder extends TreeBasedStructureViewBuilder {
|
||||
private final YAMLFile myPsiFile;
|
||||
|
||||
public YAMLStructureViewBuilder(@NotNull final YAMLFile psiFile) {
|
||||
myPsiFile = psiFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public StructureViewModel createStructureViewModel(@Nullable Editor editor) {
|
||||
return new StructureViewModelBase(myPsiFile, editor, new YAMLStructureViewElement(myPsiFile))
|
||||
.withSorters(Sorter.ALPHA_SORTER)
|
||||
.withSuitableClasses(YAMLFile.class, YAMLDocument.class, YAMLKeyValue.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.structureView;
|
||||
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.yaml.YAMLBundle;
|
||||
import org.jetbrains.yaml.psi.YAMLDocument;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
class YAMLStructureViewDocument extends PsiTreeElementBase<YAMLDocument> {
|
||||
YAMLStructureViewDocument(@NotNull YAMLDocument psiElement) {
|
||||
super(psiElement);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<StructureViewTreeElement> getChildrenBase() {
|
||||
YAMLDocument document = Objects.requireNonNull(getElement());
|
||||
return YAMLStructureViewFactory.createChildrenViewTreeElements(document.getTopLevelValue(), "<doc>");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getPresentableText() {
|
||||
return YAMLBundle.message("YAMLStructureViewDocument.element.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Icon getIcon(boolean open) {
|
||||
return PlatformIcons.XML_TAG_ICON;
|
||||
}
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
package org.jetbrains.yaml.structureView;
|
||||
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
import com.intellij.navigation.ItemPresentation;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.yaml.psi.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
*/
|
||||
public class YAMLStructureViewElement implements StructureViewTreeElement {
|
||||
private final YAMLPsiElement myElement;
|
||||
|
||||
public YAMLStructureViewElement(final YAMLPsiElement element) {
|
||||
myElement = element;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StructureViewTreeElement[] getChildren() {
|
||||
final Collection<? extends YAMLPsiElement> children;
|
||||
if (myElement instanceof YAMLFile) {
|
||||
children = ((YAMLFile)myElement).getDocuments();
|
||||
}
|
||||
else if (myElement instanceof YAMLDocument) {
|
||||
children = getChildrenForValue(((YAMLDocument)myElement).getTopLevelValue());
|
||||
}
|
||||
else if (myElement instanceof YAMLSequenceItem) {
|
||||
children = getChildrenForValue(((YAMLSequenceItem)myElement).getValue());
|
||||
}
|
||||
else if (myElement instanceof YAMLKeyValue) {
|
||||
children = getChildrenForValue(((YAMLKeyValue)myElement).getValue());
|
||||
}
|
||||
else {
|
||||
children = Collections.emptyList();
|
||||
}
|
||||
|
||||
final List<StructureViewTreeElement> structureElements = new ArrayList<>();
|
||||
for (YAMLPsiElement child : children) {
|
||||
structureElements.add(new YAMLStructureViewElement(child));
|
||||
}
|
||||
return structureElements.toArray(StructureViewTreeElement.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Collection<? extends YAMLPsiElement> getChildrenForValue(@Nullable YAMLPsiElement element) {
|
||||
if (element instanceof YAMLMapping) {
|
||||
return ((YAMLMapping)element).getKeyValues();
|
||||
}
|
||||
if (element instanceof YAMLSequence) {
|
||||
return ((YAMLSequence)element).getItems();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@NotNull
|
||||
public ItemPresentation getPresentation() {
|
||||
if (myElement instanceof YAMLKeyValue){
|
||||
final YAMLKeyValue kv = (YAMLKeyValue)myElement;
|
||||
return new ItemPresentation() {
|
||||
public String getPresentableText() {
|
||||
return kv.getKeyText();
|
||||
}
|
||||
|
||||
public String getLocationString() {
|
||||
if (kv.getValue() instanceof YAMLScalar) {
|
||||
return kv.getValueText();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Icon getIcon(boolean open) {
|
||||
final YAMLValue value = kv.getValue();
|
||||
return value instanceof YAMLScalar ? kv.getIcon(0) : PlatformIcons.XML_TAG_ICON;
|
||||
}
|
||||
};
|
||||
}
|
||||
if (myElement instanceof YAMLDocument){
|
||||
return new ItemPresentation() {
|
||||
public String getPresentableText() {
|
||||
return "YAML document";
|
||||
}
|
||||
|
||||
public String getLocationString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Icon getIcon(boolean open) {
|
||||
return PlatformIcons.XML_TAG_ICON;
|
||||
}
|
||||
};
|
||||
}
|
||||
if (myElement instanceof YAMLSequenceItem) {
|
||||
final YAMLSequenceItem item = ((YAMLSequenceItem)myElement);
|
||||
return new ItemPresentation() {
|
||||
@Nullable
|
||||
@Override
|
||||
public String getPresentableText() {
|
||||
if (item.getValue() instanceof YAMLScalar) {
|
||||
return ((YAMLScalar)item.getValue()).getTextValue();
|
||||
}
|
||||
else {
|
||||
return "Sequence Item";
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getLocationString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Icon getIcon(boolean unused) {
|
||||
return item.getValue() instanceof YAMLScalar ? PlatformIcons.PROPERTY_ICON : PlatformIcons.XML_TAG_ICON;
|
||||
}
|
||||
};
|
||||
}
|
||||
return myElement.getPresentation();
|
||||
}
|
||||
|
||||
public YAMLPsiElement getValue() {
|
||||
return myElement;
|
||||
}
|
||||
|
||||
public void navigate(boolean requestFocus) {
|
||||
myElement.navigate(requestFocus);
|
||||
}
|
||||
|
||||
public boolean canNavigate() {
|
||||
return myElement.canNavigate();
|
||||
}
|
||||
|
||||
public boolean canNavigateToSource() {
|
||||
return myElement.canNavigateToSource();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,34 @@
|
||||
package org.jetbrains.yaml.structureView;
|
||||
|
||||
import com.intellij.ide.structureView.StructureViewBuilder;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.structureView.*;
|
||||
import com.intellij.ide.util.treeView.smartTree.NodeProvider;
|
||||
import com.intellij.ide.util.treeView.smartTree.Sorter;
|
||||
import com.intellij.lang.PsiStructureViewFactory;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.yaml.psi.YAMLFile;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.yaml.psi.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
*/
|
||||
public class YAMLStructureViewFactory implements PsiStructureViewFactory {
|
||||
static final Icon ALIAS_ICON = AllIcons.Nodes.ExpandNode;
|
||||
|
||||
@Nullable
|
||||
public StructureViewBuilder getStructureViewBuilder(@NotNull final PsiFile psiFile) {
|
||||
if (!(psiFile instanceof YAMLFile)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (YAMLCustomStructureViewFactory extension : YAMLCustomStructureViewFactory.EP_NAME.getExtensions()) {
|
||||
final StructureViewBuilder builder = extension.getStructureViewBuilder((YAMLFile)psiFile);
|
||||
if (builder != null) {
|
||||
@@ -18,6 +36,44 @@ public class YAMLStructureViewFactory implements PsiStructureViewFactory {
|
||||
}
|
||||
}
|
||||
|
||||
return new YAMLStructureViewBuilder((YAMLFile) psiFile);
|
||||
return new TreeBasedStructureViewBuilder() {
|
||||
@Override
|
||||
@NotNull
|
||||
public StructureViewModel createStructureViewModel(@Nullable Editor editor) {
|
||||
return new StructureViewModelBase(psiFile, editor, new YAMLStructureViewFile((YAMLFile)psiFile)){
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<NodeProvider> getNodeProviders() {
|
||||
return Collections.singleton(new YAMLAliasResolveNodeProvider());
|
||||
}
|
||||
}
|
||||
.withSorters(Sorter.ALPHA_SORTER)
|
||||
.withSuitableClasses(YAMLFile.class, YAMLDocument.class, YAMLKeyValue.class);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static String getAliasPresentableText(@NotNull YAMLAlias alias) {
|
||||
return "*" + alias.getAliasName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static Collection<StructureViewTreeElement> createChildrenViewTreeElements(@Nullable YAMLPsiElement element, String path) {
|
||||
if (element == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Ref<Collection<StructureViewTreeElement>> result = Ref.create(Collections.emptyList());
|
||||
element.accept(new YamlPsiElementVisitor() {
|
||||
@Override
|
||||
public void visitSequence(@NotNull YAMLSequence sequence) {
|
||||
result.set(ContainerUtil.map(sequence.getItems(), i -> new YAMLStructureViewSequenceItem(i, path)));
|
||||
}
|
||||
@Override
|
||||
public void visitMapping(@NotNull YAMLMapping mapping) {
|
||||
result.set(ContainerUtil.map(mapping.getKeyValues(), kv -> new YAMLStructureViewKeyValue(kv, path)));
|
||||
}
|
||||
});
|
||||
return result.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.structureView;
|
||||
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
|
||||
import com.intellij.navigation.ItemPresentation;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.yaml.psi.YAMLFile;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
class YAMLStructureViewFile extends PsiTreeElementBase<YAMLFile> {
|
||||
YAMLStructureViewFile(@NotNull YAMLFile psiElement) {
|
||||
super(psiElement);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<StructureViewTreeElement> getChildrenBase() {
|
||||
YAMLFile file = Objects.requireNonNull(getElement());
|
||||
return ContainerUtil.map(file.getDocuments(), YAMLStructureViewDocument::new);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getPresentableText() {
|
||||
return getFilePresentation().getPresentableText();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getLocationString() {
|
||||
return getFilePresentation().getLocationString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Icon getIcon(boolean unused) {
|
||||
return getFilePresentation().getIcon(unused);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ItemPresentation getFilePresentation() {
|
||||
YAMLFile file = Objects.requireNonNull(getElement());
|
||||
return Objects.requireNonNull(file.getPresentation());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.structureView;
|
||||
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.yaml.psi.YAMLAlias;
|
||||
import org.jetbrains.yaml.psi.YAMLKeyValue;
|
||||
import org.jetbrains.yaml.psi.YAMLScalar;
|
||||
import org.jetbrains.yaml.psi.YAMLValue;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.jetbrains.yaml.structureView.YAMLStructureViewFactory.ALIAS_ICON;
|
||||
|
||||
class YAMLStructureViewKeyValue extends DuplicatedPsiTreeElementBase<YAMLKeyValue> {
|
||||
YAMLStructureViewKeyValue(@NotNull YAMLKeyValue kv, String path) {
|
||||
super(kv, path + '.' + kv.getKeyText());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<StructureViewTreeElement> getChildrenBase() {
|
||||
return YAMLStructureViewFactory.createChildrenViewTreeElements(getVal(), getDetails());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getPresentableText() {
|
||||
return getKeyValue().getKeyText();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getLocationString() {
|
||||
if (getVal() instanceof YAMLScalar) {
|
||||
return getKeyValue().getValueText();
|
||||
}
|
||||
else if (getVal() instanceof YAMLAlias) {
|
||||
return YAMLStructureViewFactory.getAliasPresentableText((YAMLAlias)getVal());
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Icon getIcon(boolean open) {
|
||||
if (getVal() instanceof YAMLScalar) {
|
||||
return getKeyValue().getIcon(0);
|
||||
}
|
||||
else if (getVal() instanceof YAMLAlias) {
|
||||
return ALIAS_ICON;
|
||||
}
|
||||
else {
|
||||
return PlatformIcons.XML_TAG_ICON;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private YAMLKeyValue getKeyValue() {
|
||||
return Objects.requireNonNull(getElement());
|
||||
}
|
||||
|
||||
// Base class already has getValue() method with different semantic
|
||||
@Nullable
|
||||
private YAMLValue getVal() {
|
||||
return getKeyValue().getValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.structureView;
|
||||
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.yaml.YAMLBundle;
|
||||
import org.jetbrains.yaml.psi.YAMLAlias;
|
||||
import org.jetbrains.yaml.psi.YAMLScalar;
|
||||
import org.jetbrains.yaml.psi.YAMLSequenceItem;
|
||||
import org.jetbrains.yaml.psi.YAMLValue;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.jetbrains.yaml.structureView.YAMLStructureViewFactory.ALIAS_ICON;
|
||||
|
||||
class YAMLStructureViewSequenceItem extends DuplicatedPsiTreeElementBase<YAMLSequenceItem> {
|
||||
YAMLStructureViewSequenceItem(@NotNull YAMLSequenceItem item, String path) {
|
||||
super(item, path + '-' + getItemNumber(item));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<StructureViewTreeElement> getChildrenBase() {
|
||||
return YAMLStructureViewFactory.createChildrenViewTreeElements(getItemValue(), getDetails());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPresentableText() {
|
||||
if (getItemValue() instanceof YAMLScalar) {
|
||||
return ((YAMLScalar)getItemValue()).getTextValue();
|
||||
}
|
||||
else if (getItemValue() instanceof YAMLAlias) {
|
||||
return YAMLStructureViewFactory.getAliasPresentableText((YAMLAlias)getItemValue());
|
||||
}
|
||||
else {
|
||||
return YAMLBundle.message("YAMLStructureViewSequenceItem.element.name");
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getLocationString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Icon getIcon(boolean unused) {
|
||||
if (getItemValue() instanceof YAMLScalar) {
|
||||
return PlatformIcons.PROPERTY_ICON;
|
||||
}
|
||||
else if (getItemValue() instanceof YAMLAlias) {
|
||||
return ALIAS_ICON;
|
||||
}
|
||||
else {
|
||||
return PlatformIcons.XML_TAG_ICON;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private YAMLValue getItemValue() {
|
||||
return getElement().getValue();
|
||||
}
|
||||
|
||||
private static int getItemNumber(@NotNull YAMLSequenceItem item) {
|
||||
int num = 0;
|
||||
for (ASTNode node = item.getNode().getTreePrev(); node != null; node = node.getTreePrev()) {
|
||||
num++;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.structure;
|
||||
|
||||
import com.intellij.openapi.application.ex.PathManagerEx;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import org.jetbrains.yaml.structureView.YAMLAliasResolveNodeProvider;
|
||||
|
||||
public class YAMLStructureTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return PathManagerEx.getCommunityHomePath() + "/plugins/yaml/testSrc/org/jetbrains/yaml/structure/data/";
|
||||
}
|
||||
|
||||
|
||||
public void testAnchorsAndAliases() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
String testName = getTestName(true);
|
||||
myFixture.configureByFile(testName + ".yml");
|
||||
doStructureTest(testName, false);
|
||||
doStructureTest(testName, true);
|
||||
}
|
||||
|
||||
private void doStructureTest(String testName, boolean resolveAliases) {
|
||||
myFixture.testStructureView(svc -> {
|
||||
svc.setActionActive(YAMLAliasResolveNodeProvider.ID, resolveAliases);
|
||||
TreeUtil.expandAll(svc.getTree());
|
||||
PlatformTestUtil.waitForPromise(svc.select(svc.getTreeModel().getCurrentEditorElement(), false));
|
||||
String suffix = resolveAliases ? "resolved" : "unresolved";
|
||||
assertSameLinesWithFile(getTestDataPath() + testName + "." + suffix + ".txt",
|
||||
PlatformTestUtil.print(svc.getTree(), false));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
-anchorsAndAliases.yml
|
||||
-YAML document
|
||||
-First occurrence
|
||||
-list
|
||||
item1
|
||||
item2
|
||||
-Second occurrence
|
||||
-list
|
||||
item1
|
||||
item2
|
||||
-Override anchor
|
||||
key
|
||||
-Reuse anchor
|
||||
key
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
-anchorsAndAliases.yml
|
||||
-YAML document
|
||||
-First occurrence
|
||||
-list
|
||||
item1
|
||||
item2
|
||||
Second occurrence
|
||||
-Override anchor
|
||||
key
|
||||
Reuse anchor
|
||||
@@ -0,0 +1,8 @@
|
||||
First occurrence: &xxx
|
||||
list:
|
||||
- item1
|
||||
- item2
|
||||
Second occurrence: *xxx
|
||||
Override anchor: &xxx
|
||||
key: val
|
||||
Reuse anchor: *xxx
|
||||
Reference in New Issue
Block a user