fix broken xml support & add undo
[fedora-idea.git] / plugins / IntelliLang / src / org / intellij / plugins / intelliLang / inject / UnInjectLanguageAction.java
blobf3825203afbe27c0bc1923392c90a20a46631959
1 package org.intellij.plugins.intelliLang.inject;
3 import com.intellij.openapi.application.Result;
4 import com.intellij.openapi.command.WriteCommandAction;
5 import com.intellij.openapi.command.undo.DocumentReference;
6 import com.intellij.openapi.command.undo.UndoManager;
7 import com.intellij.openapi.command.undo.UndoableAction;
8 import com.intellij.openapi.command.undo.UnexpectedUndoException;
9 import com.intellij.openapi.editor.Editor;
10 import com.intellij.openapi.project.Project;
11 import com.intellij.openapi.util.Pair;
12 import com.intellij.openapi.util.TextRange;
13 import com.intellij.openapi.vfs.VirtualFile;
14 import com.intellij.psi.*;
15 import com.intellij.psi.xml.XmlAttributeValue;
16 import com.intellij.psi.xml.XmlTag;
17 import com.intellij.psi.xml.XmlText;
18 import com.intellij.util.IncorrectOperationException;
19 import com.intellij.util.NullableFunction;
20 import com.intellij.util.Processor;
21 import com.intellij.util.FileContentUtil;
22 import com.intellij.util.containers.ContainerUtil;
23 import org.intellij.plugins.intelliLang.Configuration;
24 import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
25 import org.intellij.plugins.intelliLang.inject.config.MethodParameterInjection;
26 import org.intellij.plugins.intelliLang.inject.config.XmlAttributeInjection;
27 import org.intellij.plugins.intelliLang.inject.config.XmlTagInjection;
28 import org.intellij.plugins.intelliLang.util.AnnotationUtilEx;
29 import org.jetbrains.annotations.NotNull;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.List;
34 import java.util.Collections;
36 /**
37 * @author Dmitry Avdeev
39 public class UnInjectLanguageAction extends InjectLanguageAction {
41 @NotNull
42 public String getText() {
43 return "Un-inject Language";
46 public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
47 PsiLanguageInjectionHost host = findInjectionHost(editor, file);
48 if (host == null) {
49 return false;
51 List<Pair<PsiElement, TextRange>> injectedPsi = host.getInjectedPsi();
52 return injectedPsi != null && !injectedPsi.isEmpty();
55 public void invoke(@NotNull final Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
56 final PsiLanguageInjectionHost host = findInjectionHost(editor, file);
57 final Configuration configuration = Configuration.getInstance();
58 final ArrayList<BaseInjection> injectionsToRemove = new ArrayList<BaseInjection>();
59 final ArrayList<PsiAnnotation> annotationsToRemove = new ArrayList<PsiAnnotation>();
60 if (host instanceof XmlAttributeValue) {
61 for (final XmlAttributeInjection injection : configuration.getAttributeInjections()) {
62 if (injection.isApplicable((XmlAttributeValue)host)) {
63 injectionsToRemove.add(injection);
66 } else if (host instanceof XmlText) {
67 final XmlTag tag = ((XmlText)host).getParentTag();
68 if (tag != null) {
69 for (XmlTagInjection injection : configuration.getTagInjections()) {
70 if (injection.isApplicable(tag)) {
71 injectionsToRemove.add(injection);
75 } else if (host instanceof PsiLiteralExpression) {
76 ConcatenationInjector.processLiteralExpressionInjectionsInner(configuration, new Processor<ConcatenationInjector.Info>() {
77 public boolean process(final ConcatenationInjector.Info info) {
78 final PsiAnnotation[] annotations = AnnotationUtilEx.getAnnotationFrom(info.owner, configuration.getLanguageAnnotationPair(), true);
79 annotationsToRemove.addAll(Arrays.asList(annotations));
80 for (MethodParameterInjection injection : info.injections) {
81 if (injection.isApplicable(info.method)) {
82 injectionsToRemove.add(injection);
85 return true;
87 }, host);
89 if (!injectionsToRemove.isEmpty() || !annotationsToRemove.isEmpty()) {
90 final List<PsiFile> psiFiles = ContainerUtil.mapNotNull(annotationsToRemove, new NullableFunction<PsiAnnotation, PsiFile>() {
91 public PsiFile fun(final PsiAnnotation psiAnnotation) {
92 return psiAnnotation instanceof PsiCompiledElement ? null : psiAnnotation.getContainingFile();
94 });
95 final UndoableAction action = new UndoableAction() {
96 public void undo() throws UnexpectedUndoException {
97 for (BaseInjection injection : injectionsToRemove) {
98 if (injection instanceof XmlTagInjection) {
99 configuration.getTagInjections().add((XmlTagInjection)injection);
101 else if (injection instanceof XmlAttributeInjection) {
102 configuration.getAttributeInjections().add((XmlAttributeInjection)injection);
104 else if (injection instanceof MethodParameterInjection) {
105 configuration.getParameterInjections().add((MethodParameterInjection)injection);
108 configuration.configurationModified();
109 FileContentUtil.reparseFiles(project, Collections.<VirtualFile>emptyList(), true);
112 public void redo() throws UnexpectedUndoException {
113 configuration.getTagInjections().removeAll(injectionsToRemove);
114 configuration.getAttributeInjections().removeAll(injectionsToRemove);
115 configuration.getParameterInjections().removeAll(injectionsToRemove);
116 configuration.configurationModified();
117 FileContentUtil.reparseFiles(project, Collections.<VirtualFile>emptyList(), true);
121 public DocumentReference[] getAffectedDocuments() {
122 return DocumentReference.EMPTY_ARRAY;
125 public boolean isComplex() {
126 return true;
129 new WriteCommandAction(project, psiFiles.toArray(new PsiFile[psiFiles.size()])) {
130 @Override
131 protected void run(final Result result) throws Throwable {
132 for (PsiAnnotation annotation : annotationsToRemove) {
133 annotation.delete();
135 action.redo();
136 UndoManager.getInstance(project).undoableActionPerformed(action);
138 }.execute();