mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 13:31:28 +07:00
PY-7123 Structure for RST document incorrect
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* 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 com.jetbrains.rest;
|
||||
|
||||
import com.jetbrains.rest.fixtures.RestFixtureTestCase;
|
||||
|
||||
import static com.intellij.testFramework.PlatformTestUtil.assertTreeEqual;
|
||||
|
||||
public class RestStructureViewTest extends RestFixtureTestCase {
|
||||
|
||||
public void testPlain() {
|
||||
doTest("-plain.rst\n" +
|
||||
" Chapter 1 Title\n" +
|
||||
" Chapter 2 Title\n");
|
||||
}
|
||||
|
||||
|
||||
public void testFileBeginning() {
|
||||
doTest("-fileBeginning.rst\n" +
|
||||
" Chapter 1 Title\n" +
|
||||
" Chapter 2 Title\n");
|
||||
}
|
||||
|
||||
public void testOneInnerSection() {
|
||||
doTest("-oneInnerSection.rst\n" +
|
||||
" -Chapter 1 Title\n" +
|
||||
" -Section 1.1 Title\n" +
|
||||
" Subsection 1.1.1 Title\n" +
|
||||
" Section 1.2 Title\n" +
|
||||
" Chapter 2 Title\n");
|
||||
}
|
||||
|
||||
public void testTree() {
|
||||
doTest("-tree.rst\n" +
|
||||
" -Hello, world\n" +
|
||||
" -A section\n" +
|
||||
" -A subsection\n" +
|
||||
" A sub-subsection\n" +
|
||||
" An other one\n" +
|
||||
" -Back up\n" +
|
||||
" And down\n" +
|
||||
" -twice\n" +
|
||||
" with feelings\n");
|
||||
}
|
||||
|
||||
private void doTest(final String expected) {
|
||||
myFixture.configureByFile("/structureView/" + getTestName(true) + ".rst");
|
||||
myFixture.testStructureView(component -> assertTreeEqual(component.getTree(), expected));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
Chapter 1 Title
|
||||
===============
|
||||
|
||||
Chapter 2 Title
|
||||
===============
|
||||
@@ -0,0 +1,14 @@
|
||||
Chapter 1 Title
|
||||
===============
|
||||
|
||||
Section 1.1 Title
|
||||
-----------------
|
||||
|
||||
Subsection 1.1.1 Title
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Section 1.2 Title
|
||||
-----------------
|
||||
|
||||
Chapter 2 Title
|
||||
===============
|
||||
6
python/python-rest/testData/structureView/plain.rst
Normal file
6
python/python-rest/testData/structureView/plain.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
Chapter 1 Title
|
||||
===============
|
||||
|
||||
Chapter 2 Title
|
||||
===============
|
||||
30
python/python-rest/testData/structureView/tree.rst
Normal file
30
python/python-rest/testData/structureView/tree.rst
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
The following document:
|
||||
|
||||
============
|
||||
Hello, world
|
||||
============
|
||||
|
||||
A section
|
||||
=========
|
||||
|
||||
A subsection
|
||||
------------
|
||||
|
||||
A sub-subsection
|
||||
````````````````
|
||||
|
||||
An other one
|
||||
````````````
|
||||
|
||||
Back up
|
||||
=======
|
||||
|
||||
And down
|
||||
--------
|
||||
|
||||
twice
|
||||
-----
|
||||
|
||||
with feelings
|
||||
`````````````
|
||||
@@ -28,7 +28,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
*/
|
||||
public class RestParser implements PsiParser {
|
||||
@NotNull
|
||||
public ASTNode parse(IElementType root, PsiBuilder builder) {
|
||||
public ASTNode parse(@NotNull IElementType root, @NotNull PsiBuilder builder) {
|
||||
final PsiBuilder.Marker rootMarker = builder.mark();
|
||||
while (!builder.eof()) {
|
||||
IElementType type = builder.getTokenType();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.jetbrains.rest.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.jetbrains.rest.validation.RestElementVisitor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -27,6 +28,8 @@ import java.text.StringCharacterIterator;
|
||||
* User : catherine
|
||||
*/
|
||||
public class RestTitle extends RestElement {
|
||||
private static String ourAdornmentSymbols = "=-`:.'\\~^_*+#>";
|
||||
|
||||
public RestTitle(@NotNull final ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
@@ -79,6 +82,17 @@ public class RestTitle extends RestElement {
|
||||
return text.substring(start, text.length());
|
||||
}
|
||||
|
||||
public Pair<Character, Character> getAdornments() {
|
||||
final String text = getNode().getText().trim();
|
||||
if (text.length() < 2) return Pair.empty();
|
||||
Character overline = text.charAt(0);
|
||||
if (ourAdornmentSymbols.indexOf(overline) < 0) {
|
||||
overline = null;
|
||||
}
|
||||
final char underline = text.charAt(text.length()-2);
|
||||
return Pair.create(overline, underline);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void acceptRestVisitor(RestElementVisitor visitor) {
|
||||
visitor.visitTitle(this);
|
||||
|
||||
@@ -16,84 +16,85 @@
|
||||
package com.jetbrains.rest.structureView;
|
||||
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
import com.intellij.navigation.ItemPresentation;
|
||||
import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.NavigatablePsiElement;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.jetbrains.rest.psi.RestElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.rest.psi.RestTitle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* Handles nodes in ReST Structure View.
|
||||
* User : catherine
|
||||
*/
|
||||
public class RestStructureViewElement implements StructureViewTreeElement {
|
||||
|
||||
private NavigatablePsiElement myElement;
|
||||
public class RestStructureViewElement extends PsiTreeElementBase<NavigatablePsiElement> {
|
||||
|
||||
public RestStructureViewElement(NavigatablePsiElement element) {
|
||||
myElement = element;
|
||||
super(element);
|
||||
}
|
||||
|
||||
public NavigatablePsiElement getValue() {
|
||||
return myElement;
|
||||
}
|
||||
|
||||
public void navigate(boolean requestFocus) {
|
||||
myElement.navigate(requestFocus);
|
||||
}
|
||||
|
||||
public boolean canNavigate() {
|
||||
return myElement.canNavigate();
|
||||
}
|
||||
|
||||
public boolean canNavigateToSource() {
|
||||
return myElement.canNavigateToSource();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StructureViewTreeElement[] getChildren() {
|
||||
final Set<RestElement> childrenElements = new LinkedHashSet<>();
|
||||
myElement.acceptChildren(new PsiElementVisitor() {
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (element instanceof RestTitle && ((RestTitle)element).getName() != null)
|
||||
childrenElements.add((RestElement)element);
|
||||
else
|
||||
element.acceptChildren(this);
|
||||
}
|
||||
});
|
||||
StructureViewTreeElement[] children = new StructureViewTreeElement[childrenElements.size()];
|
||||
int i = 0;
|
||||
for (RestElement element : childrenElements) {
|
||||
children[i] = new RestStructureViewElement(element);
|
||||
i += 1;
|
||||
@Override
|
||||
public Collection<StructureViewTreeElement> getChildrenBase() {
|
||||
Collection<StructureViewTreeElement> result = new LinkedList<>();
|
||||
|
||||
final NavigatablePsiElement element = getElement();
|
||||
if (element == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return children;
|
||||
final PsiFile file = element.getContainingFile();
|
||||
final TextRange range = element.equals(file) ? TextRange.EMPTY_RANGE : element.getTextRange();
|
||||
Pair<Character, Character> elementAdornments = element instanceof RestTitle ? ((RestTitle)element).getAdornments() : Pair.empty();
|
||||
|
||||
Pair<Character, Character> adornmentsToUse = null;
|
||||
final Collection<RestTitle> titles = PsiTreeUtil.findChildrenOfType(file, RestTitle.class);
|
||||
final HashSet<Pair<Character, Character>> usedAdornments = new HashSet<>();
|
||||
boolean skipElements = false;
|
||||
|
||||
for (RestTitle child : titles) {
|
||||
final Pair<Character, Character> childAdornments = child.getAdornments();
|
||||
|
||||
if (child.getTextRange().getStartOffset() >= range.getEndOffset()) {
|
||||
final Character overline = childAdornments.getFirst();
|
||||
final Character underline = childAdornments.getSecond();
|
||||
if (adornmentsToUse == null) {
|
||||
adornmentsToUse = childAdornments;
|
||||
}
|
||||
if (usedAdornments.contains(childAdornments) || underline == null) {
|
||||
break;
|
||||
}
|
||||
if (underline.equals(adornmentsToUse.getSecond()) && ((adornmentsToUse.getFirst() == null && overline == null) ||
|
||||
adornmentsToUse.getFirst().equals(overline))) {
|
||||
result.add(new RestStructureViewElement(child));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (element.equals(child)) {
|
||||
skipElements = false;
|
||||
}
|
||||
else if (childAdornments.equals(elementAdornments)) {
|
||||
skipElements = true;
|
||||
}
|
||||
|
||||
if (!skipElements) {
|
||||
usedAdornments.add(child.getAdornments());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ItemPresentation getPresentation() {
|
||||
return new ItemPresentation() {
|
||||
public String getPresentableText() {
|
||||
return myElement.getName();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getLocationString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Icon getIcon(boolean open) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@Nullable
|
||||
@Override
|
||||
public String getPresentableText() {
|
||||
final NavigatablePsiElement element = getElement();
|
||||
return element != null ? element.getName() : "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.intellij.ide.structureView.StructureViewModel;
|
||||
import com.intellij.ide.structureView.StructureViewModelBase;
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
import com.intellij.ide.util.treeView.smartTree.Sorter;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.jetbrains.rest.RestFile;
|
||||
@@ -44,12 +45,12 @@ public class RestStructureViewModel extends StructureViewModelBase implements St
|
||||
|
||||
@Override
|
||||
public boolean isAlwaysLeaf(StructureViewTreeElement element) {
|
||||
return element.getValue() instanceof RestTitle;
|
||||
return element.getChildren().length == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoExpand(@NotNull StructureViewTreeElement element) {
|
||||
return element.getValue() instanceof PsiFile;
|
||||
return element.getValue() instanceof PsiFile || ApplicationManager.getApplication().isUnitTestMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user