com.jetbrains.python.codeInsight.intentions.PyConvertTripleQuotedStringIntention Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of python-community Show documentation
Show all versions of python-community Show documentation
A packaging of the IntelliJ Community Edition python-community library.
This is release number 1 of trunk branch 142.
The newest version!
/*
* Copyright 2000-2014 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 com.jetbrains.python.codeInsight.intentions;
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.PyUtil.StringNodeInfo;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* User: catherine
* Intention to convert triple quoted string to single-quoted
* For instance:
* from:
* a = """This line is ok,
* but "this" includes far too much
* whitespace at the start"""
* to:
* a = ("This line is ok," "\n"
* "but \"this\" includes far too much" "\n"
* "whitespace at the start")
*/
public class PyConvertTripleQuotedStringIntention extends BaseIntentionAction {
@NotNull
public String getFamilyName() {
return PyBundle.message("INTN.triple.quoted.string");
}
@NotNull
@Override
public String getText() {
return PyBundle.message("INTN.triple.quoted.string");
}
public boolean isAvailable(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
if (!(file instanceof PyFile)) {
return false;
}
final int caretOffset = editor.getCaretModel().getOffset();
final PyStringLiteralExpression pyString = PsiTreeUtil.getParentOfType(file.findElementAt(caretOffset), PyStringLiteralExpression.class);
if (pyString != null) {
final PyDocStringOwner docStringOwner = PsiTreeUtil.getParentOfType(pyString, PyDocStringOwner.class);
if (docStringOwner != null) {
if (docStringOwner.getDocStringExpression() == pyString) return false;
}
for (StringNodeInfo info : extractStringNodesInfo(pyString)) {
if (info.isTripleQuoted() && info.isTerminated() && info.getNode().getTextRange().contains(caretOffset)) {
return true;
}
}
}
return false;
}
public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) throws IncorrectOperationException {
final PyStringLiteralExpression pyString = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()),
PyStringLiteralExpression.class);
final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
if (pyString != null) {
final StringBuilder result = new StringBuilder();
final List nodeInfos = extractStringNodesInfo(pyString);
for (int i = 0; i < nodeInfos.size(); i++) {
final StringNodeInfo info = nodeInfos.get(i);
List lines = StringUtil.split(info.getContent(), "\n", true, false);
boolean lastLineExcluded = false;
if (lines.size() > 1 && lines.get(lines.size() - 1).isEmpty()) {
lastLineExcluded = true;
lines = lines.subList(0, lines.size() - 1);
}
final boolean inLastNode = i == nodeInfos.size() - 1;
for (int j = 0; j < lines.size(); j++) {
final String line = lines.get(j);
final boolean inLastLine = j == lines.size() - 1;
if (info.isRaw()) {
appendSplittedRawStringLine(result, info, line);
if (!inLastLine || lastLineExcluded) {
result.append(" ").append(info.getSingleQuote()).append("\\n").append(info.getSingleQuote());
}
}
else {
result.append(info.getPrefix());
result.append(info.getSingleQuote());
result.append(convertToValidSubString(line, info.getSingleQuote(), info.isTripleQuoted()));
if (!inLastLine || lastLineExcluded) {
result.append("\\n");
}
result.append(info.getSingleQuote());
}
if (!(inLastNode && inLastLine)) {
result.append("\n");
}
}
}
if (result.indexOf("\n") >= 0) {
result.insert(0, "(");
result.append(")");
}
PyExpression expression = elementGenerator.createExpressionFromText(LanguageLevel.forElement(pyString), result.toString());
final PsiElement parent = pyString.getParent();
if (expression instanceof PyParenthesizedExpression &&
(parent instanceof PyParenthesizedExpression ||
parent instanceof PyTupleExpression ||
parent instanceof PyArgumentList && ArrayUtil.getFirstElement(((PyArgumentList)parent).getArguments()) == pyString)) {
expression = ((PyParenthesizedExpression)expression).getContainedExpression();
}
if (expression != null) {
pyString.replace(expression);
}
}
}
private static void appendSplittedRawStringLine(@NotNull StringBuilder result, @NotNull StringNodeInfo info, @NotNull String line) {
boolean singleQuoteUsed = false, doubleQuoteUsed = false;
int chunkStart = 0;
boolean firstChunk = true;
for (int k = 0; k <= line.length(); k++) {
if (k < line.length()) {
singleQuoteUsed |= line.charAt(k) == '\'';
doubleQuoteUsed |= line.charAt(k) == '"';
}
final char chunkQuote;
if ((k == line.length() || line.charAt(k) == '\'') && doubleQuoteUsed) {
chunkQuote = '\'';
doubleQuoteUsed = false;
}
else if ((k == line.length() || line.charAt(k) == '"') && singleQuoteUsed) {
chunkQuote = '"';
singleQuoteUsed = false;
}
else if (k == line.length()) {
chunkQuote = info.getSingleQuote();
}
else {
continue;
}
if (!firstChunk) {
result.append(" ");
}
result.append(info.getPrefix()).append(chunkQuote).append(line.substring(chunkStart, k)).append(chunkQuote);
firstChunk = false;
chunkStart = k;
}
}
@NotNull
private static String convertToValidSubString(@NotNull String content, char newQuote, boolean isMultiline) {
return isMultiline ? StringUtil.escapeChar(content, newQuote) : content;
}
@NotNull
private static List extractStringNodesInfo(@NotNull PyStringLiteralExpression expression) {
return ContainerUtil.map(expression.getStringNodes(), new Function() {
@Override
public StringNodeInfo fun(ASTNode node) {
return new StringNodeInfo(node);
}
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy