/* * 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.*; import com.kstenschke.shifter.ShifterPreferences; import com.kstenschke.shifter.actions.ActionsPerformer; import com.kstenschke.shifter.resources.StaticTexts; import com.kstenschke.shifter.resources.ui.DialogNumericBlockOptions; import com.kstenschke.shifter.utils.UtilsEnvironment; import com.kstenschke.shifter.utils.UtilsTextual; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.Nullable; import java.util.List; // Shiftable block selection public class ShiftableBlockSelection { /** * @param blockSelectionStarts * @param blockSelectionEnds * @param editorText * @return boolean */ private static boolean areNumericValues(int[] blockSelectionStarts, int[] blockSelectionEnds, CharSequence editorText) { String currentItem; for (int i = 1; i < blockSelectionStarts.length; i++) { currentItem = editorText.subSequence(blockSelectionStarts[i], blockSelectionEnds[i]).toString(); if (!StringUtils.isNumeric(currentItem)) { return false; } } return true; } /** * @param blockSelectionStarts * @param blockSelectionEnds * @param editorText * @return boolean */ private static boolean areBlockItemsIdentical(int[] blockSelectionStarts, int[] blockSelectionEnds, CharSequence editorText) { String firstItem = editorText.subSequence(blockSelectionStarts[0], blockSelectionEnds[0]).toString(); String currentItem; for (int i = 1; i < blockSelectionStarts.length; i++) { currentItem = editorText.subSequence(blockSelectionStarts[i], blockSelectionEnds[i]).toString(); if (!currentItem.equals(firstItem)) { return false; } } return true; } /** * @param actionsPerformer * @param shiftUp * @param moreCount Current "more" count, starting w/ 1. If non-more shift: null */ public static void shiftBlockSelectionInDocument(ActionsPerformer actionsPerformer, boolean shiftUp, @Nullable Integer moreCount) { Editor editor = actionsPerformer.editor; if (null == editor) { return; } SelectionModel selectionModel = editor.getSelectionModel(); Document document = actionsPerformer.document; int[] blockSelectionStarts = selectionModel.getBlockSelectionStarts(); int[]blockSelectionEnds = selectionModel.getBlockSelectionEnds(); String documentText = document.getText(); if (ShiftableBlockSelection.areNumericValues(blockSelectionStarts, blockSelectionEnds, documentText)) { shiftNumericalBlockSelectionInDocument(shiftUp, editor, document, Integer.valueOf(documentText.subSequence(blockSelectionStarts[0], blockSelectionEnds[0]).toString()), documentText); return; } if (ShiftableBlockSelection.areBlockItemsIdentical(blockSelectionStarts, blockSelectionEnds, documentText)) { shiftIdenticalBlockItemsInDocument(shiftUp, moreCount, editor, document, blockSelectionStarts, blockSelectionEnds, documentText); } } public static void shiftIdenticalBlockItemsInDocument(boolean shiftUp, @Nullable Integer moreCount, Editor editor, Document document, int[] blockSelectionStarts, int[] blockSelectionEnds, String editorText) { String filename = UtilsEnvironment.getDocumentFilename(document); String word = editorText.subSequence(blockSelectionStarts[0], blockSelectionEnds[0]).toString(); String line = UtilsTextual.getLine(document, document.getLineNumber(blockSelectionStarts[0])).trim(); Integer wordOffset = UtilsTextual.getStartOfWordAtOffset(editorText, blockSelectionStarts[0]); String newWord = ShiftableWord.getShiftedWordInDocument(editor, shiftUp, filename, word, line, wordOffset, false, false, moreCount); if (newWord != null && !newWord.equals(word)) { for (int i = blockSelectionEnds.length - 1; i >= 0; i--) { document.replaceString(blockSelectionStarts[i], blockSelectionEnds[i], newWord); } } } /** * Ask whether to 1. replace by enumeration or 2. in/decrement each * * @param shiftUp * @param editor * @param document * @param integer * @param editorText */ public static void shiftNumericalBlockSelectionInDocument(boolean shiftUp, Editor editor, Document document, Integer integer, String editorText) { Integer firstNumber = integer; if (null == firstNumber) { firstNumber = 0; } DialogNumericBlockOptions optionsDialog = new DialogNumericBlockOptions(firstNumber); UtilsEnvironment.setDialogVisible(editor, ShifterPreferences.ID_DIALOG_NUMERIC_BLOCK_OPTIONS, optionsDialog, StaticTexts.TITLE_NUMERIC_BLOCK_OPTIONS); if (!optionsDialog.wasCancelled()) { if (optionsDialog.isShiftModeEnumerate()) { insertBlockEnumerationInDocument(editor, document, optionsDialog.getFirstNumber()); return; } inOrDecrementNumericBlockInDocument(editor, document, editorText, shiftUp); } } /** * Replace given block selection w/ enumeration starting w/ given value * * @param editor * @param document * @param firstNumber */ private static void insertBlockEnumerationInDocument(Editor editor, Document document, String firstNumber) { Integer currentValue = Integer.valueOf(firstNumber); if (null == currentValue) { currentValue = 0; } List<CaretState> caretsAndSelections = editor.getCaretModel().getCaretsAndSelections(); CaretState caretsAndSelection; LogicalPosition selectionStart; LogicalPosition selectionEnd; int offsetSelectionStart; int offsetSelectionEnd; for (CaretState caretsAndSelectionCurrent : caretsAndSelections) { caretsAndSelection = caretsAndSelectionCurrent; selectionStart = caretsAndSelection.getSelectionStart(); selectionEnd = caretsAndSelection.getSelectionEnd(); if (selectionStart != null && selectionEnd != null) { offsetSelectionStart = editor.logicalPositionToOffset(selectionStart); offsetSelectionEnd = editor.logicalPositionToOffset(selectionEnd); document.replaceString(offsetSelectionStart, offsetSelectionEnd, currentValue.toString()); currentValue++; } } } /** * Increment or decrement each item in given numeric block selection * * @param editor * @param document * @param editorText * @param shiftUp */ private static void inOrDecrementNumericBlockInDocument(Editor editor, Document document, String editorText, boolean shiftUp) { int addend = shiftUp ? 1 : -1; Integer value; List<CaretState> caretsAndSelections = editor.getCaretModel().getCaretsAndSelections(); CaretState caretsAndSelection; LogicalPosition selectionStart; LogicalPosition selectionEnd; int offsetSelectionStart; int offsetSelectionEnd; for (CaretState caretsAndSelectionCurrent : caretsAndSelections) { value = null; caretsAndSelection = caretsAndSelectionCurrent; selectionStart = caretsAndSelection.getSelectionStart(); selectionEnd = caretsAndSelection.getSelectionEnd(); if (selectionStart != null && selectionEnd != null) { offsetSelectionStart = editor.logicalPositionToOffset(selectionStart); offsetSelectionEnd = editor.logicalPositionToOffset(selectionEnd); try { value = Integer.valueOf(editorText.subSequence(offsetSelectionStart, offsetSelectionEnd).toString()); } catch (NumberFormatException e) { // Silently continue } if (null == value) { value = 0; } document.replaceString(offsetSelectionStart, offsetSelectionEnd, String.valueOf(value + addend)); } } } }