DS-4478 Reformat code removes spaces in shell commands

GitOrigin-RevId: b06215e01de70329f3c9dfef4ea330ea73400cd2
This commit is contained in:
Olga.Lavrichenko
2023-07-24 17:24:56 +00:00
committed by intellij-monorepo-bot
parent c36d312272
commit d4df46d5f0
19 changed files with 120 additions and 61 deletions

View File

@@ -601,6 +601,9 @@ public abstract class PythonCommonFormatterTest extends PythonCommonTestCase {
//DS-2583
public void testSpaceShellCommandsJupyter() { doTest(false, "formatter/jupyter/", ".ipynb"); }
//DS-4478
public void testSpaceShellCommandsPathJupyter() { doTest(false, "formatter/jupyter/", ".ipynb"); }
/**
* This test merely checks that call to {@link com.intellij.psi.codeStyle.CodeStyleManager#reformat(com.intellij.psi.PsiElement)}
* is possible for Python sources.

View File

@@ -133,8 +133,6 @@ public class PythonFormattingModelBuilder implements FormattingModelBuilder, Cus
.aroundInside(STAR_OPERATORS, STAR_PATTERNS).none()
.between(EXCEPT_KEYWORD, MULT).none()
.between(PERC, TokenSet.create(PERC, IDENTIFIER, EXPRESSION_STATEMENT)).none()
.between(DIV, IDENTIFIER).spaces(0)
.between(IDENTIFIER, DIV).spaces(0)
.around(MULTIPLICATIVE_OPERATIONS).spaceIf(commonSettings.SPACE_AROUND_MULTIPLICATIVE_OPERATORS)
.around(EXP).spaceIf(pySettings.SPACE_AROUND_POWER_OPERATOR)
.around(SHIFT_OPERATIONS).spaceIf(commonSettings.SPACE_AROUND_SHIFT_OPERATORS)

View File

@@ -113,7 +113,7 @@ public class PythonIndentingProcessor extends MergingLexerAdapter {
}
@NotNull
private String getBaseTokenText() {
protected String getBaseTokenText() {
return getBufferSequence().subSequence(getBaseTokenStart(), getBaseTokenEnd()).toString();
}

View File

@@ -28,11 +28,12 @@ public class PyConsoleParser extends PyParser {
private static final ImmutableSet<IElementType> IPYTHON_START_SYMBOLS = new ImmutableSet.Builder<IElementType>().add(
PyConsoleTokenTypes.PLING,
PyConsoleTokenTypes.QUESTION_MARK,
PyConsoleTokenTypes.SHELL_COMMAND,
PyTokenTypes.COMMA,
PyTokenTypes.DIV,
PyTokenTypes.PERC,
PyTokenTypes.SEMICOLON
).build();
).build();
private final PythonConsoleData myPythonConsoleData;
@@ -41,14 +42,13 @@ public class PyConsoleParser extends PyParser {
myLanguageLevel = languageLevel;
}
public static boolean startsWithIPythonSpecialSymbol(SyntaxTreeBuilder builder) {
IElementType tokenType = builder.getTokenType();
return IPYTHON_START_SYMBOLS.contains(tokenType);
}
@Override
protected ParsingContext createParsingContext(SyntaxTreeBuilder builder, LanguageLevel languageLevel) {
boolean iPythonStartSymbol = myPythonConsoleData.isIPythonEnabled() && startsWithIPythonSpecialSymbol(builder);
boolean iPythonStartSymbol = myPythonConsoleData.isIPythonEnabled() && isIPythonSpecialSymbol(builder.getTokenType());
return new PyConsoleParsingContext(builder, languageLevel, myPythonConsoleData, iPythonStartSymbol);
}
public static boolean isIPythonSpecialSymbol(IElementType tokenType) {
return IPYTHON_START_SYMBOLS.contains(tokenType);
}
}

View File

@@ -10,6 +10,8 @@ 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.SHELL_COMMAND;
public class PyConsoleParsingContext extends ParsingContext {
private final StatementParsing stmtParser;
private final ExpressionParsing expressionParser;
@@ -146,7 +148,6 @@ public class PyConsoleParsingContext extends ParsingContext {
}
ipythonCommand.done(PyElementTypes.EMPTY_EXPRESSION);
}
}
public static class ConsoleExpressionParsing extends ExpressionParsing {
@@ -200,7 +201,7 @@ public class PyConsoleParsingContext extends ParsingContext {
}
private boolean parseIPythonCaptureExpression() {
if (myBuilder.getTokenType() == PyConsoleTokenTypes.PLING) {
if (myBuilder.getTokenType() == SHELL_COMMAND) {
captureIPythonExpression();
return true;
}

View File

@@ -22,6 +22,8 @@ public final class PyConsoleTokenTypes {
public static final PyElementType PLING = new PyElementType("PLING"); //!
public static final PyElementType DOLLAR = new PyElementType("DOLLAR"); //$
public static final PyElementType SHELL_COMMAND = new PyElementType("SHELL_COMMAND");
private PyConsoleTokenTypes() {
}
}

View File

@@ -16,14 +16,17 @@
package com.jetbrains.python.parsing.console;
import com.google.common.collect.ImmutableMap;
import com.intellij.lexer.MergeFunction;
import com.intellij.psi.tree.IElementType;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.lexer.PythonIndentingLexer;
import com.jetbrains.python.lexer.PythonLexerKind;
import com.jetbrains.python.psi.PyElementType;
import java.util.Map;
import static com.jetbrains.python.PyTokenTypes.*;
import static com.jetbrains.python.parsing.console.PyConsoleTokenTypes.SHELL_COMMAND;
public class PythonConsoleLexer extends PythonIndentingLexer {
public PythonConsoleLexer() {
super(PythonLexerKind.CONSOLE);
@@ -41,13 +44,29 @@ public class PythonConsoleLexer extends PythonIndentingLexer {
@Override
public IElementType getTokenType() {
IElementType type = super.getTokenType();
if (type == PyTokenTypes.BAD_CHARACTER && isSpecialSymbols(getTokenText())) {
if (type == BAD_CHARACTER && isSpecialSymbols(getTokenText())) {
type = getElementType(getTokenText());
}
return type;
}
@Override
public MergeFunction getMergeFunction() {
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();
}
return SHELL_COMMAND;
}
return origMergeFunction.merge(type, originalLexer);
};
}
public static PyElementType getElementType(String token) {
return SPECIAL_IPYTHON_SYMBOLS.get(token);
}

View File

@@ -1,4 +1,3 @@
PyFile:shell1.py
PyEmptyExpression
PsiElement(Py:PLING)('!')
PsiElement(Py:IDENTIFIER)('pwd')
PsiElement(Py:SHELL_COMMAND)('!pwd')

View File

@@ -1,9 +1,3 @@
PyFile:shell2.py
PyEmptyExpression
PsiElement(Py:PLING)('!')
PsiElement(Py:IDENTIFIER)('cd')
PsiWhiteSpace(' ')
PsiElement(Py:DIV)('/')
PsiElement(Py:IDENTIFIER)('var')
PsiElement(Py:DIV)('/')
PsiElement(Py:IDENTIFIER)('etc')
PsiElement(Py:SHELL_COMMAND)('!cd /var/etc')

View File

@@ -1,8 +1,3 @@
PyFile:shell3.py
PyEmptyExpression
PsiElement(Py:PLING)('!')
PsiElement(Py:IDENTIFIER)('mvim')
PsiWhiteSpace(' ')
PsiElement(Py:IDENTIFIER)('myfile')
PsiElement(Py:DOT)('.')
PsiElement(Py:IDENTIFIER)('txt')
PsiElement(Py:SHELL_COMMAND)('!mvim myfile.txt')

View File

@@ -1,5 +1,3 @@
PyFile:shell4.py
PyEmptyExpression
PsiElement(Py:PLING)('!')
PsiElement(Py:PLING)('!')
PsiElement(Py:IDENTIFIER)('dir')
PsiElement(Py:SHELL_COMMAND)('!!dir')

View File

@@ -1,4 +1,3 @@
PyFile:shell5.py
PyEmptyExpression
PsiElement(Py:PLING)('!')
PsiElement(Py:PLING)('!')
PsiElement(Py:SHELL_COMMAND)('!!')

View File

@@ -6,6 +6,4 @@ PyFile:shell6.py
PsiElement(Py:EQ)('=')
PsiWhiteSpace(' ')
PyEmptyExpression
PsiElement(Py:PLING)('!')
PsiElement(Py:PLING)('!')
PsiElement(Py:IDENTIFIER)('dir')
PsiElement(Py:SHELL_COMMAND)('!!dir')

View File

@@ -6,5 +6,4 @@ PyFile:shellAssignment1.py
PsiElement(Py:EQ)('=')
PsiWhiteSpace(' ')
PyEmptyExpression
PsiElement(Py:PLING)('!')
PsiElement(Py:IDENTIFIER)('ls')
PsiElement(Py:SHELL_COMMAND)('!ls')

View File

@@ -6,8 +6,4 @@ PyFile:shellAssignment2.py
PsiElement(Py:EQ)('=')
PsiWhiteSpace(' ')
PyEmptyExpression
PsiElement(Py:PLING)('!')
PsiElement(Py:IDENTIFIER)('ls')
PsiWhiteSpace(' ')
PsiElement(Py:MINUS)('-')
PsiElement(Py:IDENTIFIER)('la')
PsiElement(Py:SHELL_COMMAND)('!ls -la')

View File

@@ -4,8 +4,6 @@ PyFile:shellError.py
PsiElement(Py:IDENTIFIER)('int')
PsiErrorElement:End of statement expected
<empty list>
PsiElement(Py:PLING)('!')
PsiErrorElement:Identifier expected
<empty list>
PsiErrorElement:Statement expected, found Py:PLING
PsiElement(Py:SHELL_COMMAND)('!')
PsiErrorElement:Statement expected, found Py:SHELL_COMMAND
<empty list>

View File

@@ -1,15 +1,3 @@
PyFile:shellExpansion.py
PyEmptyExpression
PsiElement(Py:PLING)('!')
PsiElement(Py:IDENTIFIER)('mv')
PsiWhiteSpace(' ')
PsiElement(Py:DOLLAR)('$')
PsiElement(Py:IDENTIFIER)('file')
PsiWhiteSpace(' ')
PsiElement(Py:LBRACE)('{')
PsiElement(Py:IDENTIFIER)('file')
PsiElement(Py:DOT)('.')
PsiElement(Py:IDENTIFIER)('upper')
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RBRACE)('}')
PsiElement(Py:SHELL_COMMAND)('!mv $file {file.upper()}')

View File

@@ -0,0 +1,36 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"!rm -r /to/folder"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

View File

@@ -0,0 +1,36 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"!rm -r /to/folder"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 0
}