From 50599de70d775bfaca4d9198bc2fb7500482ca0f Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 25 Mar 2011 22:06:42 +0100 Subject: [PATCH] IDEA-66777 (Pasting escapes quotes too eagerly) tests will follow --- .../StringLiteralCopyPasteProcessor.java | 78 ++++++++++++------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/StringLiteralCopyPasteProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/StringLiteralCopyPasteProcessor.java index 72edc6aeadb4..5f75e8d4d3af 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/StringLiteralCopyPasteProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/StringLiteralCopyPasteProcessor.java @@ -15,10 +15,12 @@ */ package com.intellij.codeInsight.editorActions; -import com.intellij.openapi.project.Project; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RawText; -import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.SelectionModel; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.LineTokenizer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; @@ -26,17 +28,13 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; public class StringLiteralCopyPasteProcessor implements CopyPastePreProcessor { public String preprocessOnCopy(final PsiFile file, final int[] startOffsets, final int[] endOffsets, final String text) { boolean isLiteral = true; for (int i = 0; i < startOffsets.length && isLiteral; i++) { - final int startOffset = startOffsets[i]; - final PsiElement elementAtCaret = file.findElementAt(startOffset); - if (!(elementAtCaret instanceof PsiJavaToken && - (((PsiJavaToken) elementAtCaret)).getTokenType() == JavaTokenType.STRING_LITERAL && - startOffset >= elementAtCaret.getTextRange().getStartOffset() && - endOffsets[i] <= elementAtCaret.getTextRange().getEndOffset())) { + if (findLiteralTokenType(file, startOffsets[i], endOffsets[i]) == null) { isLiteral = false; } } @@ -47,28 +45,54 @@ public class StringLiteralCopyPasteProcessor implements CopyPastePreProcessor { public String preprocessOnPaste(final Project project, final PsiFile file, final Editor editor, String text, final RawText rawText) { final Document document = editor.getDocument(); PsiDocumentManager.getInstance(project).commitDocument(document); - int caretOffset = editor.getCaretModel().getOffset(); - PsiElement elementAtCaret = file.findElementAt(caretOffset); - if (elementAtCaret instanceof PsiJavaToken && caretOffset > elementAtCaret.getTextOffset()) { - final IElementType tokenType = ((PsiJavaToken)elementAtCaret).getTokenType(); - if (tokenType == JavaTokenType.STRING_LITERAL) { - if (rawText != null && rawText.rawText != null) return rawText.rawText; // Copied from the string literal. Copy as is. + final SelectionModel selectionModel = editor.getSelectionModel(); - StringBuilder buffer = new StringBuilder(text.length()); - CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(project); - @NonNls String breaker = codeStyleSettings.BINARY_OPERATION_SIGN_ON_NEXT_LINE ? "\\n\"\n+ \"" : "\\n\" +\n\""; - final String[] lines = LineTokenizer.tokenize(text.toCharArray(), false, true); - for (int i = 0; i < lines.length; i++) { - String line = lines[i]; - buffer.append(StringUtil.escapeStringCharacters(line)); - if (i != lines.length - 1) buffer.append(breaker); - } - text = buffer.toString(); - } - else if (tokenType == JavaTokenType.CHARACTER_LITERAL) { - if (rawText != null && rawText.rawText != null) return rawText.rawText; // Copied from the string literal. Copy as is. + // pastes in block selection mode (column mode) are not handled by a CopyPasteProcessor + final int selectionStart = selectionModel.getSelectionStart(); + final int selectionEnd = selectionModel.getSelectionEnd(); + IElementType tokenType = findLiteralTokenType(file, selectionStart, selectionEnd); + + if (tokenType == JavaTokenType.STRING_LITERAL) { + if (rawText != null && rawText.rawText != null) return rawText.rawText; // Copied from the string literal. Copy as is. + + StringBuilder buffer = new StringBuilder(text.length()); + CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(project); + @NonNls String breaker = codeStyleSettings.BINARY_OPERATION_SIGN_ON_NEXT_LINE ? "\\n\"\n+ \"" : "\\n\" +\n\""; + final String[] lines = LineTokenizer.tokenize(text.toCharArray(), false, true); + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + buffer.append(StringUtil.escapeStringCharacters(line)); + if (i != lines.length - 1) buffer.append(breaker); } + text = buffer.toString(); + } + else if (tokenType == JavaTokenType.CHARACTER_LITERAL) { + if (rawText != null && rawText.rawText != null) return rawText.rawText; // Copied from the string literal. Copy as is. + return escapeCharCharacters(text); } return text; } + + private static IElementType findLiteralTokenType(PsiFile file, int selectionStart, int selectionEnd) { + final PsiElement elementAtSelection = file.findElementAt(selectionStart); + if (!(elementAtSelection instanceof PsiJavaToken)) { + return null; + } + final IElementType tokenType = ((PsiJavaToken)elementAtSelection).getTokenType(); + if ((tokenType != JavaTokenType.STRING_LITERAL && tokenType != JavaTokenType.CHARACTER_LITERAL)) { + return null; + } + final TextRange textRange = elementAtSelection.getTextRange(); + if (selectionStart <= textRange.getStartOffset() || selectionEnd >= textRange.getEndOffset()) { + return null; + } + return tokenType; + } + + @NotNull + public static String escapeCharCharacters(@NotNull String s) { + StringBuilder buffer = new StringBuilder(); + StringUtil.escapeStringCharacters(s.length(), s, "\'", buffer); + return buffer.toString(); + } }