@Override public void update(AnActionEvent e) { Presentation presentation = e.getPresentation(); Project project = e.getProject(); if (project == null) { presentation.setEnabled(false); return; } final DataContext dataContext = e.getDataContext(); Editor editor = getEditor(dataContext, project, true); if (editor == null) { presentation.setEnabled(false); return; } final PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, project); if (file == null) { presentation.setEnabled(false); return; } update(presentation, project, editor, file, dataContext, e.getPlace()); }
public void actionPerformedImpl(@NotNull final Project project, final Editor editor) { if (editor == null) return; // final PsiFile psiFile = // PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project); if (psiFile == null) return; CommandProcessor.getInstance() .executeCommand( project, () -> { final CodeInsightActionHandler handler = getHandler(); final Runnable action = () -> { if (!ApplicationManager.getApplication().isUnitTestMode() && !editor.getContentComponent().isShowing()) return; handler.invoke(project, editor, psiFile); }; if (handler.startInWriteAction()) { ApplicationManager.getApplication().runWriteAction(action); } else { action.run(); } }, getCommandName(), DocCommandGroupId.noneGroupId(editor.getDocument())); }
@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); }
private void invokeCompletion(final ExpressionContext context) { final Project project = context.getProject(); final Editor editor = context.getEditor(); final PsiFile psiFile = editor != null ? PsiUtilBase.getPsiFileInEditor(editor, project) : null; Runnable runnable = () -> { if (project.isDisposed() || editor == null || editor.isDisposed() || psiFile == null || !psiFile.isValid()) return; // it's invokeLater, so another completion could have started if (CompletionServiceImpl.getCompletionService().getCurrentCompletion() != null) return; CommandProcessor.getInstance() .executeCommand( project, () -> { // if we're in some completion's insert handler, make sure our new completion // isn't treated as the second invocation CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); invokeCompletionHandler(project, editor); Lookup lookup = LookupManager.getInstance(project).getActiveLookup(); if (lookup != null) { lookup.addLookupListener( new MyLookupListener(context, myCheckCompletionChar)); } }, "", null); }; ApplicationManager.getApplication().invokeLater(runnable); }
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; }
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); }
public final void invokeCompletion( @NotNull final Project project, @NotNull final Editor editor, int time, boolean hasModifiers, boolean restarted) { final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project); assert psiFile != null : "no PSI file: " + FileDocumentManager.getInstance().getFile(editor.getDocument()); checkNoWriteAccess(); CompletionAssertions.checkEditorValid(editor); if (editor.isViewer()) { editor.getDocument().fireReadOnlyModificationAttempt(); return; } if (invokedExplicitly) { CompletionLookupArranger.applyLastCompletionStatisticsUpdate(); } if (!CodeInsightUtilBase.prepareEditorForWrite(editor) || !FileDocumentManager.getInstance().requestWriting(editor.getDocument(), project)) { return; } psiFile.putUserData(PsiFileEx.BATCH_REFERENCE_PROCESSING, Boolean.TRUE); CompletionPhase phase = CompletionServiceImpl.getCompletionPhase(); boolean repeated = phase.indicator != null && phase.indicator.isRepeatedInvocation(myCompletionType, editor); /* if (repeated && isAutocompleteCommonPrefixOnInvocation() && phase.fillInCommonPrefix()) { return; } */ int newTime = phase.newCompletionStarted(time, repeated); if (invokedExplicitly) { time = newTime; } if (CompletionServiceImpl.isPhase(CompletionPhase.InsertedSingleItem.class)) { CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); } CompletionServiceImpl.assertPhase( CompletionPhase.NoCompletion.getClass(), CompletionPhase.CommittingDocuments.class); if (time > 1) { if (myCompletionType == CompletionType.BASIC) { FeatureUsageTracker.getInstance() .triggerFeatureUsed(CodeCompletionFeatures.SECOND_BASIC_COMPLETION); } } final CompletionInitializationContext[] initializationContext = {null}; Runnable initCmd = new Runnable() { @Override public void run() { Runnable runnable = new Runnable() { @Override public void run() { EditorUtil.fillVirtualSpaceUntilCaret(editor); PsiDocumentManager.getInstance(project).commitAllDocuments(); CompletionAssertions.assertCommitSuccessful(editor, psiFile); CompletionAssertions.checkEditorValid(editor); initializationContext[0] = runContributorsBeforeCompletion(editor, psiFile); } }; ApplicationManager.getApplication().runWriteAction(runnable); } }; if (autopopup) { CommandProcessor.getInstance().runUndoTransparentAction(initCmd); if (!restarted && shouldSkipAutoPopup(editor, psiFile)) { CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); return; } } else { CommandProcessor.getInstance().executeCommand(project, initCmd, null, null); } insertDummyIdentifier(initializationContext[0], hasModifiers, time); }