mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-87824 convert string to multiline
This commit is contained in:
+2
@@ -0,0 +1,2 @@
|
||||
print <spot>'''first
|
||||
second'''</spot>
|
||||
+1
@@ -0,0 +1 @@
|
||||
print <spot>'first\n second'</spot>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention converts singleline string literal to multiline literal.
|
||||
</body>
|
||||
</html>
|
||||
@@ -1106,6 +1106,11 @@
|
||||
<categoryKey>intention.category.groovy/intention.category.conversions</categoryKey>
|
||||
<className>org.jetbrains.plugins.groovy.intentions.conversions.ConvertMethodToClosureIntention</className>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<bundleName>org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle</bundleName>
|
||||
<categoryKey>intention.category.groovy/intention.category.conversions</categoryKey>
|
||||
<className>org.jetbrains.plugins.groovy.intentions.conversions.ConvertStringToMultilineIntention</className>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<bundleName>org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle</bundleName>
|
||||
<categoryKey>intention.category.groovy/intention.category.conversions</categoryKey>
|
||||
|
||||
+2
@@ -81,6 +81,8 @@ convert.closure.to.method.intention.name=Convert to method
|
||||
convert.closure.to.method.intention.family.name=Convert property to method
|
||||
convert.method.to.closure.intention.name=Convert to property
|
||||
convert.method.to.closure.intention.family.name=Convert method to property of closure type
|
||||
convert.string.to.multiline.intention.name=Convert to Multiline
|
||||
convert.string.to.multiline.intention.family.name=Convert literal to multiline literal
|
||||
convert.junit.assertion.to.assert.statement.intention.name=Convert JUnit assertion to assert statement
|
||||
convert.junit.assertion.to.assert.statement.intention.family.name=Convert JUnit assertion to assert statement
|
||||
###########################################################################################################
|
||||
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.intentions.conversions;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.intentions.base.Intention;
|
||||
import org.jetbrains.plugins.groovy.intentions.base.PsiElementPredicate;
|
||||
import org.jetbrains.plugins.groovy.lang.editor.actions.GroovyEditorActionUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrStringImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
|
||||
|
||||
/**
|
||||
* @author Max Medvedev
|
||||
*/
|
||||
public class ConvertStringToMultilineIntention extends Intention {
|
||||
private static final Logger LOG = Logger.getInstance(ConvertStringToMultilineIntention.class);
|
||||
|
||||
public static final String hint = "Convert to Multiline";
|
||||
|
||||
@Override
|
||||
protected void processIntention(@NotNull PsiElement element, Project project, Editor editor) throws IncorrectOperationException {
|
||||
String quote = element.getText().startsWith("'") ? "'''" : "\"\"\"";
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append(quote);
|
||||
|
||||
GrExpression old;
|
||||
|
||||
if (element instanceof GrLiteralImpl) {
|
||||
appendSimpleStringValue(element, buffer, quote);
|
||||
old = (GrExpression)element;
|
||||
}
|
||||
else {
|
||||
final GrStringImpl gstring = PsiTreeUtil.getParentOfType(element, GrStringImpl.class);
|
||||
for (ASTNode child = gstring.getNode().getFirstChildNode(); child != null; child = child.getTreeNext()) {
|
||||
if (child.getElementType() == GroovyTokenTypes.mGSTRING_CONTENT) {
|
||||
appendGStringContent(child, buffer);
|
||||
}
|
||||
else if (child.getElementType() == GroovyElementTypes.GSTRING_INJECTION) {
|
||||
buffer.append(child.getText());
|
||||
}
|
||||
}
|
||||
old = gstring;
|
||||
}
|
||||
|
||||
buffer.append(quote);
|
||||
try {
|
||||
final GrExpression newLiteral = GroovyPsiElementFactory.getInstance(project).createExpressionFromText(buffer.toString());
|
||||
old.replaceWithExpression(newLiteral, true);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendGStringContent(ASTNode child, StringBuilder buffer) {
|
||||
final String text = child.getText();
|
||||
final StringBuilder parsed = new StringBuilder();
|
||||
if (GrStringUtil.parseStringCharacters(text, parsed, null)) {
|
||||
buffer.append(parsed);
|
||||
}
|
||||
else {
|
||||
buffer.append(text);
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendSimpleStringValue(PsiElement element, StringBuilder buffer, String quote) {
|
||||
final Object value = ((GrLiteralImpl)element).getValue();
|
||||
if (value instanceof String) {
|
||||
if ("'''".equals(quote)) {
|
||||
GrStringUtil.escapeStringCharacters(((String)value).length(), (String)value, "", false, true, buffer);
|
||||
}
|
||||
else {
|
||||
GrStringUtil.escapeSymbolsForGString((CharSequence)value, false, false, buffer);
|
||||
}
|
||||
}
|
||||
else {
|
||||
buffer.append(GrStringUtil.removeQuotes(element.getText()));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected PsiElementPredicate getElementPredicate() {
|
||||
return new PsiElementPredicate() {
|
||||
@Override
|
||||
public boolean satisfiedBy(PsiElement element) {
|
||||
if (element instanceof GrLiteralImpl) {
|
||||
final ASTNode node = element.getFirstChild().getNode();
|
||||
final IElementType type = node.getElementType();
|
||||
if (type == GroovyTokenTypes.mSTRING_LITERAL) {
|
||||
return GroovyEditorActionUtil.isPlainStringLiteral(node);
|
||||
}
|
||||
if (type == GroovyTokenTypes.mGSTRING_LITERAL) {
|
||||
return GroovyEditorActionUtil.isPlainGString(node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
final GrStringImpl gstring = PsiTreeUtil.getParentOfType(element, GrStringImpl.class, false, GrMember.class, GroovyFile.class);
|
||||
if (gstring == null) return false;
|
||||
return gstring.isPlainString();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -248,7 +248,7 @@ public class GrStringUtil {
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
private static void escapeSymbolsForGString(CharSequence s, boolean isSingleLine, boolean forInjection, StringBuilder b) {
|
||||
public static void escapeSymbolsForGString(CharSequence s, boolean isSingleLine, boolean forInjection, StringBuilder b) {
|
||||
escapeStringCharacters(s.length(), s, isSingleLine ? "$\"" : "$", isSingleLine, true, b);
|
||||
if (!forInjection) {
|
||||
unescapeCharacters(b, isSingleLine ? "'" : "'\"", true);
|
||||
@@ -828,4 +828,28 @@ public class GrStringUtil {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void getOperandText(@NotNull GrLiteral operand, @NotNull StringBuilder builder) {
|
||||
if (operand instanceof GrRegex) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
parseRegexCharacters(removeQuotes(operand.getText()), b, null, operand.getText().startsWith("/"));
|
||||
escapeSymbolsForGString(b, false, false);
|
||||
}
|
||||
else if (operand instanceof GrString) {
|
||||
builder.append(removeQuotes(operand.getText()));
|
||||
}
|
||||
else {
|
||||
Object value = operand.getValue();
|
||||
if (value == null) {
|
||||
value = removeQuotes(operand.getText());
|
||||
}
|
||||
|
||||
String text = value.toString();
|
||||
StringBuilder buffer = new StringBuilder(text.length());
|
||||
boolean containsLineFeeds = text.indexOf('\n') >= 0 || text.indexOf('\r') >= 0;
|
||||
escapeStringCharacters(text.length(), text, "$", false, true, buffer);
|
||||
unescapeCharacters(buffer, containsLineFeeds?"'\"":"'", containsLineFeeds);
|
||||
builder.append(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.intentions
|
||||
|
||||
import com.intellij.openapi.application.WriteAction
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.jetbrains.plugins.groovy.LightGroovyTestCase
|
||||
import org.jetbrains.plugins.groovy.intentions.conversions.ConvertStringToMultilineIntention
|
||||
|
||||
/**
|
||||
* @author Max Medvedev
|
||||
*/
|
||||
public class ConvertStringToMultilineTest extends LightGroovyTestCase {
|
||||
@Override
|
||||
protected String getBasePath() {''}
|
||||
|
||||
void testPlainString() {
|
||||
doTest("print 'ab<caret>c'", "print '''abc'''")
|
||||
}
|
||||
|
||||
void testGString() {
|
||||
doTest('print "ab<caret>c"', 'print """abc"""')
|
||||
}
|
||||
|
||||
void testPlainString2() {
|
||||
doTest("print 'a\\nb<caret>c'", "print '''a\nbc'''")
|
||||
}
|
||||
|
||||
void testGString2() {
|
||||
doTest('print "a\\nb<caret>c"', 'print """a\nbc"""')
|
||||
}
|
||||
|
||||
void testGString3() {
|
||||
doTest('print "a\\nb${a<caret>}c"', 'print """a\nb${a}c"""')
|
||||
}
|
||||
|
||||
void testAlreadyMultiline() {
|
||||
doTest('print """a<caret>bc"""', null)
|
||||
}
|
||||
|
||||
private doTest(String before, @Nullable String after) {
|
||||
myFixture.with {
|
||||
configureByText('_.groovy', before)
|
||||
def intentions = filterAvailableIntentions(ConvertStringToMultilineIntention.hint)
|
||||
if (!after) {
|
||||
assertEmpty(intentions)
|
||||
return
|
||||
}
|
||||
|
||||
assertOneElement(intentions)
|
||||
def accessToken = WriteAction.start()
|
||||
try {
|
||||
intentions[0].invoke(project, editor, file)
|
||||
}
|
||||
finally {
|
||||
accessToken.finish()
|
||||
}
|
||||
checkResult(after)
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -51,7 +51,7 @@ class CreateFieldFromParameterTest extends LightCodeInsightFixtureTestCase {
|
||||
void testTypeParameter() {doTest()}
|
||||
|
||||
private void doTest() {
|
||||
myFixture.configureByFile("before${getTestName(true)}.groovy")
|
||||
myFixture.configureByFile("before${getTestName(false)}.groovy")
|
||||
def intentions = myFixture.availableIntentions
|
||||
for (intention in intentions) {
|
||||
if (intention instanceof IntentionActionWrapper) intention = intention.delegate
|
||||
@@ -61,6 +61,6 @@ class CreateFieldFromParameterTest extends LightCodeInsightFixtureTestCase {
|
||||
break
|
||||
}
|
||||
}
|
||||
myFixture.checkResultByFile("after${getTestName(true)}.groovy")
|
||||
myFixture.checkResultByFile("after${getTestName(false)}.groovy")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user