@Override public void execute(@NotNull final Editor editor, final DataContext dataContext) { final LookupImpl lookup = (LookupImpl) LookupManager.getActiveLookup(editor); if (lookup == null) { throw new AssertionError( "The last lookup disposed at: " + LookupImpl.getLastLookupDisposeTrace() + "\n-----------------------\n"); } if (finishingChar == Lookup.NORMAL_SELECT_CHAR) { if (!lookup.isFocused()) { FeatureUsageTracker.getInstance() .triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_CONTROL_ENTER); } } else if (finishingChar == Lookup.COMPLETE_STATEMENT_SELECT_CHAR) { FeatureUsageTracker.getInstance() .triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_FINISH_BY_SMART_ENTER); } else if (finishingChar == Lookup.REPLACE_SELECT_CHAR) { FeatureUsageTracker.getInstance() .triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_REPLACE); } else if (finishingChar == '.') { FeatureUsageTracker.getInstance() .triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_FINISH_BY_CONTROL_DOT); } lookup.finishLookup(finishingChar); }
public CompletionProgressIndicator( final Editor editor, CompletionParameters parameters, CodeCompletionHandlerBase handler, Semaphore freezeSemaphore, final OffsetMap offsetMap, boolean hasModifiers) { myEditor = editor; myParameters = parameters; myHandler = handler; myFreezeSemaphore = freezeSemaphore; myOffsetMap = offsetMap; myLookup = (LookupImpl) parameters.getLookup(); myLookup.setArranger(new CompletionLookupArranger(parameters, this)); myLookup.addLookupListener(myLookupListener); myLookup.setCalculating(true); myLookupManagerListener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getNewValue() != null) { LOG.error( "An attempt to change the lookup during completion, phase = " + CompletionServiceImpl.getCompletionPhase()); } } }; LookupManager.getInstance(getProject()).addPropertyChangeListener(myLookupManagerListener); myQueue = new MergingUpdateQueue( "completion lookup progress", 200, true, myEditor.getContentComponent()); myQueue.setPassThrough(false); ApplicationManager.getApplication().assertIsDispatchThread(); addMapToDispose(offsetMap); if (ApplicationManager.getApplication().isUnitTestMode()) { return; } if (!myLookup.isShown()) { scheduleAdvertising(); } if (hasModifiers) { trackModifiers(); } }
public void closeAndFinish(boolean hideLookup) { if (!myLookup.isLookupDisposed()) { Lookup lookup = LookupManager.getActiveLookup(myEditor); LOG.assertTrue(lookup == myLookup, "lookup changed: " + lookup + "; " + this); } myLookup.removeLookupListener(myLookupListener); finishCompletionProcess(true); CompletionServiceImpl.assertPhase(CompletionPhase.NoCompletion.getClass()); if (hideLookup) { LookupManager.getInstance(getProject()).hideActiveLookup(); } }
void duringCompletion(CompletionInitializationContext initContext) { if (isAutopopupCompletion()) { if (shouldFocusLookup(myParameters)) { myLookup.setFocused(true); } else if (FeatureUsageTracker.getInstance() .isToBeAdvertisedInLookup( CodeCompletionFeatures.EDITING_COMPLETION_CONTROL_ENTER, getProject())) { myLookup.addAdvertisement( "Press " + CompletionContributor.getActionShortcut( IdeActions.ACTION_CHOOSE_LOOKUP_ITEM_ALWAYS) + " to choose the first suggestion"); } if (!myEditor.isOneLineMode() && FeatureUsageTracker.getInstance() .isToBeAdvertisedInLookup( CodeCompletionFeatures.EDITING_COMPLETION_CONTROL_ARROWS, getProject())) { myLookup.addAdvertisement( CompletionContributor.getActionShortcut(IdeActions.ACTION_LOOKUP_DOWN) + " and " + CompletionContributor.getActionShortcut(IdeActions.ACTION_LOOKUP_UP) + " will move caret down and up in the editor"); } } ProgressManager.checkCanceled(); if (!initContext .getOffsetMap() .wasModified(CompletionInitializationContext.IDENTIFIER_END_OFFSET)) { try { final int selectionEndOffset = initContext.getSelectionEndOffset(); final PsiReference reference = initContext.getFile().findReferenceAt(selectionEndOffset); if (reference != null) { initContext.setReplacementOffset(findReplacementOffset(selectionEndOffset, reference)); } } catch (IndexNotReadyException ignored) { } } for (CompletionContributor contributor : CompletionContributor.forLanguage(initContext.getPositionLanguage())) { ProgressManager.checkCanceled(); if (DumbService.getInstance(initContext.getProject()).isDumb() && !DumbService.isDumbAware(contributor)) { continue; } contributor.duringCompletion(initContext); } }
private boolean updateLookup() { ApplicationManager.getApplication().assertIsDispatchThread(); if (isOutdated() || !shouldShowLookup()) return false; boolean justShown = false; if (!myLookup.isShown()) { if (hideAutopopupIfMeaningless()) { return false; } if (Registry.is("dump.threads.on.empty.lookup") && myLookup.isCalculating() && myLookup.getItems().isEmpty()) { PerformanceWatcher.getInstance().dumpThreads(true); } if (StringUtil.isEmpty(myLookup.getAdvertisementText()) && !isAutopopupCompletion()) { final String text = DefaultCompletionContributor.getDefaultAdvertisementText(myParameters); if (text != null) { myLookup.setAdvertisementText(text); } } if (!myLookup.showLookup()) { return false; } justShown = true; } myLookup.refreshUi(true, justShown); hideAutopopupIfMeaningless(); if (justShown) { myLookup.ensureSelectionVisible(); } return true; }
@NotNull private LookupImpl obtainLookup(Editor editor) { CompletionAssertions.checkEditorValid(editor); LookupImpl existing = (LookupImpl) LookupManager.getActiveLookup(editor); if (existing != null && existing.isCompletion()) { existing.markReused(); if (!autopopup) { existing.setFocusDegree(LookupImpl.FocusDegree.FOCUSED); } return existing; } LookupImpl lookup = (LookupImpl) LookupManager.getInstance(editor.getProject()) .createLookup( editor, LookupElement.EMPTY_ARRAY, "", new LookupArranger.DefaultArranger()); if (editor.isOneLineMode()) { lookup.setCancelOnClickOutside(true); lookup.setCancelOnOtherWindowOpen(true); } lookup.setFocusDegree( autopopup ? LookupImpl.FocusDegree.UNFOCUSED : LookupImpl.FocusDegree.FOCUSED); return lookup; }
public void perform(final boolean generatePrivate) { final Runnable runnable = new Runnable() { public void run() { final DocumentEx document = (DocumentEx) myEditor.getDocument(); int exprOffset = myExprMarker.getStartOffset(); final int lineOffset = getLineOffset(document, exprOffset); if (generatePrivate) { final Collection<RangeMarker> leftGreedyMarker = ContainerUtil.newArrayList(); final Collection<RangeMarker> emptyMarkers = ContainerUtil.newArrayList(); for (RangeHighlighter rangeHighlighter : myEditor.getMarkupModel().getAllHighlighters()) { collectRangeMarker(rangeHighlighter, lineOffset, leftGreedyMarker, emptyMarkers); } document.processRangeMarkers( new Processor<RangeMarker>() { @Override public boolean process(RangeMarker rangeMarker) { collectRangeMarker(rangeMarker, lineOffset, leftGreedyMarker, emptyMarkers); return true; } }); setLeftGreedy(leftGreedyMarker, false); setRightGreedy(emptyMarkers, true); // workaround for shifting empty ranges to the left document.insertString(lineOffset, " "); document.insertString(lineOffset, PRIVATE); document.deleteString( lineOffset + PRIVATE.length(), lineOffset + PRIVATE.length() + 1); setLeftGreedy(leftGreedyMarker, true); setRightGreedy(emptyMarkers, false); } else { int idx = document.getText().indexOf(PRIVATE, lineOffset); if (idx > -1 && idx < exprOffset) { document.deleteString(idx, idx + PRIVATE.length()); } } PsiDocumentManager.getInstance(myProject).commitDocument(document); } }; final LookupImpl lookup = (LookupImpl) LookupManager.getActiveLookup(myEditor); if (lookup != null) { lookup.performGuardedChange(runnable); } else { runnable.run(); } }
public synchronized void addItem(final CompletionResult item) { if (!isRunning()) return; ProgressManager.checkCanceled(); final boolean unitTestMode = ApplicationManager.getApplication().isUnitTestMode(); if (!unitTestMode) { LOG.assertTrue(!ApplicationManager.getApplication().isDispatchThread()); } LOG.assertTrue(myParameters.getPosition().isValid()); myItemSorters.put(item.getLookupElement(), (CompletionSorterImpl) item.getSorter()); myLookup.addItem(item.getLookupElement(), item.getPrefixMatcher()); myCount++; if (myCount == 1) { ApplicationManager.getApplication() .executeOnPooledThread( new Runnable() { public void run() { try { Thread.sleep(300); } catch (InterruptedException ignore) { } finally { myFreezeSemaphore.up(); } } }); } myQueue.queue(myUpdate); }
public synchronized void addItem(final CompletionResult item) { if (!isRunning()) return; ProgressManager.checkCanceled(); final boolean unitTestMode = ApplicationManager.getApplication().isUnitTestMode(); if (!unitTestMode) { LOG.assertTrue(!ApplicationManager.getApplication().isDispatchThread()); } LOG.assertTrue(myParameters.getPosition().isValid()); myItemSorters.put(item.getLookupElement(), (CompletionSorterImpl) item.getSorter()); myLookup.addItem(item.getLookupElement(), item.getPrefixMatcher()); myCount++; if (myCount == 1) { new Alarm(Alarm.ThreadToUse.SHARED_THREAD, this) .addRequest( new Runnable() { @Override public void run() { myFreezeSemaphore.up(); } }, 300); } myQueue.queue(myUpdate); }
private boolean hideAutopopupIfMeaningless() { if (!myLookup.isLookupDisposed() && isAutopopupCompletion() && !myLookup.isSelectionTouched() && !myLookup.isCalculating()) { myLookup.refreshUi(true); final List<LookupElement> items = myLookup.getItems(); for (LookupElement item : items) { if (!myLookup.itemPattern(item).equals(item.getLookupString())) { return false; } if (item.isValid()) { final LookupElementPresentation presentation = new LookupElementPresentation(); item.renderElement(presentation); if (StringUtil.isNotEmpty(presentation.getTailText())) { return false; } } } myLookup.hideLookup(false); LOG.assertTrue(CompletionServiceImpl.getCompletionService().getCurrentCompletion() == null); CompletionServiceImpl.setCompletionPhase(new CompletionPhase.EmptyAutoPopup(this)); return true; } return false; }
public void scheduleRestart() { ApplicationManager.getApplication().assertIsDispatchThread(); cancel(); final CompletionProgressIndicator current = CompletionServiceImpl.getCompletionService().getCurrentCompletion(); if (this != current) { LOG.error(current + "!=" + this); } if (isAutopopupCompletion() && !myLookup.isShown()) { if (CompletionServiceImpl.getCompletionService().getCurrentCompletion() == this) { closeAndFinish(true); } AutoPopupController.getInstance(getProject()).scheduleAutoPopup(myEditor, null); return; } hideAutopopupIfMeaningless(); CompletionPhase oldPhase = CompletionServiceImpl.getCompletionPhase(); if (oldPhase instanceof CompletionPhase.CommittingDocuments) { ((CompletionPhase.CommittingDocuments) oldPhase).replaced = true; } final CompletionPhase.CommittingDocuments phase = new CompletionPhase.CommittingDocuments(this, myEditor); CompletionServiceImpl.setCompletionPhase(phase); final Project project = getProject(); ApplicationManager.getApplication() .invokeLater( new Runnable() { @Override public void run() { CompletionAutoPopupHandler.runLaterWithCommitted( project, myEditor.getDocument(), new Runnable() { @Override public void run() { if (phase.checkExpired()) return; CompletionAutoPopupHandler.invokeCompletion( myParameters.getCompletionType(), isAutopopupCompletion(), project, myEditor, myParameters.getInvocationCount(), true); } }); } }, project.getDisposed()); }
private static int getItemToSelect( LookupImpl lookup, List<LookupElement> items, boolean onExplicitAction, @Nullable LookupElement mostRelevant) { if (items.isEmpty() || lookup.getFocusDegree() == LookupImpl.FocusDegree.UNFOCUSED) { return 0; } if (lookup.isSelectionTouched() || !onExplicitAction) { final LookupElement lastSelection = lookup.getCurrentItem(); int old = ContainerUtil.indexOfIdentity(items, lastSelection); if (old >= 0) { return old; } Object selectedValue = ((LookupImpl) lookup).getList().getSelectedValue(); if (selectedValue instanceof EmptyLookupItem && ((EmptyLookupItem) selectedValue).isLoading()) { int index = ((LookupImpl) lookup).getList().getSelectedIndex(); if (index >= 0 && index < items.size()) { return index; } } for (int i = 0; i < items.size(); i++) { String invariant = PRESENTATION_INVARIANT.get(items.get(i)); if (invariant != null && invariant.equals(PRESENTATION_INVARIANT.get(lastSelection))) { return i; } } } String selectedText = lookup.getEditor().getSelectionModel().getSelectedText(); for (int i = 0; i < items.size(); i++) { LookupElement item = items.get(i); if (isPrefixItem(lookup, item, true) && !isLiveTemplate(item) || item.getLookupString().equals(selectedText)) { return i; } } return Math.max(0, ContainerUtil.indexOfIdentity(items, mostRelevant)); }
public boolean isRepeatedInvocation(CompletionType completionType, Editor editor) { if (completionType != myParameters.getCompletionType() || editor != myEditor) { return false; } if (isAutopopupCompletion() && !myLookup.mayBeNoticed()) { return false; } return true; }
@Override public boolean isEnabled(Editor editor, DataContext dataContext) { LookupImpl lookup = (LookupImpl) LookupManager.getActiveLookup(editor); if (lookup == null) return false; if (!lookup.isAvailableToUser()) return false; if (focusedOnly && !CompletionPreview.hasPreview(lookup) && !lookup.isFocused()) return false; if (finishingChar == Lookup.NORMAL_SELECT_CHAR && hasTemplatePrefix(lookup, TemplateSettings.ENTER_CHAR) || finishingChar == Lookup.REPLACE_SELECT_CHAR && hasTemplatePrefix(lookup, TemplateSettings.TAB_CHAR)) { return false; } if (finishingChar == Lookup.REPLACE_SELECT_CHAR) { if (lookup.isFocused()) { return true; } return !lookup.getItems().isEmpty(); } return true; }
private boolean updateLookup() { ApplicationManager.getApplication().assertIsDispatchThread(); if (isOutdated()) return false; boolean justShown = false; if (!myLookup.isShown() && shouldShowLookup()) { if (hideAutopopupIfMeaningless()) { return false; } if (StringUtil.isEmpty(myLookup.getAdvertisementText()) && !isAutopopupCompletion()) { final String text = DefaultCompletionContributor.getDefaultAdvertisementText(myParameters); if (text != null) { myLookup.setAdvertisementText(text); } } if (!myLookup.showLookup()) { return false; } justShown = true; } myLookup.refreshUi(true); hideAutopopupIfMeaningless(); if (justShown) { myLookup.ensureSelectionVisible(); } return true; }
public void itemSelected(LookupEvent event) { finishCompletionProcess(false); LookupElement item = event.getItem(); if (item == null) return; setMergeCommand(); CodeCompletionHandlerBase.lookupItemSelected( CompletionProgressIndicator.this, item, event.getCompletionChar(), myLookup.getItems()); }
private static void ensureEverythingVisibleAdded( LookupImpl lookup, final LinkedHashSet<LookupElement> model, Iterator<LookupElement> byRelevance) { JList list = lookup.getList(); final boolean testMode = ApplicationManager.getApplication().isUnitTestMode(); final int limit = Math.max(list.getLastVisibleIndex(), model.size()) + ourUISettings.MAX_LOOKUP_LIST_HEIGHT * 3; addSomeItems( model, byRelevance, new Condition<LookupElement>() { @Override public boolean value(LookupElement lastAdded) { return !testMode && model.size() >= limit; } }); }
private List<LookupElement> fillModelByRelevance( LookupImpl lookup, List<LookupElement> items, MultiMap<CompletionSorterImpl, LookupElement> inputBySorter, @Nullable LookupElement relevantSelection) { Iterator<LookupElement> byRelevance = sortByRelevance(inputBySorter).iterator(); final LinkedHashSet<LookupElement> model = new LinkedHashSet<LookupElement>(); addPrefixItems(model); addFrozenItems(items, model); addSomeItems( model, byRelevance, new Condition<LookupElement>() { @Override public boolean value(LookupElement lastAdded) { return model.size() >= MAX_PREFERRED_COUNT; } }); addCurrentlySelectedItemToTop(lookup, items, model); freezeTopItems(lookup, model); ensureItemAdded(items, model, byRelevance, lookup.getCurrentItem()); ensureItemAdded(items, model, byRelevance, relevantSelection); ensureEverythingVisibleAdded(lookup, model, byRelevance); ArrayList<LookupElement> result = new ArrayList<LookupElement>(model); if (result.size() > 1) { LookupElement first = result.get(0); if (isLiveTemplate(first) && isPrefixItem(lookup, first, true)) { ContainerUtil.swapElements(result, 0, 1); } } return result; }
void scheduleAdvertising() { if (myLookup.isAvailableToUser()) { return; } final List<CompletionContributor> list = CompletionContributor.forParameters(myParameters); for (final CompletionContributor contributor : list) { if (myLookup.getAdvertisementText() != null) return; if (!myLookup.isCalculating() && !myLookup.isVisible()) return; @SuppressWarnings("deprecation") String s = contributor.advertise(myParameters); if (myLookup.getAdvertisementText() != null) return; if (s != null) { myLookup.setAdvertisementText(s); ApplicationManager.getApplication() .invokeLater( new Runnable() { @Override public void run() { if (isAutopopupCompletion() && !myLookup.isAvailableToUser()) { return; } if (!CompletionServiceImpl.isPhase( CompletionPhase.BgCalculation.class, CompletionPhase.ItemsCalculated.class)) { return; } if (CompletionServiceImpl.getCompletionPhase().indicator != CompletionProgressIndicator.this) { return; } updateLookup(); } }, myQueue.getModalityState()); return; } } }
public static boolean hasTemplatePrefix(LookupImpl lookup, char shortcutChar) { lookup.refreshUi(false, false); // to bring the list model up to date CompletionProcess completion = CompletionService.getCompletionService().getCurrentCompletion(); if (completion == null || !completion.isAutopopupCompletion()) { return false; } if (lookup.isSelectionTouched()) { return false; } final PsiFile file = lookup.getPsiFile(); if (file == null) return false; final Editor editor = lookup.getEditor(); PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument()); final int end = editor.getCaretModel().getOffset(); final int start = lookup.getLookupStart(); final String prefix = !lookup.getItems().isEmpty() ? editor.getDocument().getText(TextRange.create(start, end)) : ListTemplatesHandler.getPrefix(editor.getDocument(), end); if (TemplateSettings.getInstance().getTemplates(prefix).isEmpty()) { return false; } for (TemplateImpl template : SurroundWithTemplateHandler.getApplicableTemplates(editor, file, false)) { if (prefix.equals(template.getKey()) && shortcutChar == TemplateSettings.getInstance().getShortcutChar(template)) { return true; } } return false; }
private void freezeTopItems(LookupImpl lookup, LinkedHashSet<LookupElement> model) { myFrozenItems.clear(); if (lookup.isShown()) { myFrozenItems.addAll(model); } }
private boolean shouldShowLookup() { if (isAutopopupCompletion() && myLookup.isCalculating()) { return false; } return true; }