// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInsight.completion; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiUtilCore; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** * @author peter */ public final class CompletionParameters { private final PsiElement myPosition; private final PsiFile myOriginalFile; private final CompletionType myCompletionType; @Nonnull private final Editor myEditor; private final int myOffset; private final int myInvocationCount; private final CompletionProcess myProcess; private boolean isTestingMode = false; CompletionParameters(@Nonnull final PsiElement position, @Nonnull final PsiFile originalFile, @Nonnull CompletionType completionType, int offset, int invocationCount, @Nonnull Editor editor, @Nonnull CompletionProcess process) { PsiUtilCore.ensureValid(position); assert position.getTextRange().containsOffset(offset) : position; myPosition = position; myOriginalFile = originalFile; myCompletionType = completionType; myOffset = offset; myInvocationCount = invocationCount; myEditor = editor; myProcess = process; } @Nonnull public CompletionParameters delegateToClassName() { return withType(CompletionType.CLASS_NAME).withInvocationCount(myInvocationCount - 1); } @Nonnull public CompletionParameters withType(@Nonnull CompletionType type) { return new CompletionParameters(myPosition, myOriginalFile, type, myOffset, myInvocationCount, myEditor, myProcess); } @Nonnull public CompletionParameters withInvocationCount(int newCount) { return new CompletionParameters(myPosition, myOriginalFile, myCompletionType, myOffset, newCount, myEditor, myProcess); } /** * Return the leaf PSI element in the "completion file" at offset {@link #getOffset()}.<p></p> * <p> * "Completion file" is a PSI file used for completion purposes. Most often it's a non-physical copy of the file being edited * (the original file can be accessed from {@link PsiFile#getOriginalFile()} or {@link #getOriginalFile()}).<p></p> * <p> * A special 'dummy identifier' string is inserted to the copied file at caret offset (removing the selection). * Most often this string is an identifier (see {@link CompletionInitializationContext#DUMMY_IDENTIFIER}). * It can be changed via {@link CompletionContributor#beforeCompletion(CompletionInitializationContext)} method.<p></p> * <p> * Why? This way there'll always be some non-empty element there, which usually reduces the number of * possible cases to be considered inside a {@link CompletionContributor}. * Also, even if completion was invoked in the middle of a white space, a reference might appear there after dummy identifier is inserted, * and its {@link com.intellij.psi.PsiReference#getVariants()} can then be suggested.<p></p> * <p> * If the dummy identifier is empty, then the file isn't copied and this method returns whatever is at caret in the original file. */ @Nonnull public PsiElement getPosition() { return myPosition; } @Nullable public PsiElement getOriginalPosition() { return myOriginalFile.findElementAt(myPosition.getTextRange().getStartOffset()); } /** * @return the file being edited, possibly injected, where code completion was invoked. */ @Nonnull public PsiFile getOriginalFile() { return myOriginalFile; } @Nonnull public CompletionType getCompletionType() { return myCompletionType; } /** * @return the offset (relative to the file) where code completion was invoked. */ public int getOffset() { return myOffset; } /** * @return 0 for autopopup<br> * 1 for explicitly invoked completion<br> * >1 for next completion invocations when one lookup is already active */ public int getInvocationCount() { return myInvocationCount; } public boolean isAutoPopup() { return myInvocationCount == 0; } @Nonnull public CompletionParameters withPosition(@Nonnull PsiElement element, int offset) { return new CompletionParameters(element, myOriginalFile, myCompletionType, offset, myInvocationCount, myEditor, myProcess); } public boolean isExtendedCompletion() { return myCompletionType == CompletionType.BASIC && myInvocationCount >= 2; } /** * @return the editor where the completion was started */ @Nonnull public Editor getEditor() { return myEditor; } @Nonnull public CompletionProcess getProcess() { return myProcess; } public boolean isTestingMode() { return isTestingMode; } public void setIsTestingMode(boolean runTestingMode) { isTestingMode = runTestingMode; } }