public void commentRange( int startOffset, int endOffset, String commentPrefix, String commentSuffix, Commenter commenter) { final CharSequence chars = myDocument.getCharsSequence(); LogicalPosition caretPosition = myCaret.getLogicalPosition(); if (startOffset == 0 || chars.charAt(startOffset - 1) == '\n') { if (endOffset == myDocument.getTextLength() || endOffset > 0 && chars.charAt(endOffset - 1) == '\n') { CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(myProject); CommonCodeStyleSettings settings = CodeStyleSettingsManager.getSettings(myProject).getCommonSettings(myFile.getLanguage()); String space; if (!settings.BLOCK_COMMENT_AT_FIRST_COLUMN) { final FileType fileType = myFile.getFileType(); int line1 = myEditor.offsetToLogicalPosition(startOffset).line; int line2 = myEditor.offsetToLogicalPosition(endOffset - 1).line; Indent minIndent = CommentUtil.getMinLineIndent(myProject, myDocument, line1, line2, fileType); if (minIndent == null) { minIndent = codeStyleManager.zeroIndent(); } space = codeStyleManager.fillIndent(minIndent, fileType); } else { space = ""; } final StringBuilder nestingPrefix = new StringBuilder(space).append(commentPrefix); if (!commentPrefix.endsWith("\n")) { nestingPrefix.append("\n"); } final StringBuilder nestingSuffix = new StringBuilder(space); nestingSuffix.append( commentSuffix.startsWith("\n") ? commentSuffix.substring(1) : commentSuffix); nestingSuffix.append("\n"); TextRange range = insertNestedComments( startOffset, endOffset, nestingPrefix.toString(), nestingSuffix.toString(), commenter); myCaret.setSelection(range.getStartOffset(), range.getEndOffset()); LogicalPosition pos = new LogicalPosition(caretPosition.line + 1, caretPosition.column); myCaret.moveToLogicalPosition(pos); return; } } TextRange range = insertNestedComments(startOffset, endOffset, commentPrefix, commentSuffix, commenter); myCaret.setSelection(range.getStartOffset(), range.getEndOffset()); LogicalPosition pos = new LogicalPosition(caretPosition.line, caretPosition.column + commentPrefix.length()); myCaret.moveToLogicalPosition(pos); }
private static void restoreBlockSelection( Editor editor, List<RangeMarker> caretsAfter, int caretLine) { int column = -1; int minLine = Integer.MAX_VALUE; int maxLine = -1; for (RangeMarker marker : caretsAfter) { if (marker.isValid()) { LogicalPosition lp = editor.offsetToLogicalPosition(marker.getStartOffset()); if (column == -1) { column = lp.column; } else if (column != lp.column) { return; } minLine = Math.min(minLine, lp.line); maxLine = Math.max(maxLine, lp.line); if (lp.line == caretLine) { editor.getCaretModel().moveToLogicalPosition(lp); } } } editor .getSelectionModel() .setBlockSelection( new LogicalPosition(minLine, column), new LogicalPosition(maxLine, column)); }
private void updateCursorHighlighting(boolean scroll) { hideBalloon(); if (myCursorHighlighter != null) { HighlightManager.getInstance(mySearchResults.getProject()) .removeSegmentHighlighter(mySearchResults.getEditor(), myCursorHighlighter); myCursorHighlighter = null; } final FindResult cursor = mySearchResults.getCursor(); Editor editor = mySearchResults.getEditor(); SelectionModel selection = editor.getSelectionModel(); if (cursor != null) { Set<RangeHighlighter> dummy = new HashSet<RangeHighlighter>(); highlightRange( cursor, new TextAttributes(null, null, Color.BLACK, EffectType.ROUNDED_BOX, 0), dummy); if (!dummy.isEmpty()) { myCursorHighlighter = dummy.iterator().next(); } if (scroll) { if (mySearchResults.getFindModel().isGlobal()) { FoldingModel foldingModel = editor.getFoldingModel(); final FoldRegion[] allRegions = editor.getFoldingModel().getAllFoldRegions(); foldingModel.runBatchFoldingOperation( new Runnable() { @Override public void run() { for (FoldRegion region : allRegions) { if (!region.isValid()) continue; if (cursor.intersects(TextRange.create(region))) { region.setExpanded(true); } } } }); selection.setSelection(cursor.getStartOffset(), cursor.getEndOffset()); editor.getCaretModel().moveToOffset(cursor.getEndOffset()); editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); } else { if (!SearchResults.insideVisibleArea(editor, cursor)) { LogicalPosition pos = editor.offsetToLogicalPosition(cursor.getStartOffset()); editor.getScrollingModel().scrollTo(pos, ScrollType.CENTER); } } } editor .getScrollingModel() .runActionOnScrollingFinished( new Runnable() { @Override public void run() { showReplacementPreview(); } }); } }
private static void indentLinesIn( final Editor editor, final PsiFile file, final Document document, final Project project, RangeMarker range) { final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); int line1 = editor.offsetToLogicalPosition(range.getStartOffset()).line; int line2 = editor.offsetToLogicalPosition(range.getEndOffset()).line; while (!lineContainsNonSpaces(document, line1) && line1 < line2) line1++; while (!lineContainsNonSpaces(document, line2) && line1 < line2) line2--; final FileViewProvider provider = file.getViewProvider(); PsiFile rootToAdjustIndentIn = provider.getPsi(provider.getBaseLanguage()); codeStyleManager.adjustLineIndent( rootToAdjustIndentIn, new TextRange(document.getLineStartOffset(line1), document.getLineStartOffset(line2))); }
/** * Applies given caret/selection state to the editor. Editor text must have been set up * previously. */ public static void setCaretsAndSelection(Editor editor, CaretAndSelectionState caretsState) { CaretModel caretModel = editor.getCaretModel(); if (caretModel.supportsMultipleCarets()) { List<CaretState> states = new ArrayList<CaretState>(caretsState.carets.size()); for (CaretInfo caret : caretsState.carets) { states.add( new CaretState( caret.position == null ? null : editor.offsetToLogicalPosition(caret.getCaretOffset(editor.getDocument())), caret.selection == null ? null : editor.offsetToLogicalPosition(caret.selection.getStartOffset()), caret.selection == null ? null : editor.offsetToLogicalPosition(caret.selection.getEndOffset()))); } caretModel.setCaretsAndSelections(states); } else { assertEquals("Multiple carets are not supported by the model", 1, caretsState.carets.size()); CaretInfo caret = caretsState.carets.get(0); if (caret.position != null) { caretModel.moveToOffset(caret.getCaretOffset(editor.getDocument())); } if (caret.selection != null) { editor .getSelectionModel() .setSelection(caret.selection.getStartOffset(), caret.selection.getEndOffset()); } else { editor.getSelectionModel().removeSelection(); } } if (caretsState.blockSelection != null) { editor .getSelectionModel() .setBlockSelection( editor.offsetToLogicalPosition(caretsState.blockSelection.getStartOffset()), editor.offsetToLogicalPosition(caretsState.blockSelection.getEndOffset())); } }
/** * Calculates difference in columns between current editor caret position and end of the logical * line fragment displayed on a current visual line. * * @param editor target editor * @return difference in columns between current editor caret position and end of the logical line * fragment displayed on a current visual line */ public static int calcAfterLineEnd(Editor editor) { Document document = editor.getDocument(); CaretModel caretModel = editor.getCaretModel(); LogicalPosition logicalPosition = caretModel.getLogicalPosition(); int lineNumber = logicalPosition.line; int columnNumber = logicalPosition.column; if (lineNumber >= document.getLineCount()) { return columnNumber; } int caretOffset = caretModel.getOffset(); int anchorLineEndOffset = document.getLineEndOffset(lineNumber); List<? extends SoftWrap> softWraps = editor.getSoftWrapModel().getSoftWrapsForLine(logicalPosition.line); for (SoftWrap softWrap : softWraps) { if (!editor.getSoftWrapModel().isVisible(softWrap)) { continue; } int softWrapOffset = softWrap.getStart(); if (softWrapOffset == caretOffset) { // There are two possible situations: // *) caret is located on a visual line before soft wrap-introduced line feed; // *) caret is located on a visual line after soft wrap-introduced line feed; VisualPosition position = editor.offsetToVisualPosition(caretOffset - 1); VisualPosition visualCaret = caretModel.getVisualPosition(); if (position.line == visualCaret.line) { return visualCaret.column - position.column - 1; } } if (softWrapOffset > caretOffset) { anchorLineEndOffset = softWrapOffset; break; } // Same offset corresponds to all soft wrap-introduced symbols, however, current method should // behave differently in // situations when the caret is located just before the soft wrap and at the next visual line. if (softWrapOffset == caretOffset) { boolean visuallyBeforeSoftWrap = caretModel.getVisualPosition().line < editor.offsetToVisualPosition(caretOffset).line; if (visuallyBeforeSoftWrap) { anchorLineEndOffset = softWrapOffset; break; } } } int lineEndColumnNumber = editor.offsetToLogicalPosition(anchorLineEndOffset).column; return columnNumber - lineEndColumnNumber; }
private static void indentLinesIn( final Editor editor, final PsiFile file, final Document document, final Project project, RangeMarker range) { final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); int line1 = editor.offsetToLogicalPosition(range.getStartOffset()).line; int line2 = editor.offsetToLogicalPosition(range.getEndOffset()).line; /* if (PsiUtil.isInJspFile(file)) { // This version is slow because of each moved line cause commit // and right now we unable to fix JSP formatter quickly // TODO: remove this code for (int line = line1; line <= line2; line++) { if (lineContainsNonSpaces(document, line)) { int lineStart = document.getLineStartOffset(line); codeStyleManager.adjustLineIndent(document, lineStart); } } } else {*/ while (!lineContainsNonSpaces(document, line1) && line1 <= line2) line1++; while (!lineContainsNonSpaces(document, line2) && line2 > line1) line2--; try { final FileViewProvider provider = file.getViewProvider(); PsiFile rootToAdjustIndentIn = provider.getPsi(provider.getBaseLanguage()); codeStyleManager.adjustLineIndent( rootToAdjustIndentIn, new TextRange(document.getLineStartOffset(line1), document.getLineStartOffset(line2))); } catch (IncorrectOperationException ex) { throw new RuntimeException(ex); } /* } */ }
public static void verifyCaretAndSelectionState( Editor editor, CaretAndSelectionState caretState, String message) { boolean hasChecks = false; for (int i = 0; i < caretState.carets.size(); i++) { EditorTestUtil.CaretInfo expected = caretState.carets.get(i); if (expected.position != null || expected.selection != null) { hasChecks = true; break; } } if (!hasChecks) { return; // nothing to check, so we skip caret/selection assertions } String messageSuffix = message == null ? "" : (message + ": "); CaretModel caretModel = editor.getCaretModel(); List<Caret> allCarets = new ArrayList<Caret>(caretModel.getAllCarets()); assertEquals( messageSuffix + " Unexpected number of carets", caretState.carets.size(), allCarets.size()); for (int i = 0; i < caretState.carets.size(); i++) { String caretDescription = caretState.carets.size() == 1 ? "" : "caret " + (i + 1) + "/" + caretState.carets.size() + " "; Caret currentCaret = allCarets.get(i); int actualCaretLine = editor.getDocument().getLineNumber(currentCaret.getOffset()); int actualCaretColumn = currentCaret.getOffset() - editor.getDocument().getLineStartOffset(actualCaretLine); LogicalPosition actualCaretPosition = new LogicalPosition(actualCaretLine, actualCaretColumn); int selectionStart = currentCaret.getSelectionStart(); int selectionEnd = currentCaret.getSelectionEnd(); LogicalPosition actualSelectionStart = editor.offsetToLogicalPosition(selectionStart); LogicalPosition actualSelectionEnd = editor.offsetToLogicalPosition(selectionEnd); CaretInfo expected = caretState.carets.get(i); if (expected.position != null) { assertEquals( messageSuffix + caretDescription + "unexpected caret position", expected.position, actualCaretPosition); } if (expected.selection != null) { LogicalPosition expectedSelectionStart = editor.offsetToLogicalPosition(expected.selection.getStartOffset()); LogicalPosition expectedSelectionEnd = editor.offsetToLogicalPosition(expected.selection.getEndOffset()); assertEquals( messageSuffix + caretDescription + "unexpected selection start", expectedSelectionStart, actualSelectionStart); assertEquals( messageSuffix + caretDescription + "unexpected selection end", expectedSelectionEnd, actualSelectionEnd); } else { assertFalse( messageSuffix + caretDescription + "should has no selection, but was: (" + actualSelectionStart + ", " + actualSelectionEnd + ")", currentCaret.hasSelection()); } } }
private static void doPaste( final Editor editor, final Project project, final PsiFile file, final Document document, final Producer<Transferable> producer) { Transferable content = null; if (producer != null) { content = producer.produce(); } else { CopyPasteManager manager = CopyPasteManager.getInstance(); if (manager.areDataFlavorsAvailable(DataFlavor.stringFlavor)) { content = manager.getContents(); if (content != null) { manager.stopKillRings(); } } } if (content != null) { String text = null; try { text = (String) content.getTransferData(DataFlavor.stringFlavor); } catch (Exception e) { editor.getComponent().getToolkit().beep(); } if (text == null) return; final CodeInsightSettings settings = CodeInsightSettings.getInstance(); final Map<CopyPastePostProcessor, TextBlockTransferableData> extraData = new HashMap<CopyPastePostProcessor, TextBlockTransferableData>(); for (CopyPastePostProcessor processor : Extensions.getExtensions(CopyPastePostProcessor.EP_NAME)) { TextBlockTransferableData data = processor.extractTransferableData(content); if (data != null) { extraData.put(processor, data); } } text = TextBlockTransferable.convertLineSeparators(text, "\n", extraData.values()); final CaretModel caretModel = editor.getCaretModel(); final SelectionModel selectionModel = editor.getSelectionModel(); final int col = caretModel.getLogicalPosition().column; // There is a possible case that we want to perform paste while there is an active selection // at the editor and caret is located // inside it (e.g. Ctrl+A is pressed while caret is not at the zero column). We want to insert // the text at selection start column // then, hence, inserted block of text should be indented according to the selection start as // well. final int blockIndentAnchorColumn; final int caretOffset = caretModel.getOffset(); if (selectionModel.hasSelection() && caretOffset >= selectionModel.getSelectionStart()) { blockIndentAnchorColumn = editor.offsetToLogicalPosition(selectionModel.getSelectionStart()).column; } else { blockIndentAnchorColumn = col; } // We assume that EditorModificationUtil.insertStringAtCaret() is smart enough to remove // currently selected text (if any). RawText rawText = RawText.fromTransferable(content); String newText = text; for (CopyPastePreProcessor preProcessor : Extensions.getExtensions(CopyPastePreProcessor.EP_NAME)) { newText = preProcessor.preprocessOnPaste(project, file, editor, newText, rawText); } int indentOptions = text.equals(newText) ? settings.REFORMAT_ON_PASTE : CodeInsightSettings.REFORMAT_BLOCK; text = newText; if (LanguageFormatting.INSTANCE.forContext(file) == null && indentOptions != CodeInsightSettings.NO_REFORMAT) { indentOptions = CodeInsightSettings.INDENT_BLOCK; } final String _text = text; ApplicationManager.getApplication() .runWriteAction( new Runnable() { @Override public void run() { EditorModificationUtil.insertStringAtCaret(editor, _text, false, true); } }); int length = text.length(); int offset = caretModel.getOffset() - length; if (offset < 0) { length += offset; offset = 0; } final RangeMarker bounds = document.createRangeMarker(offset, offset + length); caretModel.moveToOffset(bounds.getEndOffset()); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); selectionModel.removeSelection(); final Ref<Boolean> indented = new Ref<Boolean>(Boolean.FALSE); for (Map.Entry<CopyPastePostProcessor, TextBlockTransferableData> e : extraData.entrySet()) { //noinspection unchecked e.getKey() .processTransferableData(project, editor, bounds, caretOffset, indented, e.getValue()); } boolean pastedTextContainsWhiteSpacesOnly = CharArrayUtil.shiftForward(document.getCharsSequence(), bounds.getStartOffset(), " \n\t") >= bounds.getEndOffset(); VirtualFile virtualFile = file.getVirtualFile(); if (!pastedTextContainsWhiteSpacesOnly && (virtualFile == null || !SingleRootFileViewProvider.isTooLargeForIntelligence(virtualFile))) { final int indentOptions1 = indentOptions; ApplicationManager.getApplication() .runWriteAction( new Runnable() { @Override public void run() { switch (indentOptions1) { case CodeInsightSettings.INDENT_BLOCK: if (!indented.get()) { indentBlock( project, editor, bounds.getStartOffset(), bounds.getEndOffset(), blockIndentAnchorColumn); } break; case CodeInsightSettings.INDENT_EACH_LINE: if (!indented.get()) { indentEachLine( project, editor, bounds.getStartOffset(), bounds.getEndOffset()); } break; case CodeInsightSettings.REFORMAT_BLOCK: indentEachLine( project, editor, bounds.getStartOffset(), bounds .getEndOffset()); // this is needed for example when inserting a // comment before method reformatBlock( project, editor, bounds.getStartOffset(), bounds.getEndOffset()); break; } } }); } if (bounds.isValid()) { caretModel.moveToOffset(bounds.getEndOffset()); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); selectionModel.removeSelection(); editor.putUserData(EditorEx.LAST_PASTED_REGION, TextRange.create(bounds)); } } }