mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
fixed PY-3777 ReST: Field lists do not wrap correctly
(added formatter)
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
<lang.psiStructureViewFactory language="ReST"
|
||||
implementationClass="com.jetbrains.rest.structureView.RestStructureViewFactory"/>
|
||||
<annotator language="ReST" implementationClass="com.jetbrains.rest.validation.RestAnnotatingVisitor"/>
|
||||
|
||||
<lang.formatter language="ReST" implementationClass="com.jetbrains.rest.formatter.RestFormattingModelBuilder"/>
|
||||
|
||||
|
||||
</extensions>
|
||||
|
||||
@@ -12,5 +12,6 @@ public interface RestElementTypes {
|
||||
RestElementType INLINE_BLOCK = new RestElementType("INLINE_BLOCK");
|
||||
|
||||
RestElementType LINE_TEXT = new RestElementType("LINE_TEXT");
|
||||
RestElementType FIELD_LIST = new RestElementType("FIELD_LIST");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.jetbrains.rest.formatter;
|
||||
|
||||
|
||||
import com.intellij.formatting.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.jetbrains.rest.RestElementTypes;
|
||||
import com.jetbrains.rest.RestTokenTypes;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class RestBlock implements ASTBlock {
|
||||
private RestBlock myParent;
|
||||
private ASTNode myNode;
|
||||
private final Alignment myAlignment;
|
||||
private final Indent myIndent;
|
||||
private Wrap myWrap;
|
||||
private List<RestBlock> mySubBlocks = null;
|
||||
|
||||
public RestBlock(RestBlock parent, ASTNode node, final Alignment alignment, Indent indent, Wrap wrap) {
|
||||
myParent = parent;
|
||||
myNode = node;
|
||||
myAlignment = alignment;
|
||||
myIndent = indent;
|
||||
myWrap = wrap;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ASTNode getNode() {
|
||||
return myNode;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TextRange getTextRange() {
|
||||
return myNode.getTextRange();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Block> getSubBlocks() {
|
||||
if (mySubBlocks == null) {
|
||||
mySubBlocks = buildSubBlocks();
|
||||
}
|
||||
return new ArrayList<Block>(mySubBlocks);
|
||||
}
|
||||
private List<RestBlock> buildSubBlocks() {
|
||||
List<RestBlock> blocks = new ArrayList<RestBlock>();
|
||||
for (ASTNode child = myNode.getFirstChildNode(); child != null; child = child.getTreeNext()) {
|
||||
|
||||
IElementType childType = child.getElementType();
|
||||
if (child.getTextRange().getLength() == 0) continue;
|
||||
if (childType == RestTokenTypes.WHITESPACE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
blocks.add(buildSubBlock(child));
|
||||
}
|
||||
return Collections.unmodifiableList(blocks);
|
||||
}
|
||||
|
||||
private RestBlock buildSubBlock(ASTNode child) {
|
||||
IElementType parentType = myNode.getElementType();
|
||||
IElementType childType = child.getElementType();
|
||||
IElementType grandparentType = myNode.getTreeParent() == null ? null : myNode.getTreeParent().getElementType();
|
||||
Wrap wrap = null;
|
||||
Indent childIndent = Indent.getNoneIndent();
|
||||
Alignment childAlignment = null;
|
||||
|
||||
if (grandparentType == RestElementTypes.FIELD_LIST && parentType == RestElementTypes.LINE_TEXT &&
|
||||
childType == RestTokenTypes.LINE) {
|
||||
childIndent = Indent.getNormalIndent();
|
||||
}
|
||||
return new RestBlock(this, child, childAlignment, childIndent, wrap);
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Wrap getWrap() {
|
||||
return myWrap;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Indent getIndent() {
|
||||
return myIndent;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Alignment getAlignment() {
|
||||
return myAlignment;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChildAttributes getChildAttributes(int newChildIndex) {
|
||||
return new ChildAttributes(Indent.getNoneIndent(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIncomplete() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeaf() {
|
||||
return myNode.getFirstChildNode() == null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.jetbrains.rest.formatter;
|
||||
|
||||
import com.intellij.formatting.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.jetbrains.rest.RestLanguage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public class RestFormattingModelBuilder implements FormattingModelBuilderEx, CustomFormattingModelBuilder {
|
||||
|
||||
@Override
|
||||
public boolean isEngagedToFormat(PsiElement context) {
|
||||
PsiFile file = context.getContainingFile();
|
||||
return file != null && file.getLanguage() == RestLanguage.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FormattingModel createModel(@NotNull PsiElement element,
|
||||
@NotNull CodeStyleSettings settings,
|
||||
@NotNull FormattingMode mode) {
|
||||
|
||||
final RestBlock block = new RestBlock(null, element.getNode(), null, Indent.getNoneIndent(), null);
|
||||
return FormattingModelProvider.createFormattingModelForPsiFile(element.getContainingFile(), block, settings);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FormattingModel createModel(PsiElement element, CodeStyleSettings settings) {
|
||||
return createModel(element, settings, FormattingMode.REFORMAT);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TextRange getRangeAffectingIndent(PsiFile file, int offset, ASTNode elementAtOffset) {
|
||||
final PsiElement element = elementAtOffset.getPsi();
|
||||
final PsiElement container = element.getParent();
|
||||
return container != null ? container.getTextRange() : null;
|
||||
}
|
||||
}
|
||||
@@ -47,9 +47,7 @@ public class RestParser implements PsiParser {
|
||||
marker.done(RestTokenTypes.TITLE);
|
||||
}
|
||||
else if (type == RestTokenTypes.FIELD) {
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
builder.advanceLexer();
|
||||
marker.done(RestTokenTypes.FIELD);
|
||||
parseFieldList(builder);
|
||||
}
|
||||
else if (type == RestTokenTypes.INLINE_LINE) {
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
@@ -62,13 +60,7 @@ public class RestParser implements PsiParser {
|
||||
marker.done(RestElementTypes.REFERENCE_TARGET);
|
||||
}
|
||||
else if (type == RestTokenTypes.LINE) {
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
while (type == RestTokenTypes.LINE || type == RestTokenTypes.WHITESPACE) {
|
||||
builder.advanceLexer();
|
||||
type = builder.getTokenType();
|
||||
}
|
||||
|
||||
marker.done(RestElementTypes.LINE_TEXT);
|
||||
parseLineText(builder, type);
|
||||
}
|
||||
else
|
||||
builder.advanceLexer();
|
||||
@@ -77,6 +69,32 @@ public class RestParser implements PsiParser {
|
||||
return builder.getTreeBuilt();
|
||||
}
|
||||
|
||||
private static boolean parseLineText(PsiBuilder builder, IElementType type) {
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
boolean gotLine = false;
|
||||
while (type == RestTokenTypes.LINE || type == RestTokenTypes.WHITESPACE) {
|
||||
builder.advanceLexer();
|
||||
type = builder.getTokenType();
|
||||
gotLine = true;
|
||||
}
|
||||
if (gotLine)
|
||||
marker.done(RestElementTypes.LINE_TEXT);
|
||||
else
|
||||
marker.drop();
|
||||
return gotLine;
|
||||
}
|
||||
|
||||
private static void parseFieldList(PsiBuilder builder) {
|
||||
PsiBuilder.Marker listMarker = builder.mark();
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
builder.advanceLexer();
|
||||
marker.done(RestTokenTypes.FIELD);
|
||||
if (parseLineText(builder, builder.getTokenType()))
|
||||
listMarker.done(RestElementTypes.FIELD_LIST);
|
||||
else
|
||||
listMarker.drop();
|
||||
}
|
||||
|
||||
private void parseMarkup(PsiBuilder builder) {
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
IElementType type = builder.getTokenType();
|
||||
|
||||
@@ -30,6 +30,9 @@ public class RestASTFactory implements RestTokenTypes, RestElementTypes {
|
||||
if (type == FIELD) {
|
||||
return new RestRole(node);
|
||||
}
|
||||
if (type == FIELD_LIST) {
|
||||
return new RestFieldList(node);
|
||||
}
|
||||
if (type == INLINE_BLOCK) {
|
||||
return new RestInlineBlock(node);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.jetbrains.rest.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class RestFieldList extends RestElement {
|
||||
public RestFieldList(@NotNull final ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RestFieldList:" + getNode().getElementType().toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiLanguageInjectionHost;
|
||||
import com.intellij.psi.ResolveResult;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
|
||||
import com.jetbrains.python.psi.PyQualifiedExpression;
|
||||
import com.jetbrains.python.psi.impl.references.PyReferenceImpl;
|
||||
import com.jetbrains.python.psi.resolve.*;
|
||||
@@ -63,8 +62,8 @@ public class PyDocReference extends PyReferenceImpl {
|
||||
|
||||
ResolveProcessor processor = new ResolveProcessor(referencedName);
|
||||
|
||||
final ScopeOwner scopeOwner = ScopeUtil.getScopeOwner(myElement);
|
||||
PyResolveUtil.scopeCrawlUp(processor, scopeOwner != null? scopeOwner : (ScopeOwner)file, referencedName, file);
|
||||
if (file instanceof ScopeOwner)
|
||||
PyResolveUtil.scopeCrawlUp(processor, (ScopeOwner)file, referencedName, file);
|
||||
final List<RatedResolveResult> resultList = getResultsFromProcessor(referencedName, processor, file, file);
|
||||
if (resultList.size() > 0)
|
||||
return resultList.toArray(new RatedResolveResult[resultList.size()]);
|
||||
@@ -86,7 +85,8 @@ public class PyDocReference extends PyReferenceImpl {
|
||||
|
||||
// include our own names
|
||||
final CompletionVariantsProcessor processor = new CompletionVariantsProcessor(element);
|
||||
PyResolveUtil.scopeCrawlUp(processor, (ScopeOwner)file, null, null);
|
||||
if (file instanceof ScopeOwner)
|
||||
PyResolveUtil.scopeCrawlUp(processor, (ScopeOwner)file, null, null);
|
||||
|
||||
ret.addAll(processor.getResultList());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user