blob: ebd20cf982024c5a892528258b33e323484908eb [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.lookup.impl.actions;
import com.intellij.codeInsight.completion.CodeCompletionFeatures;
import com.intellij.codeInsight.completion.CompletionProcess;
import com.intellij.codeInsight.completion.CompletionService;
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.*;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorAction;
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public abstract class ChooseItemAction extends EditorAction {
public ChooseItemAction(Handler handler) {
super(handler);
}
protected static class Handler extends EditorActionHandler {
final boolean focusedOnly;
final char finishingChar;
protected Handler(boolean focusedOnly, char finishingChar) {
this.focusedOnly = focusedOnly;
this.finishingChar = finishingChar;
}
@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);
}
@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 && lookup.getFocusDegree() == LookupImpl.FocusDegree.UNFOCUSED) 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) {
return !lookup.getItems().isEmpty();
}
return true;
}
}
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();
final int offset = editor.getCaretModel().getOffset();
PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument());
final LiveTemplateLookupElement liveTemplateLookup = ContainerUtil.findInstance(lookup.getItems(), LiveTemplateLookupElement.class);
if (liveTemplateLookup == null || !liveTemplateLookup.sudden) {
// Lookup doesn't contain sudden live templates. It means that
// - there are no live template with given key:
// in this case we should find live template with appropriate prefix (custom live templates doesn't participate in this action).
// - completion provider worked too long:
// in this case we should check custom templates that provides completion lookup.
if (LiveTemplateCompletionContributor.customTemplateAvailableAndHasCompletionItem(shortcutChar, editor, file, offset)) {
return true;
}
List<TemplateImpl> templates = TemplateManagerImpl.listApplicableTemplateWithInsertingDummyIdentifier(editor, file, false);
TemplateImpl template = LiveTemplateCompletionContributor.findFullMatchedApplicableTemplate(editor, offset, templates);
if (template != null && shortcutChar == TemplateSettings.getInstance().getShortcutChar(template)) {
return true;
}
return false;
}
return liveTemplateLookup.getTemplateShortcut() == shortcutChar;
}
public static class FocusedOnly extends ChooseItemAction {
public FocusedOnly() {
super(new Handler(true, Lookup.NORMAL_SELECT_CHAR));
}
}
public static class Replacing extends ChooseItemAction {
public Replacing() {
super(new Handler(false, Lookup.REPLACE_SELECT_CHAR));
}
}
public static class CompletingStatement extends ChooseItemAction {
public CompletingStatement() {
super(new Handler(true, Lookup.COMPLETE_STATEMENT_SELECT_CHAR));
}
}
public static class ChooseWithDot extends ChooseItemAction {
public ChooseWithDot() {
super(new Handler(false, '.'));
}
}
}