/*
* Copyright 2011-present Greg Shrago
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.intellij.jflex.editor;
import com.intellij.ide.structureView.*;
import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
import com.intellij.ide.util.treeView.smartTree.SortableTreeElement;
import com.intellij.lang.PsiStructureViewFactory;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.SyntaxTraverser;
import com.intellij.util.Function;
import com.intellij.util.containers.JBIterable;
import org.intellij.jflex.psi.*;
import org.intellij.jflex.psi.impl.JFlexFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Collection;
import java.util.Collections;
import static com.intellij.openapi.util.Conditions.instanceOf;
import static com.intellij.openapi.util.text.StringUtil.*;
/**
* @author gregsh
*/
public class JFlexStructureViewFactory implements PsiStructureViewFactory {
public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) {
return new TreeBasedStructureViewBuilder() {
@NotNull
public StructureViewModel createStructureViewModel(@Nullable Editor editor) {
return new MyModel(psiFile);
}
@Override
public boolean isRootNodeShown() {
return false;
}
};
}
static class MyModel extends StructureViewModelBase implements StructureViewModel.ElementInfoProvider {
static final Class[] CLASSES = {JFlexOption.class, JFlexMacroDefinition.class, JFlexRule.class};
protected MyModel(@NotNull PsiFile psiFile) {
super(psiFile, new MyElement(psiFile));
withSuitableClasses(CLASSES);
}
@Override
public boolean isAlwaysShowsPlus(StructureViewTreeElement element) {
return false;
}
@Override
public boolean isAlwaysLeaf(StructureViewTreeElement element) {
Object o = element.getValue();
return o instanceof JFlexOption || o instanceof JFlexMacroDefinition;
}
@Override
public boolean shouldEnterElement(Object element) {
return false;
}
}
static final Function<PsiElement, StructureViewTreeElement> WRAPPER = element -> new MyElement(element);
static final Function<PsiElement, String> TO_TEXT = element -> element.getText();
static class MyElement extends PsiTreeElementBase<PsiElement> implements SortableTreeElement {
MyElement(PsiElement element) {
super(element);
}
@NotNull
@Override
public String getAlphaSortKey() {
return notNullize(getPresentableText());
}
@NotNull
@Override
public Collection<StructureViewTreeElement> getChildrenBase() {
PsiElement o = getElement();
if (o == null) return Collections.emptyList();
if (o instanceof JFlexFile) {
return SyntaxTraverser.psiTraverser(o)
.expand(instanceOf(JFlexFile.class, JFlexFileSection.class))
.traverse()
.filter(instanceOf(MyModel.CLASSES))
.transform(WRAPPER)
.toList();
}
else if (o instanceof JFlexRule) {
return SyntaxTraverser.psiApi().children(o)
.filter(instanceOf(MyModel.CLASSES))
.transform(WRAPPER)
.toList();
}
return Collections.emptyList();
}
@Override
public String getPresentableText() {
PsiElement o = getElement();
if (o == null) return null;
if (o instanceof JFlexFile) {
return ((JFlexFile)o).getName();
}
else if (o instanceof JFlexOption) {
return trimEnd(o.getFirstChild().getText(), "{");
}
else if (o instanceof JFlexMacroDefinition) {
return ((JFlexMacroDefinition)o).getName();
}
else if (o instanceof JFlexRule) {
JFlexStateList states = ((JFlexRule)o).getStateList();
JFlexExpression expr = ((JFlexRule)o).getExpression();
StringBuilder sb = new StringBuilder();
if (states != null) {
sb.append("<");
sb.append(join(JBIterable.from(states.getStateReferenceList()).transform(TO_TEXT), ", "));
sb.append(">");
}
if (expr != null) {
if (states != null) sb.append(" ");
sb.append(firstLast(expr.getText(), 40));
}
return sb.toString();
}
return o.getClass().getSimpleName();
}
@Override
public Icon getIcon(boolean open) {
PsiElement o = getElement();
if (o == null) return null;
return o.getIcon(0);
}
}
}