diff --git a/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PyConsoleParser.java b/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PyConsoleParser.java index bf019089c921..4be398afb716 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PyConsoleParser.java +++ b/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PyConsoleParser.java @@ -29,6 +29,7 @@ public class PyConsoleParser extends PyParser { PyConsoleTokenTypes.PLING, PyConsoleTokenTypes.QUESTION_MARK, PyConsoleTokenTypes.SHELL_COMMAND, + PyConsoleTokenTypes.MAGIC_COMMAND_LINE, PyTokenTypes.COMMA, PyTokenTypes.DIV, PyTokenTypes.PERC, diff --git a/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PyConsoleParsingContext.java b/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PyConsoleParsingContext.java index 0c0cdb32095d..060627f6909a 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PyConsoleParsingContext.java +++ b/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PyConsoleParsingContext.java @@ -10,6 +10,7 @@ import com.jetbrains.python.parsing.ParsingContext; import com.jetbrains.python.parsing.StatementParsing; import com.jetbrains.python.psi.LanguageLevel; +import static com.jetbrains.python.parsing.console.PyConsoleTokenTypes.MAGIC_COMMAND_LINE; import static com.jetbrains.python.parsing.console.PyConsoleTokenTypes.SHELL_COMMAND; public class PyConsoleParsingContext extends ParsingContext { @@ -201,7 +202,7 @@ public class PyConsoleParsingContext extends ParsingContext { } private boolean parseIPythonCaptureExpression() { - if (myBuilder.getTokenType() == SHELL_COMMAND) { + if (myBuilder.getTokenType() == SHELL_COMMAND || myBuilder.getTokenType() == MAGIC_COMMAND_LINE) { captureIPythonExpression(); return true; } diff --git a/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PyConsoleTokenTypes.java b/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PyConsoleTokenTypes.java index 8de31d8410eb..d945c2cdd96b 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PyConsoleTokenTypes.java +++ b/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PyConsoleTokenTypes.java @@ -23,6 +23,7 @@ public final class PyConsoleTokenTypes { public static final PyElementType DOLLAR = new PyElementType("DOLLAR"); //$ public static final PyElementType SHELL_COMMAND = new PyElementType("SHELL_COMMAND"); + public static final PyElementType MAGIC_COMMAND_LINE = new PyElementType("MAGIC_COMMAND_LINE"); private PyConsoleTokenTypes() { } diff --git a/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PythonConsoleLexer.java b/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PythonConsoleLexer.java index 1d03efce13a2..70b3dcc32cac 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PythonConsoleLexer.java +++ b/python/python-psi-impl/src/com/jetbrains/python/parsing/console/PythonConsoleLexer.java @@ -16,6 +16,8 @@ package com.jetbrains.python.parsing.console; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.intellij.lexer.Lexer; import com.intellij.lexer.MergeFunction; import com.intellij.psi.tree.IElementType; import com.jetbrains.python.lexer.PythonIndentingLexer; @@ -25,6 +27,7 @@ import com.jetbrains.python.psi.PyElementType; import java.util.Map; import static com.jetbrains.python.PyTokenTypes.*; +import static com.jetbrains.python.parsing.console.PyConsoleTokenTypes.MAGIC_COMMAND_LINE; import static com.jetbrains.python.parsing.console.PyConsoleTokenTypes.SHELL_COMMAND; public class PythonConsoleLexer extends PythonIndentingLexer { @@ -56,17 +59,26 @@ public class PythonConsoleLexer extends PythonIndentingLexer { MergeFunction origMergeFunction = super.getMergeFunction(); return (type, originalLexer) -> { if (type == BAD_CHARACTER && getElementType(getBaseTokenText()) == PyConsoleTokenTypes.PLING) { - while (originalLexer.getTokenType() != LINE_BREAK && - originalLexer.getTokenType() != STATEMENT_BREAK && - originalLexer.getTokenType() != null) { - originalLexer.advance(); - } + collectFullLine(originalLexer); return SHELL_COMMAND; } + if (type == PERC && + (getBaseTokenStart() == 0 || (!myTokenQueue.isEmpty() && Iterables.getLast(myTokenQueue).getType() == STATEMENT_BREAK))) { + collectFullLine(originalLexer); + return MAGIC_COMMAND_LINE; + } return origMergeFunction.merge(type, originalLexer); }; } + private static void collectFullLine(Lexer originalLexer) { + while (originalLexer.getTokenType() != LINE_BREAK && + originalLexer.getTokenType() != STATEMENT_BREAK && + originalLexer.getTokenType() != null) { + originalLexer.advance(); + } + } + public static PyElementType getElementType(String token) { return SPECIAL_IPYTHON_SYMBOLS.get(token); } diff --git a/python/testData/console/ipython/psi/magic1.txt b/python/testData/console/ipython/psi/magic1.txt index 4dd1bb261c43..bae4eac7443e 100644 --- a/python/testData/console/ipython/psi/magic1.txt +++ b/python/testData/console/ipython/psi/magic1.txt @@ -1,4 +1,3 @@ PyFile:magic1.py PyEmptyExpression - PsiElement(Py:PERC)('%') - PsiElement(Py:IDENTIFIER)('xmode') \ No newline at end of file + PsiElement(Py:MAGIC_COMMAND_LINE)('%xmode') \ No newline at end of file diff --git a/python/testData/console/ipython/psi/magic2.txt b/python/testData/console/ipython/psi/magic2.txt index 61681b1b54f8..f614cedfdb16 100644 --- a/python/testData/console/ipython/psi/magic2.txt +++ b/python/testData/console/ipython/psi/magic2.txt @@ -1,8 +1,3 @@ PyFile:magic2.py PyEmptyExpression - PsiElement(Py:PERC)('%') - PsiElement(Py:IDENTIFIER)('alias_magic') - PsiWhiteSpace(' ') - PsiElement(Py:IDENTIFIER)('t') - PsiWhiteSpace(' ') - PsiElement(Py:IDENTIFIER)('timeit') \ No newline at end of file + PsiElement(Py:MAGIC_COMMAND_LINE)('%alias_magic t timeit') \ No newline at end of file diff --git a/python/testData/console/ipython/psi/magic3.txt b/python/testData/console/ipython/psi/magic3.txt index acdd939b9e1b..156a50cd0cfb 100644 --- a/python/testData/console/ipython/psi/magic3.txt +++ b/python/testData/console/ipython/psi/magic3.txt @@ -1,10 +1,3 @@ PyFile:magic3.py PyEmptyExpression - PsiElement(Py:PERC)('%') - PsiElement(Py:IDENTIFIER)('config') - PsiWhiteSpace(' ') - PsiElement(Py:IDENTIFIER)('Class') - PsiElement(Py:DOT)('.') - PsiElement(Py:IDENTIFIER)('trait') - PsiElement(Py:EQ)('=') - PsiElement(Py:IDENTIFIER)('value') \ No newline at end of file + PsiElement(Py:MAGIC_COMMAND_LINE)('%config Class.trait=value') \ No newline at end of file diff --git a/python/testData/console/ipython/psi/magicMultiline.txt b/python/testData/console/ipython/psi/magicMultiline.txt index 3f7d8a56364c..21327961b56f 100644 --- a/python/testData/console/ipython/psi/magicMultiline.txt +++ b/python/testData/console/ipython/psi/magicMultiline.txt @@ -1,8 +1,6 @@ PyFile:magicMultiline.py PyEmptyExpression - PsiElement(Py:PERC)('%') - PsiElement(Py:PERC)('%') - PsiElement(Py:IDENTIFIER)('bash') + PsiElement(Py:MAGIC_COMMAND_LINE)('%%bash') PsiWhiteSpace('\n') PsiElement(Py:IDENTIFIER)('echo') PsiWhiteSpace(' ')