/* * Copyright 2011-2017 Kay Stenschke * * 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.kstenschke.shifter.models; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.project.Project; import com.kstenschke.shifter.models.shiftableTypes.Css; import com.kstenschke.shifter.resources.StaticTexts; import com.kstenschke.shifter.utils.UtilsEnvironment; import com.kstenschke.shifter.utils.UtilsFile; import com.kstenschke.shifter.utils.UtilsTextual; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.List; // Shiftable (non-block) selection public class ShiftableSelection { /** * @param editor * @param caretOffset * @param isUp Are we shifting up or down? * @param moreCount Current "more" count, starting w/ 1. If non-more shift: null */ public static void shiftSelectionInDocument(Editor editor, Integer caretOffset, boolean isUp, @Nullable Integer moreCount) { Document document = editor.getDocument(); String filename = UtilsEnvironment.getDocumentFilename(document); Project project = editor.getProject(); SelectionModel selectionModel = editor.getSelectionModel(); int offsetStart = selectionModel.getSelectionStart(); int offsetEnd = selectionModel.getSelectionEnd(); CharSequence editorText = document.getCharsSequence(); String selectedText = UtilsTextual.getSubString(editorText, offsetStart, offsetEnd); if (selectedText == null || selectedText.trim().isEmpty()) { return; } if (com.kstenschke.shifter.models.shiftableTypes.PhpDocComment.isPhpDocComment(selectedText) && com.kstenschke.shifter.models.shiftableTypes.PhpDocComment.containsAtParam(selectedText)) { String shifted = com.kstenschke.shifter.models.shiftableTypes.PhpDocComment.getShifted(selectedText); if (!shifted.equals(selectedText)) { // PHP doc comment block: guess missing data shiftableTypes by resp. variable names document.replaceString(offsetStart, offsetEnd, shifted); UtilsEnvironment.reformatSubString(editor, project, offsetStart, offsetEnd); return; } } // Shift selected comment: Must be before multi-line sort to allow multi-line comment shifting if (com.kstenschke.shifter.models.shiftableTypes.Comment.isComment(selectedText) && shiftSelectedCommentInDocument(editor, document, filename, project, offsetStart, offsetEnd, selectedText)) { return; } int lineNumberSelStart = document.getLineNumber(offsetStart); int lineNumberSelEnd = document.getLineNumber(offsetEnd); if (document.getLineStartOffset(lineNumberSelEnd) == offsetEnd) { lineNumberSelEnd--; } ShiftableTypesManager shiftingShiftableTypesManager = new ShiftableTypesManager(); int wordType = shiftingShiftableTypesManager.getWordType(selectedText, editorText, offsetStart, filename); boolean isPhpVariable = wordType == ShiftableTypesManager.TYPE_PHP_VARIABLE; boolean isJsVarsDeclarations = !isPhpVariable && wordType == ShiftableTypesManager.TYPE_JS_VARIABLES_DECLARATIONS; boolean containsQuotes = UtilsTextual.containsQuotes(selectedText); boolean isMultiLine = UtilsTextual.isMultiLine(selectedText); if (UtilsFile.isCssFile(filename) && isMultiLine) { // Sort attributes per selector alphabetically String shifted = Css.getShifted(selectedText); if (null != shifted) { document.replaceString(offsetStart, offsetEnd, shifted); UtilsEnvironment.reformatSubString(editor, project, offsetStart, offsetStart + shifted.length()); return; } } if (!isJsVarsDeclarations && ((lineNumberSelEnd - lineNumberSelStart) > 0 && !isPhpVariable)) { // Selection is multi-lined: sort lines or swap quotes new ShiftableSelectionWithPopup(project, document, offsetStart, offsetEnd).sortLinesOrSwapQuotesInDocument(isUp); return; } if (isJsVarsDeclarations) { document.replaceString(offsetStart, offsetEnd, com.kstenschke.shifter.models.shiftableTypes.JsVariablesDeclarations.getShifted(selectedText)); return; } if (!isPhpVariable && wordType == ShiftableTypesManager.TYPE_SIZZLE_SELECTOR) { document.replaceString(offsetStart, offsetEnd, com.kstenschke.shifter.models.shiftableTypes.SizzleSelector.getShifted(selectedText)); return; } if (wordType == ShiftableTypesManager.TYPE_TRAILING_COMMENT) { int offsetStartCaretLine = document.getLineStartOffset(lineNumberSelStart); int offsetEndCaretLine = document.getLineEndOffset(lineNumberSelStart); String leadWhitespace = UtilsTextual.getLeadWhitespace(editorText.subSequence(offsetStartCaretLine, offsetEndCaretLine).toString()); String caretLine = editorText.subSequence(offsetStartCaretLine, offsetEndCaretLine).toString(); document.replaceString(offsetStartCaretLine, offsetEndCaretLine, com.kstenschke.shifter.models.shiftableTypes.TrailingComment.getShifted(caretLine, leadWhitespace)); return; } if (!isPhpVariable && UtilsFile.isPhpFile(filename) && shiftSelectionInPhpDocument(document, filename, project, offsetStart, offsetEnd, selectedText, containsQuotes)) { return; } if (com.kstenschke.shifter.models.shiftableTypes.TernaryExpression.isTernaryExpression(selectedText, "")) { document.replaceString(offsetStart, offsetEnd, com.kstenschke.shifter.models.shiftableTypes.TernaryExpression.getShifted(selectedText)); return; } if (!isPhpVariable) { if (com.kstenschke.shifter.models.shiftableTypes.SeparatedList.isSeparatedList(selectedText,",")) { // Comma-separated list new ShiftableSelectionWithPopup(project, document, offsetStart, offsetEnd).sortListOrSwapQuotesInDocument(",(\\s)*", ", ", isUp); return; } if (com.kstenschke.shifter.models.shiftableTypes.SeparatedList.isSeparatedList(selectedText,"|")) { // Pipe-separated list new ShiftableSelectionWithPopup(project, document, offsetStart, offsetEnd).sortListOrSwapQuotesInDocument("\\|(\\s)*", "|", isUp); return; } if (containsQuotes) { document.replaceString(offsetStart, offsetEnd, UtilsTextual.swapQuotes(selectedText)); return; } if (com.kstenschke.shifter.models.shiftableTypes.StringCamelCase.isCamelCase(selectedText) && com.kstenschke.shifter.models.shiftableTypes.StringCamelCase.isWordPair(selectedText)) { document.replaceString(offsetStart, offsetEnd, com.kstenschke.shifter.models.shiftableTypes.StringCamelCase.flipWordPairOrder(selectedText)); return; } com.kstenschke.shifter.models.shiftableTypes.Tupel wordsTupel = new com.kstenschke.shifter.models.shiftableTypes.Tupel(); if (wordsTupel.isWordsTupel(selectedText)) { document.replaceString(offsetStart, offsetEnd, wordsTupel.getShifted(selectedText)); return; } if (UtilsTextual.containsSlashes(selectedText)) { document.replaceString(offsetStart, offsetEnd, UtilsTextual.swapSlashes(selectedText)); return; } if (com.kstenschke.shifter.models.shiftableTypes.LogicalOperator.isLogicalOperator(selectedText)) { document.replaceString(offsetStart, offsetEnd, com.kstenschke.shifter.models.shiftableTypes.LogicalOperator.getShifted(selectedText)); return; } if (com.kstenschke.shifter.models.shiftableTypes.StringHtmlEncodable.isHtmlEncodable(selectedText)) { document.replaceString(offsetStart, offsetEnd, com.kstenschke.shifter.models.shiftableTypes.StringHtmlEncodable.getShifted(selectedText)); return; } } String shiftedWord = shiftingShiftableTypesManager.getShiftedWord(selectedText, isUp, editorText, caretOffset, moreCount, filename, editor); if (isPhpVariable) { document.replaceString(offsetStart, offsetEnd, shiftedWord); return; } if (UtilsTextual.isAllUppercase(selectedText)) { document.replaceString(offsetStart, offsetEnd, shiftedWord.toUpperCase()); return; } if (UtilsTextual.isUpperCamelCase(selectedText) || UtilsTextual.isUcFirst(selectedText)) { document.replaceString(offsetStart, offsetEnd, UtilsTextual.toUcFirst(shiftedWord)); return; } document.replaceString(offsetStart, offsetEnd, shiftedWord); } private static boolean shiftSelectionInPhpDocument(Document document, String filename, Project project, int offsetStart, int offsetEnd, String selectedText, boolean containsQuotes) { com.kstenschke.shifter.models.shiftableTypes.PhpConcatenation phpConcatenation = new com.kstenschke.shifter.models.shiftableTypes.PhpConcatenation(selectedText); if (phpConcatenation.isPhpConcatenation()) { new ShiftableSelectionWithPopup(project, document, offsetStart, offsetEnd).shiftPhpConcatenationOrSwapQuotesInDocument(phpConcatenation); return true; } if (com.kstenschke.shifter.models.shiftableTypes.Comment.isHtmlComment(selectedText)) { document.replaceString(offsetStart, offsetEnd, com.kstenschke.shifter.models.shiftableTypes.Comment.getPhpBlockCommentFromHtmlComment(selectedText)); return true; } if (com.kstenschke.shifter.models.shiftableTypes.Comment.isPhpBlockComment(selectedText)) { document.replaceString(offsetStart, offsetEnd, com.kstenschke.shifter.models.shiftableTypes.Comment.getShifted(selectedText, filename, project)); return true; } return false; } private static boolean shiftSelectedCommentInDocument(Editor editor, Document document, String filename, Project project, int offsetStart, int offsetEnd, String selectedText) { if (UtilsTextual.isMultiLine(selectedText)) { if (filename.endsWith("js") && com.kstenschke.shifter.models.shiftableTypes.JsDoc.isJsDocBlock(selectedText) && com.kstenschke.shifter.models.shiftableTypes.JsDoc.correctDocBlockInDocument(editor, document, offsetStart, offsetEnd)) { return true; } if (com.kstenschke.shifter.models.shiftableTypes.Comment.isBlockComment(selectedText)) { com.kstenschke.shifter.models.shiftableTypes.Comment.shiftMultiLineBlockCommentInDocument(selectedText, project, document, offsetStart, offsetEnd); return true; } if (com.kstenschke.shifter.models.shiftableTypes.Comment.isMultipleSingleLineComments(selectedText)) { com.kstenschke.shifter.models.shiftableTypes.Comment.shiftMultipleSingleLineCommentsInDocument(selectedText, project, document, offsetStart, offsetEnd); return true; } } document.replaceString(offsetStart, offsetEnd, com.kstenschke.shifter.models.shiftableTypes.Comment.getShifted(selectedText, filename, project)); return true; } /** * Sort lines in document alphabetically ascending / descending * * @param shiftUp * @param lineNumberSelStart * @param lineNumberSelEnd */ protected static void sortLinesInDocument(Document document, boolean shiftUp, int lineNumberSelStart, int lineNumberSelEnd) { List<String> lines = UtilsTextual.extractLines(document, lineNumberSelStart, lineNumberSelEnd); List<String> linesSorted = UtilsTextual.sortLinesNatural(lines, shiftUp); String linesString = UtilsTextual.joinLines(linesSorted).toString(); if (UtilsTextual.hasDuplicateLines(linesString) && JOptionPane.showConfirmDialog( null, StaticTexts.MESSAGE_REDUCE_DUPLICATE_LINES, StaticTexts.TITLE_REDUCE_DUPLICATE_LINES, JOptionPane.OK_CANCEL_OPTION ) == JOptionPane.OK_OPTION) { linesString = UtilsTextual.reduceDuplicateLines(linesString); } int offsetLineStart = document.getLineStartOffset(lineNumberSelStart); int offsetLineEnd = document.getLineEndOffset(lineNumberSelEnd) + document.getLineSeparatorLength(lineNumberSelEnd); document.replaceString(offsetLineStart, offsetLineEnd, linesString); } }