mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-8989 Several improvements in PyConvertTripleQuotedStringIntention
* Do not replace Python-specific escape sequences with StringUtil#escapeStringCharacter, take care of quotes only with StringUtil#escapeChar * Do not show intention for multiline raw strings, because we can't insert '\n' inside them. * Do not include empty line before closing triple quote in result, but insert '\n' in the line before * Do not place closing brace on its own line
This commit is contained in:
+35
-26
@@ -45,6 +45,9 @@ import java.util.List;
|
||||
*/
|
||||
public class PyConvertTripleQuotedStringIntention extends BaseIntentionAction {
|
||||
|
||||
public static final String TRIPLE_SINGLE_QUOTE = "'''";
|
||||
public static final String TRIPLE_DOUBLE_QUOTE = "\"\"\"";
|
||||
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return PyBundle.message("INTN.triple.quoted.string");
|
||||
@@ -69,11 +72,16 @@ public class PyConvertTripleQuotedStringIntention extends BaseIntentionAction {
|
||||
if (docStringOwner.getDocStringExpression() == string) return false;
|
||||
}
|
||||
String stringText = string.getText();
|
||||
|
||||
final int prefixLength = PyStringLiteralExpressionImpl.getPrefixLength(stringText);
|
||||
final String prefix = stringText.substring(0, prefixLength);
|
||||
if (StringUtil.containsIgnoreCase(prefix, "r")) {
|
||||
return false;
|
||||
}
|
||||
stringText = stringText.substring(prefixLength);
|
||||
if (stringText.length() >= 6) {
|
||||
if (stringText.startsWith("'''") && stringText.endsWith("'''") ||
|
||||
stringText.startsWith("\"\"\"") && stringText.endsWith("\"\"\"")) {
|
||||
if (stringText.startsWith(TRIPLE_SINGLE_QUOTE) && stringText.endsWith(TRIPLE_SINGLE_QUOTE) ||
|
||||
stringText.startsWith(TRIPLE_DOUBLE_QUOTE) && stringText.endsWith(TRIPLE_DOUBLE_QUOTE)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -89,31 +97,37 @@ public class PyConvertTripleQuotedStringIntention extends BaseIntentionAction {
|
||||
String stringText = string.getText();
|
||||
final int prefixLength = PyStringLiteralExpressionImpl.getPrefixLength(stringText);
|
||||
final String prefix = stringText.substring(0, prefixLength);
|
||||
final char firstQuote = stringText.substring(prefixLength).charAt(0);
|
||||
stringText = stringText.substring(prefixLength);
|
||||
final char firstQuote = stringText.charAt(0);
|
||||
|
||||
stringText = string.getStringValue();
|
||||
final List<String> subStrings = StringUtil.split(stringText, "\n", false, true);
|
||||
List<String> lines = StringUtil.split(stringText, "\n", true, false);
|
||||
final String lastLine = lines.get(lines.size() - 1);
|
||||
boolean lastLineExcluded = false;
|
||||
if (lastLine.equals(TRIPLE_SINGLE_QUOTE) || lastLine.equals(TRIPLE_DOUBLE_QUOTE)) {
|
||||
lastLineExcluded = true;
|
||||
lines = lines.subList(0, lines.size() - 1);
|
||||
}
|
||||
|
||||
final StringBuilder result = new StringBuilder();
|
||||
if (subStrings.size() != 1) {
|
||||
if (lines.size() != 1) {
|
||||
result.append("(");
|
||||
}
|
||||
boolean lastString = false;
|
||||
for (String s : subStrings) {
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
final String validSubstring = convertToValidSubString(lines.get(i), firstQuote);
|
||||
|
||||
final boolean isLastLine = i == lines.size() - 1;
|
||||
result.append(prefix);
|
||||
result.append(firstQuote);
|
||||
final String validSubstring = convertToValidSubString(s, firstQuote);
|
||||
|
||||
if (s.endsWith("'''") || s.endsWith("\"\"\"")) {
|
||||
lastString = true;
|
||||
}
|
||||
result.append(validSubstring);
|
||||
if (!isLastLine || lastLineExcluded) {
|
||||
result.append("\\n");
|
||||
}
|
||||
result.append(firstQuote);
|
||||
if (!lastString) {
|
||||
result.append(" ").append("\n");
|
||||
if (!isLastLine) {
|
||||
result.append("\n");
|
||||
}
|
||||
}
|
||||
if (subStrings.size() != 1) {
|
||||
if (lines.size() != 1) {
|
||||
result.append(")");
|
||||
}
|
||||
final PyExpressionStatement e = elementGenerator.createFromText(LanguageLevel.forElement(string), PyExpressionStatement.class, result.toString());
|
||||
@@ -131,19 +145,14 @@ public class PyConvertTripleQuotedStringIntention extends BaseIntentionAction {
|
||||
|
||||
@NotNull
|
||||
private static String convertToValidSubString(@NotNull String s, char firstQuote) {
|
||||
final String subString;
|
||||
if (s.startsWith("'''") || s.startsWith("\"\"\"")) {
|
||||
subString = convertToValidSubString(s.substring(3), firstQuote);
|
||||
if (s.startsWith(TRIPLE_SINGLE_QUOTE) || s.startsWith(TRIPLE_DOUBLE_QUOTE)) {
|
||||
return convertToValidSubString(s.substring(3), firstQuote);
|
||||
}
|
||||
else if (s.endsWith("'''") || s.endsWith("\"\"\"")) {
|
||||
final String trimmed = s.trim();
|
||||
subString = convertToValidSubString(trimmed.substring(0, trimmed.length() - 3), firstQuote);
|
||||
else if (s.endsWith(TRIPLE_SINGLE_QUOTE) || s.endsWith(TRIPLE_DOUBLE_QUOTE)) {
|
||||
return convertToValidSubString(s.substring(0, s.length() - 3), firstQuote);
|
||||
}
|
||||
else {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder = StringUtil.escapeStringCharacters(s.length(), s, String.valueOf(firstQuote), true, stringBuilder);
|
||||
subString = stringBuilder.toString();
|
||||
return StringUtil.escapeChar(s, firstQuote);
|
||||
}
|
||||
return subString;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
S = r"""foo<caret>
|
||||
bar"""
|
||||
@@ -1,7 +1,5 @@
|
||||
if True:
|
||||
if True:
|
||||
a = ('\'Hello\' - said man.\n'
|
||||
'\n'
|
||||
a = ('\'Hello\' - said man.\n\n'
|
||||
' Let\'s go.\n'
|
||||
' And they went out.'
|
||||
)
|
||||
' And they went out.')
|
||||
@@ -1,3 +1,2 @@
|
||||
s = ("\n"
|
||||
"my quote\" some text after it\n"
|
||||
)
|
||||
"my quote\" some text after it\n")
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
s = ("Hex escape\x01\n"
|
||||
"Octal escape\015\n"
|
||||
"Not standard short escape \v\n"
|
||||
"Unicode name escape \N{FF}\n"
|
||||
"Long Unicode escape \U00020002\n"
|
||||
"Should be escaped \" ")
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
s = """<caret>Hex escape\x01
|
||||
Octal escape\015
|
||||
Not standard short escape \v
|
||||
Unicode name escape \N{FF}
|
||||
Long Unicode escape \U00020002
|
||||
Should be escaped " """
|
||||
@@ -251,6 +251,22 @@ public class PyIntentionTest extends PyTestCase {
|
||||
doTest(PyBundle.message("INTN.triple.quoted.string"));
|
||||
}
|
||||
|
||||
// PY-8989
|
||||
public void testConvertTripleQuotedStringIsNotAvailableForRawStrings() {
|
||||
myFixture.configureByFile("intentions/" + getTestName(false) + ".py");
|
||||
assertEmpty(myFixture.filterAvailableIntentions(PyBundle.message("INTN.triple.quoted.string")));
|
||||
}
|
||||
|
||||
// PY-8989
|
||||
public void testConvertTripleQuotedStringDoesNotReplacePythonEscapes() {
|
||||
doTest(PyBundle.message("INTN.triple.quoted.string"), LanguageLevel.PYTHON33);
|
||||
}
|
||||
|
||||
// PY-8989
|
||||
public void testConvertTripleQuotedStringMultilineGluedString() {
|
||||
doTest(PyBundle.message("INTN.triple.quoted.string"), LanguageLevel.PYTHON33);
|
||||
}
|
||||
|
||||
public void testTransformConditionalExpression() { //PY-3094
|
||||
doTest(PyBundle.message("INTN.transform.into.if.else.statement"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user