@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(); } }
@Override public boolean doEnter(Editor editor, PsiElement psiElement, boolean isModified) { PsiCodeBlock block = getControlStatementBlock(editor.getCaretModel().getOffset(), psiElement); if (processExistingBlankLine(editor, block, psiElement)) { return true; } EditorActionHandler enterHandler = getEnterHandler(IdeActions.ACTION_EDITOR_START_NEW_LINE); if (block != null) { PsiElement firstElement = block.getFirstBodyElement(); if (firstElement == null) { firstElement = block.getRBrace(); // Plain enter processor inserts enter after the end of line, hence, we don't want to use it // here because the line ends with // the empty braces block. So, we get the following in case of default handler usage: // Before: // if (condition[caret]) {} // After: // if (condition) {} // [caret] enterHandler = getEnterHandler(IdeActions.ACTION_EDITOR_ENTER); } editor .getCaretModel() .moveToOffset( firstElement != null ? firstElement.getTextRange().getStartOffset() : block.getTextRange().getEndOffset()); } enterHandler.execute(editor, ((EditorEx) editor).getDataContext()); return true; }
private void performAction( final String fileName, final EditorActionHandler handler, final String afterFileName) throws Exception { configureByFile(fileName); final boolean enabled = handler.isEnabled(myEditor, null); assertEquals( "not enabled for " + afterFileName, new File(getTestDataPath(), afterFileName).exists(), enabled); if (enabled) { handler.execute(myEditor, null); checkResultByFile(afterFileName); } }
@Override public void execute(Editor editor, Caret caret, DataContext dataContext) { LookupImpl lookup = (LookupImpl) LookupManager.getActiveLookup(editor); if (lookup == null || !lookup.isAvailableToUser() || myRequireFocusedLookup && !lookup.isFocused()) { Project project = editor.getProject(); if (project != null) { LookupManager.getInstance(project).hideActiveLookup(); } myOriginalHandler.executeInCaretContext(editor, caret, dataContext); return; } lookup.markSelectionTouched(); executeInLookup(lookup, dataContext, caret); }
public static void performTypingAction(Editor editor, char c) { EditorActionManager actionManager = EditorActionManager.getInstance(); if (c == BACKSPACE_FAKE_CHAR) { EditorActionHandler actionHandler = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_BACKSPACE); actionHandler.execute(editor, DataManager.getInstance().getDataContext()); } else if (c == SMART_ENTER_FAKE_CHAR) { EditorActionHandler actionHandler = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_COMPLETE_STATEMENT); actionHandler.execute(editor, DataManager.getInstance().getDataContext()); } else if (c == '\n') { EditorActionHandler actionHandler = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_ENTER); actionHandler.execute(editor, DataManager.getInstance().getDataContext()); } else { TypedAction action = actionManager.getTypedAction(); action.actionPerformed(editor, c, DataManager.getInstance().getDataContext()); } }
protected boolean handleBackspace( Editor editor, Caret caret, DataContext dataContext, boolean toWordStart) { Project project = CommonDataKeys.PROJECT.getData(dataContext); if (project == null) return false; PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, project); if (file == null) return false; if (editor.getSelectionModel().hasSelection()) return false; int offset = editor.getCaretModel().getOffset() - 1; if (offset < 0) return false; CharSequence chars = editor.getDocument().getCharsSequence(); char c = chars.charAt(offset); final Editor injectedEditor = TypedHandler.injectedEditorIfCharTypedIsSignificant(c, editor, file); final Editor originalEditor = editor; if (injectedEditor != editor) { int injectedOffset = injectedEditor.getCaretModel().getOffset(); if (isOffsetInsideInjected(injectedEditor, injectedOffset)) { file = PsiDocumentManager.getInstance(project).getPsiFile(injectedEditor.getDocument()); editor = injectedEditor; offset = injectedOffset - 1; } } final BackspaceHandlerDelegate[] delegates = Extensions.getExtensions(BackspaceHandlerDelegate.EP_NAME); if (!toWordStart) { for (BackspaceHandlerDelegate delegate : delegates) { delegate.beforeCharDeleted(c, file, editor); } } FileType fileType = file.getFileType(); final QuoteHandler quoteHandler = TypedHandler.getQuoteHandler(file, editor); HighlighterIterator hiterator = ((EditorEx) editor).getHighlighter().createIterator(offset); boolean wasClosingQuote = quoteHandler != null && quoteHandler.isClosingQuote(hiterator, offset); myOriginalHandler.execute(originalEditor, caret, dataContext); if (!toWordStart) { for (BackspaceHandlerDelegate delegate : delegates) { if (delegate.charDeleted(c, file, editor)) { return true; } } } if (offset >= editor.getDocument().getTextLength()) return true; chars = editor.getDocument().getCharsSequence(); if ((c == '(' || c == '[' || c == '{') && CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) { char c1 = chars.charAt(offset); if (c1 != getRightChar(c)) return true; HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset); BraceMatcher braceMatcher = BraceMatchingUtil.getBraceMatcher(fileType, iterator); if (!braceMatcher.isLBraceToken(iterator, chars, fileType) && !braceMatcher.isRBraceToken(iterator, chars, fileType)) { return true; } int rparenOffset = BraceMatchingUtil.findRightmostRParen(iterator, iterator.getTokenType(), chars, fileType); if (rparenOffset >= 0) { iterator = ((EditorEx) editor).getHighlighter().createIterator(rparenOffset); boolean matched = BraceMatchingUtil.matchBrace(chars, fileType, iterator, false); if (matched) return true; } editor.getDocument().deleteString(offset, offset + 1); } else if ((c == '"' || c == '\'' || c == '`') && CodeInsightSettings.getInstance().AUTOINSERT_PAIR_QUOTE) { char c1 = chars.charAt(offset); if (c1 != c) return true; if (wasClosingQuote) return true; HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset); if (quoteHandler == null || !quoteHandler.isOpeningQuote(iterator, offset)) return true; editor.getDocument().deleteString(offset, offset + 1); } return true; }
@Override public void executeWriteAction(Editor editor, Caret caret, DataContext dataContext) { if (!handleBackspace(editor, caret, dataContext, false)) { myOriginalHandler.execute(editor, caret, dataContext); } }
/** * There is a possible case that target code block already starts with the empty line: * * <pre> * void test(int i) { * if (i > 1[caret]) { * * } * } * </pre> * * We want just move caret to correct position at that empty line without creating additional * empty line then. * * @param editor target editor * @param codeBlock target code block to which new empty line is going to be inserted * @param element target element under caret * @return <code>true</code> if it was found out that the given code block starts with the empty * line and caret is pointed to correct position there, i.e. no additional processing is * required; <code>false</code> otherwise */ private static boolean processExistingBlankLine( @NotNull Editor editor, @Nullable PsiCodeBlock codeBlock, @Nullable PsiElement element) { PsiWhiteSpace whiteSpace = null; if (codeBlock == null) { if (element != null) { final PsiElement next = PsiTreeUtil.nextLeaf(element); if (next instanceof PsiWhiteSpace) { whiteSpace = (PsiWhiteSpace) next; } } } else { whiteSpace = PsiTreeUtil.findChildOfType(codeBlock, PsiWhiteSpace.class); if (whiteSpace == null) { return false; } PsiElement lbraceCandidate = whiteSpace.getPrevSibling(); if (lbraceCandidate == null) { return false; } ASTNode node = lbraceCandidate.getNode(); if (node == null || node.getElementType() != JavaTokenType.LBRACE) { return false; } } if (whiteSpace == null) { return false; } final TextRange textRange = whiteSpace.getTextRange(); final Document document = editor.getDocument(); final CharSequence whiteSpaceText = document .getCharsSequence() .subSequence(textRange.getStartOffset(), textRange.getEndOffset()); if (StringUtil.countNewLines(whiteSpaceText) < 2) { return false; } int i = CharArrayUtil.shiftForward(whiteSpaceText, 0, " \t"); if (i >= whiteSpaceText.length() - 1) { assert false : String.format( "code block: %s, white space: %s", codeBlock == null ? "undefined" : codeBlock.getTextRange(), whiteSpace.getTextRange()); return false; } editor.getCaretModel().moveToOffset(i + 1 + textRange.getStartOffset()); EditorActionManager actionManager = EditorActionManager.getInstance(); EditorActionHandler actionHandler = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_MOVE_LINE_END); final DataContext dataContext = DataManager.getInstance().getDataContext(editor.getComponent()); if (dataContext == null) { i = CharArrayUtil.shiftForwardUntil(whiteSpaceText, i, "\n"); if (i >= whiteSpaceText.length()) { i = whiteSpaceText.length(); } editor.getCaretModel().moveToOffset(i + textRange.getStartOffset()); } else { actionHandler.execute(editor, dataContext); } return true; }
@Override public boolean isEnabled(Editor editor, DataContext dataContext) { LookupImpl lookup = (LookupImpl) LookupManager.getActiveLookup(editor); return lookup != null || myOriginalHandler.isEnabled(editor, dataContext); }
private void executeWriteActionInner(Editor editor, DataContext dataContext, Project project) { CodeInsightSettings settings = CodeInsightSettings.getInstance(); if (project == null) { myOriginalHandler.execute(editor, dataContext); return; } final Document document = editor.getDocument(); final PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, project); if (file == null) { myOriginalHandler.execute(editor, dataContext); return; } CommandProcessor.getInstance() .setCurrentCommandName(CodeInsightBundle.message("command.name.typing")); EditorModificationUtil.deleteSelectedText(editor); int caretOffset = editor.getCaretModel().getOffset(); CharSequence text = document.getCharsSequence(); int length = document.getTextLength(); if (caretOffset < length && text.charAt(caretOffset) != '\n') { int offset1 = CharArrayUtil.shiftBackward(text, caretOffset, " \t"); if (offset1 < 0 || text.charAt(offset1) == '\n') { int offset2 = CharArrayUtil.shiftForward(text, offset1 + 1, " \t"); boolean isEmptyLine = offset2 >= length || text.charAt(offset2) == '\n'; if (!isEmptyLine) { // we are in leading spaces of a non-empty line myOriginalHandler.execute(editor, dataContext); return; } } } final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); documentManager.commitDocument(document); boolean forceIndent = false; boolean forceSkipIndent = false; Ref<Integer> caretOffsetRef = new Ref<Integer>(caretOffset); Ref<Integer> caretAdvanceRef = new Ref<Integer>(0); final EnterHandlerDelegate[] delegates = Extensions.getExtensions(EnterHandlerDelegate.EP_NAME); for (EnterHandlerDelegate delegate : delegates) { EnterHandlerDelegate.Result result = delegate.preprocessEnter( file, editor, caretOffsetRef, caretAdvanceRef, dataContext, myOriginalHandler); if (caretOffsetRef.get() > document.getTextLength()) { throw new AssertionError("Wrong caret offset change by " + delegate); } if (result == EnterHandlerDelegate.Result.Stop) { return; } if (result != EnterHandlerDelegate.Result.Continue) { if (result == EnterHandlerDelegate.Result.DefaultForceIndent) { forceIndent = true; } else if (result == EnterHandlerDelegate.Result.DefaultSkipIndent) { forceSkipIndent = true; } break; } } text = document.getCharsSequence(); // update after changes done in preprocessEnter() caretOffset = caretOffsetRef.get().intValue(); boolean isFirstColumn = caretOffset == 0 || text.charAt(caretOffset - 1) == '\n'; final boolean insertSpace = !isFirstColumn && !(caretOffset >= text.length() || text.charAt(caretOffset) == ' ' || text.charAt(caretOffset) == '\t'); editor.getCaretModel().moveToOffset(caretOffset); myOriginalHandler.execute(editor, dataContext); if (!editor.isInsertMode() || forceSkipIndent) { return; } if (settings.SMART_INDENT_ON_ENTER || forceIndent) { caretOffset += 1; caretOffset = CharArrayUtil.shiftForward(editor.getDocument().getCharsSequence(), caretOffset, " \t"); } else { caretOffset = editor.getCaretModel().getOffset(); } documentManager.commitAllDocuments(); final DoEnterAction action = new DoEnterAction( file, editor, document, dataContext, caretOffset, !insertSpace, caretAdvanceRef.get(), project); action.setForceIndent(forceIndent); action.run(); documentManager.commitDocument(document); for (EnterHandlerDelegate delegate : delegates) { if (delegate.postProcessEnter(file, editor, dataContext) == EnterHandlerDelegate.Result.Stop) { break; } } documentManager.commitDocument(document); }
@Override public boolean isEnabled(Editor editor, DataContext dataContext) { return myOriginalHandler.isEnabled(editor, dataContext); }
@Override public boolean isEnabledForCaret( @NotNull Editor editor, @NotNull Caret caret, DataContext dataContext) { return myOriginalHandler.isEnabled(editor, caret, dataContext); }
public static void performPaste(Editor editor) { EditorActionManager actionManager = EditorActionManager.getInstance(); EditorActionHandler actionHandler = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_PASTE); actionHandler.execute(editor, DataManager.getInstance().getDataContext()); }