text blocks: add text block escaping (only escape """ and \) when pasting (IDEA-217353)

GitOrigin-RevId: 03db759d2b770edc191aa0614251bdbaaa1742ed
This commit is contained in:
Bas Leijdekkers
2019-08-01 01:02:50 +03:00
committed by intellij-monorepo-bot
parent 1094935f12
commit 507c853824
7 changed files with 75 additions and 23 deletions
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInsight.editorActions;
import com.intellij.application.options.CodeStyle;
@@ -135,7 +121,9 @@ public class StringLiteralCopyPasteProcessor implements CopyPastePreProcessor {
return escapeCharCharacters(text, token);
}
else if (isTextBlock(token)) {
return escapeTextBlock(text);
final String before = document.getText(new TextRange(selectionStart - 1, selectionStart));
final String after = document.getText(new TextRange(selectionEnd, selectionEnd + 1));
return escapeTextBlock(text, "\"".equals(before), "\"".equals(after));
}
return text;
}
@@ -241,13 +229,11 @@ public class StringLiteralCopyPasteProcessor implements CopyPastePreProcessor {
}
@NotNull
protected String escapeTextBlock(@NotNull String text) {
protected String escapeTextBlock(@NotNull String text, boolean escapeStartQuote, boolean escapeEndQuote) {
StringBuilder buffer = new StringBuilder(text.length());
final String[] lines = LineTokenizer.tokenize(text.toCharArray(), false, true);
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
//todo don't escape single quote; prefer \""" if the next char is not a quote
StringUtil.escapeStringCharacters(line.length(), line, buffer);
buffer.append(StringUtil.escapeTextBlockCharacters(lines[i], i == 0 && escapeStartQuote, i == lines.length - 1 && escapeEndQuote));
if (i < lines.length - 1) {
buffer.append("\n");
}
@@ -1,5 +1,5 @@
class C {
String empty = """
\"\"\"
target\"\"\"<caret>""";
\"""
target\""\"<caret>""";
}
@@ -0,0 +1,6 @@
class C {
String x = """
"\"
target\""
""";
}
@@ -0,0 +1,5 @@
class C {
String x = """
"<caret>"
""";
}
@@ -23,7 +23,11 @@ class JavaTextBlocksHighlightingTest : LightJavaCodeInsightFixtureTestCase() {
}
fun testEscapeQuotes() {
doTestPaste("\"\"\"\ntarget\"\"\"".trimIndent())
doTestPaste("\"\"\"\ntarget\"\"\"")
}
fun testEscapeQuotes2() {
doTestPaste("\"\ntarget\"")
}
fun testNoEscapeWhenNotInTextBlockContent() {
@@ -641,6 +641,51 @@ public class StringUtil extends StringUtilRt {
t != Character.CONTROL && t != Character.FORMAT && t != Character.PRIVATE_USE && t != Character.SURROGATE;
}
@NotNull
@Contract(pure = true)
public static String escapeTextBlockCharacters(@NotNull String s) {
return escapeTextBlockCharacters(s, false, true);
}
@NotNull
@Contract(pure = true)
public static String escapeTextBlockCharacters(@NotNull String s, boolean escapeStartQuote, boolean escapeEndQuote) {
int length = s.length();
StringBuilder result = new StringBuilder(length);
int q = 0;
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
if (c == '"') {
if (escapeStartQuote && i == 0) result.append('\\');
q++;
}
else {
appendQuotes(q, result);
if (c == '\\') result.append('\\');
result.append(c);
q = 0;
}
}
appendQuotes(q, result);
if (escapeEndQuote && result.charAt(result.length() - 1) == '"') {
result.insert(result.length() - 1, '\\');
}
return result.toString();
}
private static void appendQuotes(int quotes, StringBuilder result) {
int q = quotes;
while (q > 0) {
if (quotes >= 3) result.append('\\');
switch (q) {
default: result.append('"');
case 2: result.append('"');
case 1: result.append('"');
}
q -= 3;
}
}
@NotNull
@Contract(pure = true)
public static String escapeStringCharacters(@NotNull String s) {
@@ -268,6 +268,12 @@ public class StringUtilTest {
assertEquals("AspectJ (Syntax Highlighting Only)", StringUtil.capitalizeWords("AspectJ (syntax highlighting only)", true));
}
@Test
public void testEscapeTextBlockCharacters() {
assertEquals("\\\"\"\"\\\"\"\"\\\"\\\"", StringUtil.escapeTextBlockCharacters("\"\"\"\"\"\"\"\"", false, true));
assertEquals("\\\\", StringUtil.escapeTextBlockCharacters("\\", false, true));
}
@Test
public void testEscapeStringCharacters() {
assertEquals("\\\"\\n", StringUtil.escapeStringCharacters(3, "\\\"\n", "\"", false, new StringBuilder()).toString());