IDEADEV-40832

This commit is contained in:
Alexey Kudravtsev
2009-10-16 17:34:32 +04:00
parent 5951b46eab
commit 9e06f0c46f
3 changed files with 83 additions and 75 deletions
@@ -23,15 +23,14 @@ import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.intention.AbstractIntentionAction;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.IntentionManager;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.codeInsight.intention.impl.IntentionHintComponent;
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
import com.intellij.codeInsight.intention.impl.config.IntentionManagerSettings;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
import com.intellij.codeInsight.template.impl.TemplateState;
import com.intellij.ide.DataManager;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
@@ -44,14 +43,13 @@ import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.IntentionFilterOwner;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
@@ -188,27 +186,13 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass {
public static void getActionsToShow(@NotNull final Editor editor, @NotNull final PsiFile psiFile, @NotNull IntentionsInfo intentions, int passIdToShowIntentionsFor) {
final PsiElement psiElement = psiFile.findElementAt(editor.getCaretModel().getOffset());
LOG.assertTrue(psiElement == null || psiElement.isValid(), psiElement);
final boolean isInProject = psiFile.getManager().isInProject(psiFile);
int offset = editor.getCaretModel().getOffset();
Project project = psiFile.getProject();
PsiElement injected = InjectedLanguageManager.getInstance(project).findInjectedElementAt(psiFile, offset);
PsiFile injectedFile;
Editor injectedEditor;
if (injected != null) {
injectedFile = injected.getContainingFile();
injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
}
else {
injectedFile = null;
injectedEditor = null;
}
for (IntentionAction action : IntentionManager.getInstance().getIntentionActions()) {
if (injectedFile != null && isAvailableHere(injectedEditor, injectedFile, injected, isInProject, project, action) ||
isAvailableHere(editor, psiFile, psiElement, isInProject, project, action)
) {
Pair<PsiFile,Editor> place = ShowIntentionActionsHandler.availableFor(psiFile, editor, action, psiElement);
if (place != null) {
List<IntentionAction> enableDisableIntentionAction = new ArrayList<IntentionAction>();
enableDisableIntentionAction.add(new IntentionHintComponent.EnableDisableIntentionAction(action));
intentions.intentionsToShow.add(new HighlightInfo.IntentionActionDescriptor(action, enableDisableIntentionAction, null));
@@ -256,19 +240,4 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass {
}
}
private static boolean isAvailableHere(Editor editor, PsiFile psiFile, PsiElement psiElement, boolean inProject, Project project,
IntentionAction action) {
try {
if (action instanceof PsiElementBaseIntentionAction) {
if (!inProject || !((PsiElementBaseIntentionAction)action).isAvailable(project, editor, psiElement)) return false;
}
else if (!action.isAvailable(project, editor, psiFile)) {
return false;
}
}
catch (IndexNotReadyException e) {
return false;
}
return true;
}
}
@@ -29,6 +29,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.*;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.util.PsiUtilBase;
@@ -83,52 +84,56 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
private boolean wrapActionsTo(final List<HighlightInfo.IntentionActionDescriptor> descriptors, final Set<IntentionActionWithTextCaching> cachedActions) {
boolean result = true;
for (HighlightInfo.IntentionActionDescriptor descriptor : descriptors) {
IntentionAction action = descriptor.getAction();
IntentionActionWithTextCaching cachedAction = new IntentionActionWithTextCaching(action, descriptor.getDisplayName(), descriptor.getIcon());
result &= !cachedActions.add(cachedAction);
final int caretOffset = myEditor.getCaretModel().getOffset();
final int fileOffset = caretOffset > 0 && caretOffset == myFile.getTextLength() ? caretOffset - 1 : caretOffset;
PsiElement element;
if (myFile instanceof PsiCompiledElement) {
element = myFile;
}
else if (PsiDocumentManager.getInstance(myProject).isUncommited(myEditor.getDocument())) {
//???
FileViewProvider viewProvider = myFile.getViewProvider();
element = viewProvider.findElementAt(fileOffset, viewProvider.getBaseLanguage());
}
else {
element = InjectedLanguageUtil.findElementAtNoCommit(myFile, fileOffset);
}
final List<IntentionAction> options;
if (element != null && (options = descriptor.getOptions(element)) != null) {
for (IntentionAction option : options) {
boolean isErrorFix = myCachedErrorFixes.contains(new IntentionActionWithTextCaching(option, option.getText()));
if (isErrorFix) {
cachedAction.addErrorFix(option);
}
boolean isInspectionFix = myCachedInspectionFixes.contains(new IntentionActionWithTextCaching(option, option.getText()));
if (isInspectionFix) {
cachedAction.addInspectionFix(option);
}
else {
cachedAction.addIntention(option);
final int caretOffset = myEditor.getCaretModel().getOffset();
final int fileOffset = caretOffset > 0 && caretOffset == myFile.getTextLength() ? caretOffset - 1 : caretOffset;
PsiElement element;
if (myFile instanceof PsiCompiledElement) {
element = myFile;
}
else if (PsiDocumentManager.getInstance(myProject).isUncommited(myEditor.getDocument())) {
//???
FileViewProvider viewProvider = myFile.getViewProvider();
element = viewProvider.findElementAt(fileOffset, viewProvider.getBaseLanguage());
}
else {
element = InjectedLanguageUtil.findElementAtNoCommit(myFile, fileOffset);
}
if (!descriptors.isEmpty()) {
for (HighlightInfo.IntentionActionDescriptor descriptor : descriptors) {
IntentionAction action = descriptor.getAction();
IntentionActionWithTextCaching cachedAction = new IntentionActionWithTextCaching(action, descriptor.getDisplayName(), descriptor.getIcon());
result &= !cachedActions.add(cachedAction);
final List<IntentionAction> options;
if (element != null && (options = descriptor.getOptions(element)) != null) {
for (IntentionAction option : options) {
boolean isErrorFix = myCachedErrorFixes.contains(new IntentionActionWithTextCaching(option, option.getText()));
if (isErrorFix) {
cachedAction.addErrorFix(option);
}
boolean isInspectionFix = myCachedInspectionFixes.contains(new IntentionActionWithTextCaching(option, option.getText()));
if (isInspectionFix) {
cachedAction.addInspectionFix(option);
}
else {
cachedAction.addIntention(option);
}
}
}
}
}
result &= removeInvalidActions(cachedActions);
result &= removeInvalidActions(cachedActions, element);
return result;
}
private boolean removeInvalidActions(final Collection<IntentionActionWithTextCaching> cachedActions) {
private boolean removeInvalidActions(final Collection<IntentionActionWithTextCaching> cachedActions, final PsiElement element) {
boolean result = true;
Iterator<IntentionActionWithTextCaching> iterator = cachedActions.iterator();
while (iterator.hasNext()) {
IntentionActionWithTextCaching cachedAction = iterator.next();
IntentionAction action = cachedAction.getAction();
if (!myFile.isValid() || !action.isAvailable(myProject, myEditor, myFile)) {
Pair<PsiFile,Editor> place = ShowIntentionActionsHandler.availableFor(myFile, myEditor, action, element);
if (place == null) {
iterator.remove();
result = false;
}
@@ -39,6 +39,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
@@ -50,6 +51,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -142,7 +144,10 @@ public class ShowIntentionActionsHandler implements CodeInsightActionHandler {
return false;
}
public static void chooseActionAndInvoke(PsiFile file, final Editor editor, final IntentionAction action, final String text) {
// returns editor,file where the action is available or null if there are none
@Nullable
public static Pair<PsiFile, Editor> availableFor(PsiFile file, final Editor editor, final IntentionAction action, final PsiElement element) {
if (!file.isValid()) return null;
final Project project = file.getProject();
final Editor editorToApply;
@@ -150,29 +155,58 @@ public class ShowIntentionActionsHandler implements CodeInsightActionHandler {
int offset = editor.getCaretModel().getOffset();
PsiElement injected = InjectedLanguageManager.getInstance(project).findInjectedElementAt(file, offset);
boolean inProject = file.getManager().isInProject(file);
if (injected != null) {
PsiFile injectedFile = injected.getContainingFile();
Editor injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
if (action.isAvailable(project, injectedEditor, injectedFile)) {
if (isAvailableHere(injectedEditor, injectedFile, injected, inProject, action)) {
editorToApply = injectedEditor;
fileToApply = injectedFile;
}
else if (!action.isAvailable(project, editor, file)) {
return;
else if (!isAvailableHere(editor, file, element, inProject, action)) {
return null;
}
else {
editorToApply = editor;
fileToApply = file;
}
}
else if (!action.isAvailable(project, editor, file)) {
return;
else if (!isAvailableHere(editor, file, element, inProject, action)) {
return null;
}
else {
editorToApply = editor;
fileToApply = file;
}
return Pair.create(fileToApply, editorToApply);
}
private static boolean isAvailableHere(Editor editor, PsiFile psiFile, PsiElement psiElement, boolean inProject, IntentionAction action) {
try {
Project project = psiFile.getProject();
if (action instanceof PsiElementBaseIntentionAction) {
if (!inProject || !((PsiElementBaseIntentionAction)action).isAvailable(project, editor, psiElement)) return false;
}
else if (!action.isAvailable(project, editor, psiFile)) {
return false;
}
}
catch (IndexNotReadyException e) {
return false;
}
return true;
}
public static void chooseActionAndInvoke(PsiFile file, final Editor editor, final IntentionAction action, final String text) {
final Project project = file.getProject();
int offset = editor.getCaretModel().getOffset();
PsiElement element = file.findElementAt(offset);
Pair<PsiFile, Editor> pair = availableFor(file, editor, action, element);
if (pair == null) return;
final Editor editorToApply = pair.second;
final PsiFile fileToApply = pair.first;
Runnable runnable = new Runnable() {
public void run() {