public static PsiFile insertDummyIdentifier(final Editor editor, PsiFile file) { boolean selection = editor.getSelectionModel().hasSelection(); final int startOffset = selection ? editor.getSelectionModel().getSelectionStart() : editor.getCaretModel().getOffset(); final int endOffset = selection ? editor.getSelectionModel().getSelectionEnd() : startOffset; return insertDummyIdentifierIfNeeded( file, startOffset, endOffset, CompletionUtil.DUMMY_IDENTIFIER_TRIMMED); }
public void startTemplateWithPrefix( final Editor editor, final TemplateImpl template, final int templateStart, @Nullable final PairProcessor<String, String> processor, @Nullable final String argument) { final int caretOffset = editor.getCaretModel().getOffset(); final TemplateState templateState = initTemplateState(editor); CommandProcessor commandProcessor = CommandProcessor.getInstance(); commandProcessor.executeCommand( myProject, () -> { editor.getDocument().deleteString(templateStart, caretOffset); editor.getCaretModel().moveToOffset(templateStart); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); editor.getSelectionModel().removeSelection(); Map<String, String> predefinedVarValues = null; if (argument != null) { predefinedVarValues = new HashMap<String, String>(); predefinedVarValues.put(TemplateImpl.ARG, argument); } templateState.start(template, processor, predefinedVarValues); }, CodeInsightBundle.message("insert.code.template.command"), null); }
public static List<TemplateImpl> listApplicableTemplateWithInsertingDummyIdentifier( Editor editor, PsiFile file, boolean selectionOnly) { int startOffset = editor.getSelectionModel().getSelectionStart(); file = insertDummyIdentifier(editor, file); return listApplicableTemplates(file, startOffset, selectionOnly); }
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)); }
@Override public void execute( final Editor editor, final DataContext dataContext, @Nullable final Producer<Transferable> producer) { if (!CodeInsightUtilBase.prepareEditorForWrite(editor)) return; final Document document = editor.getDocument(); if (!FileDocumentManager.getInstance() .requestWriting(document, CommonDataKeys.PROJECT.getData(dataContext))) { return; } DataContext context = dataContext; if (producer != null) { context = new DataContext() { @Override public Object getData(@NonNls String dataId) { return PasteAction.TRANSFERABLE_PROVIDER.is(dataId) ? producer : dataContext.getData(dataId); } }; } final Project project = editor.getProject(); if (project == null || editor.isColumnMode() || editor.getSelectionModel().hasBlockSelection() || editor.getCaretModel().getCaretCount() > 1) { if (myOriginalHandler != null) { myOriginalHandler.execute(editor, context); } return; } final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document); if (file == null) { if (myOriginalHandler != null) { myOriginalHandler.execute(editor, context); } return; } document.startGuardedBlockChecking(); try { for (PasteProvider provider : Extensions.getExtensions(EP_NAME)) { if (provider.isPasteEnabled(context)) { provider.performPaste(context); return; } } doPaste(editor, project, file, document, producer); } catch (ReadOnlyFragmentModificationException e) { EditorActionManager.getInstance().getReadonlyFragmentModificationHandler(document).handle(e); } finally { document.stopGuardedBlockChecking(); } }
private void removeFromEditor() { Editor editor = mySearchResults.getEditor(); if (myReplacementBalloon != null) { myReplacementBalloon.hide(); } if (editor != null) { for (VisibleAreaListener visibleAreaListener : myVisibleAreaListenersToRemove) { editor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener); } myVisibleAreaListenersToRemove.clear(); Project project = mySearchResults.getProject(); if (project != null && !project.isDisposed()) { for (RangeHighlighter h : myHighlighters) { HighlightManager.getInstance(project).removeSegmentHighlighter(editor, h); } if (myCursorHighlighter != null) { HighlightManager.getInstance(project) .removeSegmentHighlighter(editor, myCursorHighlighter); myCursorHighlighter = null; } } myHighlighters.clear(); if (myListeningSelection) { editor.getSelectionModel().removeSelectionListener(this); myListeningSelection = false; } } }
public static void typeInStringAtCaretHonorBlockSelection( final Editor editor, final String str, final boolean toProcessOverwriteMode) throws ReadOnlyFragmentModificationException { Document doc = editor.getDocument(); final SelectionModel selectionModel = editor.getSelectionModel(); if (selectionModel.hasBlockSelection()) { RangeMarker guard = selectionModel.getBlockSelectionGuard(); if (guard != null) { DocumentEvent evt = new MockDocumentEvent(doc, editor.getCaretModel().getOffset()); ReadOnlyFragmentModificationException e = new ReadOnlyFragmentModificationException(evt, guard); EditorActionManager.getInstance().getReadonlyFragmentModificationHandler(doc).handle(e); } else { final LogicalPosition start = selectionModel.getBlockStart(); final LogicalPosition end = selectionModel.getBlockEnd(); assert start != null; assert end != null; int column = Math.min(start.column, end.column); int startLine = Math.min(start.line, end.line); int endLine = Math.max(start.line, end.line); deleteBlockSelection(editor); for (int i = startLine; i <= endLine; i++) { editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(i, column)); insertStringAtCaret(editor, str, toProcessOverwriteMode, true); } selectionModel.setBlockSelection( new LogicalPosition(startLine, column + str.length()), new LogicalPosition(endLine, column + str.length())); } } else { insertStringAtCaret(editor, str, toProcessOverwriteMode, true); } }
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 zeroWidthBlockSelectionAtCaretColumn( final Editor editor, final int startLine, final int endLine) { int caretColumn = editor.getCaretModel().getLogicalPosition().column; editor .getSelectionModel() .setBlockSelection( new LogicalPosition(startLine, caretColumn), new LogicalPosition(endLine, caretColumn)); }
public static int insertStringAtCaret( Editor editor, @NotNull String s, boolean toProcessOverwriteMode, boolean toMoveCaret, int caretShift) { final SelectionModel selectionModel = editor.getSelectionModel(); if (selectionModel.hasSelection()) { editor.getCaretModel().moveToOffset(selectionModel.getSelectionStart(), true); } // There is a possible case that particular soft wraps become hard wraps if the caret is located // at soft wrap-introduced virtual // space, hence, we need to give editor a chance to react accordingly. editor.getSoftWrapModel().beforeDocumentChangeAtCaret(); int oldOffset = editor.getCaretModel().getOffset(); String filler = calcStringToFillVirtualSpace(editor); if (filler.length() > 0) { s = filler + s; } Document document = editor.getDocument(); if (editor.isInsertMode() || !toProcessOverwriteMode) { if (selectionModel.hasSelection()) { oldOffset = selectionModel.getSelectionStart(); document.replaceString( selectionModel.getSelectionStart(), selectionModel.getSelectionEnd(), s); } else { document.insertString(oldOffset, s); } } else { deleteSelectedText(editor); int lineNumber = editor.getCaretModel().getLogicalPosition().line; if (lineNumber >= document.getLineCount()) { return insertStringAtCaret(editor, s, false, toMoveCaret); } int endOffset = document.getLineEndOffset(lineNumber); document.replaceString(oldOffset, Math.min(endOffset, oldOffset + s.length()), s); } int offset = oldOffset + filler.length() + caretShift; if (toMoveCaret) { editor.getCaretModel().moveToOffset(offset, true); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); selectionModel.removeSelection(); } else if (editor.getCaretModel().getOffset() != oldOffset) { // handling the case when caret model tracks document changes editor.getCaretModel().moveToOffset(oldOffset); } return offset; }
private static void restoreSelection( final Editor editor, final int selectionStart, final int selectionEnd, final int moveOffset, int insOffset) { final int selectionRelativeOffset = selectionStart - moveOffset; int newSelectionStart = insOffset + selectionRelativeOffset; int newSelectionEnd = newSelectionStart + selectionEnd - selectionStart; editor.getSelectionModel().setSelection(newSelectionStart, newSelectionEnd); }
/** * Emulates pressing <code>Enter</code> at current caret position. * * @param editor target editor * @param project target project * @param shifts two-elements array which is expected to be filled with the following info: 1. The * first element holds added lines number; 2. The second element holds added symbols number; */ private static void emulateEnter( @NotNull final Editor editor, @NotNull Project project, int[] shifts) { final DataContext dataContext = prepareContext(editor.getComponent(), project); int caretOffset = editor.getCaretModel().getOffset(); Document document = editor.getDocument(); SelectionModel selectionModel = editor.getSelectionModel(); int startSelectionOffset = 0; int endSelectionOffset = 0; boolean restoreSelection = selectionModel.hasSelection(); if (restoreSelection) { startSelectionOffset = selectionModel.getSelectionStart(); endSelectionOffset = selectionModel.getSelectionEnd(); selectionModel.removeSelection(); } int textLengthBeforeWrap = document.getTextLength(); int lineCountBeforeWrap = document.getLineCount(); DataManager.getInstance() .saveInDataContext(dataContext, WRAP_LONG_LINE_DURING_FORMATTING_IN_PROGRESS_KEY, true); CommandProcessor commandProcessor = CommandProcessor.getInstance(); try { Runnable command = new Runnable() { @Override public void run() { EditorActionManager.getInstance() .getActionHandler(IdeActions.ACTION_EDITOR_ENTER) .execute(editor, dataContext); } }; if (commandProcessor.getCurrentCommand() == null) { commandProcessor.executeCommand(editor.getProject(), command, WRAP_LINE_COMMAND_NAME, null); } else { command.run(); } } finally { DataManager.getInstance() .saveInDataContext(dataContext, WRAP_LONG_LINE_DURING_FORMATTING_IN_PROGRESS_KEY, null); } int symbolsDiff = document.getTextLength() - textLengthBeforeWrap; if (restoreSelection) { int newSelectionStart = startSelectionOffset; int newSelectionEnd = endSelectionOffset; if (startSelectionOffset >= caretOffset) { newSelectionStart += symbolsDiff; } if (endSelectionOffset >= caretOffset) { newSelectionEnd += symbolsDiff; } selectionModel.setSelection(newSelectionStart, newSelectionEnd); } shifts[0] = document.getLineCount() - lineCountBeforeWrap; shifts[1] = symbolsDiff; }
public static void pasteTransferableAsBlock( Editor editor, @Nullable Producer<Transferable> producer) { String text = getStringContent(producer); if (text == null) return; int caretLine = editor.getCaretModel().getLogicalPosition().line; int originalCaretLine = caretLine; int selectedLinesCount = 0; final SelectionModel selectionModel = editor.getSelectionModel(); if (selectionModel.hasBlockSelection()) { final LogicalPosition start = selectionModel.getBlockStart(); final LogicalPosition end = selectionModel.getBlockEnd(); assert start != null; assert end != null; LogicalPosition caret = new LogicalPosition(Math.min(start.line, end.line), Math.min(start.column, end.column)); selectedLinesCount = Math.abs(end.line - start.line); caretLine = caret.line; deleteSelectedText(editor); editor.getCaretModel().moveToLogicalPosition(caret); } LogicalPosition caretToRestore = editor.getCaretModel().getLogicalPosition(); String[] lines = LineTokenizer.tokenize(text.toCharArray(), false); if (lines.length > 1 || selectedLinesCount == 0) { int longestLineLength = 0; for (int i = 0; i < lines.length; i++) { String line = lines[i]; longestLineLength = Math.max(longestLineLength, line.length()); editor .getCaretModel() .moveToLogicalPosition(new LogicalPosition(caretLine + i, caretToRestore.column)); insertStringAtCaret(editor, line, false, true); } caretToRestore = new LogicalPosition(originalCaretLine, caretToRestore.column + longestLineLength); } else { for (int i = 0; i <= selectedLinesCount; i++) { editor .getCaretModel() .moveToLogicalPosition(new LogicalPosition(caretLine + i, caretToRestore.column)); insertStringAtCaret(editor, text, false, true); } caretToRestore = new LogicalPosition(originalCaretLine, caretToRestore.column + text.length()); } editor.getCaretModel().moveToLogicalPosition(caretToRestore); zeroWidthBlockSelectionAtCaretColumn(editor, caretLine, caretLine + selectedLinesCount); }
/** * 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())); } }
public static void deleteSelectedText(Editor editor) { SelectionModel selectionModel = editor.getSelectionModel(); if (selectionModel.hasBlockSelection()) deleteBlockSelection(editor); if (!selectionModel.hasSelection()) return; int selectionStart = selectionModel.getSelectionStart(); int selectionEnd = selectionModel.getSelectionEnd(); editor.getCaretModel().moveToOffset(selectionStart); selectionModel.removeSelection(); editor.getDocument().deleteString(selectionStart, selectionEnd); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); }
private static Runnable rememberDocumentState(final Editor _editor) { final Editor editor = InjectedLanguageUtil.getTopLevelEditor(_editor); final String documentText = editor.getDocument().getText(); final int caret = editor.getCaretModel().getOffset(); final int selStart = editor.getSelectionModel().getSelectionStart(); final int selEnd = editor.getSelectionModel().getSelectionEnd(); final int vOffset = editor.getScrollingModel().getVerticalScrollOffset(); final int hOffset = editor.getScrollingModel().getHorizontalScrollOffset(); return new Runnable() { @Override public void run() { DocumentEx document = (DocumentEx) editor.getDocument(); document.replaceString(0, document.getTextLength(), documentText); editor.getCaretModel().moveToOffset(caret); editor.getSelectionModel().setSelection(selStart, selEnd); editor.getScrollingModel().scrollHorizontally(hOffset); editor.getScrollingModel().scrollVertically(vOffset); } }; }
@Nullable public Runnable prepareTemplate( final Editor editor, char shortcutChar, @Nullable final PairProcessor<String, String> processor) { if (editor.getSelectionModel().hasSelection()) { return null; } PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, myProject); if (file == null) return null; Map<TemplateImpl, String> template2argument = findMatchingTemplates(file, editor, shortcutChar, TemplateSettings.getInstance()); List<CustomLiveTemplate> customCandidates = ContainerUtil.findAll( CustomLiveTemplate.EP_NAME.getExtensions(), customLiveTemplate -> shortcutChar == customLiveTemplate.getShortcut() && (editor.getCaretModel().getCaretCount() <= 1 || supportsMultiCaretMode(customLiveTemplate))); if (!customCandidates.isEmpty()) { int caretOffset = editor.getCaretModel().getOffset(); PsiFile fileCopy = insertDummyIdentifierIfNeeded(file, caretOffset, caretOffset, ""); Document document = editor.getDocument(); for (final CustomLiveTemplate customLiveTemplate : customCandidates) { if (isApplicable(customLiveTemplate, editor, fileCopy)) { final String key = customLiveTemplate.computeTemplateKey(new CustomTemplateCallback(editor, fileCopy)); if (key != null) { int offsetBeforeKey = caretOffset - key.length(); CharSequence text = document.getImmutableCharSequence(); if (template2argument == null || !containsTemplateStartingBefore( template2argument, offsetBeforeKey, caretOffset, text)) { return () -> customLiveTemplate.expand(key, new CustomTemplateCallback(editor, file)); } } } } } return startNonCustomTemplates(template2argument, editor, processor); }
public void navigateIn(@NotNull Editor e) { final int offset = getOffset(); CaretModel caretModel = e.getCaretModel(); boolean caretMoved = false; if (myLogicalLine >= 0) { LogicalPosition pos = new LogicalPosition(myLogicalLine, Math.max(myLogicalColumn, 0)); if (offset < 0 || offset == e.logicalPositionToOffset(pos)) { caretModel.moveToLogicalPosition(pos); caretMoved = true; } } if (!caretMoved && offset >= 0) { caretModel.moveToOffset(Math.min(offset, e.getDocument().getTextLength())); caretMoved = true; } if (caretMoved) { e.getSelectionModel().removeSelection(); scrollToCaret(e); unfoldCurrentLine(e); } }
private void startTemplate( final Editor editor, final String selectionString, final Template template, boolean inSeparateCommand, TemplateEditingListener listener, final PairProcessor<String, String> processor, final Map<String, String> predefinedVarValues) { final TemplateState templateState = initTemplateState(editor); //noinspection unchecked templateState.getProperties().put(ExpressionContext.SELECTION, selectionString); if (listener != null) { templateState.addTemplateStateListener(listener); } Runnable r = () -> { if (selectionString != null) { ApplicationManager.getApplication() .runWriteAction(() -> EditorModificationUtil.deleteSelectedText(editor)); } else { editor.getSelectionModel().removeSelection(); } templateState.start((TemplateImpl) template, processor, predefinedVarValues); }; if (inSeparateCommand) { CommandProcessor.getInstance() .executeCommand( myProject, r, CodeInsightBundle.message("insert.code.template.command"), null); } else { r.run(); } if (shouldSkipInTests()) { if (!templateState.isFinished()) templateState.gotoEnd(false); } }
public static void deleteBlockSelection(Editor editor) { SelectionModel selectionModel = editor.getSelectionModel(); if (!selectionModel.hasBlockSelection()) return; LogicalPosition blockStart = selectionModel.getBlockStart(); LogicalPosition blockEnd = selectionModel.getBlockEnd(); if (blockStart == null || blockEnd == null) { return; } int startLine = blockStart.line; int endLine = blockEnd.line; int[] starts = selectionModel.getBlockSelectionStarts(); int[] ends = selectionModel.getBlockSelectionEnds(); for (int i = starts.length - 1; i >= 0; i--) { editor.getDocument().deleteString(starts[i], ends[i]); } editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); zeroWidthBlockSelectionAtCaretColumn(editor, startLine, endLine); }
private static CompletionAssertions.WatchingInsertionContext insertItemHonorBlockSelection( CompletionProgressIndicator indicator, LookupElement item, char completionChar, List<LookupElement> items, CompletionLookupArranger.StatisticsUpdate update) { final Editor editor = indicator.getEditor(); final int caretOffset = editor.getCaretModel().getOffset(); int idEndOffset = indicator.getIdentifierEndOffset(); if (idEndOffset < 0) { idEndOffset = CompletionInitializationContext.calcDefaultIdentifierEnd(editor, caretOffset); } CompletionAssertions.WatchingInsertionContext context = null; if (editor.getSelectionModel().hasBlockSelection() && editor.getSelectionModel().getBlockSelectionEnds().length > 0) { List<RangeMarker> insertionPoints = new ArrayList<RangeMarker>(); int idDelta = 0; Document document = editor.getDocument(); int caretLine = document.getLineNumber(editor.getCaretModel().getOffset()); for (int point : editor.getSelectionModel().getBlockSelectionEnds()) { insertionPoints.add(document.createRangeMarker(point, point)); if (document.getLineNumber(point) == document.getLineNumber(idEndOffset)) { idDelta = idEndOffset - point; } } List<RangeMarker> caretsAfter = new ArrayList<RangeMarker>(); for (RangeMarker marker : insertionPoints) { if (marker.isValid()) { int insertionPoint = marker.getStartOffset(); context = insertItem( indicator, item, completionChar, items, update, editor, insertionPoint, idDelta + insertionPoint); int offset = editor.getCaretModel().getOffset(); caretsAfter.add(document.createRangeMarker(offset, offset)); } } assert context != null; restoreBlockSelection(editor, caretsAfter, caretLine); for (RangeMarker insertionPoint : insertionPoints) { insertionPoint.dispose(); } for (RangeMarker marker : caretsAfter) { marker.dispose(); } } else { context = insertItem( indicator, item, completionChar, items, update, editor, caretOffset, idEndOffset); } return context; }
private static CompletionAssertions.WatchingInsertionContext insertItemHonorBlockSelection( final CompletionProgressIndicator indicator, final LookupElement item, final char completionChar, final List<LookupElement> items, final CompletionLookupArranger.StatisticsUpdate update) { final Editor editor = indicator.getEditor(); final int caretOffset = editor.getCaretModel().getOffset(); int idEndOffset = indicator.getIdentifierEndOffset(); if (idEndOffset < 0) { idEndOffset = CompletionInitializationContext.calcDefaultIdentifierEnd(editor, caretOffset); } final int idEndOffsetDelta = idEndOffset - caretOffset; CompletionAssertions.WatchingInsertionContext context = null; if (editor.getSelectionModel().hasBlockSelection() && editor.getSelectionModel().getBlockSelectionEnds().length > 0) { List<RangeMarker> insertionPoints = new ArrayList<RangeMarker>(); int idDelta = 0; Document document = editor.getDocument(); int caretLine = document.getLineNumber(editor.getCaretModel().getOffset()); for (int point : editor.getSelectionModel().getBlockSelectionEnds()) { insertionPoints.add(document.createRangeMarker(point, point)); if (document.getLineNumber(point) == document.getLineNumber(idEndOffset)) { idDelta = idEndOffset - point; } } List<RangeMarker> caretsAfter = new ArrayList<RangeMarker>(); for (RangeMarker marker : insertionPoints) { if (marker.isValid()) { int insertionPoint = marker.getStartOffset(); context = insertItem( indicator, item, completionChar, items, update, editor, insertionPoint, idDelta + insertionPoint); int offset = editor.getCaretModel().getOffset(); caretsAfter.add(document.createRangeMarker(offset, offset)); } } assert context != null; restoreBlockSelection(editor, caretsAfter, caretLine); for (RangeMarker insertionPoint : insertionPoints) { insertionPoint.dispose(); } for (RangeMarker marker : caretsAfter) { marker.dispose(); } } else { final Ref<CompletionAssertions.WatchingInsertionContext> contextRef = new Ref<CompletionAssertions.WatchingInsertionContext>(); editor .getCaretModel() .runForEachCaret( new CaretAction() { @Override public void perform(Caret caret) { CompletionAssertions.WatchingInsertionContext currentContext = insertItem( indicator, item, completionChar, items, update, editor, caret.getOffset(), caret.getOffset() + idEndOffsetDelta); if (caret .getVisualPosition() .equals(editor.getCaretModel().getPrimaryCaret().getVisualPosition())) { contextRef.set(currentContext); } } }); context = contextRef.get(); } return context; }
public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { myProject = project; myFile = file.getViewProvider().getPsi(file.getViewProvider().getBaseLanguage()); myEditor = editor; PsiElement context = myFile.getContext(); if (context != null && (context.textContains('\'') || context.textContains('\"'))) { String s = context.getText(); if (StringUtil.startsWith(s, "\"") || StringUtil.startsWith(s, "\'")) { myFile = context.getContainingFile(); myEditor = editor instanceof EditorWindow ? ((EditorWindow) editor).getDelegate() : editor; } } myDocument = myEditor.getDocument(); if (!FileDocumentManager.getInstance().requestWriting(myDocument, project)) { return; } PsiDocumentManager.getInstance(project).commitDocument(myDocument); FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.comment.line"); myCodeStyleManager = CodeStyleManager.getInstance(myProject); final SelectionModel selectionModel = myEditor.getSelectionModel(); boolean hasSelection = selectionModel.hasSelection(); myStartOffset = selectionModel.getSelectionStart(); myEndOffset = selectionModel.getSelectionEnd(); FoldRegion fold = myEditor.getFoldingModel().getCollapsedRegionAtOffset(myStartOffset); if (fold != null && fold.shouldNeverExpand() && fold.getStartOffset() == myStartOffset && fold.getEndOffset() == myEndOffset) { // Foldings that never expand are automatically selected, so the fact it is selected must not // interfer with commenter's logic hasSelection = false; } if (myDocument.getTextLength() == 0) return; while (true) { int lastLineEnd = myDocument.getLineEndOffset(myDocument.getLineNumber(myEndOffset)); FoldRegion collapsedAt = myEditor.getFoldingModel().getCollapsedRegionAtOffset(lastLineEnd); if (collapsedAt != null) { final int endOffset = collapsedAt.getEndOffset(); if (endOffset <= myEndOffset) { break; } myEndOffset = endOffset; } else { break; } } boolean wholeLinesSelected = !hasSelection || myStartOffset == myDocument.getLineStartOffset(myDocument.getLineNumber(myStartOffset)) && myEndOffset == myDocument.getLineEndOffset(myDocument.getLineNumber(myEndOffset - 1)) + 1; boolean startingNewLineComment = !hasSelection && isLineEmpty(myDocument.getLineNumber(myStartOffset)) && !Comparing.equal( IdeActions.ACTION_COMMENT_LINE, ActionManagerEx.getInstanceEx().getPrevPreformedActionId()); doComment(); if (startingNewLineComment) { final Commenter commenter = myCommenters[0]; if (commenter != null) { String prefix; if (commenter instanceof SelfManagingCommenter) { prefix = ((SelfManagingCommenter) commenter) .getCommentPrefix( myStartLine, myDocument, myCommenterStateMap.get((SelfManagingCommenter) commenter)); if (prefix == null) prefix = ""; // TODO } else { prefix = commenter.getLineCommentPrefix(); if (prefix == null) prefix = commenter.getBlockCommentPrefix(); } int lineStart = myDocument.getLineStartOffset(myStartLine); lineStart = CharArrayUtil.shiftForward(myDocument.getCharsSequence(), lineStart, " \t"); lineStart += prefix.length(); lineStart = CharArrayUtil.shiftForward(myDocument.getCharsSequence(), lineStart, " \t"); if (lineStart > myDocument.getTextLength()) lineStart = myDocument.getTextLength(); myEditor.getCaretModel().moveToOffset(lineStart); myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } } else { if (!hasSelection) { // Don't tweak caret position if we're already located on the last document line. LogicalPosition position = myEditor.getCaretModel().getLogicalPosition(); if (position.line < myDocument.getLineCount() - 1) { int verticalShift = 1 + myEditor.getSoftWrapModel().getSoftWrapsForLine(position.line).size() - position.softWrapLinesOnCurrentLogicalLine; myEditor.getCaretModel().moveCaretRelatively(0, verticalShift, false, false, true); } } else { if (wholeLinesSelected) { selectionModel.setSelection(myStartOffset, selectionModel.getSelectionEnd()); } } } }
private void dumpEditorMarkupAndSelection(PrintStream dumpStream) { dumpStream.println(mySearchResults.getFindModel()); if (myReplacementPreviewText != null) { dumpStream.println("--"); dumpStream.println("Replacement Preview: " + myReplacementPreviewText); } dumpStream.println("--"); Editor editor = mySearchResults.getEditor(); RangeHighlighter[] highlighters = editor.getMarkupModel().getAllHighlighters(); List<Pair<Integer, Character>> ranges = new ArrayList<Pair<Integer, Character>>(); for (RangeHighlighter highlighter : highlighters) { ranges.add(new Pair<Integer, Character>(highlighter.getStartOffset(), '[')); ranges.add(new Pair<Integer, Character>(highlighter.getEndOffset(), ']')); } SelectionModel selectionModel = editor.getSelectionModel(); if (selectionModel.getSelectionStart() != selectionModel.getSelectionEnd()) { ranges.add(new Pair<Integer, Character>(selectionModel.getSelectionStart(), '<')); ranges.add(new Pair<Integer, Character>(selectionModel.getSelectionEnd(), '>')); } ranges.add(new Pair<Integer, Character>(-1, '\n')); ranges.add(new Pair<Integer, Character>(editor.getDocument().getTextLength() + 1, '\n')); ContainerUtil.sort( ranges, new Comparator<Pair<Integer, Character>>() { @Override public int compare(Pair<Integer, Character> pair, Pair<Integer, Character> pair2) { int res = pair.first - pair2.first; if (res == 0) { Character c1 = pair.second; Character c2 = pair2.second; if (c1 == '<' && c2 == '[') { return 1; } else if (c1 == '[' && c2 == '<') { return -1; } return c1.compareTo(c2); } return res; } }); Document document = editor.getDocument(); for (int i = 0; i < ranges.size() - 1; ++i) { Pair<Integer, Character> pair = ranges.get(i); Pair<Integer, Character> pair1 = ranges.get(i + 1); dumpStream.print( pair.second + document.getText( TextRange.create( Math.max(pair.first, 0), Math.min(pair1.first, document.getTextLength())))); } dumpStream.println("\n--"); if (NotFound) { dumpStream.println("Not Found"); dumpStream.println("--"); NotFound = false; } for (RangeHighlighter highlighter : highlighters) { dumpStream.println(highlighter + " : " + highlighter.getTextAttributes()); } dumpStream.println("------------"); }
public final void move(Editor editor, final PsiFile file) { myMover.beforeMove(editor, myInfo, myIsDown); final Document document = editor.getDocument(); final int start = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.startLine); final int end = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.endLine); myInfo.range1 = document.createRangeMarker(start, end); String textToInsert = document.getCharsSequence().subSequence(start, end).toString(); if (!StringUtil.endsWithChar(textToInsert, '\n')) textToInsert += '\n'; final int start2 = document.getLineStartOffset(myInfo.toMove2.startLine); final int end2 = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove2.endLine); String textToInsert2 = document.getCharsSequence().subSequence(start2, end2).toString(); if (!StringUtil.endsWithChar(textToInsert2, '\n')) textToInsert2 += '\n'; myInfo.range2 = document.createRangeMarker(start2, end2); if (myInfo.range1.getStartOffset() < myInfo.range2.getStartOffset()) { myInfo.range1.setGreedyToLeft(true); myInfo.range1.setGreedyToRight(false); myInfo.range2.setGreedyToLeft(true); myInfo.range2.setGreedyToRight(true); } else { myInfo.range1.setGreedyToLeft(true); myInfo.range1.setGreedyToRight(true); myInfo.range2.setGreedyToLeft(true); myInfo.range2.setGreedyToRight(false); } final CaretModel caretModel = editor.getCaretModel(); final int caretRelativePos = caretModel.getOffset() - start; final SelectionModel selectionModel = editor.getSelectionModel(); final int selectionStart = selectionModel.getSelectionStart(); final int selectionEnd = selectionModel.getSelectionEnd(); final boolean hasSelection = selectionModel.hasSelection(); // to prevent flicker caretModel.moveToOffset(0); // There is a possible case that the user performs, say, method move. It's also possible that // one (or both) of moved methods // are folded. We want to preserve their states then. The problem is that folding processing is // based on PSI element pointers // and the pointers behave as following during move up/down: // method1() {} // method2() {} // Pointer for the fold region from method1 points to 'method2()' now and vice versa (check // range markers processing on // document change for further information). I.e. information about fold regions statuses holds // the data swapped for // 'method1' and 'method2'. Hence, we want to apply correct 'collapsed' status. FoldRegion topRegion = null; FoldRegion bottomRegion = null; for (FoldRegion foldRegion : editor.getFoldingModel().getAllFoldRegions()) { if (!foldRegion.isValid() || (!contains(myInfo.range1, foldRegion) && !contains(myInfo.range2, foldRegion))) { continue; } if (contains(myInfo.range1, foldRegion) && !contains(topRegion, foldRegion)) { topRegion = foldRegion; } else if (contains(myInfo.range2, foldRegion) && !contains(bottomRegion, foldRegion)) { bottomRegion = foldRegion; } } document.insertString(myInfo.range1.getStartOffset(), textToInsert2); document.deleteString( myInfo.range1.getStartOffset() + textToInsert2.length(), myInfo.range1.getEndOffset()); document.insertString(myInfo.range2.getStartOffset(), textToInsert); int s = myInfo.range2.getStartOffset() + textToInsert.length(); int e = myInfo.range2.getEndOffset(); if (e > s) { document.deleteString(s, e); } final Project project = file.getProject(); PsiDocumentManager.getInstance(project).commitAllDocuments(); // Swap fold regions status if necessary. if (topRegion != null && bottomRegion != null) { final FoldRegion finalTopRegion = topRegion; final FoldRegion finalBottomRegion = bottomRegion; editor .getFoldingModel() .runBatchFoldingOperation( new Runnable() { @Override public void run() { boolean topExpanded = finalTopRegion.isExpanded(); finalTopRegion.setExpanded(finalBottomRegion.isExpanded()); finalBottomRegion.setExpanded(topExpanded); } }); } CodeFoldingManager.getInstance(project).allowFoldingOnCaretLine(editor); if (hasSelection) { restoreSelection(editor, selectionStart, selectionEnd, start, myInfo.range2.getStartOffset()); } caretModel.moveToOffset(myInfo.range2.getStartOffset() + caretRelativePos); if (myInfo.indentTarget) { indentLinesIn(editor, file, document, project, myInfo.range2); } if (myInfo.indentSource) { indentLinesIn(editor, file, document, project, myInfo.range1); } myMover.afterMove(editor, file, myInfo, myIsDown); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); }
@Override public void run() { CaretModel caretModel = myEditor.getCaretModel(); try { final CharSequence chars = myDocument.getCharsSequence(); int i = CharArrayUtil.shiftBackwardUntil(chars, myOffset - 1, LINE_SEPARATOR) - 1; i = CharArrayUtil.shiftBackwardUntil(chars, i, LINE_SEPARATOR) + 1; if (i < 0) i = 0; int lineStart = CharArrayUtil.shiftForward(chars, i, " \t"); CodeDocumentationUtil.CommentContext commentContext = CodeDocumentationUtil.tryParseCommentContext(myFile, chars, myOffset, lineStart); PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(getProject()); if (commentContext.docStart) { PsiElement element = myFile.findElementAt(commentContext.lineStart); final String text = element.getText(); final PsiElement parent = element.getParent(); if (text.equals(commentContext.commenter.getDocumentationCommentPrefix()) && isDocComment(parent, commentContext.commenter) || text.startsWith(commentContext.commenter.getDocumentationCommentPrefix()) && element instanceof PsiComment) { PsiComment comment = isDocComment(parent, commentContext.commenter) ? (PsiComment) parent : (PsiComment) element; int commentEnd = comment.getTextRange().getEndOffset(); if (myOffset >= commentEnd) { commentContext.docStart = false; } else { if (isCommentComplete(comment, commentContext.commenter, myEditor)) { if (myOffset >= commentEnd) { commentContext.docAsterisk = false; commentContext.docStart = false; } else { commentContext.docAsterisk = true; commentContext.docStart = false; } } else { generateJavadoc(commentContext.commenter); } } } else { commentContext.docStart = false; } } else if (commentContext.cStyleStart) { PsiElement element = myFile.findElementAt(commentContext.lineStart); if (element instanceof PsiComment && commentContext.commenter.getBlockCommentTokenType() == ((PsiComment) element).getTokenType()) { final PsiComment comment = (PsiComment) element; int commentEnd = comment.getTextRange().getEndOffset(); if (myOffset >= commentEnd && myOffset < myFile.getTextRange().getEndOffset()) { commentContext.docStart = false; } else { if (isCommentComplete(comment, commentContext.commenter, myEditor)) { if (myOffset >= commentEnd) { commentContext.docAsterisk = false; commentContext.docStart = false; } else { commentContext.docAsterisk = true; commentContext.docStart = false; } } else { final int currentEndOfLine = CharArrayUtil.shiftForwardUntil(chars, myOffset, "\n"); myDocument.insertString( currentEndOfLine, " " + commentContext.commenter.getBlockCommentSuffix()); int lstart = CharArrayUtil.shiftBackwardUntil(chars, myOffset, "\n"); myDocument.insertString(currentEndOfLine, chars.subSequence(lstart, myOffset)); psiDocumentManager.commitDocument(myDocument); } } } else { commentContext.docStart = false; } } String indentInsideJavadoc = null; if (myOffset < myDocument.getTextLength()) { final int line = myDocument.getLineNumber(myOffset); if (line > 0 && (commentContext.docAsterisk || commentContext.docStart)) { indentInsideJavadoc = CodeDocumentationUtil.getIndentInsideJavadoc( myDocument, myDocument.getLineStartOffset(line - 1)); } } if (commentContext.docAsterisk) { commentContext.docAsterisk = insertDocAsterisk( commentContext.lineStart, commentContext.docAsterisk, !StringUtil.isEmpty(indentInsideJavadoc), commentContext.commenter); } boolean docIndentApplied = false; CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance(); if (codeInsightSettings.SMART_INDENT_ON_ENTER || myForceIndent || commentContext.docStart || commentContext.docAsterisk || commentContext.slashSlash) { final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(getProject()); myOffset = codeStyleManager.adjustLineIndent(myFile, myOffset); psiDocumentManager.commitAllDocuments(); if (!StringUtil.isEmpty(indentInsideJavadoc) && myOffset < myDocument.getTextLength()) { myDocument.insertString(myOffset + 1, indentInsideJavadoc); myOffset += indentInsideJavadoc.length(); docIndentApplied = true; } if (myForceIndent && indentInsideJavadoc != null) { int indentSize = CodeStyleSettingsManager.getSettings(myProject).getIndentSize(myFile.getFileType()); myDocument.insertString(myOffset + 1, StringUtil.repeatSymbol(' ', indentSize)); myCaretAdvance += indentSize; } } if ((commentContext.docAsterisk || commentContext.docStart || commentContext.slashSlash) && !docIndentApplied) { if (myInsertSpace) { if (myOffset == myDocument.getTextLength()) { myDocument.insertString(myOffset, " "); } myDocument.insertString(myOffset + 1, " "); } final char c = myDocument.getCharsSequence().charAt(myOffset); if (c != '\n') { myOffset += 1; } } if ((commentContext.docAsterisk || commentContext.slashSlash) && !commentContext.docStart) { myCaretAdvance += commentContext.slashSlash ? commentContext.commenter.getLineCommentPrefix().length() : 1; } } catch (IncorrectOperationException e) { LOG.error(e); } myOffset = Math.min(myOffset, myDocument.getTextLength()); caretModel.moveToOffset(myOffset); myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); myEditor.getSelectionModel().removeSelection(); if (myCaretAdvance != 0) { LogicalPosition caretPosition = caretModel.getLogicalPosition(); LogicalPosition pos = new LogicalPosition(caretPosition.line, caretPosition.column + myCaretAdvance); caretModel.moveToLogicalPosition(pos); } }
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)); } } }
private static CompletionAssertions.WatchingInsertionContext insertItemHonorBlockSelection( final CompletionProgressIndicator indicator, final LookupElement item, final char completionChar, final List<LookupElement> items, final CompletionLookupArranger.StatisticsUpdate update) { final Editor editor = indicator.getEditor(); final int caretOffset = editor.getCaretModel().getOffset(); int idEndOffset = indicator.getIdentifierEndOffset(); if (idEndOffset < 0) { idEndOffset = CompletionInitializationContext.calcDefaultIdentifierEnd(editor, caretOffset); } final int idEndOffsetDelta = idEndOffset - caretOffset; CompletionAssertions.WatchingInsertionContext context = null; if (editor.getSelectionModel().hasBlockSelection() && editor.getSelectionModel().getBlockSelectionEnds().length > 0) { List<RangeMarker> insertionPoints = new ArrayList<RangeMarker>(); int idDelta = 0; Document document = editor.getDocument(); int caretLine = document.getLineNumber(editor.getCaretModel().getOffset()); for (int point : editor.getSelectionModel().getBlockSelectionEnds()) { insertionPoints.add(document.createRangeMarker(point, point)); if (document.getLineNumber(point) == document.getLineNumber(idEndOffset)) { idDelta = idEndOffset - point; } } List<RangeMarker> caretsAfter = new ArrayList<RangeMarker>(); for (RangeMarker marker : insertionPoints) { if (marker.isValid()) { int insertionPoint = marker.getStartOffset(); context = insertItem( indicator, item, completionChar, items, update, editor, indicator.getParameters().getOriginalFile(), insertionPoint, idDelta + insertionPoint); int offset = editor.getCaretModel().getOffset(); caretsAfter.add(document.createRangeMarker(offset, offset)); } } assert context != null; restoreBlockSelection(editor, caretsAfter, caretLine); for (RangeMarker insertionPoint : insertionPoints) { insertionPoint.dispose(); } for (RangeMarker marker : caretsAfter) { marker.dispose(); } } else if (editor.getCaretModel().supportsMultipleCarets()) { final List<CompletionAssertions.WatchingInsertionContext> contexts = new ArrayList<CompletionAssertions.WatchingInsertionContext>(); final Editor hostEditor = InjectedLanguageUtil.getTopLevelEditor(editor); hostEditor .getCaretModel() .runForEachCaret( new CaretAction() { @Override public void perform(Caret caret) { PsiFile hostFile = InjectedLanguageUtil.getTopLevelFile( indicator.getParameters().getOriginalFile()); PsiFile targetFile = InjectedLanguageUtil.findInjectedPsiNoCommit(hostFile, caret.getOffset()); Editor targetEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(hostEditor, targetFile); int targetCaretOffset = targetEditor.getCaretModel().getOffset(); CompletionAssertions.WatchingInsertionContext currentContext = insertItem( indicator, item, completionChar, items, update, targetEditor, targetFile == null ? hostFile : targetFile, targetCaretOffset, targetCaretOffset + idEndOffsetDelta); contexts.add(currentContext); } }, true); context = contexts.get(contexts.size() - 1); if (context.shouldAddCompletionChar() && context.getCompletionChar() != Lookup.COMPLETE_STATEMENT_SELECT_CHAR) { ApplicationManager.getApplication() .runWriteAction( new Runnable() { @Override public void run() { DataContext dataContext = DataManager.getInstance().getDataContext(editor.getContentComponent()); EditorActionManager.getInstance() .getTypedAction() .getHandler() .execute(editor, completionChar, dataContext); } }); } for (CompletionAssertions.WatchingInsertionContext insertionContext : contexts) { insertionContext.stopWatching(); } } else { context = insertItem( indicator, item, completionChar, items, update, editor, indicator.getParameters().getOriginalFile(), caretOffset, idEndOffset); } return context; }
private void addListeners() { myEditor .getDocument() .addDocumentListener( new DocumentAdapter() { @Override public void documentChanged(DocumentEvent e) { if (!myChangeGuard && !myFinishing) { hide(); } } }, this); final CaretListener caretListener = new CaretAdapter() { @Override public void caretPositionChanged(CaretEvent e) { if (!myChangeGuard && !myFinishing) { hide(); } } }; final SelectionListener selectionListener = new SelectionListener() { @Override public void selectionChanged(final SelectionEvent e) { if (!myChangeGuard && !myFinishing) { hide(); } } }; final EditorMouseListener mouseListener = new EditorMouseAdapter() { @Override public void mouseClicked(EditorMouseEvent e) { e.consume(); hide(); } }; myEditor.getCaretModel().addCaretListener(caretListener); myEditor.getSelectionModel().addSelectionListener(selectionListener); myEditor.addEditorMouseListener(mouseListener); Disposer.register( this, new Disposable() { @Override public void dispose() { myEditor.getCaretModel().removeCaretListener(caretListener); myEditor.getSelectionModel().removeSelectionListener(selectionListener); myEditor.removeEditorMouseListener(mouseListener); } }); JComponent editorComponent = myEditor.getContentComponent(); if (editorComponent.isShowing()) { Disposer.register( this, new UiNotifyConnector( editorComponent, new Activatable() { @Override public void showNotify() {} @Override public void hideNotify() { hideLookup(false); } })); } myList.addListSelectionListener( new ListSelectionListener() { private LookupElement oldItem = null; @Override public void valueChanged(@NotNull ListSelectionEvent e) { if (!myUpdating) { final LookupElement item = getCurrentItem(); fireCurrentItemChanged(oldItem, item); oldItem = item; } } }); new ClickListener() { @Override public boolean onClick(@NotNull MouseEvent e, int clickCount) { setFocusDegree(FocusDegree.FOCUSED); markSelectionTouched(); if (clickCount == 2) { CommandProcessor.getInstance() .executeCommand( myProject, new Runnable() { @Override public void run() { finishLookup(NORMAL_SELECT_CHAR); } }, "", null); } return true; } }.installOn(myList); }
@Nullable @Override public TextBlockTransferableData collectTransferableData( PsiFile file, Editor editor, int[] startOffsets, int[] endOffsets) { if (!Registry.is("editor.richcopy.enable")) { return null; } try { for (TextWithMarkupBuilder builder : myBuilders) { builder.reset(); } SelectionModel selectionModel = editor.getSelectionModel(); if (selectionModel.hasBlockSelection()) { return null; // unsupported legacy mode } RichCopySettings settings = RichCopySettings.getInstance(); List<Caret> carets = editor.getCaretModel().getAllCarets(); Caret firstCaret = carets.get(0); final int indentSymbolsToStrip; final int firstLineStartOffset; if (settings.isStripIndents() && carets.size() == 1) { Pair<Integer, Integer> p = calcIndentSymbolsToStrip( editor.getDocument(), firstCaret.getSelectionStart(), firstCaret.getSelectionEnd()); firstLineStartOffset = p.first; indentSymbolsToStrip = p.second; } else { firstLineStartOffset = firstCaret.getSelectionStart(); indentSymbolsToStrip = 0; } logInitial(editor, startOffsets, endOffsets, indentSymbolsToStrip, firstLineStartOffset); CharSequence text = editor.getDocument().getCharsSequence(); EditorColorsScheme schemeToUse = settings.getColorsScheme(editor.getColorsScheme()); EditorHighlighter highlighter = HighlighterFactory.createHighlighter( file.getVirtualFile(), schemeToUse, file.getProject()); highlighter.setText(text); MarkupModel markupModel = DocumentMarkupModel.forDocument(editor.getDocument(), file.getProject(), false); Context context = new Context(text, schemeToUse, indentSymbolsToStrip); int shift = 0; int endOffset = 0; Caret prevCaret = null; for (Caret caret : carets) { int caretSelectionStart = caret.getSelectionStart(); int caretSelectionEnd = caret.getSelectionEnd(); int startOffsetToUse; if (caret == firstCaret) { startOffsetToUse = firstLineStartOffset; } else { startOffsetToUse = caretSelectionStart; assert prevCaret != null; String prevCaretSelectedText = prevCaret.getSelectedText(); // Block selection fills short lines by white spaces. int fillStringLength = prevCaretSelectedText == null ? 0 : prevCaretSelectedText.length() - (prevCaret.getSelectionEnd() - prevCaret.getSelectionStart()); int endLineOffset = endOffset + shift + fillStringLength; context.builder.addText(endLineOffset, endLineOffset + 1); shift++; // Block selection ends '\n' at line end shift += fillStringLength; } shift += endOffset - caretSelectionStart; endOffset = caretSelectionEnd; context.reset(shift); prevCaret = caret; if (endOffset <= startOffsetToUse) { continue; } MarkupIterator markupIterator = new MarkupIterator( text, new CompositeRangeIterator( schemeToUse, new HighlighterRangeIterator(highlighter, startOffsetToUse, endOffset), new MarkupModelRangeIterator( markupModel, schemeToUse, startOffsetToUse, endOffset)), schemeToUse); try { context.iterate(markupIterator, endOffset); } finally { markupIterator.dispose(); } } SyntaxInfo syntaxInfo = context.finish(); logSyntaxInfo(syntaxInfo); for (TextWithMarkupBuilder builder : myBuilders) { builder.build(syntaxInfo); } } catch (Exception e) { // catching the exception so that the rest of copy/paste functionality can still work fine LOG.error(e); } return null; }