diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java index c3d1ec195f9e..829910392524 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java @@ -77,7 +77,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { private int myMinPrefixLength; private int myPreferredItemsCount; - private long myShownStamp = -1; private String myInitialPrefix; private LookupArranger myArranger; @@ -493,10 +492,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { } public void finishLookup(final char completionChar) { - if (justShown()) { - return; - } - final LookupElement item = (LookupElement)myList.getSelectedValue(); doHide(false, true); if (item == null || @@ -537,10 +532,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { fireItemSelected(item, completionChar); } - public boolean justShown() { - return myShownStamp > 0 && System.currentTimeMillis() - myShownStamp < 42 && !ApplicationManager.getApplication().isUnitTestMode(); - } - public int getLookupStart() { if (myLookupStartMarker == null) { final int start = calcLookupStart(); @@ -581,8 +572,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { hintManager.showEditorHint(this, myEditor, p, HintManagerImpl.HIDE_BY_ESCAPE | HintManagerImpl.UPDATE_BY_SCROLLING, 0, false); getComponent().getRootPane().getLayeredPane().add(myIconPanel, 42, 0); - - myShownStamp = System.currentTimeMillis(); } private void addListeners() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemAction.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemAction.java index 80f9c4b5da78..ecaf3f02a204 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemAction.java @@ -19,6 +19,7 @@ package com.intellij.codeInsight.lookup.impl.actions; import com.intellij.codeInsight.lookup.Lookup; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.codeInsight.template.impl.TemplateSettings; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.editor.Editor; @@ -33,6 +34,7 @@ public class ChooseItemAction extends EditorAction { private static class Handler extends EditorActionHandler { public void execute(final Editor editor, final DataContext dataContext) { LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor); + assert lookup != null; lookup.finishLookup(Lookup.NORMAL_SELECT_CHAR); } } @@ -41,7 +43,8 @@ public class ChooseItemAction extends EditorAction { LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor); if (lookup != null) { lookup.refreshUi(); // to bring the list model up to date - presentation.setEnabled(!lookup.justShown() && (lookup.isFocused() || lookup.isCompletion() && !lookup.getItems().isEmpty())); + presentation.setEnabled(lookup.isFocused() && + !ChooseItemReplaceAction.hasTemplatePrefix(lookup, TemplateSettings.ENTER_CHAR)); } else { presentation.setEnabled(false); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemReplaceAction.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemReplaceAction.java index fb3ea96fabf1..08052e24bd8a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemReplaceAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemReplaceAction.java @@ -17,15 +17,21 @@ package com.intellij.codeInsight.lookup.impl.actions; import com.intellij.codeInsight.completion.CodeCompletionFeatures; +import com.intellij.codeInsight.completion.CompletionUtil; import com.intellij.codeInsight.lookup.Lookup; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.codeInsight.template.impl.LiveTemplateCompletionContributor; +import com.intellij.codeInsight.template.impl.TemplateImpl; +import com.intellij.codeInsight.template.impl.TemplateSettings; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorAction; import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; public class ChooseItemReplaceAction extends EditorAction { public ChooseItemReplaceAction(){ @@ -36,15 +42,28 @@ public class ChooseItemReplaceAction extends EditorAction { public void executeWriteAction(Editor editor, DataContext dataContext) { FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_REPLACE); LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor); + assert lookup != null; lookup.finishLookup(Lookup.REPLACE_SELECT_CHAR); } } + static boolean hasTemplatePrefix(LookupImpl lookup, char shortcutChar) { + final PsiFile file = lookup.getPsiFile(); + final Editor editor = lookup.getEditor(); + PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument()); + + final int offset = editor.getCaretModel().getOffset(); + final String prefix = CompletionUtil.findJavaIdentifierPrefix(file, offset); + final TemplateImpl template = LiveTemplateCompletionContributor.findApplicableTemplate(file, offset, prefix); + return template != null && shortcutChar == TemplateSettings.getInstance().getShortcutChar(template); + } + public void update(Editor editor, Presentation presentation, DataContext dataContext){ LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor); if (lookup != null) { lookup.refreshUi(); // to bring the list model up to date - presentation.setEnabled(!lookup.justShown() && (lookup.isFocused() || lookup.isCompletion() && !lookup.getItems().isEmpty())); + presentation.setEnabled((lookup.isFocused() || lookup.isCompletion() && !lookup.getItems().isEmpty()) && + !hasTemplatePrefix(lookup, TemplateSettings.TAB_CHAR)); } else { presentation.setEnabled(false); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCompletionContributor.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCompletionContributor.java index 4124b438c120..bb3b5915a753 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCompletionContributor.java @@ -19,10 +19,17 @@ import com.intellij.codeInsight.completion.*; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.codeInsight.template.TemplateManager; +import com.intellij.openapi.util.Condition; import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.PsiFile; import com.intellij.util.ProcessingContext; +import com.intellij.util.containers.CollectionFactory; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; /** * @author peter @@ -39,23 +46,42 @@ public class LiveTemplateCompletionContributor extends CompletionContributor { final PsiFile file = parameters.getOriginalFile(); final int offset = parameters.getOffset(); final String prefix = result.getPrefixMatcher().getPrefix(); - for (final TemplateImpl template : TemplateSettings.getInstance().getTemplates()) { - final String key = template.getKey(); - if (!template.isDeactivated() && !template.isSelectionTemplate() && TemplateManagerImpl.isApplicable(file, offset, template)) { - if (prefix.equals(key)) { - result.addElement(LookupElementBuilder.create(key).setTypeText(template.getDescription()).setInsertHandler(new InsertHandler() { - @Override - public void handleInsert(InsertionContext context, LookupElement item) { - context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset()); - context.setAddCompletionChar(false); - TemplateManager.getInstance(context.getProject()).startTemplate(context.getEditor(), template); - } - })); - } else { - result.restartCompletionOnPrefixChange(key); + final TemplateImpl template = findApplicableTemplate(file, offset, prefix); + if (template != null) { + result.addElement(LookupElementBuilder.create(prefix).setTypeText(template.getDescription()).setInsertHandler(new InsertHandler() { + @Override + public void handleInsert(InsertionContext context, LookupElement item) { + context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset()); + context.setAddCompletionChar(false); + TemplateManager.getInstance(context.getProject()).startTemplate(context.getEditor(), template); } + })); + } else { + for (final TemplateImpl possible : listApplicableTemplates(file, offset)) { + result.restartCompletionOnPrefixChange(possible.getKey()); } } + + } + }); + } + + private static List listApplicableTemplates(PsiFile file, int offset) { + final ArrayList result = CollectionFactory.arrayList(); + for (final TemplateImpl template : TemplateSettings.getInstance().getTemplates()) { + if (!template.isDeactivated() && !template.isSelectionTemplate() && TemplateManagerImpl.isApplicable(file, offset, template)) { + result.add(template); + } + } + return result; + } + + @Nullable + public static TemplateImpl findApplicableTemplate(PsiFile file, int offset, final String key) { + return ContainerUtil.find(listApplicableTemplates(file, offset), new Condition() { + @Override + public boolean value(TemplateImpl template) { + return key.equals(template.getKey()); } }); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java index ffc78ecdb415..6eb72386deba 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java @@ -690,7 +690,7 @@ public class TemplateSettings implements PersistentStateComponent, Expo return candidates; } - private char getShortcutChar(TemplateImpl template) { + public char getShortcutChar(TemplateImpl template) { char c = template.getShortcutChar(); if (c == DEFAULT_CHAR) { return getDefaultShortcutChar();