static CharFilter.Result getLookupAction(final char charTyped, final LookupImpl lookup) { final CharFilter.Result filtersDecision = getFiltersDecision(charTyped, lookup); if (!Registry.is("ide.completion.allow.finishing.by.chars") && filtersDecision == CharFilter.Result.SELECT_ITEM_AND_FINISH_LOOKUP) { return CharFilter.Result.HIDE_LOOKUP; } final LookupElement currentItem = lookup.getCurrentItem(); if (currentItem != null && charTyped != ' ') { String postfix = lookup.getAdditionalPrefix() + charTyped; final PrefixMatcher matcher = lookup.itemMatcher(currentItem); for (String lookupString : currentItem.getAllLookupStrings()) { if (lookupString.startsWith(matcher.getPrefix() + postfix)) { return CharFilter.Result.ADD_TO_PREFIX; } } } if (filtersDecision != null) { return filtersDecision; } throw new AssertionError( "Typed char not handler by char filter: c=" + charTyped + "; prefix=" + currentItem + "; filters=" + Arrays.toString(getFilters())); }
@Nullable private static CharFilter.Result getFiltersDecision(char charTyped, LookupImpl lookup) { LookupElement item = lookup.getCurrentItem(); int prefixLength = item == null ? lookup.getAdditionalPrefix().length() : lookup.itemPattern(item).length(); for (final CharFilter extension : getFilters()) { final CharFilter.Result result = extension.acceptChar(charTyped, prefixLength, lookup); if (result != null) { return result; } } return null; }
private static boolean completeTillTypedCharOccurrence( char charTyped, LookupImpl lookup, LookupElement item) { PrefixMatcher matcher = lookup.itemMatcher(item); final String oldPrefix = matcher.getPrefix() + lookup.getAdditionalPrefix(); PrefixMatcher expanded = matcher.cloneWithPrefix(oldPrefix + charTyped); if (expanded.prefixMatches(item)) { for (String s : item.getAllLookupStrings()) { if (matcher.prefixMatches(s)) { int i = -1; while (true) { i = s.indexOf(charTyped, i + 1); if (i < 0) break; final String newPrefix = s.substring(0, i + 1); if (expanded.prefixMatches(newPrefix)) { lookup.replacePrefix(oldPrefix, newPrefix); return true; } } } } } return false; }
private static void finishLookup(final char charTyped, @NotNull final LookupImpl lookup) { final Editor editor = lookup.getEditor(); FeatureUsageTracker.getInstance() .triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_FINISH_BY_DOT_ETC); CompletionProcess process = CompletionService.getCompletionService().getCurrentCompletion(); SelectionModel sm = editor.getSelectionModel(); final boolean smartUndo = false; // !sm.hasSelection() && !sm.hasBlockSelection() && process != null && // process.isAutopopupCompletion(); final ScrollingModelEx scrollingModel = (ScrollingModelEx) editor.getScrollingModel(); scrollingModel.accumulateViewportChanges(); try { final LinkedList<EditorChangeAction> events = smartUndo ? justTypeChar(charTyped, lookup, editor) : null; if (lookup.isLookupDisposed()) { // if justTypeChar corrupted the start offset return; } CommandProcessor.getInstance() .executeCommand( editor.getProject(), new Runnable() { @Override public void run() { if (smartUndo && !undoEvents(lookup, events)) { return; } lookup.finishLookup(charTyped); } }, null, "Undo inserting the completion char and select the item"); } finally { scrollingModel.flushViewportChanges(); } }
private static boolean undoEvents( LookupImpl lookup, @NotNull final LinkedList<EditorChangeAction> events) { AccessToken token = WriteAction.start(); try { return lookup.performGuardedChange( new Runnable() { @Override public void run() { for (EditorChangeAction event : events) { event.performUndo(); } } }, events.toString()); } finally { token.finish(); } }
@SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod") @Override public Result beforeCharTyped( final char charTyped, Project project, final Editor editor, PsiFile file, FileType fileType) { assert !inside; inside = true; try { final LookupImpl lookup = (LookupImpl) LookupManager.getActiveLookup(editor); if (lookup == null) { return Result.CONTINUE; } if (charTyped == ' ' && ChooseItemReplaceAction.hasTemplatePrefix(lookup, TemplateSettings.SPACE_CHAR)) { return Result.CONTINUE; } final CharFilter.Result result = getLookupAction(charTyped, lookup); if (lookup.isLookupDisposed()) { return Result.CONTINUE; } if (!lookup.performGuardedChange( new Runnable() { @Override public void run() { EditorModificationUtil.deleteSelectedText(editor); } })) { return Result.STOP; } if (result == CharFilter.Result.ADD_TO_PREFIX) { Document document = editor.getDocument(); long modificationStamp = document.getModificationStamp(); if (!lookup.performGuardedChange( new Runnable() { @Override public void run() { EditorModificationUtil.typeInStringAtCaretHonorBlockSelection( editor, String.valueOf(charTyped), true); } })) { return Result.STOP; } lookup.appendPrefix(charTyped); if (lookup.isStartCompletionWhenNothingMatches() && lookup.getItems().isEmpty()) { final CompletionProgressIndicator completion = CompletionServiceImpl.getCompletionService().getCurrentCompletion(); if (completion != null) { completion.scheduleRestart(); } else { AutoPopupController.getInstance(editor.getProject()).scheduleAutoPopup(editor, null); } } AutoHardWrapHandler.getInstance() .wrapLineIfNecessary( editor, DataManager.getInstance().getDataContext(editor.getContentComponent()), modificationStamp); final CompletionProgressIndicator completion = CompletionServiceImpl.getCompletionService().getCurrentCompletion(); if (completion != null) { completion.prefixUpdated(); } return Result.STOP; } if (result == CharFilter.Result.SELECT_ITEM_AND_FINISH_LOOKUP && lookup.isFocused()) { LookupElement item = lookup.getCurrentItem(); if (item != null) { if (completeTillTypedCharOccurrence(charTyped, lookup, item)) { return Result.STOP; } inside = false; ((CommandProcessorEx) CommandProcessor.getInstance()).enterModal(); try { finishLookup(charTyped, lookup); } finally { ((CommandProcessorEx) CommandProcessor.getInstance()).leaveModal(); } return Result.STOP; } } lookup.hide(); TypedHandler.autoPopupCompletion(editor, charTyped, project); return Result.CONTINUE; } finally { inside = false; } }