mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 21:55:01 +07:00
initial doctests support
This commit is contained in:
@@ -683,6 +683,15 @@
|
||||
|
||||
<problemFileHighlightFilter implementation="com.jetbrains.python.buildout.config.BuildoutCfgProblemFileHighlightFilter"/>
|
||||
|
||||
|
||||
<!-- PyDocstring -->
|
||||
<languageInjector implementation="com.jetbrains.python.documentation.doctest.PyDocstringLanguageInjector"/>
|
||||
<lang.parserDefinition language="PyDocstring" implementationClass="com.jetbrains.python.documentation.doctest.PyDocstringParserDefinition"/>
|
||||
|
||||
|
||||
|
||||
<lang.syntaxHighlighterFactory key="PyDocstring" implementationClass="com.jetbrains.python.documentation.doctest.PyDocstringSyntaxHighlighterFactory"/>
|
||||
|
||||
<!-- Mako files -->
|
||||
<multiLangCommenter implementation="com.jetbrains.python.templateLanguages.TemplatesCommentProvider"/>
|
||||
<highlightErrorFilter implementation="com.jetbrains.mako.inspection.MakoErrorFilter"/>
|
||||
@@ -838,6 +847,10 @@
|
||||
<dialectsTokenSetContributor implementation="com.jetbrains.mako.MakoTokenSetContributor"/>
|
||||
<visitorFilter language="Mako" implementationClass="com.jetbrains.mako.highlighting.MakoVisitorFilter"/>
|
||||
|
||||
<!-- PyDocstring -->
|
||||
<dialectsTokenSetContributor implementation="com.jetbrains.python.documentation.doctest.PyDocstringTokenSetContributor"/>
|
||||
<visitorFilter language="PyDocstring" implementationClass="com.jetbrains.python.documentation.doctest.PyDocstringVisitorFilter"/>
|
||||
|
||||
<!-- Console -->
|
||||
<visitorFilter language="Python" implementationClass="com.jetbrains.python.console.ConsoleVisitorFilter"/>
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.codeInsight.completion.CompletionUtil;
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
|
||||
import com.jetbrains.python.psi.PyQualifiedExpression;
|
||||
import com.jetbrains.python.psi.impl.ResolveResultList;
|
||||
import com.jetbrains.python.psi.impl.references.PyReferenceImpl;
|
||||
import com.jetbrains.python.psi.resolve.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyDocReference extends PyReferenceImpl {
|
||||
public PyDocReference(PyQualifiedExpression element, @NotNull PyResolveContext context) {
|
||||
super(element, context);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ResolveResult[] multiResolve(boolean incompleteCode) {
|
||||
ResolveResult[] results = super.multiResolve(incompleteCode);
|
||||
if (results.length == 0) {
|
||||
final ResolveResultList ret = new ResolveResultList();
|
||||
PsiFile file = myElement.getContainingFile();
|
||||
final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myElement.getProject());
|
||||
final PsiLanguageInjectionHost host = languageManager.getInjectionHost(myElement);
|
||||
if (host != null) file = host.getContainingFile();
|
||||
|
||||
final String referencedName = myElement.getReferencedName();
|
||||
if (referencedName == null) return ResolveResult.EMPTY_ARRAY;
|
||||
ResolveProcessor processor = new ResolveProcessor(referencedName);
|
||||
|
||||
PyResolveUtil.scopeCrawlUp(processor, (ScopeOwner)file, referencedName, file);
|
||||
PsiElement uexpr = processor.getResult();
|
||||
if (uexpr != null) ret.add(new RatedResolveResult(RatedResolveResult.RATE_NORMAL, uexpr));
|
||||
if (ret.size() > 0) {
|
||||
return ret.toArray(new RatedResolveResult[ret.size()]);
|
||||
}
|
||||
return new ResolveResult[] { new PsiElementResolveResult(myElement) };
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Object[] getVariants() {
|
||||
final ArrayList<Object> ret = Lists.newArrayList(super.getVariants());
|
||||
PsiFile file = myElement.getContainingFile();
|
||||
final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myElement.getProject());
|
||||
final PsiLanguageInjectionHost host = languageManager.getInjectionHost(myElement);
|
||||
if (host != null) file = host.getContainingFile();
|
||||
|
||||
final PsiElement originalElement = CompletionUtil.getOriginalElement(myElement);
|
||||
final PyQualifiedExpression element = originalElement instanceof PyQualifiedExpression ?
|
||||
(PyQualifiedExpression)originalElement : myElement;
|
||||
|
||||
// include our own names
|
||||
final CompletionVariantsProcessor processor = new CompletionVariantsProcessor(element);
|
||||
PyResolveUtil.scopeCrawlUp(processor, (ScopeOwner)file, null, null);
|
||||
|
||||
ret.addAll(processor.getResultList());
|
||||
|
||||
return ret.toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiPolyVariantReference;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.impl.PyReferenceExpressionImpl;
|
||||
import com.jetbrains.python.psi.impl.references.PyQualifiedReference;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
*
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyDocReferenceExpression extends PyReferenceExpressionImpl {
|
||||
|
||||
public PyDocReferenceExpression(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiPolyVariantReference getReference(PyResolveContext context) {
|
||||
final PyExpression qualifier = getQualifier();
|
||||
if (qualifier != null) {
|
||||
return new PyQualifiedReference(this, context);
|
||||
}
|
||||
return new PyDocReference(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.intellij.lang.PsiBuilder;
|
||||
import com.jetbrains.python.parsing.ParsingContext;
|
||||
import com.jetbrains.python.parsing.PyParser;
|
||||
import com.jetbrains.python.parsing.StatementParsing;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyDocstingParser extends PyParser {
|
||||
@Override
|
||||
protected ParsingContext createParsingContext(PsiBuilder builder, LanguageLevel languageLevel, StatementParsing.FUTURE futureFlag) {
|
||||
return new PyDocstringParsingContext(builder, languageLevel, futureFlag);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.jetbrains.python.psi.PyFileElementType;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyDocstringFileElementType extends PyFileElementType {
|
||||
public PyDocstringFileElementType(Language language) {
|
||||
super(language);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExternalId() {
|
||||
return "PyDocstring.FILE";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.jetbrains.python.PythonFileType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyDocstringFileType extends PythonFileType {
|
||||
public static PythonFileType INSTANCE = new PyDocstringFileType();
|
||||
|
||||
protected PyDocstringFileType() {
|
||||
super(new PyDocstringLanguageDialect());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "PyDocstring";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "python docstring";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDefaultExtension() {
|
||||
return "docstring";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.jetbrains.python.PythonLanguage;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyDocstringLanguageDialect extends Language {
|
||||
public static PyDocstringLanguageDialect getInstance() {
|
||||
return (PyDocstringLanguageDialect)PyDocstringFileType.INSTANCE.getLanguage();
|
||||
}
|
||||
|
||||
protected PyDocstringLanguageDialect() {
|
||||
super(PythonLanguage.getInstance(), "PyDocstring");
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.InjectedLanguagePlaces;
|
||||
import com.intellij.psi.LanguageInjector;
|
||||
import com.intellij.psi.PsiLanguageInjectionHost;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.python.psi.PyDocStringOwner;
|
||||
import com.jetbrains.python.psi.PyStringLiteralExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User: ktisha
|
||||
*/
|
||||
public class PyDocstringLanguageInjector implements LanguageInjector {
|
||||
@Override
|
||||
public void getLanguagesToInject(@NotNull final PsiLanguageInjectionHost host, @NotNull final InjectedLanguagePlaces injectionPlacesRegistrar) {
|
||||
if (host instanceof PyStringLiteralExpression) {
|
||||
final PyDocStringOwner docStringOwner = PsiTreeUtil.getParentOfType(host, PyDocStringOwner.class);
|
||||
if (docStringOwner != null) {
|
||||
if (docStringOwner.getDocStringExpression() == host) {
|
||||
|
||||
int start = 0;
|
||||
int end = host.getTextLength() - 1;
|
||||
final String text = host.getText();
|
||||
final List<String> strings = StringUtil.split(text, "\n", false);
|
||||
|
||||
boolean gotExample = false;
|
||||
|
||||
int currentPosition = 0;
|
||||
for (String string : strings) {
|
||||
final String trimmedString = string.trim();
|
||||
if (!trimmedString.startsWith(">>>") && !trimmedString.startsWith("...") && gotExample && start < end) {
|
||||
gotExample = false;
|
||||
injectionPlacesRegistrar.addPlace(PyDocstringLanguageDialect.getInstance(), TextRange.create(start, end-1), null, null);
|
||||
}
|
||||
if (trimmedString.startsWith(">>>")) {
|
||||
if (!gotExample)
|
||||
start = currentPosition;
|
||||
|
||||
gotExample = true;
|
||||
end = getEndOffset(currentPosition, string);
|
||||
}
|
||||
else if (trimmedString.startsWith("...") && gotExample) {
|
||||
end = getEndOffset(currentPosition, string);
|
||||
}
|
||||
currentPosition = currentPosition + string.length();
|
||||
}
|
||||
if (gotExample && start < end)
|
||||
injectionPlacesRegistrar.addPlace(PyDocstringLanguageDialect.getInstance(), TextRange.create(start, end-1), null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getEndOffset(int start, String s) {
|
||||
int end;
|
||||
int length = s.length();
|
||||
if (s.trim().endsWith("\"\"\"") || s.trim().endsWith("'''"))
|
||||
length = length - 3;
|
||||
else if (s.trim().endsWith("\"") || s.trim().endsWith("'"))
|
||||
length = length - 1;
|
||||
|
||||
end = start + length;
|
||||
return end;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.lexer.PythonIndentingLexer;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyDocstringLexer extends PythonIndentingLexer {
|
||||
@Override
|
||||
public void advance() {
|
||||
if (super.getTokenType() == PyTokenTypes.DOT) {
|
||||
advanceBase();
|
||||
if (super.getTokenType() == PyTokenTypes.DOT) {
|
||||
advanceBase();
|
||||
if (super.getTokenType() == PyTokenTypes.DOT) {
|
||||
advanceBase();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (super.getTokenType() == PyTokenTypes.GTGT) {
|
||||
super.advance();
|
||||
if (super.getTokenType() == PyTokenTypes.GT) {
|
||||
super.advance();
|
||||
}
|
||||
}
|
||||
else {
|
||||
super.advance();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.intellij.lang.PsiParser;
|
||||
import com.intellij.lexer.Lexer;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.FileViewProvider;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.tree.IFileElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.jetbrains.python.PythonParserDefinition;
|
||||
import com.jetbrains.python.psi.impl.PyFileImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyDocstringParserDefinition extends PythonParserDefinition {
|
||||
public static final IFileElementType PYTHON_DOCSTRING_FILE = new PyDocstringFileElementType(PyDocstringLanguageDialect
|
||||
.getInstance());
|
||||
|
||||
@NotNull
|
||||
public Lexer createLexer(Project project) {
|
||||
return new PyDocstringLexer();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiParser createParser(Project project) {
|
||||
return new PyDocstingParser();
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TokenSet getWhitespaceTokens() {
|
||||
return TokenSet.orSet(super.getWhitespaceTokens(), TokenSet.create(PyDocstringTokenTypes.DOTS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFileElementType getFileNodeType() {
|
||||
return PYTHON_DOCSTRING_FILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiFile createFile(FileViewProvider viewProvider) {
|
||||
return new PyFileImpl(viewProvider, PyDocstringLanguageDialect.getInstance()) {
|
||||
@NotNull
|
||||
@Override
|
||||
public FileType getFileType() {
|
||||
return PyDocstringFileType.INSTANCE;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.intellij.lang.PsiBuilder;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.parsing.ExpressionParsing;
|
||||
import com.jetbrains.python.parsing.ParsingContext;
|
||||
import com.jetbrains.python.parsing.ParsingScope;
|
||||
import com.jetbrains.python.parsing.StatementParsing;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyDocstringParsingContext extends ParsingContext {
|
||||
private final StatementParsing stmtParser;
|
||||
private final ExpressionParsing exprParser;
|
||||
|
||||
public PyDocstringParsingContext(final PsiBuilder builder,
|
||||
LanguageLevel languageLevel,
|
||||
StatementParsing.FUTURE futureFlag) {
|
||||
super(builder, languageLevel, futureFlag);
|
||||
stmtParser = new PyDocstringStatementParsing(this, futureFlag);
|
||||
exprParser = new PyDocstringExpressionParsing(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionParsing getExpressionParser() {
|
||||
return exprParser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementParsing getStatementParser() {
|
||||
return stmtParser;
|
||||
}
|
||||
|
||||
private static class PyDocstringExpressionParsing extends ExpressionParsing {
|
||||
public PyDocstringExpressionParsing(ParsingContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElementType getReferenceType() {
|
||||
return PyDocstringTokenTypes.DOC_REFERENCE;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PyDocstringStatementParsing extends StatementParsing {
|
||||
|
||||
protected IElementType getReferenceType() {
|
||||
return PyDocstringTokenTypes.DOC_REFERENCE;
|
||||
}
|
||||
|
||||
protected PyDocstringStatementParsing(ParsingContext context,
|
||||
@Nullable FUTURE futureFlag) {
|
||||
super(context, futureFlag);
|
||||
}
|
||||
@Override
|
||||
public void parseStatement(ParsingScope scope) {
|
||||
IElementType type = myBuilder.getTokenType();
|
||||
while (!myBuilder.eof() && type != PyDocstringTokenTypes.WELCOME) {
|
||||
myBuilder.advanceLexer();
|
||||
type = myBuilder.getTokenType();
|
||||
}
|
||||
if (type == PyDocstringTokenTypes.WELCOME) { // >>> case
|
||||
myBuilder.advanceLexer();
|
||||
super.parseStatement(scope);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IElementType filter(IElementType source, int start, int end, CharSequence text) {
|
||||
if (source == PyTokenTypes.DOT && CharArrayUtil.regionMatches(text, start, end, "..."))
|
||||
return PyDocstringTokenTypes.DOTS;
|
||||
if (source == PyTokenTypes.GTGT && CharArrayUtil.regionMatches(text, start, end, ">>>"))
|
||||
return PyDocstringTokenTypes.WELCOME;
|
||||
return super.filter(source, start, end, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.jetbrains.python.highlighting.PyHighlighter;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyDocstringSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
|
||||
@NotNull
|
||||
public SyntaxHighlighter getSyntaxHighlighter(final Project project, final VirtualFile virtualFile) {
|
||||
return new PyHighlighter(LanguageLevel.getDefault()){
|
||||
@NotNull
|
||||
@Override
|
||||
public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
|
||||
return new TextAttributesKey[0];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.jetbrains.python.PythonTokenSetContributor;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyDocstringTokenSetContributor extends PythonTokenSetContributor {
|
||||
@Override
|
||||
public TokenSet getExpressionTokens() {
|
||||
return TokenSet.orSet(super.getExpressionTokens(), TokenSet.create(PyDocstringTokenTypes.DOC_REFERENCE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.jetbrains.python.psi.PyElementType;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyDocstringTokenTypes {
|
||||
public static final PyElementType DOC_REFERENCE = new PyElementType("DOC_REFERENCE", PyDocReferenceExpression.class);
|
||||
public static final PyElementType WELCOME = new PyElementType("WELCOME");
|
||||
public static final PyElementType DOTS = new PyElementType("DOTS");
|
||||
|
||||
private PyDocstringTokenTypes() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.jetbrains.python.inspections.*;
|
||||
import com.jetbrains.python.validation.DocStringAnnotator;
|
||||
import com.jetbrains.python.validation.HighlightingAnnotator;
|
||||
import com.jetbrains.python.validation.ParameterListAnnotator;
|
||||
import com.jetbrains.python.validation.ReturnAnnotator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*
|
||||
* filter out some python inspections and annotations if we're in docstring substitution
|
||||
*/
|
||||
public class PyDocstringVisitorFilter implements PythonVisitorFilter {
|
||||
@Override
|
||||
public boolean isSupported(@NotNull final Class visitorClass, @NotNull final PsiFile file) {
|
||||
//inspections
|
||||
if (visitorClass == PyArgumentListInspection.class) {
|
||||
return false;
|
||||
}
|
||||
if (visitorClass == PyDocstringInspection.class || visitorClass == PyStatementEffectInspection.class ||
|
||||
visitorClass == PyUnboundLocalVariableInspection.class || visitorClass == PyUnnecessaryBackslashInspection.class ||
|
||||
visitorClass == PyUnresolvedReferencesInspection.class) {
|
||||
return false;
|
||||
}
|
||||
//annotators
|
||||
if (visitorClass == DocStringAnnotator.class || visitorClass == ParameterListAnnotator.class || visitorClass == ReturnAnnotator.class ||
|
||||
visitorClass == HighlightingAnnotator.class)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -355,7 +355,10 @@ public class PyStringLiteralExpressionImpl extends PyElementImpl implements PySt
|
||||
|
||||
@Override
|
||||
public int getOffsetInHost(final int offsetInDecoded, @NotNull TextRange rangeInsideHost) {
|
||||
return myHost.valueOffsetToTextOffset(offsetInDecoded);
|
||||
int offset = offsetInDecoded + rangeInsideHost.getStartOffset();
|
||||
if (offset < rangeInsideHost.getStartOffset()) offset = rangeInsideHost.getStartOffset();
|
||||
if (offset > rangeInsideHost.getEndOffset()) offset = rangeInsideHost.getEndOffset();
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
class Test:
|
||||
pass
|
||||
|
||||
def foo():
|
||||
"""
|
||||
>>> a = Tes<caret>
|
||||
|
||||
"""
|
||||
@@ -0,0 +1,8 @@
|
||||
class Test:
|
||||
pass
|
||||
|
||||
def foo():
|
||||
"""
|
||||
>>> a = Test
|
||||
|
||||
"""
|
||||
@@ -0,0 +1,5 @@
|
||||
def foo():
|
||||
"""
|
||||
>>> fo<caret>
|
||||
|
||||
"""
|
||||
@@ -0,0 +1,5 @@
|
||||
def foo():
|
||||
"""
|
||||
>>> foo
|
||||
|
||||
"""
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.jetbrains.python;
|
||||
|
||||
import com.intellij.lexer.Lexer;
|
||||
import com.jetbrains.python.documentation.doctest.PyDocstringParserDefinition;
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
|
||||
/**
|
||||
* User: ktisha
|
||||
*/
|
||||
public class PyDocstringTest extends PyTestCase {
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return super.getTestDataPath() + "/doctests/";
|
||||
}
|
||||
|
||||
public void testWelcome() {
|
||||
doTestLexer(" >>> foo()", "Py:SPACE", "Py:INDENT", "Py:GTGT", "Py:SPACE", "Py:IDENTIFIER", "Py:LPAR", "Py:RPAR", "Py:STATEMENT_BREAK");
|
||||
}
|
||||
|
||||
public void testDots() {
|
||||
doTestLexer(">>> grouped == { 2:2,\n" +
|
||||
" ... 3:3}", "Py:GTGT","Py:SPACE", "Py:IDENTIFIER", "Py:SPACE", "Py:EQEQ", "Py:SPACE", "Py:LBRACE", "Py:SPACE", "Py:INTEGER_LITERAL", "Py:COLON", "Py:INTEGER_LITERAL", "Py:COMMA", "Py:LINE_BREAK", "Py:DOT", "Py:SPACE", "Py:SPACE", "Py:INTEGER_LITERAL", "Py:COLON", "Py:INTEGER_LITERAL", "Py:RBRACE", "Py:STATEMENT_BREAK");
|
||||
}
|
||||
|
||||
public void testFunctionName() throws Throwable {
|
||||
doCompletionTest();
|
||||
}
|
||||
|
||||
public void testClassName() throws Throwable {
|
||||
doCompletionTest();
|
||||
}
|
||||
|
||||
public void doCompletionTest() throws Throwable {
|
||||
String inputDataFileName = getInputDataFileName(getTestName(true));
|
||||
String expectedResultFileName = getExpectedResultFileName(getTestName(true));
|
||||
myFixture.testCompletion(inputDataFileName, expectedResultFileName);
|
||||
}
|
||||
|
||||
// util methods
|
||||
private static String getInputDataFileName(String testName) {
|
||||
return testName + ".docstring";
|
||||
}
|
||||
|
||||
private static String getExpectedResultFileName(String testName) {
|
||||
return testName + ".expected.docstring";
|
||||
}
|
||||
|
||||
|
||||
private void doTestLexer(final String text, String... expectedTokens) {
|
||||
Lexer lexer = new PyDocstringParserDefinition().createLexer(myFixture.getProject());
|
||||
lexer.start(text);
|
||||
int idx = 0;
|
||||
while (lexer.getTokenType() != null) {
|
||||
if (idx >= expectedTokens.length) {
|
||||
StringBuilder remainingTokens = new StringBuilder("\"" + lexer.getTokenType().toString() + "\"");
|
||||
lexer.advance();
|
||||
while (lexer.getTokenType() != null) {
|
||||
remainingTokens.append(",");
|
||||
remainingTokens.append(" \"").append(lexer.getTokenType().toString()).append("\"");
|
||||
lexer.advance();
|
||||
}
|
||||
fail("Too many tokens. Following tokens: " + remainingTokens.toString());
|
||||
}
|
||||
String tokenName = lexer.getTokenType().toString();
|
||||
assertEquals("Token mismatch at position " + idx, expectedTokens[idx], tokenName);
|
||||
idx++;
|
||||
lexer.advance();
|
||||
}
|
||||
|
||||
if (idx < expectedTokens.length) fail("Not enough tokens");
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,8 @@ public class PyStringLiteralTest extends PyTestCase {
|
||||
assertEquals("\n", builder.toString());
|
||||
|
||||
assertEquals(1, escaper.getOffsetInHost(0, new TextRange(1, 5)));
|
||||
assertEquals(3, escaper.getOffsetInHost(1, new TextRange(1, 5)));
|
||||
assertEquals(6, escaper.getOffsetInHost(4, new TextRange(1, 5)));
|
||||
assertEquals(2, escaper.getOffsetInHost(1, new TextRange(1, 5)));
|
||||
assertEquals(5, escaper.getOffsetInHost(4, new TextRange(1, 5)));
|
||||
}
|
||||
|
||||
private PyStringLiteralExpression createLiteralFromText(final String text) {
|
||||
|
||||
Reference in New Issue
Block a user