mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' of git@git.labs.intellij.net:idea/community
This commit is contained in:
+6
-4
@@ -173,8 +173,9 @@ public class AnnotationsHighlightUtil {
|
||||
Set<String> names = new HashSet<String>();
|
||||
PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
|
||||
for (PsiNameValuePair attribute : attributes) {
|
||||
if (attribute.getName() != null) {
|
||||
names.add(attribute.getName());
|
||||
final String name = attribute.getName();
|
||||
if (name != null) {
|
||||
names.add(name);
|
||||
}
|
||||
else {
|
||||
names.add(PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME);
|
||||
@@ -211,8 +212,9 @@ public class AnnotationsHighlightUtil {
|
||||
|
||||
@Nullable
|
||||
public static HighlightInfo checkConstantExpression(PsiExpression expression) {
|
||||
if (expression.getParent() instanceof PsiAnnotationMethod || expression.getParent() instanceof PsiNameValuePair) {
|
||||
if (PsiType.NULL.equals(expression.getType()) || !PsiUtil.isConstantExpression(expression)) {
|
||||
final PsiElement parent = expression.getParent();
|
||||
if (parent instanceof PsiAnnotationMethod || parent instanceof PsiNameValuePair || parent instanceof PsiArrayInitializerMemberValue) {
|
||||
if (!PsiUtil.isConstantExpression(expression)) {
|
||||
return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, JavaErrorMessages.message("annotation.nonconstant.attribute.value"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,11 +415,14 @@ public class ClassElement extends CompositeElement implements Constants {
|
||||
else {
|
||||
// The main idea is to avoid to anchor to 'white space' element because that causes reformatting algorithm
|
||||
// to perform incorrectly. The algorithm is encapsulated at PostprocessReformattingAspect.doPostponedFormattingInner().
|
||||
PsiElement result = aClass.getLBrace().getNextSibling();
|
||||
while (result instanceof PsiWhiteSpace) {
|
||||
result = result.getNextSibling();
|
||||
final PsiElement lBrace = aClass.getLBrace();
|
||||
if (lBrace != null) {
|
||||
PsiElement result = lBrace.getNextSibling();
|
||||
while (result instanceof PsiWhiteSpace) {
|
||||
result = result.getNextSibling();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
lastMember = child;
|
||||
|
||||
+1
-1
@@ -230,7 +230,7 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer {
|
||||
final PsiFile containingFile = element.getContainingFile();
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject);
|
||||
for (RangeMarker occurrenceMarker : myOccurrenceMarkers) {
|
||||
restoreExpression(containingFile, (PsiVariable)vars[0], elementFactory, occurrenceMarker, myExpressionText);
|
||||
if (restoreExpression(containingFile, (PsiVariable)vars[0], elementFactory, occurrenceMarker, myExpressionText) == null) return;
|
||||
}
|
||||
element.delete();
|
||||
}
|
||||
|
||||
+4
@@ -1,10 +1,14 @@
|
||||
@interface Ann {
|
||||
int i ();
|
||||
|
||||
String[] j();
|
||||
}
|
||||
|
||||
class D {
|
||||
int field;
|
||||
@Ann(i=<error descr="Attribute value must be constant">field</error>) void foo () {}
|
||||
|
||||
@Ann(j={<error descr="Attribute value must be constant">null</error>}) void bar() {}
|
||||
}
|
||||
|
||||
@interface ManistaDouble
|
||||
|
||||
@@ -98,7 +98,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable {
|
||||
* @param preserveCase the value of the Preserve Case flag.
|
||||
*/
|
||||
public void setPreserveCase(boolean preserveCase) {
|
||||
boolean changed = isPreserveCase != preserveCase;
|
||||
isPreserveCase = preserveCase;
|
||||
if (changed) {
|
||||
notifyObservers();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPreserveCase = false;
|
||||
|
||||
@@ -67,7 +67,7 @@ public interface FormattingDocumentModel {
|
||||
boolean containsWhiteSpaceSymbolsOnly(int startOffset, int endOffset);
|
||||
|
||||
/**
|
||||
* There is a possible case that white space to apply because of formatter processing should be additionally adjusted. That is
|
||||
* There is a possible case that white space to apply should be additionally adjusted because of formatter processing. That is
|
||||
* true, for example, for Python where it may be mandatory to use <code>'\'</code> symbol at multi-line expression.
|
||||
* <p/>
|
||||
* Current method adjusts given white space text if necessary.
|
||||
@@ -75,10 +75,12 @@ public interface FormattingDocumentModel {
|
||||
* @param whiteSpaceText white space text to use by default
|
||||
* @param startOffset start offset of the document text that is intended to be replaced by the given white space text (inclusive)
|
||||
* @param endOffset end offset of the document text that is intended to be replaced by the given white space text (exclusive)
|
||||
* @param changedViaPsi flag that identifies whether formatter introduces changes via PSI tree or directly via the document
|
||||
* @return white space to use for replacing document symbols at <code>[startOffset; endOffset)</code> region
|
||||
*/
|
||||
@NotNull
|
||||
CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, int startOffset, int endOffset);
|
||||
CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, int startOffset, int endOffset,
|
||||
boolean changedViaPsi);
|
||||
|
||||
///**
|
||||
// * Allows to answer if given symbol is treated by the current model as white space symbol during formatting.
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.formatting;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -65,5 +66,24 @@ public interface WhiteSpaceFormattingStrategy {
|
||||
* @return symbols to use for replacing <code>[startOffset; endOffset)</code> sub-sequence of the given text
|
||||
*/
|
||||
@NotNull
|
||||
CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, @NotNull CharSequence text, int startOffset, int endOffset);
|
||||
CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, @NotNull CharSequence text, int startOffset,
|
||||
int endOffset);
|
||||
|
||||
|
||||
/**
|
||||
* PSI-based version of {@link #adjustWhiteSpaceIfNecessary(CharSequence, CharSequence, int, int)}.
|
||||
* <p/>
|
||||
* There is a possible case that particular changes are performed to PSI tree and it's not yet synchronized with the underlying
|
||||
* document. Hence, we can't directly work with document char sequence but need to traverse PSI tree instead. I.e. we start with
|
||||
* particular PSI element that contains given start offset and process its right siblings/relatives until given end offset
|
||||
* is reached.
|
||||
*
|
||||
* @param whiteSpaceText white space text to use by default for replacing sub-sequence of the given text
|
||||
* @param startElement PSI element that contains given start offset
|
||||
* @param startOffset start offset to use with the given text (inclusive)
|
||||
* @param endOffset end offset to use with the given text (exclusive)
|
||||
* @return symbols to use for replacing <code>[startOffset; endOffset)</code> sub-sequence of the given text
|
||||
*/
|
||||
CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, @NotNull PsiElement startElement, int startOffset,
|
||||
int endOffset);
|
||||
}
|
||||
|
||||
@@ -80,6 +80,10 @@ public class WizardContext {
|
||||
"Projects";
|
||||
}
|
||||
|
||||
public boolean isProjectFileDirectorySet() {
|
||||
return myProjectFileDirectory != null;
|
||||
}
|
||||
|
||||
public void setProjectFileDirectory(String projectFileDirectory) {
|
||||
myProjectFileDirectory = projectFileDirectory;
|
||||
}
|
||||
|
||||
+12
-1
@@ -16,8 +16,11 @@
|
||||
package com.intellij.psi.codeStyle;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationBundle;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface CodeStyleSettingsCustomizable {
|
||||
enum OptionAnchor {NONE, BEFORE, AFTER}
|
||||
|
||||
String SPACES_AROUND_OPERATORS = ApplicationBundle.message("group.spaces.around.operators");
|
||||
String SPACES_BEFORE_PARENTHESES = ApplicationBundle.message("group.spaces.before.parentheses");
|
||||
String SPACES_BEFORE_LEFT_BRACE = ApplicationBundle.message("group.spaces.before.left.brace");
|
||||
@@ -107,7 +110,15 @@ public interface CodeStyleSettingsCustomizable {
|
||||
void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass,
|
||||
String fieldName,
|
||||
String title,
|
||||
String groupName,
|
||||
@Nullable String groupName,
|
||||
Object... options);
|
||||
|
||||
void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass,
|
||||
String fieldName,
|
||||
String title,
|
||||
@Nullable String groupName,
|
||||
@Nullable OptionAnchor anchor,
|
||||
@Nullable String anchorFieldName,
|
||||
Object... options);
|
||||
|
||||
void renameStandardOption(String fieldName, String newTitle);
|
||||
|
||||
+54
@@ -16,7 +16,11 @@
|
||||
package com.intellij.psi.formatter;
|
||||
|
||||
import com.intellij.formatting.WhiteSpaceFormattingStrategy;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Abstract common {@link WhiteSpaceFormattingStrategy} implementation that doesn't replace default strategy and doesn't
|
||||
@@ -42,4 +46,54 @@ public abstract class AbstractWhiteSpaceFormattingStrategy implements WhiteSpace
|
||||
// Does nothing
|
||||
return whiteSpaceText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText,
|
||||
@NotNull PsiElement startElement,
|
||||
final int startOffset,
|
||||
final int endOffset)
|
||||
{
|
||||
assert startElement.getTextRange().contains(startOffset)
|
||||
: String.format("Element: %s, range: %s, offset: %d", startElement, startElement.getTextRange(), startOffset);
|
||||
|
||||
// Collect target text from the PSI elements and delegate to the text-based method.
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
for (PsiElement current = startElement; current != null && current.getTextRange().getStartOffset() < endOffset; current = next(current)) {
|
||||
final TextRange range = current.getTextRange();
|
||||
final String text = current.getText();
|
||||
if (StringUtil.isEmpty(text)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int start = startOffset > range.getStartOffset() ? startOffset - range.getStartOffset() : 0;
|
||||
if (start >= text.length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int end = endOffset < range.getEndOffset() ? text.length() - (range.getEndOffset() - endOffset) : text.length();
|
||||
if (end <= start) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (start == 0 && end == text.length()) {
|
||||
buffer.append(text);
|
||||
}
|
||||
else {
|
||||
buffer.append(text.substring(start, end));
|
||||
}
|
||||
}
|
||||
|
||||
return adjustWhiteSpaceIfNecessary(whiteSpaceText, buffer, 0, endOffset - startOffset);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiElement next(final @NotNull PsiElement element) {
|
||||
for (PsiElement anchor = element; anchor != null; anchor = anchor.getParent()) {
|
||||
final PsiElement result = element.getNextSibling();
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -16,6 +16,7 @@
|
||||
package com.intellij.psi.formatter;
|
||||
|
||||
import com.intellij.formatting.WhiteSpaceFormattingStrategy;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -86,4 +87,17 @@ public class CompositeWhiteSpaceFormattingStrategy implements WhiteSpaceFormatti
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText,
|
||||
@NotNull PsiElement startElement,
|
||||
int startOffset,
|
||||
int endOffset)
|
||||
{
|
||||
CharSequence result = whiteSpaceText;
|
||||
for (WhiteSpaceFormattingStrategy strategy : myStrategies) {
|
||||
result = strategy.adjustWhiteSpaceIfNecessary(result, startElement, startOffset, endOffset);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.project.ProjectUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -37,6 +38,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -102,4 +104,10 @@ public class FileContentUtil {
|
||||
}
|
||||
events.add(new VFilePropertyChangeEvent(FORCE_RELOAD_REQUESTOR, virtualFile, VirtualFile.PROP_NAME, virtualFile.getName(), virtualFile.getName(), false));
|
||||
}
|
||||
|
||||
public static void reparseOpenedFiles() {
|
||||
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
|
||||
reparseFiles(project, Collections.<VirtualFile>emptyList(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -27,6 +27,7 @@ import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
|
||||
import com.intellij.ui.OptionGroup;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -185,10 +186,21 @@ public class CodeStyleBlankLinesPanel extends MultilanguageCodeStyleAbstractPane
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass,
|
||||
String fieldName,
|
||||
String title,
|
||||
String groupName, Object... options) {
|
||||
showCustomOption(settingsClass, fieldName, title, groupName, null, null, options);
|
||||
}
|
||||
|
||||
public void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass,
|
||||
String fieldName,
|
||||
String title,
|
||||
String groupName,
|
||||
@Nullable OptionAnchor anchor,
|
||||
@Nullable String anchorFieldName,
|
||||
Object... options) {
|
||||
if (myIsFirstUpdate) {
|
||||
myCustomOptions.putValue(groupName, (Trinity)Trinity.create(settingsClass, fieldName, title));
|
||||
}
|
||||
|
||||
+95
-20
@@ -35,7 +35,11 @@ import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable;
|
||||
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -45,6 +49,10 @@ import javax.swing.event.AncestorListener;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Base class for code style settings panels supporting multiple programming languages.
|
||||
@@ -63,15 +71,15 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
for(LanguageCodeStyleSettingsProvider provider: Extensions.getExtensions(LanguageCodeStyleSettingsProvider.EP_NAME)) {
|
||||
for (LanguageCodeStyleSettingsProvider provider : Extensions.getExtensions(LanguageCodeStyleSettingsProvider.EP_NAME)) {
|
||||
provider.customizeSettings(this, getSettingsType());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setPanelLanguage(Language language) {
|
||||
public boolean setPanelLanguage(Language language) {
|
||||
|
||||
boolean languageProviderFound = false;
|
||||
for(LanguageCodeStyleSettingsProvider provider: Extensions.getExtensions(LanguageCodeStyleSettingsProvider.EP_NAME)) {
|
||||
for (LanguageCodeStyleSettingsProvider provider : Extensions.getExtensions(LanguageCodeStyleSettingsProvider.EP_NAME)) {
|
||||
if (provider.getLanguage().is(language)) {
|
||||
provider.customizeSettings(this, getSettingsType());
|
||||
languageProviderFound = true;
|
||||
@@ -79,7 +87,7 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr
|
||||
}
|
||||
}
|
||||
if (!languageProviderFound) return false;
|
||||
|
||||
|
||||
myLanguage = language;
|
||||
|
||||
setSkipPreviewHighlighting(true);
|
||||
@@ -162,21 +170,21 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr
|
||||
final PsiDocumentManager manager = PsiDocumentManager.getInstance(project);
|
||||
final Document doc = manager.getDocument(psiFile);
|
||||
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
public void run() {
|
||||
doc.replaceString(0, doc.getTextLength(), text);
|
||||
manager.commitDocument(doc);
|
||||
try {
|
||||
CodeStyleManager.getInstance(project).reformat(psiFile);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, "", "");
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
public void run() {
|
||||
doc.replaceString(0, doc.getTextLength(), text);
|
||||
manager.commitDocument(doc);
|
||||
try {
|
||||
CodeStyleManager.getInstance(project).reformat(psiFile);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, "", "");
|
||||
if (doc != null) {
|
||||
manager.commitDocument(doc);
|
||||
}
|
||||
@@ -237,7 +245,7 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr
|
||||
}
|
||||
|
||||
private void selectCurrentLanguageTab() {
|
||||
for(int i = 0; i < tabbedPane.getTabCount(); i ++) {
|
||||
for (int i = 0; i < tabbedPane.getTabCount(); i++) {
|
||||
if (getTabName(myLanguage).equals(tabbedPane.getTitleAt(i))) {
|
||||
tabbedPane.setSelectedIndex(i);
|
||||
return;
|
||||
@@ -272,4 +280,71 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr
|
||||
public Language getDefaultLanguage() {
|
||||
return getSelectedLanguage();
|
||||
}
|
||||
|
||||
protected <T extends OrderedOption>List<T> sortOptions(Collection<T> options) {
|
||||
Set<String> names = new THashSet<String>(ContainerUtil.map(options, new Function<OrderedOption, String>() {
|
||||
@Override
|
||||
public String fun(OrderedOption option) {
|
||||
return option.getOptionName();
|
||||
}
|
||||
}));
|
||||
|
||||
List<T> order = new ArrayList<T>(options.size());
|
||||
MultiMap<String, T> afters = new MultiMap<String, T>();
|
||||
MultiMap<String, T> befores = new MultiMap<String, T>();
|
||||
|
||||
for (T each : options) {
|
||||
String anchorOptionName = each.getAnchorOptionName();
|
||||
if (anchorOptionName != null && names.contains(anchorOptionName)) {
|
||||
if (each.getAnchor() == OptionAnchor.AFTER) {
|
||||
afters.putValue(anchorOptionName, each);
|
||||
continue;
|
||||
}
|
||||
else if (each.getAnchor() == OptionAnchor.BEFORE) {
|
||||
befores.putValue(anchorOptionName, each);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
order.add(each);
|
||||
}
|
||||
|
||||
List<T> result = new ArrayList<T>(options.size());
|
||||
for (T each : order) {
|
||||
result.addAll(befores.get(each.getOptionName()));
|
||||
result.add(each);
|
||||
result.addAll(afters.get(each.getOptionName()));
|
||||
}
|
||||
|
||||
assert result.size() == options.size();
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract static class OrderedOption {
|
||||
@NotNull private final String optionName;
|
||||
@Nullable private final OptionAnchor anchor;
|
||||
@Nullable private final String anchorOptionName;
|
||||
|
||||
protected OrderedOption(@NotNull String optionName,
|
||||
OptionAnchor anchor,
|
||||
String anchorOptionName) {
|
||||
this.optionName = optionName;
|
||||
this.anchor = anchor;
|
||||
this.anchorOptionName = anchorOptionName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getOptionName() {
|
||||
return optionName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public OptionAnchor getAnchor() {
|
||||
return anchor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getAnchorOptionName() {
|
||||
return anchorOptionName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+30
-11
@@ -125,19 +125,31 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass,
|
||||
String fieldName,
|
||||
String title,
|
||||
String groupName, Object... options) {
|
||||
showCustomOption(settingsClass, fieldName, title, groupName, null, null, options);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass,
|
||||
String fieldName,
|
||||
String title,
|
||||
String groupName,
|
||||
@Nullable OptionAnchor anchor,
|
||||
@Nullable String anchorFieldName,
|
||||
Object... options) {
|
||||
if (isFirstUpdate) {
|
||||
Option option;
|
||||
if (options.length == 2) {
|
||||
option = new SelectionOption(settingsClass, fieldName, title, groupName, (String[])options[0], (int[])options[1]);
|
||||
option =
|
||||
new SelectionOption(settingsClass, fieldName, title, groupName, anchor, anchorFieldName, (String[])options[0], (int[])options[1]);
|
||||
}
|
||||
else {
|
||||
option = new BooleanOption(settingsClass, fieldName, title, groupName);
|
||||
option = new BooleanOption(settingsClass, fieldName, title, groupName, anchor, anchorFieldName);
|
||||
}
|
||||
myCustomOptions.add(option);
|
||||
option.setEnabled(true);
|
||||
@@ -162,7 +174,8 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle
|
||||
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode();
|
||||
Map<String, DefaultMutableTreeNode> groupsMap = new THashMap<String, DefaultMutableTreeNode>();
|
||||
|
||||
for (Option each : ContainerUtil.concat(myOptions, myCustomOptions)) {
|
||||
List<Option> sorted = sortOptions(ContainerUtil.concat(myOptions, myCustomOptions));
|
||||
for (Option each : sorted) {
|
||||
if (!(myCustomOptions.contains(each) || myAllowedOptions.contains(each.field.getName()) || myShowAllStandardOptions)) continue;
|
||||
|
||||
String group = each.groupName;
|
||||
@@ -314,19 +327,19 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle
|
||||
}
|
||||
|
||||
protected void addOption(@NotNull String fieldName, @NotNull String title, @Nullable String groupName) {
|
||||
myOptions.add(new BooleanOption(null, fieldName, title, groupName));
|
||||
myOptions.add(new BooleanOption(null, fieldName, title, groupName, null, null));
|
||||
}
|
||||
|
||||
protected void addOption(@NotNull String fieldName, @NotNull String title, @Nullable String groupName,
|
||||
@NotNull String[] options, @NotNull int[] values) {
|
||||
myOptions.add(new SelectionOption(null, fieldName, title, groupName, options, values));
|
||||
myOptions.add(new SelectionOption(null, fieldName, title, groupName, null, null, options, values));
|
||||
}
|
||||
|
||||
protected void prepareForReformat(final PsiFile psiFile) {
|
||||
//
|
||||
}
|
||||
|
||||
private abstract class Option {
|
||||
private abstract class Option extends OrderedOption {
|
||||
@Nullable final Class<? extends CustomCodeStyleSettings> clazz;
|
||||
@NotNull final Field field;
|
||||
@NotNull final String title;
|
||||
@@ -336,7 +349,10 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle
|
||||
public Option(Class<? extends CustomCodeStyleSettings> clazz,
|
||||
@NotNull String fieldName,
|
||||
@NotNull String title,
|
||||
@Nullable String groupName) {
|
||||
@Nullable String groupName,
|
||||
@Nullable OptionAnchor anchor,
|
||||
@Nullable String anchorFiledName) {
|
||||
super(fieldName, anchor, anchorFiledName);
|
||||
this.clazz = clazz;
|
||||
this.title = title;
|
||||
this.groupName = groupName;
|
||||
@@ -372,9 +388,10 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle
|
||||
private BooleanOption(Class<? extends CustomCodeStyleSettings> clazz,
|
||||
@NotNull String fieldName,
|
||||
@NotNull String title,
|
||||
@Nullable String groupName) {
|
||||
super(clazz, fieldName, title, groupName);
|
||||
|
||||
@Nullable String groupName,
|
||||
@Nullable OptionAnchor anchor,
|
||||
@Nullable String anchorFiledName) {
|
||||
super(clazz, fieldName, title, groupName, anchor, anchorFiledName);
|
||||
}
|
||||
|
||||
public Object getValue(CodeStyleSettings settings) {
|
||||
@@ -403,9 +420,11 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle
|
||||
@NotNull String fieldName,
|
||||
@NotNull String title,
|
||||
@Nullable String groupName,
|
||||
@Nullable OptionAnchor anchor,
|
||||
@Nullable String anchorFiledName,
|
||||
@NotNull String[] options,
|
||||
@NotNull int[] values) {
|
||||
super(clazz, fieldName, title, groupName);
|
||||
super(clazz, fieldName, title, groupName, anchor, anchorFiledName);
|
||||
this.options = options;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
+83
-34
@@ -17,7 +17,6 @@ package com.intellij.application.options.codeStyle;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
|
||||
@@ -29,6 +28,7 @@ import com.intellij.util.ui.tree.TreeUtil;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.*;
|
||||
@@ -39,6 +39,7 @@ import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
@@ -51,8 +52,7 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
|
||||
|
||||
private boolean myShowAllStandardOptions = false;
|
||||
private Set<String> myAllowedOptions = new HashSet<String>();
|
||||
private MultiMap<String, Trinity<Class<? extends CustomCodeStyleSettings>, String, String>> myCustomOptions
|
||||
= new MultiMap<String, Trinity<Class<? extends CustomCodeStyleSettings>, String, String>>();
|
||||
private MultiMap<String, CustomBooleanOptionInfo> myCustomOptions = new MultiMap<String, CustomBooleanOptionInfo>();
|
||||
private boolean isFirstUpdate = true;
|
||||
private final Map<String, String> myRenamedFields = new THashMap<String, String>();
|
||||
|
||||
@@ -102,13 +102,24 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
|
||||
updateOptions(false, optionNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass,
|
||||
String fieldName,
|
||||
String title,
|
||||
String groupName, Object... options) {
|
||||
showCustomOption(settingsClass, fieldName, title, groupName, null, null, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass,
|
||||
String fieldName,
|
||||
String title,
|
||||
@Nullable String groupName,
|
||||
@Nullable OptionAnchor anchor,
|
||||
@Nullable String anchorFieldName,
|
||||
Object... options) {
|
||||
if (isFirstUpdate) {
|
||||
myCustomOptions.putValue(groupName,
|
||||
Trinity.<Class<? extends CustomCodeStyleSettings>, String, String>create(settingsClass, fieldName, title));
|
||||
myCustomOptions.putValue(groupName, new CustomBooleanOptionInfo(settingsClass, fieldName, title, groupName, anchor, anchorFieldName));
|
||||
}
|
||||
enableOption(fieldName);
|
||||
}
|
||||
@@ -158,7 +169,10 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
|
||||
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode();
|
||||
String groupName = "";
|
||||
DefaultMutableTreeNode groupNode = null;
|
||||
for (BooleanOptionKey key : myKeys) {
|
||||
|
||||
List<BooleanOptionKey> result = sortOptions(myKeys);
|
||||
|
||||
for (BooleanOptionKey key : result) {
|
||||
String newGroupName = key.groupName;
|
||||
if (!newGroupName.equals(groupName) || groupNode == null) {
|
||||
groupName = newGroupName;
|
||||
@@ -205,6 +219,7 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
|
||||
return optionsTree;
|
||||
}
|
||||
|
||||
|
||||
private void selectCheckbox(TreePath treePath) {
|
||||
if (treePath == null) {
|
||||
return;
|
||||
@@ -283,7 +298,6 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
private static boolean isModified(TreeNode node, final CodeStyleSettings settings) {
|
||||
@@ -326,7 +340,7 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
|
||||
Class styleSettingsClass = CodeStyleSettings.class;
|
||||
Field field = styleSettingsClass.getField(fieldName);
|
||||
|
||||
BooleanOptionKey key = new BooleanOptionKey(groupName, getRenamedTitle(fieldName, title), field);
|
||||
BooleanOptionKey key = new BooleanOptionKey(fieldName, groupName, getRenamedTitle(fieldName, title), field);
|
||||
myKeys.add(key);
|
||||
}
|
||||
catch (NoSuchFieldException e) {
|
||||
@@ -343,25 +357,21 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
|
||||
}
|
||||
|
||||
protected void initCustomOptions(String groupName) {
|
||||
for (Trinity<Class<? extends CustomCodeStyleSettings>, String, String> option : myCustomOptions.get(groupName)) {
|
||||
doInitCustomBooleanField(option.first, option.second, option.third, groupName);
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends CustomCodeStyleSettings> void doInitCustomBooleanField(@NotNull Class<T> customClass,
|
||||
String fieldName,
|
||||
String title,
|
||||
String groupName) {
|
||||
try {
|
||||
Field field = customClass.getField(fieldName);
|
||||
|
||||
myKeys.add(new CustomBooleanOptionKey<T>(groupName, getRenamedTitle(fieldName, title), customClass, field));
|
||||
}
|
||||
catch (NoSuchFieldException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
catch (SecurityException e) {
|
||||
LOG.error(e);
|
||||
for (CustomBooleanOptionInfo option : myCustomOptions.get(groupName)) {
|
||||
try {
|
||||
Field field = option.settingClass.getField(option.fieldName);
|
||||
myKeys.add(new CustomBooleanOptionKey(option.fieldName,
|
||||
groupName,
|
||||
getRenamedTitle(option.fieldName, option.title),
|
||||
option.anchor, option.anchorFieldName,
|
||||
option.settingClass, field));
|
||||
}
|
||||
catch (NoSuchFieldException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
catch (SecurityException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,19 +425,29 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
|
||||
}
|
||||
}
|
||||
|
||||
private class BooleanOptionKey {
|
||||
private class BooleanOptionKey extends OrderedOption {
|
||||
final String groupName;
|
||||
String title;
|
||||
final Field field;
|
||||
private boolean enabled = true;
|
||||
|
||||
public BooleanOptionKey(String groupName, String title, Field field) {
|
||||
public BooleanOptionKey(String fieldName, String groupName, String title, Field field) {
|
||||
this(fieldName, groupName, title, null, null, field);
|
||||
}
|
||||
|
||||
public BooleanOptionKey(String fieldName,
|
||||
String groupName,
|
||||
String title,
|
||||
@Nullable OptionAnchor anchor,
|
||||
@Nullable String anchorFiledName,
|
||||
Field field) {
|
||||
super(fieldName, anchor, anchorFiledName);
|
||||
this.groupName = groupName;
|
||||
this.title = title;
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public void setValue(CodeStyleSettings settings, Boolean aBoolean) {
|
||||
public void setValue(CodeStyleSettings settings, Boolean aBoolean) {
|
||||
try {
|
||||
CommonCodeStyleSettings commonSettings = settings.getCommonSettings(getSelectedLanguage());
|
||||
field.set(commonSettings, aBoolean);
|
||||
@@ -451,11 +471,40 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
|
||||
}
|
||||
}
|
||||
|
||||
private static class CustomBooleanOptionInfo {
|
||||
@NotNull final Class<? extends CustomCodeStyleSettings> settingClass;
|
||||
@NotNull final String fieldName;
|
||||
@NotNull final String title;
|
||||
@Nullable final String groupName;
|
||||
@Nullable final OptionAnchor anchor;
|
||||
@Nullable final String anchorFieldName;
|
||||
|
||||
private CustomBooleanOptionInfo(@NotNull Class<? extends CustomCodeStyleSettings> settingClass,
|
||||
@NotNull String fieldName,
|
||||
@NotNull String title,
|
||||
String groupName,
|
||||
OptionAnchor anchor,
|
||||
String anchorFieldName) {
|
||||
this.settingClass = settingClass;
|
||||
this.fieldName = fieldName;
|
||||
this.title = title;
|
||||
this.groupName = groupName;
|
||||
this.anchor = anchor;
|
||||
this.anchorFieldName = anchorFieldName;
|
||||
}
|
||||
}
|
||||
|
||||
private class CustomBooleanOptionKey<T extends CustomCodeStyleSettings> extends BooleanOptionKey {
|
||||
private final Class<T> mySettingsClass;
|
||||
|
||||
public CustomBooleanOptionKey(String groupName, String title, Class<T> settingsClass, Field field) {
|
||||
super(groupName, title, field);
|
||||
public CustomBooleanOptionKey(String fieldName,
|
||||
String groupName,
|
||||
String title,
|
||||
OptionAnchor anchor,
|
||||
String anchorFieldName,
|
||||
Class<T> settingsClass,
|
||||
Field field) {
|
||||
super(fieldName, groupName, title, anchor, anchorFieldName, field);
|
||||
mySettingsClass = settingsClass;
|
||||
}
|
||||
|
||||
@@ -529,8 +578,8 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
|
||||
result.addAll(myRenamedFields.values());
|
||||
for (String groupName : myCustomOptions.keySet()) {
|
||||
result.add(groupName);
|
||||
for (Trinity<Class<? extends CustomCodeStyleSettings>, String, String> trinity : myCustomOptions.get(groupName)) {
|
||||
result.add(trinity.third);
|
||||
for (CustomBooleanOptionInfo trinity : myCustomOptions.get(groupName)) {
|
||||
result.add(trinity.title);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -539,7 +539,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec
|
||||
FindSettings settings = FindSettings.getInstance();
|
||||
String[] recents = textField == mySearchField ? settings.getRecentFindStrings() : settings.getRecentReplaceStrings();
|
||||
Utils.showCompletionPopup(byClickingToolbarButton ? myToolbarComponent : null, new JBList(ArrayUtil.reverseArray(recents)),
|
||||
"Recent Searches",
|
||||
"Recent " + (textField == mySearchField ? "Searches" : "Replaces"),
|
||||
(JTextField)textField);
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ public class FindUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void configureFindModel(boolean replace, @Nullable String selectedText, FindModel model) {
|
||||
public static void configureFindModel(boolean replace, @Nullable String selectedText, FindModel model, boolean firstSearch) {
|
||||
boolean isGlobal = true;
|
||||
String stringToFind = null;
|
||||
if (!StringUtil.isEmpty(selectedText)) {
|
||||
@@ -109,9 +109,12 @@ public class FindUtil {
|
||||
stringToFind = selectedText;
|
||||
}
|
||||
} else {
|
||||
stringToFind = model.getStringToFind();
|
||||
if (firstSearch) {
|
||||
stringToFind = "";
|
||||
} else {
|
||||
stringToFind = model.getStringToFind();
|
||||
}
|
||||
}
|
||||
|
||||
model.setReplaceState(replace);
|
||||
model.setStringToFind(stringToFind);
|
||||
model.setGlobal(isGlobal);
|
||||
|
||||
@@ -37,6 +37,6 @@ public class SwitchToFind extends EditorHeaderAction {
|
||||
}
|
||||
|
||||
final FindModel findModel = getEditorSearchComponent().getFindModel();
|
||||
FindUtil.configureFindModel(false, null, findModel);
|
||||
FindUtil.configureFindModel(false, null, findModel, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,6 @@ public class SwitchToReplace extends EditorHeaderAction {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
final FindModel findModel = getEditorSearchComponent().getFindModel();
|
||||
FindUtil.configureFindModel(true, null, findModel);
|
||||
FindUtil.configureFindModel(true, null, findModel, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ class FormatProcessor {
|
||||
for (LeafBlockWrapper block : blocksToModify) {
|
||||
WhiteSpace whiteSpace = block.getWhiteSpace();
|
||||
CharSequence newWs = documentModel.adjustWhiteSpaceIfNecessary(
|
||||
whiteSpace.generateWhiteSpace(indentOption), whiteSpace.getStartOffset(), whiteSpace.getEndOffset()
|
||||
whiteSpace.generateWhiteSpace(indentOption), whiteSpace.getStartOffset(), whiteSpace.getEndOffset(), false
|
||||
);
|
||||
changes.add(new TextChangeImpl(newWs, whiteSpace.getStartOffset(), whiteSpace.getEndOffset()));
|
||||
}
|
||||
|
||||
@@ -84,6 +84,10 @@ class NavBarItem extends SimpleColoredComponent {
|
||||
return myAttributes;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return myText;
|
||||
}
|
||||
|
||||
void update() {
|
||||
clear();
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.intellij.openapi.util.AsyncResult;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
@@ -295,6 +296,9 @@ public class NavBarPanel extends JPanel implements DataProvider, PopupOwner, Dis
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!StringUtil.equals(eachLabel.getText(), NavBarPresentation.getPresentableText(eachElement, null))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SimpleTextAttributes modelAttributes1 = myPresentation.getTextAttributes(eachElement, true);
|
||||
SimpleTextAttributes modelAttributes2 = myPresentation.getTextAttributes(eachElement, false);
|
||||
|
||||
+2
-2
@@ -47,7 +47,7 @@ public class IncrementalFindAction extends EditorAction {
|
||||
if (headerComponent instanceof EditorSearchComponent) {
|
||||
EditorSearchComponent editorSearchComponent = (EditorSearchComponent)headerComponent;
|
||||
headerComponent.requestFocus();
|
||||
FindUtil.configureFindModel(myReplace, editor.getSelectionModel().getSelectedText(), editorSearchComponent.getFindModel());
|
||||
FindUtil.configureFindModel(myReplace, editor.getSelectionModel().getSelectedText(), editorSearchComponent.getFindModel(), false);
|
||||
} else {
|
||||
FindManager findManager = FindManager.getInstance(project);
|
||||
FindModel model;
|
||||
@@ -57,7 +57,7 @@ public class IncrementalFindAction extends EditorAction {
|
||||
model = new FindModel();
|
||||
model.copyFrom(findManager.getFindInFileModel());
|
||||
}
|
||||
FindUtil.configureFindModel(myReplace, editor.getSelectionModel().getSelectedText(), model);
|
||||
FindUtil.configureFindModel(myReplace, editor.getSelectionModel().getSelectedText(), model, true);
|
||||
final EditorSearchComponent header = new EditorSearchComponent(editor, project, model);
|
||||
editor.setHeaderComponent(header);
|
||||
header.requestFocus();
|
||||
|
||||
+47
-1
@@ -19,11 +19,14 @@ package com.intellij.packageDependencies;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.impl.ContentManagerWatcher;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.StateSplitter;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.components.StorageScheme;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.ToolWindowAnchor;
|
||||
import com.intellij.openapi.wm.ToolWindowId;
|
||||
@@ -32,6 +35,8 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.search.scope.packageSet.*;
|
||||
import com.intellij.ui.content.Content;
|
||||
import com.intellij.ui.content.ContentManager;
|
||||
import com.intellij.util.text.UniqueNameGenerator;
|
||||
import org.jdom.Attribute;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -46,7 +51,8 @@ import java.util.*;
|
||||
@Storage(
|
||||
id="other",
|
||||
file = "$PROJECT_FILE$"
|
||||
)}
|
||||
), @Storage(id = "dir", file = "$PROJECT_CONFIG_DIR$/scopes/", scheme = StorageScheme.DIRECTORY_BASED,
|
||||
stateSplitter = DependencyValidationManagerImpl.ScopesStateSplitter.class)}
|
||||
)
|
||||
public class DependencyValidationManagerImpl extends DependencyValidationManager {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.packageDependencies.DependencyValidationManagerImpl");
|
||||
@@ -303,4 +309,44 @@ public class DependencyValidationManagerImpl extends DependencyValidationManager
|
||||
if (fromNamedScope == null || toNamedScope == null) return null;
|
||||
return new DependencyRule(fromNamedScope, toNamedScope, Boolean.valueOf(denyRule).booleanValue());
|
||||
}
|
||||
|
||||
public static class ScopesStateSplitter implements StateSplitter {
|
||||
public List<Pair<Element, String>> splitState(Element e) {
|
||||
final UniqueNameGenerator generator = new UniqueNameGenerator();
|
||||
final List<Pair<Element, String>> result = new ArrayList<Pair<Element, String>>();
|
||||
|
||||
final Element[] elements = JDOMUtil.getElements(e);
|
||||
for (Element element : elements) {
|
||||
if (element.getName().equals("scope")) {
|
||||
element.detach();
|
||||
String scopeName = element.getAttributeValue("name");
|
||||
assert scopeName != null;
|
||||
final String name = generator.generateUniqueName(FileUtil.sanitizeFileName(scopeName)) + ".xml";
|
||||
result.add(new Pair<Element, String>(element, name));
|
||||
}
|
||||
}
|
||||
result.add(new Pair<Element, String>(e, generator.generateUniqueName("scope_settings") + ".xml"));
|
||||
return result;
|
||||
}
|
||||
|
||||
public void mergeStatesInto(Element target, Element[] elements) {
|
||||
for (Element element : elements) {
|
||||
if (element.getName().equals("scope")) {
|
||||
element.detach();
|
||||
target.addContent(element);
|
||||
}
|
||||
else {
|
||||
final Element[] states = JDOMUtil.getElements(element);
|
||||
for (Element state : states) {
|
||||
state.detach();
|
||||
target.addContent(state);
|
||||
}
|
||||
for (Object attr : element.getAttributes()) {
|
||||
target.setAttribute((Attribute)((Attribute)attr).clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -44,9 +44,9 @@ public class PatternCompilerFactoryImpl extends PatternCompilerFactory {
|
||||
return result.isEmpty()? ArrayUtil.EMPTY_CLASS_ARRAY : result.toArray(new Class[result.size()]);
|
||||
}
|
||||
};
|
||||
private final Map<Class[], PatternCompiler> myCompilers = new ConcurrentFactoryMap<Class[], PatternCompiler>() {
|
||||
private final Map<List<Class>, PatternCompiler> myCompilers = new ConcurrentFactoryMap<List<Class>, PatternCompiler>() {
|
||||
@Override
|
||||
protected PatternCompiler create(Class[] key) {
|
||||
protected PatternCompiler create(List<Class> key) {
|
||||
return new PatternCompilerImpl(key);
|
||||
}
|
||||
};
|
||||
@@ -60,6 +60,6 @@ public class PatternCompilerFactoryImpl extends PatternCompilerFactory {
|
||||
@NotNull
|
||||
@Override
|
||||
public <T> PatternCompiler<T> getPatternCompiler(@NotNull Class[] patternClasses) {
|
||||
return myCompilers.get(patternClasses);
|
||||
return myCompilers.get(Arrays.asList(patternClasses));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public class DocumentBasedFormattingModel implements FormattingModel {
|
||||
}
|
||||
|
||||
CharSequence whiteSpaceToUse = getDocumentModel().adjustWhiteSpaceIfNecessary(
|
||||
whiteSpace, textRange.getStartOffset(), textRange.getEndOffset()
|
||||
whiteSpace, textRange.getStartOffset(), textRange.getEndOffset(), false
|
||||
);
|
||||
|
||||
myDocument.replaceString(textRange.getStartOffset(),
|
||||
|
||||
@@ -25,13 +25,14 @@ import com.intellij.openapi.editor.impl.DocumentImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.PsiDocumentManagerImpl;
|
||||
import com.intellij.psi.impl.PsiToDocumentSynchronizer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class FormattingDocumentModelImpl implements FormattingDocumentModel{
|
||||
public class FormattingDocumentModelImpl implements FormattingDocumentModel {
|
||||
|
||||
private final WhiteSpaceFormattingStrategy myWhiteSpaceStrategy;
|
||||
//private final CharBuffer myBuffer = CharBuffer.allocate(1);
|
||||
@@ -119,8 +120,20 @@ public class FormattingDocumentModelImpl implements FormattingDocumentModel{
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, int startOffset, int endOffset) {
|
||||
return myWhiteSpaceStrategy.adjustWhiteSpaceIfNecessary(whiteSpaceText, myDocument.getCharsSequence(), startOffset, endOffset);
|
||||
public CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, int startOffset, int endOffset,
|
||||
boolean changedViaPsi)
|
||||
{
|
||||
if (!changedViaPsi) {
|
||||
return myWhiteSpaceStrategy.adjustWhiteSpaceIfNecessary(whiteSpaceText, myDocument.getCharsSequence(), startOffset, endOffset);
|
||||
}
|
||||
|
||||
final PsiElement element = myFile.findElementAt(startOffset);
|
||||
if (element == null) {
|
||||
return whiteSpaceText;
|
||||
}
|
||||
else {
|
||||
return myWhiteSpaceStrategy.adjustWhiteSpaceIfNecessary(whiteSpaceText, element, startOffset, endOffset);
|
||||
}
|
||||
}
|
||||
|
||||
//@Override
|
||||
|
||||
@@ -54,7 +54,7 @@ public class PsiBasedFormattingModel implements FormattingModel {
|
||||
|
||||
public TextRange replaceWhiteSpace(TextRange textRange, String whiteSpace) {
|
||||
String whiteSpaceToUse
|
||||
= myDocumentModel.adjustWhiteSpaceIfNecessary(whiteSpace, textRange.getStartOffset(), textRange.getEndOffset()).toString();
|
||||
= myDocumentModel.adjustWhiteSpaceIfNecessary(whiteSpace, textRange.getStartOffset(), textRange.getEndOffset(), true).toString();
|
||||
final String wsReplaced = replaceWithPSI(textRange, whiteSpaceToUse);
|
||||
|
||||
if (wsReplaced != null){
|
||||
|
||||
@@ -17,7 +17,6 @@ package com.intellij.ui.table;
|
||||
|
||||
import com.intellij.Patches;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.intellij.ui.ComponentWithExpandableItems;
|
||||
import com.intellij.ui.ExpandableItemsHandler;
|
||||
@@ -125,8 +124,7 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component
|
||||
|
||||
@Override
|
||||
public int getRowHeight() {
|
||||
if (myRowHeightIsComputing
|
||||
|| !SystemInfo.isMac) { //todo[kirillk]: looks weird on Win/Linux
|
||||
if (myRowHeightIsComputing) {
|
||||
return super.getRowHeight();
|
||||
}
|
||||
|
||||
@@ -163,13 +161,8 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component
|
||||
|
||||
@Override
|
||||
public void setRowHeight(int rowHeight) {
|
||||
//todo[kirillk]: looks weird on Win/Linux
|
||||
if (SystemInfo.isMac) {
|
||||
myRowHeight = rowHeight;
|
||||
myRowHeightIsExplicitlySet = true;
|
||||
} else {
|
||||
super.setRowHeight(rowHeight);
|
||||
}
|
||||
myRowHeight = rowHeight;
|
||||
myRowHeightIsExplicitlySet = true;
|
||||
}
|
||||
|
||||
private void repaintViewport() {
|
||||
@@ -319,6 +312,7 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component
|
||||
final TableCellEditor editor = getCellEditor(row, column);
|
||||
if (editor != null && editor.isCellEditable(e)) {
|
||||
editorComp = prepareEditor(editor, row, column);
|
||||
((JComponent)editorComp).setBorder(null);
|
||||
if (editorComp == null) {
|
||||
removeEditor();
|
||||
return false;
|
||||
|
||||
+47
-23
@@ -50,6 +50,7 @@ import com.intellij.ui.HintHint;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IconUtil;
|
||||
import com.intellij.util.NullableFunction;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import gnu.trove.TIntArrayList;
|
||||
@@ -122,7 +123,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
}
|
||||
}
|
||||
})
|
||||
.setImageProvider(new Function<DnDActionInfo, DnDImage>() {
|
||||
.setImageProvider(new NullableFunction<DnDActionInfo, DnDImage>() {
|
||||
@Override
|
||||
public DnDImage fun(DnDActionInfo info) {
|
||||
return new DnDImage(IconUtil.toImage(getGutterRenderer(info.getPoint()).getIcon()));
|
||||
@@ -690,18 +691,21 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
return new VisualPosition(myEditor.offsetToVisualPosition(offset).line, 0);
|
||||
}
|
||||
|
||||
private void doPaintFoldingTree(Graphics2D g, Rectangle clip, int firstVisibleOffset, int lastVisibleOffset) {
|
||||
int anchorX = getFoldingAreaOffset();
|
||||
int width = getFoldingAnchorWidth();
|
||||
private void doPaintFoldingTree(final Graphics2D g, final Rectangle clip, int firstVisibleOffset, int lastVisibleOffset) {
|
||||
final int anchorX = getFoldingAreaOffset();
|
||||
final int width = getFoldingAnchorWidth();
|
||||
|
||||
FoldRegion[] visibleFoldRegions = ((FoldingModelImpl)myEditor.getFoldingModel()).fetchVisible();
|
||||
|
||||
for (FoldRegion visibleFoldRegion : visibleFoldRegions) {
|
||||
if (!visibleFoldRegion.isValid()) continue;
|
||||
if (visibleFoldRegion.getStartOffset() > lastVisibleOffset) continue;
|
||||
if (getEndOffset(visibleFoldRegion) < firstVisibleOffset) continue;
|
||||
drawAnchor(visibleFoldRegion, width, clip, g, anchorX, false, false);
|
||||
}
|
||||
doForVisibleFoldRegions(
|
||||
new NullableFunction<FoldRegion, Void>() {
|
||||
@Override
|
||||
public Void fun(FoldRegion foldRegion) {
|
||||
drawAnchor(foldRegion, width, clip, g, anchorX, false, false);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
firstVisibleOffset,
|
||||
lastVisibleOffset
|
||||
);
|
||||
|
||||
if (myActiveFoldRegion != null) {
|
||||
drawAnchor(myActiveFoldRegion, width, clip, g, anchorX, true, true);
|
||||
@@ -709,6 +713,23 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
}
|
||||
}
|
||||
|
||||
private void doForVisibleFoldRegions(@NotNull NullableFunction<FoldRegion, Void> action, int firstVisibleOffset, int lastVisibleOffset) {
|
||||
FoldRegion[] visibleFoldRegions = ((FoldingModelImpl)myEditor.getFoldingModel()).fetchVisible();
|
||||
final Document document = myEditor.getDocument();
|
||||
for (FoldRegion visibleFoldRegion : visibleFoldRegions) {
|
||||
if (!visibleFoldRegion.isValid()) continue;
|
||||
final int startOffset = visibleFoldRegion.getStartOffset();
|
||||
if (startOffset > lastVisibleOffset) continue;
|
||||
final int endOffset = getEndOffset(visibleFoldRegion);
|
||||
if (endOffset < firstVisibleOffset) continue;
|
||||
if (document.getLineNumber(startOffset) >= document.getLineNumber(endOffset)) {
|
||||
//TODO den remove this check as soon as editor performance on dimension mapping is improved (IDEA-69317)
|
||||
continue;
|
||||
}
|
||||
action.fun(visibleFoldRegion);
|
||||
}
|
||||
}
|
||||
|
||||
private void paintFoldingBackground(Graphics g, Rectangle clip, int firstVisibleOffset, int lastVisibleOffset) {
|
||||
int lineX = getWhitespaceSeparatorOffset();
|
||||
paintBackground(g, clip, getFoldingAreaOffset(), getFoldingAreaWidth());
|
||||
@@ -721,26 +742,29 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
doPaintFoldingBoxBackground((Graphics2D)g, clip, firstVisibleOffset, lastVisibleOffset);
|
||||
}
|
||||
|
||||
private void doPaintFoldingBoxBackground(Graphics2D g, Rectangle clip, int firstVisibleOffset, int lastVisibleOffset) {
|
||||
private void doPaintFoldingBoxBackground(final Graphics2D g, final Rectangle clip, int firstVisibleOffset, int lastVisibleOffset) {
|
||||
if (!isFoldingOutlineShown()) return;
|
||||
|
||||
UIUtil.drawVDottedLine(g, getWhitespaceSeparatorOffset(), clip.y, clip.y + clip.height, null, getOutlineColor(false));
|
||||
|
||||
int anchorX = getFoldingAreaOffset();
|
||||
int width = getFoldingAnchorWidth();
|
||||
|
||||
FoldRegion[] visibleFoldRegions = ((FoldingModelImpl)myEditor.getFoldingModel()).fetchVisible();
|
||||
final int anchorX = getFoldingAreaOffset();
|
||||
final int width = getFoldingAnchorWidth();
|
||||
|
||||
if (myActiveFoldRegion != null) {
|
||||
drawFoldingLines(myActiveFoldRegion, clip, width, anchorX, g);
|
||||
}
|
||||
|
||||
for (FoldRegion visibleFoldRegion : visibleFoldRegions) {
|
||||
if (!visibleFoldRegion.isValid()) continue;
|
||||
if (visibleFoldRegion.getStartOffset() > lastVisibleOffset) continue;
|
||||
if (getEndOffset(visibleFoldRegion) < firstVisibleOffset) continue;
|
||||
drawAnchor(visibleFoldRegion, width, clip, g, anchorX, false, true);
|
||||
}
|
||||
doForVisibleFoldRegions(
|
||||
new NullableFunction<FoldRegion, Void>() {
|
||||
@Override
|
||||
public Void fun(FoldRegion foldRegion) {
|
||||
drawAnchor(foldRegion, width, clip, g, anchorX, false, true);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
firstVisibleOffset,
|
||||
lastVisibleOffset
|
||||
);
|
||||
}
|
||||
|
||||
public int getWhitespaceSeparatorOffset() {
|
||||
|
||||
+2
-1
@@ -242,7 +242,8 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
|
||||
return message;
|
||||
}
|
||||
|
||||
private ProjectImpl createAndInitProject(String projectName, String filePath, boolean isDefault, boolean isOptimiseTestLoadSpeed,
|
||||
private ProjectImpl
|
||||
createAndInitProject(String projectName, String filePath, boolean isDefault, boolean isOptimiseTestLoadSpeed,
|
||||
@Nullable Project template) throws IOException {
|
||||
final ProjectImpl project = isDefault ? new DefaultProject(this, filePath, isOptimiseTestLoadSpeed, projectName) :
|
||||
new ProjectImpl(this, filePath, isOptimiseTestLoadSpeed, projectName);
|
||||
|
||||
+175
-13
@@ -19,12 +19,17 @@ package com.intellij.patterns.compiler;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringHash;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.patterns.ElementPatternCondition;
|
||||
import com.intellij.patterns.InitialPatternCondition;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.ReflectionCache;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import com.intellij.util.containers.StringInterner;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -39,17 +44,15 @@ public class PatternCompilerImpl<T> implements PatternCompiler<T> {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(PatternCompilerImpl.class.getName());
|
||||
|
||||
private Set<Method> myStaticMethods;
|
||||
private final Set<Method> myStaticMethods;
|
||||
private final StringInterner myStringInterner = new StringInterner();
|
||||
|
||||
public PatternCompilerImpl(final Class[] patternClasses) {
|
||||
public PatternCompilerImpl(final List<Class> patternClasses) {
|
||||
myStaticMethods = getStaticMethods(patternClasses);
|
||||
}
|
||||
|
||||
protected void preInvoke(Object target, String methodName, Object[] arguments) {
|
||||
}
|
||||
|
||||
private static final Node ERROR_NODE = new Node(null, null, null);
|
||||
@Override
|
||||
@Nullable
|
||||
public ElementPattern<T> createElementPattern(final String text, final String displayName) {
|
||||
try {
|
||||
return compileElementPattern(text);
|
||||
@@ -57,27 +60,46 @@ public class PatternCompilerImpl<T> implements PatternCompiler<T> {
|
||||
catch (Exception ex) {
|
||||
final Throwable cause = ex.getCause() != null ? ex.getCause() : ex;
|
||||
LOG.warn("error processing place: " + displayName + " [" + text + "]", cause);
|
||||
return null;
|
||||
return new LazyPresentablePattern<T>(new Node(ERROR_NODE, text, null));
|
||||
}
|
||||
}
|
||||
|
||||
//@Override
|
||||
//public ElementPattern<T> compileElementPattern(final String text) {
|
||||
// return processElementPatternText(text, new Function<Frame, Object>() {
|
||||
// public Object fun(final Frame frame) {
|
||||
// try {
|
||||
// final Object[] args = frame.params.toArray();
|
||||
// preInvoke(frame.target, frame.methodName, args);
|
||||
// return invokeMethod(frame.target, frame.methodName, args, myStaticMethods);
|
||||
// }
|
||||
// catch (Throwable throwable) {
|
||||
// throw new IllegalArgumentException(text, throwable);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//}
|
||||
|
||||
@Override
|
||||
public ElementPattern<T> compileElementPattern(final String text) {
|
||||
return processElementPatternText(text, new Function<Frame, Object>() {
|
||||
public Object fun(final Frame frame) {
|
||||
final Node node = processElementPatternText(text, new Function<Frame, Object>() {
|
||||
public Node fun(final Frame frame) {
|
||||
try {
|
||||
final Object[] args = frame.params.toArray();
|
||||
preInvoke(frame.target, frame.methodName, args);
|
||||
return invokeMethod(frame.target, frame.methodName, args, myStaticMethods);
|
||||
for (int i = 0, argsLength = args.length; i < argsLength; i++) {
|
||||
args[i] = args[i] instanceof String ? myStringInterner.intern((String)args[i]) : args[i];
|
||||
}
|
||||
return new Node((Node)frame.target, myStringInterner.intern(frame.methodName), args);
|
||||
}
|
||||
catch (Throwable throwable) {
|
||||
throw new IllegalArgumentException(text, throwable);
|
||||
}
|
||||
}
|
||||
});
|
||||
return new LazyPresentablePattern(node);
|
||||
}
|
||||
|
||||
private static Set<Method> getStaticMethods(Class[] patternClasses) {
|
||||
private static Set<Method> getStaticMethods(List<Class> patternClasses) {
|
||||
return new THashSet<Method>(ContainerUtil.concat(patternClasses, new Function<Class, Collection<? extends Method>>() {
|
||||
public Collection<Method> fun(final Class aClass) {
|
||||
return ContainerUtil.findAll(ReflectionCache.getMethods(aClass), new Condition<Method>() {
|
||||
@@ -249,7 +271,7 @@ public class PatternCompilerImpl<T> implements PatternCompiler<T> {
|
||||
}
|
||||
|
||||
private static Object makeParam(final String s) {
|
||||
if (s.length() > 2 && s.startsWith("\"") && s.endsWith("\"")) return s.substring(1, s.length()-1);
|
||||
if (s.length() >= 2 && s.startsWith("\"") && s.endsWith("\"")) return s.substring(1, s.length()-1);
|
||||
try {
|
||||
return Integer.valueOf(s);
|
||||
}
|
||||
@@ -500,4 +522,144 @@ public class PatternCompilerImpl<T> implements PatternCompiler<T> {
|
||||
// }
|
||||
// return null;
|
||||
//}
|
||||
|
||||
private static final ElementPattern<?> ALWAYS_FALSE = new FalsePattern();
|
||||
|
||||
private static class Node {
|
||||
final Node target;
|
||||
final String method;
|
||||
final Object[] args;
|
||||
|
||||
private Node(final Node target, final String method, final Object[] args) {
|
||||
this.target = target;
|
||||
this.method = method;
|
||||
this.args = args;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FalsePattern extends InitialPatternCondition<Object> implements ElementPattern<Object> {
|
||||
private final ElementPatternCondition<Object> myCondition = new ElementPatternCondition<Object>(this);
|
||||
|
||||
protected FalsePattern() {
|
||||
super(Object.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accepts(@Nullable final Object o) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accepts(@Nullable final Object o, final ProcessingContext context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementPatternCondition<Object> getCondition() {
|
||||
return myCondition;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class LazyPresentablePattern<T> implements ElementPattern<T> {
|
||||
|
||||
private ElementPattern<T> myCompiledPattern;
|
||||
private final Node myNode;
|
||||
private final long myHashCode;
|
||||
|
||||
public LazyPresentablePattern(final Node node) {
|
||||
myNode = node;
|
||||
myHashCode = StringHash.calc(toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accepts(@Nullable final Object o) {
|
||||
return getCompiledPattern().accepts(o, new ProcessingContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accepts(@Nullable final Object o, final ProcessingContext context) {
|
||||
return getCompiledPattern().accepts(o, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementPatternCondition<T> getCondition() {
|
||||
return getCompiledPattern().getCondition();
|
||||
}
|
||||
|
||||
public ElementPattern<T> getCompiledPattern() {
|
||||
if (myCompiledPattern == null) {
|
||||
Object result;
|
||||
try {
|
||||
result = myNode.target == ERROR_NODE? ALWAYS_FALSE : execute(myNode);
|
||||
}
|
||||
catch (Throwable throwable) {
|
||||
LOG.error(toString(), throwable);
|
||||
result = ALWAYS_FALSE;
|
||||
}
|
||||
myCompiledPattern = (ElementPattern<T>)result;
|
||||
}
|
||||
return myCompiledPattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(myNode, new StringBuilder()).toString();
|
||||
}
|
||||
|
||||
private StringBuilder toString(final Node node, final StringBuilder sb) {
|
||||
if (node.target == ERROR_NODE) {
|
||||
return sb.append(node.method);
|
||||
}
|
||||
if (node.target != null) {
|
||||
toString(node.target, sb);
|
||||
sb.append('.');
|
||||
}
|
||||
sb.append(node.method).append('(');
|
||||
boolean first = true;
|
||||
for (Object arg : node.args) {
|
||||
if (first) first = false;
|
||||
else sb.append(',').append(' ');
|
||||
if (arg instanceof Node) {
|
||||
toString((Node)arg, sb);
|
||||
}
|
||||
else if (arg instanceof String) {
|
||||
// todo no escaping!
|
||||
sb.append('\"').append(arg).append('\"');
|
||||
}
|
||||
else if (arg instanceof Number) {
|
||||
sb.append(arg);
|
||||
}
|
||||
}
|
||||
sb.append(')');
|
||||
return sb;
|
||||
}
|
||||
|
||||
private Object execute(final Node node) throws Throwable {
|
||||
final Object target = node.target != null? execute(node.target) : null;
|
||||
final String methodName = node.method;
|
||||
final Object[] args;
|
||||
if (node.args.length == 0) {
|
||||
args = node.args;
|
||||
}
|
||||
else {
|
||||
args = new Object[node.args.length];
|
||||
for (int i = 0, len = node.args.length; i < len; i++) {
|
||||
args[i] = node.args[i] instanceof Node? execute((Node)node.args[i]) : node.args[i];
|
||||
}
|
||||
}
|
||||
return invokeMethod(target, methodName, args, myStaticMethods);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int)myHashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
return obj instanceof LazyPresentablePattern &&
|
||||
((LazyPresentablePattern)obj).myHashCode == myHashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.intellij.util;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
|
||||
@@ -167,7 +167,7 @@ public class MultiMap<K, V> {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
itr.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,19 +15,16 @@
|
||||
*/
|
||||
package com.intellij.openapi.diff.impl.dir;
|
||||
|
||||
import com.intellij.ide.diff.DiffElement;
|
||||
import com.intellij.ide.diff.DirDiffSettings;
|
||||
import com.intellij.ide.diff.VirtualFileDiffElement;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.diff.DirDiffManager;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.fileChooser.FileChooserFactory;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
@@ -35,21 +32,19 @@ import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
public class TestDirDiffAction extends AnAction {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
final Project project = e.getData(PlatformDataKeys.PROJECT);
|
||||
if (project != null) {
|
||||
final VirtualFile src = VirtualFileManager.getInstance().findFileByUrl(Registry.stringValue("dir.diff.default.src.folder"));
|
||||
final VirtualFile trg = VirtualFileManager.getInstance().findFileByUrl(Registry.stringValue("dir.diff.default.trg.folder"));
|
||||
final FileChooserDescriptor descriptor = new FileChooserDescriptor(false, true, false, false, false, false);
|
||||
final VirtualFile[] files1 = src != null ? new VirtualFile[]{src} : FileChooserFactory.getInstance().createFileChooser(descriptor, project).choose(null, project);
|
||||
final VirtualFile[] files2 = trg != null ? new VirtualFile[]{trg} : FileChooserFactory.getInstance().createFileChooser(descriptor, project).choose(null, project);
|
||||
if (files1.length == 1 && files2.length == 1) {
|
||||
DiffElement elem1 = new VirtualFileDiffElement(files1[0]);
|
||||
DiffElement elem2 = new VirtualFileDiffElement(files2[0]);
|
||||
final DirDiffManager diffManager = DirDiffManager.getInstance(project);
|
||||
if (diffManager.canShow(elem1, elem2)) {
|
||||
diffManager.showDiff(elem1, elem2, new DirDiffSettings());
|
||||
}
|
||||
new DialogWrapper(e.getData(PlatformDataKeys.PROJECT)) {
|
||||
{
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
final JPanel panel = new JPanel(new BorderLayout());
|
||||
final JBTable table = new JBTable();
|
||||
table.setModel(new DefaultTableModel(new Object[][]{{"aaa", "bbb"}, {"ccc", "ddd"}}, new Object[]{"foo", "bar"}));
|
||||
panel.add(ScrollPaneFactory.createScrollPane(table), BorderLayout.CENTER);
|
||||
return panel;
|
||||
}
|
||||
}.show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,6 +392,7 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
|
||||
}
|
||||
final boolean refresh = (! myInRefresh) && myHistorySession.shouldBeRefreshed();
|
||||
myUpdateAlarm.cancelAllRequests();
|
||||
if (myUpdateAlarm.isDisposed()) return;
|
||||
myUpdateAlarm.addRequest(this, 20000);
|
||||
|
||||
if (refresh) {
|
||||
|
||||
+2
-2
@@ -43,7 +43,7 @@ import java.util.Arrays;
|
||||
* @author Gregory.Shrago
|
||||
*/
|
||||
public class AdvancedSettingsUI implements Configurable {
|
||||
private final Configuration myConfiguration;
|
||||
private final Configuration.AdvancedConfiguration myConfiguration;
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration", "FieldCanBeLocal"})
|
||||
private JPanel myRoot;
|
||||
@@ -65,7 +65,7 @@ public class AdvancedSettingsUI implements Configurable {
|
||||
private final ReferenceEditorWithBrowseButton mySubstField;
|
||||
|
||||
public AdvancedSettingsUI(@NotNull final Project project, Configuration configuration) {
|
||||
myConfiguration = configuration;
|
||||
myConfiguration = configuration.getAdvancedConfiguration();
|
||||
|
||||
myAnnotationField = new ReferenceEditorWithBrowseButton(null, project, new Function<String, Document>() {
|
||||
public Document fun(String s) {
|
||||
|
||||
+7
-2
@@ -21,6 +21,7 @@ import com.intellij.openapi.util.JDOMExternalizableStringList;
|
||||
import com.intellij.openapi.util.JDOMExternalizer;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.patterns.compiler.PatternCompiler;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiFormatUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
@@ -118,8 +119,12 @@ public class MethodParameterInjection extends BaseInjection {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> generatePlaces() {
|
||||
return getPatternString(this);
|
||||
public void generatePlaces() {
|
||||
getInjectionPlaces().clear();
|
||||
final PatternCompiler<PsiElement> compiler = getCompiler();
|
||||
for (String text : getPatternString(this)) {
|
||||
getInjectionPlaces().add(new InjectionPlace(compiler.createElementPattern(text, getDisplayName()), true));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"RedundantIfStatement"})
|
||||
|
||||
+4
-4
@@ -80,7 +80,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
|
||||
}, false);
|
||||
myAnnoIndex = CachedValuesManager.getManager(myProject).createCachedValue(new CachedValueProvider<Collection<String>>() {
|
||||
public Result<Collection<String>> compute() {
|
||||
final String annotationClass = myConfiguration.getLanguageAnnotationClass();
|
||||
final String annotationClass = myConfiguration.getAdvancedConfiguration().getLanguageAnnotationClass();
|
||||
final Collection<String> result = new THashSet<String>();
|
||||
final ArrayList<String> annoClasses = new ArrayList<String>(3);
|
||||
annoClasses.add(StringUtil.getShortName(annotationClass));
|
||||
@@ -211,7 +211,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
|
||||
}
|
||||
|
||||
public boolean visitVariable(PsiVariable variable) {
|
||||
if (myConfiguration.getDfaOption() != Configuration.DfaOption.OFF && visitedVars.add(variable)) {
|
||||
if (myConfiguration.getAdvancedConfiguration().getDfaOption() != Configuration.DfaOption.OFF && visitedVars.add(variable)) {
|
||||
ReferencesSearch.search(variable, searchScope).forEach(new Processor<PsiReference>() {
|
||||
@Override
|
||||
public boolean process(PsiReference psiReference) {
|
||||
@@ -247,7 +247,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
|
||||
}
|
||||
|
||||
public boolean visitReference(PsiReferenceExpression expression) {
|
||||
if (myConfiguration.getDfaOption() == Configuration.DfaOption.OFF) return true;
|
||||
if (myConfiguration.getAdvancedConfiguration().getDfaOption() == Configuration.DfaOption.OFF) return true;
|
||||
final PsiElement e = expression.resolve();
|
||||
if (e instanceof PsiVariable) {
|
||||
if (e instanceof PsiParameter) {
|
||||
@@ -300,7 +300,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
|
||||
else checkName = null;
|
||||
if (checkName == null || !areThereInjectionsWithName(checkName, true)) return true;
|
||||
final PsiAnnotation[] annotations =
|
||||
AnnotationUtilEx.getAnnotationFrom(annoElement, myConfiguration.getLanguageAnnotationPair(), true);
|
||||
AnnotationUtilEx.getAnnotationFrom(annoElement, myConfiguration.getAdvancedConfiguration().getLanguageAnnotationPair(), true);
|
||||
if (annotations.length > 0) {
|
||||
final String id = AnnotationUtilEx.calcAnnotationValue(annotations, "value");
|
||||
final String prefix = AnnotationUtilEx.calcAnnotationValue(annotations, "prefix");
|
||||
|
||||
+16
-15
@@ -32,6 +32,7 @@ import com.intellij.openapi.util.Factory;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.patterns.PsiJavaPatterns;
|
||||
import com.intellij.patterns.compiler.PatternCompiler;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
@@ -102,11 +103,11 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
|
||||
|
||||
public boolean removeInjectionInPlace(final PsiLanguageInjectionHost psiElement) {
|
||||
if (!isMine(psiElement)) return false;
|
||||
final Configuration configuration = Configuration.getInstance();
|
||||
final HashMap<BaseInjection, Pair<PsiMethod, Integer>> injectionsMap = new HashMap<BaseInjection, Pair<PsiMethod, Integer>>();
|
||||
final ArrayList<PsiAnnotation> annotations = new ArrayList<PsiAnnotation>();
|
||||
final PsiLiteralExpression host = (PsiLiteralExpression)psiElement;
|
||||
final Project project = host.getProject();
|
||||
final Configuration configuration = Configuration.getProjectInstance(project);
|
||||
collectInjections(host, configuration, injectionsMap, annotations);
|
||||
|
||||
if (injectionsMap.isEmpty() && annotations.isEmpty()) return false;
|
||||
@@ -120,17 +121,17 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
|
||||
return newInjection;
|
||||
}
|
||||
});
|
||||
Configuration.getInstance().replaceInjectionsWithUndo(project, newInjections, originalInjections, annotations);
|
||||
configuration.replaceInjectionsWithUndo(project, newInjections, originalInjections, annotations);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean editInjectionInPlace(final PsiLanguageInjectionHost psiElement) {
|
||||
if (!isMine(psiElement)) return false;
|
||||
final Configuration configuration = Configuration.getInstance();
|
||||
final HashMap<BaseInjection, Pair<PsiMethod, Integer>> injectionsMap = new HashMap<BaseInjection, Pair<PsiMethod, Integer>>();
|
||||
final ArrayList<PsiAnnotation> annotations = new ArrayList<PsiAnnotation>();
|
||||
final PsiLiteralExpression host = (PsiLiteralExpression)psiElement;
|
||||
final Project project = host.getProject();
|
||||
final Configuration configuration = Configuration.getProjectInstance(project);
|
||||
collectInjections(host, configuration, injectionsMap, annotations);
|
||||
if (injectionsMap.isEmpty() || !annotations.isEmpty()) return false;
|
||||
|
||||
@@ -139,10 +140,9 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
|
||||
final MethodParameterInjection copy = methodParameterInjection.copy();
|
||||
final BaseInjection newInjection = showInjectionUI(project, methodParameterInjection);
|
||||
if (newInjection != null) {
|
||||
copy.initializePlaces(false);
|
||||
newInjection.mergeOriginalPlacesFrom(copy, false);
|
||||
newInjection.mergeOriginalPlacesFrom(originalInjection, true);
|
||||
Configuration.getInstance().replaceInjectionsWithUndo(
|
||||
configuration.replaceInjectionsWithUndo(
|
||||
project, Collections.singletonList(newInjection), Collections.singletonList(originalInjection), Collections.<PsiAnnotation>emptyList());
|
||||
}
|
||||
return true;
|
||||
@@ -165,7 +165,6 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
|
||||
}
|
||||
});
|
||||
if (builder.show() == DialogWrapper.OK_EXIT_CODE) {
|
||||
methodParameterInjection.initializePlaces(false);
|
||||
return new BaseInjection(methodParameterInjection.getSupportId()).copyFrom(methodParameterInjection);
|
||||
}
|
||||
return null;
|
||||
@@ -256,6 +255,7 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
|
||||
info.getParamFlags()[parameterIndex] = true;
|
||||
}
|
||||
injection.setMethodInfos(Collections.singletonList(info));
|
||||
injection.generatePlaces();
|
||||
doEditInjection(project, injection, psiMethod);
|
||||
return true;
|
||||
}
|
||||
@@ -307,11 +307,9 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
|
||||
}
|
||||
|
||||
private static void doEditInjection(final Project project, final MethodParameterInjection template, final PsiMethod contextMethod) {
|
||||
final Configuration configuration = Configuration.getInstance();
|
||||
template.initializePlaces(false);
|
||||
final Configuration configuration = Configuration.getProjectInstance(project);
|
||||
final BaseInjection baseTemplate = new BaseInjection(template.getSupportId()).copyFrom(template);
|
||||
final MethodParameterInjection allMethodParameterInjection = createFrom(project, baseTemplate, contextMethod, true);
|
||||
allMethodParameterInjection.initializePlaces(false);
|
||||
// find existing injection for this class.
|
||||
final BaseInjection originalInjection = configuration.findExistingInjection(allMethodParameterInjection);
|
||||
final MethodParameterInjection methodParameterInjection;
|
||||
@@ -326,12 +324,11 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
|
||||
methodParameterInjection = createFrom(project, originalCopy, contextMethod, false);
|
||||
}
|
||||
if (InjectLanguageAction.doEditConfigurable(project, new MethodParameterInjectionConfigurable(methodParameterInjection, null, project))) {
|
||||
methodParameterInjection.initializePlaces(false);
|
||||
final BaseInjection newInjection = new BaseInjection(methodParameterInjection.getSupportId()).copyFrom(methodParameterInjection);
|
||||
if (originalInjection != null) {
|
||||
newInjection.mergeOriginalPlacesFrom(originalInjection, true);
|
||||
}
|
||||
Configuration.getInstance().replaceInjectionsWithUndo(
|
||||
configuration.replaceInjectionsWithUndo(
|
||||
project, Collections.singletonList(newInjection),
|
||||
ContainerUtil.createMaybeSingletonList(originalInjection),
|
||||
Collections.<PsiElement>emptyList());
|
||||
@@ -344,7 +341,7 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
|
||||
new ConcatenationInjector.InjectionProcessor(configuration, host) {
|
||||
@Override
|
||||
protected boolean processAnnotationInjections(PsiModifierListOwner annoElement) {
|
||||
ContainerUtil.addAll(annotations, AnnotationUtilEx.getAnnotationFrom(annoElement, configuration.getLanguageAnnotationPair(), true));
|
||||
ContainerUtil.addAll(annotations, AnnotationUtilEx.getAnnotationFrom(annoElement, configuration.getAdvancedConfiguration().getLanguageAnnotationPair(), true));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -395,6 +392,7 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
|
||||
final ArrayList<MethodInfo> infos = new ArrayList<MethodInfo>();
|
||||
if (classes.length > 0) {
|
||||
final THashSet<String> visitedSignatures = new THashSet<String>();
|
||||
final PatternCompiler<PsiElement> compiler = injection.getCompiler();
|
||||
for (PsiClass psiClass : classes) {
|
||||
for (PsiMethod method : psiClass.getMethods()) {
|
||||
final PsiModifierList modifiers = method.getModifierList();
|
||||
@@ -404,7 +402,8 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
|
||||
if (!visitedSignatures.add(methodInfo.getMethodSignature())) continue;
|
||||
if (isInjectable(method.getReturnType(), method.getProject())) {
|
||||
final int parameterIndex = -1;
|
||||
final InjectionPlace place = injection.findPlaceByText(getPatternStringForJavaPlace(method, parameterIndex));
|
||||
final InjectionPlace place = ContainerUtil.find(
|
||||
injection.getInjectionPlaces(), new InjectionPlace(compiler.compileElementPattern(getPatternStringForJavaPlace(method, parameterIndex)), true));
|
||||
methodInfo.setReturnFlag(place != null && place.isEnabled() || includeAllPlaces);
|
||||
add = true;
|
||||
}
|
||||
@@ -412,7 +411,9 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
final PsiParameter p = parameters[i];
|
||||
if (isInjectable(p.getType(), p.getProject())) {
|
||||
final InjectionPlace place = injection.findPlaceByText(getPatternStringForJavaPlace(method, i));
|
||||
final InjectionPlace place = ContainerUtil.find(
|
||||
injection.getInjectionPlaces(),
|
||||
new InjectionPlace(compiler.compileElementPattern(getPatternStringForJavaPlace(method, i)), true));
|
||||
methodInfo.getParamFlags()[i] = place != null && place.isEnabled() || includeAllPlaces;
|
||||
add = true;
|
||||
}
|
||||
@@ -433,6 +434,7 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
|
||||
//}
|
||||
}
|
||||
result.setMethodInfos(infos);
|
||||
result.generatePlaces();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -470,7 +472,6 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
|
||||
if (newInjection != null) {
|
||||
newInjection.mergeOriginalPlacesFrom(originalInjection, mergeEnabled);
|
||||
originalInjection.copyFrom(newInjection);
|
||||
originalInjection.initializePlaces(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
+3
-10
@@ -16,7 +16,6 @@
|
||||
package org.intellij.plugins.intelliLang.inject.java;
|
||||
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.patterns.PatternCondition;
|
||||
import com.intellij.patterns.StandardPatterns;
|
||||
import com.intellij.psi.*;
|
||||
@@ -32,20 +31,14 @@ import static com.intellij.patterns.PsiJavaPatterns.literalExpression;
|
||||
* Provides references to Language-IDs and RegExp enums for completion.
|
||||
*/
|
||||
public final class LanguageReferenceProvider extends PsiReferenceContributor {
|
||||
private final Configuration myConfig = Configuration.getInstance();
|
||||
|
||||
private final Computable<String> ANNOTATION_NAME = new Computable<String>() {
|
||||
public String compute() {
|
||||
return myConfig.getLanguageAnnotationClass();
|
||||
}
|
||||
};
|
||||
|
||||
public void registerReferenceProviders(PsiReferenceRegistrar registrar) {
|
||||
final Configuration configuration = Configuration.getInstance();
|
||||
registrar.registerReferenceProvider(
|
||||
literalExpression().annotationParam(StandardPatterns.string().with(new PatternCondition<String>("isLanguageAnnotation") {
|
||||
@Override
|
||||
public boolean accepts(@NotNull final String s, final ProcessingContext context) {
|
||||
return Comparing.equal(ANNOTATION_NAME.compute(), s);
|
||||
return Comparing.equal(configuration.getAdvancedConfiguration().getLanguageAnnotationClass(), s);
|
||||
}
|
||||
}), "value").and(literalExpression().with(new PatternCondition<PsiLiteralExpression>("isStringLiteral") {
|
||||
@Override
|
||||
@@ -72,7 +65,7 @@ public final class LanguageReferenceProvider extends PsiReferenceContributor {
|
||||
final PsiModifierListOwner owner =
|
||||
AnnotationUtilEx.getAnnotatedElementFor(expression, AnnotationUtilEx.LookupType.PREFER_DECLARATION);
|
||||
if (owner != null && PsiUtilEx.isLanguageAnnotationTarget(owner)) {
|
||||
final PsiAnnotation[] annotations = AnnotationUtilEx.getAnnotationFrom(owner, myConfig.getPatternAnnotationPair(), true);
|
||||
final PsiAnnotation[] annotations = AnnotationUtilEx.getAnnotationFrom(owner, configuration.getAdvancedConfiguration().getPatternAnnotationPair(), true);
|
||||
if (annotations.length > 0) {
|
||||
final String pattern = AnnotationUtilEx.calcAnnotationValue(annotations, "value");
|
||||
if (pattern != null) {
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ public class InjectionNotApplicable extends LocalInspectionTool {
|
||||
@NotNull
|
||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
final String annotationName = Configuration.getInstance().getLanguageAnnotationClass();
|
||||
final String annotationName = Configuration.getProjectInstance(holder.getProject()).getAdvancedConfiguration().getLanguageAnnotationClass();
|
||||
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
}
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ public class LanguageMismatch extends LocalInspectionTool {
|
||||
@NotNull
|
||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
final Pair<String, ? extends Set<String>> annotationName = Configuration.getInstance().getLanguageAnnotationPair();
|
||||
final Pair<String, ? extends Set<String>> annotationName = Configuration.getProjectInstance(holder.getProject()).getAdvancedConfiguration().getLanguageAnnotationPair();
|
||||
|
||||
public void visitExpression(PsiExpression expression) {
|
||||
checkExpression(expression, holder, annotationName);
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ public class UnknownLanguageID extends LocalInspectionTool {
|
||||
@NotNull
|
||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
final String annotationName = Configuration.getInstance().getLanguageAnnotationClass();
|
||||
final String annotationName = Configuration.getProjectInstance(holder.getProject()).getAdvancedConfiguration().getLanguageAnnotationClass();
|
||||
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
}
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ public class PatternAnnotationNotApplicable extends LocalInspectionTool {
|
||||
@NotNull
|
||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
final String annotationName = Configuration.getInstance().getPatternAnnotationClass();
|
||||
final String annotationName = Configuration.getProjectInstance(holder.getProject()).getAdvancedConfiguration().getPatternAnnotationClass();
|
||||
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
}
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ public class PatternOverriddenByNonAnnotatedMethod extends LocalInspectionTool {
|
||||
@NotNull
|
||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
final Pair<String, ? extends Set<String>> annotationName = Configuration.getInstance().getPatternAnnotationPair();
|
||||
final Pair<String, ? extends Set<String>> annotationName = Configuration.getProjectInstance(holder.getProject()).getAdvancedConfiguration().getPatternAnnotationPair();
|
||||
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
}
|
||||
|
||||
+5
-5
@@ -173,7 +173,7 @@ public class PatternValidator extends LocalInspectionTool {
|
||||
final PsiModifierListOwner element;
|
||||
if (isAnnotationValue) {
|
||||
final PsiAnnotation psiAnnotation = PsiTreeUtil.getParentOfType(expression, PsiAnnotation.class);
|
||||
if (psiAnnotation != null && myConfiguration.getSubstAnnotationClass().equals(psiAnnotation.getQualifiedName())) {
|
||||
if (psiAnnotation != null && myConfiguration.getAdvancedConfiguration().getSubstAnnotationClass().equals(psiAnnotation.getQualifiedName())) {
|
||||
element = PsiTreeUtil.getParentOfType(expression, PsiModifierListOwner.class);
|
||||
}
|
||||
else {
|
||||
@@ -184,7 +184,7 @@ public class PatternValidator extends LocalInspectionTool {
|
||||
element = AnnotationUtilEx.getAnnotatedElementFor(expression, AnnotationUtilEx.LookupType.PREFER_CONTEXT);
|
||||
}
|
||||
if (element != null && PsiUtilEx.isLanguageAnnotationTarget(element)) {
|
||||
PsiAnnotation[] annotations = AnnotationUtilEx.getAnnotationFrom(element, myConfiguration.getPatternAnnotationPair(), true);
|
||||
PsiAnnotation[] annotations = AnnotationUtilEx.getAnnotationFrom(element, myConfiguration.getAdvancedConfiguration().getPatternAnnotationPair(), true);
|
||||
checkExpression(expression, annotations, holder);
|
||||
}
|
||||
}
|
||||
@@ -224,7 +224,7 @@ public class PatternValidator extends LocalInspectionTool {
|
||||
|
||||
List<PsiExpression> nonConstantElements = new SmartList<PsiExpression>();
|
||||
final Object result = new SubstitutedExpressionEvaluationHelper(expression.getProject()).computeExpression(
|
||||
expression, myConfiguration.getDfaOption(), false, nonConstantElements);
|
||||
expression, myConfiguration.getAdvancedConfiguration().getDfaOption(), false, nonConstantElements);
|
||||
final String o = result == null ? null : String.valueOf(result);
|
||||
if (o != null) {
|
||||
if (!pattern.matcher(o).matches()) {
|
||||
@@ -258,13 +258,13 @@ public class PatternValidator extends LocalInspectionTool {
|
||||
final PsiModifierListOwner owner = e instanceof PsiModifierListOwner? (PsiModifierListOwner)e : null;
|
||||
LocalQuickFix quickFix;
|
||||
if (owner != null && PsiUtilEx.isLanguageAnnotationTarget(owner)) {
|
||||
PsiAnnotation[] resolvedAnnos = AnnotationUtilEx.getAnnotationFrom(owner, myConfiguration.getPatternAnnotationPair(), true);
|
||||
PsiAnnotation[] resolvedAnnos = AnnotationUtilEx.getAnnotationFrom(owner, myConfiguration.getAdvancedConfiguration().getPatternAnnotationPair(), true);
|
||||
if (resolvedAnnos.length == 2 && annotations.length == 2 && Comparing.strEqual(resolvedAnnos[1].getQualifiedName(), annotations[1].getQualifiedName())) {
|
||||
// both target and source annotated indirectly with the same anno
|
||||
return;
|
||||
}
|
||||
|
||||
final String classname = Configuration.getInstance().getSubstAnnotationPair().first;
|
||||
final String classname = myConfiguration.getAdvancedConfiguration().getSubstAnnotationPair().first;
|
||||
final AnnotateFix fix = new AnnotateFix((PsiModifierListOwner)e, classname);
|
||||
quickFix = fix.canApply() ? fix : new IntroduceVariableFix(expr);
|
||||
}
|
||||
|
||||
+4
-3
@@ -45,7 +45,8 @@ public class PatternValidationCompiler extends AnnotationBasedInstrumentingCompi
|
||||
protected String[] getAnnotationNames(Project project) {
|
||||
synchronized (myAnnotations) {
|
||||
myAnnotations.clear();
|
||||
final Pair<String, ? extends Set<String>> patternAnnotation = Configuration.getInstance().getPatternAnnotationPair();
|
||||
final Pair<String, ? extends Set<String>> patternAnnotation =
|
||||
Configuration.getProjectInstance(project).getAdvancedConfiguration().getPatternAnnotationPair();
|
||||
|
||||
final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
|
||||
final PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(patternAnnotation.first, scope);
|
||||
@@ -83,14 +84,14 @@ public class PatternValidationCompiler extends AnnotationBasedInstrumentingCompi
|
||||
}
|
||||
|
||||
protected boolean isEnabled() {
|
||||
final Configuration.InstrumentationType option = Configuration.getInstance().getInstrumentation();
|
||||
final Configuration.InstrumentationType option = Configuration.getInstance().getAdvancedConfiguration().getInstrumentation();
|
||||
return option == Configuration.InstrumentationType.ASSERT || option == Configuration.InstrumentationType.EXCEPTION;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Instrumenter createInstrumenter(ClassWriter classwriter) {
|
||||
synchronized (myAnnotations) {
|
||||
final Configuration.InstrumentationType instrumentation = Configuration.getInstance().getInstrumentation();
|
||||
final Configuration.InstrumentationType instrumentation = Configuration.getInstance().getAdvancedConfiguration().getInstrumentation();
|
||||
return new PatternValidationInstrumenter(new HashMap<String, String>(myAnnotations), classwriter, instrumentation);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -45,7 +45,7 @@ public class SubstitutedExpressionEvaluationHelper {
|
||||
}
|
||||
|
||||
public Object computeExpression(final PsiExpression e, final List<PsiExpression> uncomputables) {
|
||||
return computeExpression(e, myConfiguration.getDfaOption(), myConfiguration.isIncludeUncomputablesAsLiterals(), uncomputables);
|
||||
return computeExpression(e, myConfiguration.getAdvancedConfiguration().getDfaOption(), myConfiguration.getAdvancedConfiguration().isIncludeUncomputablesAsLiterals(), uncomputables);
|
||||
}
|
||||
|
||||
public Object computeExpression(final PsiExpression e, final Configuration.DfaOption dfaOption, final boolean includeUncomputablesAsLiterals, final List<PsiExpression> uncomputables) {
|
||||
@@ -127,7 +127,7 @@ public class SubstitutedExpressionEvaluationHelper {
|
||||
|
||||
@Nullable
|
||||
private Object calcSubstituted(final PsiModifierListOwner owner) {
|
||||
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, myConfiguration.getSubstAnnotationPair().second);
|
||||
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, myConfiguration.getAdvancedConfiguration().getSubstAnnotationPair().second);
|
||||
if (annotation != null) {
|
||||
return AnnotationUtilEx.calcAnnotationValue(annotation, "value");
|
||||
}
|
||||
|
||||
@@ -39,20 +39,17 @@
|
||||
|
||||
<highlightErrorFilter implementation="org.intellij.plugins.intelliLang.inject.CustomErrorElementFilter"/>
|
||||
|
||||
<applicationConfigurable instance="org.intellij.plugins.intelliLang.Settings"/>
|
||||
<projectConfigurable instance="org.intellij.plugins.intelliLang.Settings"/>
|
||||
|
||||
<multiHostInjector implementation="org.intellij.plugins.intelliLang.inject.TemporaryPlacesInjector"/>
|
||||
<multiHostInjector implementation="org.intellij.plugins.intelliLang.inject.DefaultLanguageInjector" order="last"/>
|
||||
|
||||
<projectService serviceInterface="org.intellij.plugins.intelliLang.inject.TemporaryPlacesRegistry"
|
||||
serviceImplementation="org.intellij.plugins.intelliLang.inject.TemporaryPlacesRegistry"/>
|
||||
</extensions>
|
||||
<applicationService serviceInterface="org.intellij.plugins.intelliLang.Configuration"
|
||||
serviceImplementation="org.intellij.plugins.intelliLang.Configuration$App"/>
|
||||
<projectService serviceInterface="org.intellij.plugins.intelliLang.Configuration"
|
||||
serviceImplementation="org.intellij.plugins.intelliLang.Configuration$Prj"/>
|
||||
|
||||
<application-components>
|
||||
<component>
|
||||
<!-- Making it a service may result in FileContentUtil.reparseFiles at a random loading moment which may cause
|
||||
mysterious PSI validity losses -->
|
||||
<implementation-class>org.intellij.plugins.intelliLang.Configuration</implementation-class>
|
||||
</component>
|
||||
</application-components>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -19,22 +19,16 @@ import com.intellij.ide.plugins.IdeaPluginDescriptor;
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptorImpl;
|
||||
import com.intellij.ide.plugins.PluginManager;
|
||||
import com.intellij.ide.plugins.cl.PluginClassLoader;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.UndoConfirmationPolicy;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.command.undo.GlobalUndoableAction;
|
||||
import com.intellij.openapi.command.undo.UndoManager;
|
||||
import com.intellij.openapi.command.undo.UndoableAction;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.components.StorageScheme;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiCompiledElement;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
@@ -46,6 +40,7 @@ import com.intellij.util.NullableFunction;
|
||||
import com.intellij.util.PairProcessor;
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import org.intellij.plugins.intelliLang.inject.InjectorUtils;
|
||||
@@ -72,12 +67,88 @@ import java.util.*;
|
||||
* Making it a service may result in FileContentUtil.reparseFiles at a random loading moment which may cause
|
||||
* mysterious PSI validity losses
|
||||
*/
|
||||
@State(
|
||||
name = Configuration.COMPONENT_NAME,
|
||||
storages = {@Storage(id = "dir", file = "$APP_CONFIG$/IntelliLang.xml", scheme = StorageScheme.DIRECTORY_BASED)})
|
||||
public final class Configuration implements PersistentStateComponent<Element>, ModificationTracker {
|
||||
public class Configuration implements PersistentStateComponent<Element>, ModificationTracker {
|
||||
|
||||
static final Logger LOG = Logger.getInstance(Configuration.class.getName());
|
||||
|
||||
@State(
|
||||
name = Configuration.COMPONENT_NAME,
|
||||
storages = {@Storage(id = "dir", file = "$APP_CONFIG$/IntelliLang.xml", scheme = StorageScheme.DIRECTORY_BASED)})
|
||||
public static class App extends Configuration {
|
||||
|
||||
private final List<BaseInjection> myDefaultInjections;
|
||||
private final AdvancedConfiguration myAdvancedConfiguration;
|
||||
|
||||
App() {
|
||||
myDefaultInjections = loadDefaultInjections();
|
||||
myAdvancedConfiguration = new AdvancedConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BaseInjection> getDefaultInjections() {
|
||||
return myDefaultInjections;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancedConfiguration getAdvancedConfiguration() {
|
||||
return myAdvancedConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(final Element element) {
|
||||
myAdvancedConfiguration.loadState(element);
|
||||
super.loadState(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element getState() {
|
||||
final Element element = new Element(COMPONENT_NAME);
|
||||
myAdvancedConfiguration.writeState(element);
|
||||
return getState(element);
|
||||
}
|
||||
}
|
||||
@State(
|
||||
name = Configuration.COMPONENT_NAME,
|
||||
storages = {@Storage(id = "default", file = "$PROJECT_FILE$"),
|
||||
@Storage(id = "dir", file = "$PROJECT_CONFIG_DIR$/IntelliLang.xml", scheme = StorageScheme.DIRECTORY_BASED)})
|
||||
public static class Prj extends Configuration {
|
||||
|
||||
private final Configuration myParentConfiguration;
|
||||
|
||||
Prj(final Configuration configuration) {
|
||||
myParentConfiguration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancedConfiguration getAdvancedConfiguration() {
|
||||
return myParentConfiguration.getAdvancedConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BaseInjection> getDefaultInjections() {
|
||||
return myParentConfiguration.getDefaultInjections();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<BaseInjection> getInjections(final String injectorId) {
|
||||
return ContainerUtil.concat(myParentConfiguration.getInjections(injectorId), getOwnInjections(injectorId));
|
||||
}
|
||||
|
||||
public Configuration getParentConfiguration() {
|
||||
return myParentConfiguration;
|
||||
}
|
||||
|
||||
public List<BaseInjection> getOwnInjections(final String injectorId) {
|
||||
return super.getInjections(injectorId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getModificationCount() {
|
||||
return super.getModificationCount() + myParentConfiguration.getModificationCount();
|
||||
}
|
||||
}
|
||||
|
||||
public enum InstrumentationType {
|
||||
NONE, ASSERT, EXCEPTION
|
||||
}
|
||||
@@ -108,37 +179,17 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
return ContainerUtil.createEmptyCOWList();
|
||||
}
|
||||
};
|
||||
private ArrayList<BaseInjection> myDefaultInjections;
|
||||
|
||||
// runtime pattern validation instrumentation
|
||||
@NotNull private InstrumentationType myInstrumentationType = InstrumentationType.ASSERT;
|
||||
|
||||
// annotation class names
|
||||
@NotNull private String myLanguageAnnotation;
|
||||
@NotNull private String myPatternAnnotation;
|
||||
@NotNull private String mySubstAnnotation;
|
||||
|
||||
private boolean myIncludeUncomputablesAsLiterals;
|
||||
private DfaOption myDfaOption = DfaOption.RESOLVE;
|
||||
|
||||
// cached annotation name pairs
|
||||
private Pair<String, ? extends Set<String>> myLanguageAnnotationPair;
|
||||
private Pair<String, ? extends Set<String>> myPatternAnnotationPair;
|
||||
|
||||
private Pair<String, ? extends Set<String>> mySubstAnnotationPair;
|
||||
private volatile long myModificationCount;
|
||||
|
||||
public Configuration() {
|
||||
setLanguageAnnotation("org.intellij.lang.annotations.Language");
|
||||
setPatternAnnotation("org.intellij.lang.annotations.Pattern");
|
||||
setSubstAnnotation("org.intellij.lang.annotations.Subst");
|
||||
}
|
||||
|
||||
public AdvancedConfiguration getAdvancedConfiguration() {
|
||||
throw new UnsupportedOperationException("getAdvancedConfiguration should not be called");
|
||||
}
|
||||
|
||||
public void loadState(final Element element) {
|
||||
loadState(element, true);
|
||||
}
|
||||
|
||||
public void loadState(final Element element, final boolean mergeWithOriginalAndCompile) {
|
||||
final THashMap<String, LanguageInjectionSupport> supports = new THashMap<String, LanguageInjectionSupport>();
|
||||
for (LanguageInjectionSupport support : Extensions.getExtensions(LanguageInjectionSupport.EP_NAME)) {
|
||||
supports.put(support.getId(), support);
|
||||
@@ -151,30 +202,7 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
injection.loadState(child);
|
||||
myInjections.get(key).add(injection);
|
||||
}
|
||||
setInstrumentationType(JDOMExternalizerUtil.readField(element, INSTRUMENTATION_TYPE_NAME));
|
||||
setLanguageAnnotation(JDOMExternalizerUtil.readField(element, LANGUAGE_ANNOTATION_NAME));
|
||||
setPatternAnnotation(JDOMExternalizerUtil.readField(element, PATTERN_ANNOTATION_NAME));
|
||||
setSubstAnnotation(JDOMExternalizerUtil.readField(element, SUBST_ANNOTATION_NAME));
|
||||
if (readBoolean(element, RESOLVE_REFERENCES, true)) {
|
||||
setDfaOption(DfaOption.RESOLVE);
|
||||
}
|
||||
if (readBoolean(element, LOOK_FOR_VAR_ASSIGNMENTS, false)) {
|
||||
setDfaOption(DfaOption.ASSIGNMENTS);
|
||||
}
|
||||
if (readBoolean(element, USE_DFA_IF_AVAILABLE, false)) {
|
||||
setDfaOption(DfaOption.DFA);
|
||||
}
|
||||
setIncludeUncomputablesAsLiterals(readBoolean(element, INCLUDE_UNCOMPUTABLES_AS_LITERALS, false));
|
||||
|
||||
if (mergeWithOriginalAndCompile) {
|
||||
mergeWithDefaultConfiguration();
|
||||
|
||||
for (String supportId : InjectorUtils.getActiveInjectionSupportIds()) {
|
||||
for (BaseInjection injection : getInjections(supportId)) {
|
||||
injection.initializePlaces(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
importPlaces(getDefaultInjections());
|
||||
}
|
||||
|
||||
private void loadStateOld(Element element, final LanguageInjectionSupport xmlSupport, final LanguageInjectionSupport javaSupport) {
|
||||
@@ -208,7 +236,7 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
private void mergeWithDefaultConfiguration() {
|
||||
private static List<BaseInjection> loadDefaultInjections() {
|
||||
final ArrayList<Configuration> cfgList = new ArrayList<Configuration>();
|
||||
for (LanguageInjectionSupport support : InjectorUtils.getActiveInjectionSupports()) {
|
||||
final String config = support.getDefaultConfigUrl();
|
||||
@@ -247,47 +275,26 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
}
|
||||
}
|
||||
|
||||
final ArrayList<BaseInjection> originalInjections = new ArrayList<BaseInjection>();
|
||||
final ArrayList<BaseInjection> newInjections = new ArrayList<BaseInjection>();
|
||||
myDefaultInjections = new ArrayList<BaseInjection>();
|
||||
final ArrayList<BaseInjection> defaultInjections = new ArrayList<BaseInjection>();
|
||||
for (String supportId : InjectorUtils.getActiveInjectionSupportIds()) {
|
||||
for (Configuration cfg : cfgList) {
|
||||
final List<BaseInjection> imported = cfg.getInjections(supportId);
|
||||
myDefaultInjections.addAll(imported);
|
||||
importInjections(getInjections(supportId), imported, originalInjections, newInjections);
|
||||
defaultInjections.addAll(imported);
|
||||
}
|
||||
}
|
||||
replaceInjections(newInjections, originalInjections);
|
||||
return defaultInjections;
|
||||
}
|
||||
|
||||
public Element getState() {
|
||||
final Element element = new Element(COMPONENT_NAME);
|
||||
|
||||
JDOMExternalizerUtil.writeField(element, INSTRUMENTATION_TYPE_NAME, myInstrumentationType.toString());
|
||||
JDOMExternalizerUtil.writeField(element, LANGUAGE_ANNOTATION_NAME, myLanguageAnnotation);
|
||||
JDOMExternalizerUtil.writeField(element, PATTERN_ANNOTATION_NAME, myPatternAnnotation);
|
||||
JDOMExternalizerUtil.writeField(element, SUBST_ANNOTATION_NAME, mySubstAnnotation);
|
||||
switch (myDfaOption) {
|
||||
case OFF:
|
||||
break;
|
||||
case RESOLVE:
|
||||
JDOMExternalizerUtil.writeField(element, RESOLVE_REFERENCES, Boolean.TRUE.toString());
|
||||
break;
|
||||
case ASSIGNMENTS:
|
||||
JDOMExternalizerUtil.writeField(element, LOOK_FOR_VAR_ASSIGNMENTS, Boolean.TRUE.toString());
|
||||
break;
|
||||
case DFA:
|
||||
JDOMExternalizerUtil.writeField(element, USE_DFA_IF_AVAILABLE, Boolean.TRUE.toString());
|
||||
break;
|
||||
}
|
||||
return getState(new Element(COMPONENT_NAME));
|
||||
}
|
||||
|
||||
protected Element getState(final Element element) {
|
||||
final List<String> injectorIds = new ArrayList<String>(myInjections.keySet());
|
||||
Collections.sort(injectorIds);
|
||||
for (String key : injectorIds) {
|
||||
final List<BaseInjection> injections = new ArrayList<BaseInjection>(myInjections.get(key));
|
||||
if (myDefaultInjections != null) {
|
||||
injections.removeAll(myDefaultInjections);
|
||||
}
|
||||
injections.removeAll(getDefaultInjections());
|
||||
Collections.sort(injections, new Comparator<BaseInjection>() {
|
||||
public int compare(final BaseInjection o1, final BaseInjection o2) {
|
||||
return Comparing.compare(o1.getDisplayName(), o2.getDisplayName());
|
||||
@@ -315,59 +322,15 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
}
|
||||
|
||||
public static Configuration getInstance() {
|
||||
return ApplicationManager.getApplication().getComponent(Configuration.class);
|
||||
return ServiceManager.getService(Configuration.class);
|
||||
}
|
||||
|
||||
public String getLanguageAnnotationClass() {
|
||||
return myLanguageAnnotation;
|
||||
public static Configuration getProjectInstance(Project project) {
|
||||
return ServiceManager.getService(project, Configuration.class);
|
||||
}
|
||||
|
||||
public String getPatternAnnotationClass() {
|
||||
return myPatternAnnotation;
|
||||
}
|
||||
|
||||
public String getSubstAnnotationClass() {
|
||||
return mySubstAnnotation;
|
||||
}
|
||||
|
||||
public void setInstrumentationType(@Nullable String type) {
|
||||
if (type != null) {
|
||||
setInstrumentationType(InstrumentationType.valueOf(type));
|
||||
}
|
||||
}
|
||||
|
||||
public void setInstrumentationType(@NotNull InstrumentationType type) {
|
||||
myInstrumentationType = type;
|
||||
}
|
||||
|
||||
public void setLanguageAnnotation(@Nullable String languageAnnotation) {
|
||||
if (languageAnnotation == null) return;
|
||||
myLanguageAnnotation = languageAnnotation;
|
||||
myLanguageAnnotationPair = Pair.create(languageAnnotation, Collections.singleton(languageAnnotation));
|
||||
}
|
||||
|
||||
public Pair<String, ? extends Set<String>> getLanguageAnnotationPair() {
|
||||
return myLanguageAnnotationPair;
|
||||
}
|
||||
|
||||
public void setPatternAnnotation(@Nullable String patternAnnotation) {
|
||||
if (patternAnnotation == null) return;
|
||||
myPatternAnnotation = patternAnnotation;
|
||||
myPatternAnnotationPair = Pair.create(patternAnnotation, Collections.singleton(patternAnnotation));
|
||||
}
|
||||
|
||||
public Pair<String, ? extends Set<String>> getPatternAnnotationPair() {
|
||||
return myPatternAnnotationPair;
|
||||
}
|
||||
|
||||
public void setSubstAnnotation(@Nullable String substAnnotation) {
|
||||
if (substAnnotation == null) return;
|
||||
mySubstAnnotation = substAnnotation;
|
||||
mySubstAnnotationPair = Pair.create(substAnnotation, Collections.singleton(substAnnotation));
|
||||
}
|
||||
|
||||
public Pair<String, ? extends Set<String>> getSubstAnnotationPair() {
|
||||
return mySubstAnnotationPair;
|
||||
public List<BaseInjection> getDefaultInjections() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -375,16 +338,23 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
try {
|
||||
final Document document = JDOMUtil.loadDocument(is);
|
||||
final ArrayList<Element> elements = new ArrayList<Element>();
|
||||
elements.add(document.getRootElement());
|
||||
elements.addAll(document.getRootElement().getChildren("component"));
|
||||
final Element element = ContainerUtil.find(elements, new Condition<Element>() {
|
||||
public boolean value(final Element element) {
|
||||
return "component".equals(element.getName()) && COMPONENT_NAME.equals(element.getAttributeValue("name"));
|
||||
}
|
||||
});
|
||||
if (element != null) {
|
||||
final Element rootElement = document.getRootElement();
|
||||
final Element state;
|
||||
if (rootElement.getName().equals(COMPONENT_NAME)) {
|
||||
state = rootElement;
|
||||
}
|
||||
else {
|
||||
elements.add(rootElement);
|
||||
elements.addAll(rootElement.getChildren("component"));
|
||||
state = ContainerUtil.find(elements, new Condition<Element>() {
|
||||
public boolean value(final Element element) {
|
||||
return "component".equals(element.getName()) && COMPONENT_NAME.equals(element.getAttributeValue("name"));
|
||||
}
|
||||
});
|
||||
}
|
||||
if (state != null) {
|
||||
final Configuration cfg = new Configuration();
|
||||
cfg.loadState(element, false);
|
||||
cfg.loadState(state);
|
||||
return cfg;
|
||||
}
|
||||
return null;
|
||||
@@ -394,16 +364,19 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Import from another configuration (e.g. imported file). Returns the number of imported items.
|
||||
* @param cfg configuration to import from
|
||||
* @return added injections count
|
||||
*/
|
||||
public int importFrom(final Configuration cfg) {
|
||||
private int importPlaces(final List<BaseInjection> injections) {
|
||||
final Map<String, Set<BaseInjection>> map = ContainerUtil.classify(injections.iterator(), new Convertor<BaseInjection, String>() {
|
||||
@Override
|
||||
public String convert(final BaseInjection o) {
|
||||
return o.getSupportId();
|
||||
}
|
||||
});
|
||||
final ArrayList<BaseInjection> originalInjections = new ArrayList<BaseInjection>();
|
||||
final ArrayList<BaseInjection> newInjections = new ArrayList<BaseInjection>();
|
||||
for (String supportId : InjectorUtils.getActiveInjectionSupportIds()) {
|
||||
importInjections(getInjections(supportId), cfg.getInjections(supportId), originalInjections, newInjections);
|
||||
final Set<BaseInjection> importingInjections = map.get(supportId);
|
||||
if (importingInjections == null) continue;
|
||||
importInjections(getInjections(supportId), importingInjections, originalInjections, newInjections);
|
||||
}
|
||||
if (!newInjections.isEmpty()) configurationModified();
|
||||
replaceInjections(newInjections, originalInjections);
|
||||
@@ -412,11 +385,16 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
|
||||
static void importInjections(final Collection<BaseInjection> existingInjections, final Collection<BaseInjection> importingInjections,
|
||||
final Collection<BaseInjection> originalInjections, final Collection<BaseInjection> newInjections) {
|
||||
final MultiValuesMap<String, BaseInjection> existingMap = createInjectionMap(existingInjections);
|
||||
final MultiValuesMap<InjectionPlace, BaseInjection> placeMap = new MultiValuesMap<InjectionPlace, BaseInjection>();
|
||||
for (BaseInjection exising : existingInjections) {
|
||||
for (InjectionPlace place : exising.getInjectionPlaces()) {
|
||||
placeMap.put(place, exising);
|
||||
}
|
||||
}
|
||||
main: for (BaseInjection other : importingInjections) {
|
||||
final List<BaseInjection> matchingInjections = ContainerUtil.concat(other.getInjectionPlaces(), new Function<InjectionPlace, Collection<? extends BaseInjection>>() {
|
||||
public Collection<? extends BaseInjection> fun(final InjectionPlace o) {
|
||||
final Collection<BaseInjection> collection = existingMap.get(o.getText());
|
||||
final Collection<BaseInjection> collection = placeMap.get(o);
|
||||
return collection == null? Collections.<BaseInjection>emptyList() : collection;
|
||||
}
|
||||
});
|
||||
@@ -442,16 +420,6 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
}
|
||||
}
|
||||
|
||||
private static MultiValuesMap<String, BaseInjection> createInjectionMap(final Collection<BaseInjection> injections) {
|
||||
final MultiValuesMap<String, BaseInjection> existingMap = new MultiValuesMap<String, BaseInjection>();
|
||||
for (BaseInjection injection : injections) {
|
||||
for (InjectionPlace place : injection.getInjectionPlaces()) {
|
||||
existingMap.put(place.getText(), injection);
|
||||
}
|
||||
}
|
||||
return existingMap;
|
||||
}
|
||||
|
||||
public void configurationModified() {
|
||||
myModificationCount ++;
|
||||
}
|
||||
@@ -460,23 +428,6 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
return myModificationCount;
|
||||
}
|
||||
|
||||
public boolean isIncludeUncomputablesAsLiterals() {
|
||||
return myIncludeUncomputablesAsLiterals;
|
||||
}
|
||||
|
||||
public void setIncludeUncomputablesAsLiterals(boolean flag) {
|
||||
myIncludeUncomputablesAsLiterals = flag;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DfaOption getDfaOption() {
|
||||
return myDfaOption;
|
||||
}
|
||||
|
||||
public void setDfaOption(@NotNull final DfaOption dfaOption) {
|
||||
myDfaOption = dfaOption;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BaseInjection findExistingInjection(@NotNull final BaseInjection injection) {
|
||||
final List<BaseInjection> list = getInjections(injection.getSupportId());
|
||||
@@ -489,15 +440,15 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
public boolean setHostInjectionEnabled(final PsiLanguageInjectionHost host, final Collection<String> languages, final boolean enabled) {
|
||||
final ArrayList<BaseInjection> originalInjections = new ArrayList<BaseInjection>();
|
||||
final ArrayList<BaseInjection> newInjections = new ArrayList<BaseInjection>();
|
||||
for (String supportId : getAllInjectorIds()) {
|
||||
for (BaseInjection injection : getInjections(supportId)) {
|
||||
for (LanguageInjectionSupport support : InjectorUtils.getActiveInjectionSupports()) {
|
||||
for (BaseInjection injection : getInjections(support.getId())) {
|
||||
if (!languages.contains(injection.getInjectedLanguageId())) continue;
|
||||
boolean replace = false;
|
||||
final ArrayList<InjectionPlace> newPlaces = new ArrayList<InjectionPlace>();
|
||||
for (InjectionPlace place : injection.getInjectionPlaces()) {
|
||||
if (place.isEnabled() != enabled && place.getElementPattern() != null &&
|
||||
(place.getElementPattern().accepts(host) || place.getElementPattern().accepts(host.getParent()))) {
|
||||
newPlaces.add(new InjectionPlace(place.getText(), place.getElementPattern(), enabled));
|
||||
newPlaces.add(place.enabled(enabled));
|
||||
replace = true;
|
||||
}
|
||||
else newPlaces.add(place);
|
||||
@@ -518,8 +469,10 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
return false;
|
||||
}
|
||||
|
||||
public InstrumentationType getInstrumentation() {
|
||||
return myInstrumentationType;
|
||||
protected void setInjections(Collection<BaseInjection> injections) {
|
||||
for (BaseInjection injection : injections) {
|
||||
myInjections.get(injection.getSupportId()).add(injection);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -527,21 +480,23 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
return Collections.unmodifiableList(myInjections.get(injectorId));
|
||||
}
|
||||
|
||||
public Set<String> getAllInjectorIds() {
|
||||
return Collections.unmodifiableSet(myInjections.keySet());
|
||||
}
|
||||
|
||||
public void replaceInjectionsWithUndo(final Project project,
|
||||
final List<? extends BaseInjection> newInjections,
|
||||
final List<? extends BaseInjection> originalInjections,
|
||||
final List<? extends PsiElement> psiElementsToRemove) {
|
||||
replaceInjectionsWithUndo(project, newInjections, originalInjections, psiElementsToRemove,
|
||||
new PairProcessor<List<? extends BaseInjection>, List<? extends BaseInjection>>() {
|
||||
public boolean process(final List<? extends BaseInjection> add, final List<? extends BaseInjection> remove) {
|
||||
replaceInjections(add, remove);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
new PairProcessor<List<? extends BaseInjection>, List<? extends BaseInjection>>() {
|
||||
public boolean process(final List<? extends BaseInjection> add,
|
||||
final List<? extends BaseInjection> remove) {
|
||||
replaceInjectionsWithUndoInner(add, remove);
|
||||
FileContentUtil.reparseOpenedFiles();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void replaceInjectionsWithUndoInner(final List<? extends BaseInjection> add, final List<? extends BaseInjection> remove) {
|
||||
replaceInjections(add, remove);
|
||||
}
|
||||
|
||||
public static <T> void replaceInjectionsWithUndo(final Project project, final T add, final T remove,
|
||||
@@ -582,14 +537,144 @@ public final class Configuration implements PersistentStateComponent<Element>, M
|
||||
myInjections.get(injection.getSupportId()).remove(injection);
|
||||
}
|
||||
for (BaseInjection injection : newInjections) {
|
||||
injection.initializePlaces(true);
|
||||
myInjections.get(injection.getSupportId()).add(injection);
|
||||
}
|
||||
configurationModified();
|
||||
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
|
||||
FileContentUtil.reparseFiles(project, Collections.<VirtualFile>emptyList(), true);
|
||||
}
|
||||
}
|
||||
|
||||
public static class AdvancedConfiguration {
|
||||
// runtime pattern validation instrumentation
|
||||
@NotNull private InstrumentationType myInstrumentationType = InstrumentationType.ASSERT;
|
||||
|
||||
// annotation class names
|
||||
@NotNull private String myLanguageAnnotation;
|
||||
@NotNull private String myPatternAnnotation;
|
||||
@NotNull private String mySubstAnnotation;
|
||||
|
||||
private boolean myIncludeUncomputablesAsLiterals;
|
||||
private DfaOption myDfaOption = DfaOption.RESOLVE;
|
||||
|
||||
// cached annotation name pairs
|
||||
private Pair<String, ? extends Set<String>> myLanguageAnnotationPair;
|
||||
private Pair<String, ? extends Set<String>> myPatternAnnotationPair;
|
||||
|
||||
private Pair<String, ? extends Set<String>> mySubstAnnotationPair;
|
||||
|
||||
public AdvancedConfiguration() {
|
||||
setLanguageAnnotation("org.intellij.lang.annotations.Language");
|
||||
setPatternAnnotation("org.intellij.lang.annotations.Pattern");
|
||||
setSubstAnnotation("org.intellij.lang.annotations.Subst");
|
||||
}
|
||||
|
||||
public String getLanguageAnnotationClass() {
|
||||
return myLanguageAnnotation;
|
||||
}
|
||||
|
||||
public String getPatternAnnotationClass() {
|
||||
return myPatternAnnotation;
|
||||
}
|
||||
|
||||
public String getSubstAnnotationClass() {
|
||||
return mySubstAnnotation;
|
||||
}
|
||||
|
||||
public void setInstrumentationType(@Nullable String type) {
|
||||
if (type != null) {
|
||||
setInstrumentationType(InstrumentationType.valueOf(type));
|
||||
}
|
||||
}
|
||||
|
||||
public void setInstrumentationType(@NotNull InstrumentationType type) {
|
||||
myInstrumentationType = type;
|
||||
}
|
||||
|
||||
public void setLanguageAnnotation(@Nullable String languageAnnotation) {
|
||||
if (languageAnnotation == null) return;
|
||||
myLanguageAnnotation = languageAnnotation;
|
||||
myLanguageAnnotationPair = Pair.create(languageAnnotation, Collections.singleton(languageAnnotation));
|
||||
}
|
||||
|
||||
public Pair<String, ? extends Set<String>> getLanguageAnnotationPair() {
|
||||
return myLanguageAnnotationPair;
|
||||
}
|
||||
|
||||
public void setPatternAnnotation(@Nullable String patternAnnotation) {
|
||||
if (patternAnnotation == null) return;
|
||||
myPatternAnnotation = patternAnnotation;
|
||||
myPatternAnnotationPair = Pair.create(patternAnnotation, Collections.singleton(patternAnnotation));
|
||||
}
|
||||
|
||||
public Pair<String, ? extends Set<String>> getPatternAnnotationPair() {
|
||||
return myPatternAnnotationPair;
|
||||
}
|
||||
|
||||
public void setSubstAnnotation(@Nullable String substAnnotation) {
|
||||
if (substAnnotation == null) return;
|
||||
mySubstAnnotation = substAnnotation;
|
||||
mySubstAnnotationPair = Pair.create(substAnnotation, Collections.singleton(substAnnotation));
|
||||
}
|
||||
|
||||
public Pair<String, ? extends Set<String>> getSubstAnnotationPair() {
|
||||
return mySubstAnnotationPair;
|
||||
}
|
||||
|
||||
public boolean isIncludeUncomputablesAsLiterals() {
|
||||
return myIncludeUncomputablesAsLiterals;
|
||||
}
|
||||
|
||||
public void setIncludeUncomputablesAsLiterals(boolean flag) {
|
||||
myIncludeUncomputablesAsLiterals = flag;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DfaOption getDfaOption() {
|
||||
return myDfaOption;
|
||||
}
|
||||
|
||||
public void setDfaOption(@NotNull final DfaOption dfaOption) {
|
||||
myDfaOption = dfaOption;
|
||||
}
|
||||
|
||||
|
||||
public InstrumentationType getInstrumentation() {
|
||||
return myInstrumentationType;
|
||||
}
|
||||
|
||||
private void writeState(final Element element) {
|
||||
JDOMExternalizerUtil.writeField(element, INSTRUMENTATION_TYPE_NAME, myInstrumentationType.toString());
|
||||
JDOMExternalizerUtil.writeField(element, LANGUAGE_ANNOTATION_NAME, myLanguageAnnotation);
|
||||
JDOMExternalizerUtil.writeField(element, PATTERN_ANNOTATION_NAME, myPatternAnnotation);
|
||||
JDOMExternalizerUtil.writeField(element, SUBST_ANNOTATION_NAME, mySubstAnnotation);
|
||||
switch (myDfaOption) {
|
||||
case OFF:
|
||||
break;
|
||||
case RESOLVE:
|
||||
JDOMExternalizerUtil.writeField(element, RESOLVE_REFERENCES, Boolean.TRUE.toString());
|
||||
break;
|
||||
case ASSIGNMENTS:
|
||||
JDOMExternalizerUtil.writeField(element, LOOK_FOR_VAR_ASSIGNMENTS, Boolean.TRUE.toString());
|
||||
break;
|
||||
case DFA:
|
||||
JDOMExternalizerUtil.writeField(element, USE_DFA_IF_AVAILABLE, Boolean.TRUE.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void loadState(final Element element) {
|
||||
setInstrumentationType(JDOMExternalizerUtil.readField(element, INSTRUMENTATION_TYPE_NAME));
|
||||
setLanguageAnnotation(JDOMExternalizerUtil.readField(element, LANGUAGE_ANNOTATION_NAME));
|
||||
setPatternAnnotation(JDOMExternalizerUtil.readField(element, PATTERN_ANNOTATION_NAME));
|
||||
setSubstAnnotation(JDOMExternalizerUtil.readField(element, SUBST_ANNOTATION_NAME));
|
||||
if (readBoolean(element, RESOLVE_REFERENCES, true)) {
|
||||
setDfaOption(DfaOption.RESOLVE);
|
||||
}
|
||||
if (readBoolean(element, LOOK_FOR_VAR_ASSIGNMENTS, false)) {
|
||||
setDfaOption(DfaOption.ASSIGNMENTS);
|
||||
}
|
||||
if (readBoolean(element, USE_DFA_IF_AVAILABLE, false)) {
|
||||
setDfaOption(DfaOption.DFA);
|
||||
}
|
||||
setIncludeUncomputablesAsLiterals(readBoolean(element, INCLUDE_UNCOMPUTABLES_AS_LITERALS, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+368
-134
@@ -23,6 +23,7 @@ import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDialog;
|
||||
import com.intellij.openapi.fileChooser.FileChooserFactory;
|
||||
import com.intellij.openapi.fileChooser.FileSaverDescriptor;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
@@ -33,32 +34,35 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileWrapper;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.table.TableView;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.Icons;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.ui.ColumnInfo;
|
||||
import com.intellij.util.ui.ListTableModel;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TObjectHashingStrategy;
|
||||
import org.intellij.plugins.intelliLang.inject.AbstractLanguageInjectionSupport;
|
||||
import org.intellij.plugins.intelliLang.inject.InjectedLanguage;
|
||||
import org.intellij.plugins.intelliLang.inject.InjectorUtils;
|
||||
import org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport;
|
||||
import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
|
||||
import org.intellij.plugins.intelliLang.inject.config.InjectionPlace;
|
||||
import org.jdom.Document;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import java.awt.*;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
@@ -68,10 +72,7 @@ import java.util.List;
|
||||
public class InjectionsSettingsUI implements Configurable {
|
||||
|
||||
private final Project myProject;
|
||||
private final Configuration myConfiguration;
|
||||
private final List<BaseInjection> myInjections;
|
||||
private final List<BaseInjection> myOriginalInjections;
|
||||
|
||||
private final CfgInfo[] myInfos;
|
||||
|
||||
private final JPanel myRoot;
|
||||
private final InjectionsTable myInjectionsTable;
|
||||
@@ -83,27 +84,15 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
|
||||
public InjectionsSettingsUI(final Project project, final Configuration configuration) {
|
||||
myProject = project;
|
||||
myConfiguration = configuration;
|
||||
|
||||
myOriginalInjections = ContainerUtil
|
||||
.concat(InjectorUtils.getActiveInjectionSupportIds(), new Function<String, Collection<? extends BaseInjection>>() {
|
||||
public Collection<? extends BaseInjection> fun(final String s) {
|
||||
return ContainerUtil.findAll(myConfiguration.getInjections(s), new Condition<BaseInjection>() {
|
||||
public boolean value(final BaseInjection injection) {
|
||||
return InjectedLanguage.findLanguageById(injection.getInjectedLanguageId()) != null;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
sortInjections(myOriginalInjections);
|
||||
myInjections = new ArrayList<BaseInjection>();
|
||||
for (BaseInjection injection : myOriginalInjections) {
|
||||
myInjections.add(injection.copy());
|
||||
}
|
||||
final CfgInfo currentInfo = new CfgInfo(configuration, "project");
|
||||
myInfos = configuration instanceof Configuration.Prj ?
|
||||
new CfgInfo[]{new CfgInfo(((Configuration.Prj)configuration).getParentConfiguration(), "global"), currentInfo}
|
||||
: new CfgInfo[]{currentInfo};
|
||||
|
||||
myRoot = new JPanel(new BorderLayout());
|
||||
|
||||
myInjectionsTable = new InjectionsTable(myInjections);
|
||||
myInjectionsTable = new InjectionsTable(getInjInfoList(myInfos));
|
||||
myInjectionsTable.getEmptyText().setText("No injections configured");
|
||||
final JPanel tablePanel = new JPanel(new BorderLayout());
|
||||
|
||||
@@ -130,7 +119,8 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
};
|
||||
final Factory<BaseInjection> producer = new NullableFactory<BaseInjection>() {
|
||||
public BaseInjection create() {
|
||||
return getSelectedInjection();
|
||||
final InjInfo info = getSelectedInjection();
|
||||
return info == null? null : info.injection;
|
||||
}
|
||||
};
|
||||
for (LanguageInjectionSupport support : InjectorUtils.getActiveInjectionSupports()) {
|
||||
@@ -161,7 +151,14 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
final AnAction removeAction = new AnAction("Remove", "Remove", Icons.DELETE_ICON) {
|
||||
@Override
|
||||
public void update(final AnActionEvent e) {
|
||||
e.getPresentation().setEnabled(!getSelectedInjections().isEmpty());
|
||||
boolean enabled = false;
|
||||
for (InjInfo info : getSelectedInjections()) {
|
||||
if (!info.bundled) {
|
||||
enabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
e.getPresentation().setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -193,9 +190,9 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
final BaseInjection injection = getSelectedInjection();
|
||||
final InjInfo injection = getSelectedInjection();
|
||||
if (injection != null) {
|
||||
addInjection(injection.copy());
|
||||
addInjection(injection.injection.copy());
|
||||
//performEditAction(e);
|
||||
}
|
||||
}
|
||||
@@ -209,13 +206,6 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
removeAction.registerCustomShortcutSet(CommonShortcuts.DELETE, myInjectionsTable);
|
||||
editAction.registerCustomShortcutSet(CommonShortcuts.ENTER, myInjectionsTable);
|
||||
|
||||
group.add(new AnAction("Import", "Import", IconLoader.getIcon("/actions/install.png")) {
|
||||
@Override
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
doImportAction(e.getDataContext());
|
||||
updateCountLabel();
|
||||
}
|
||||
});
|
||||
group.addSeparator();
|
||||
group.add(new AnAction("Enable Selected Injections", "Enable Selected Injections", Icons.SELECT_ALL_ICON) {
|
||||
@Override
|
||||
@@ -236,15 +226,97 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
performToggleAction();
|
||||
}
|
||||
}.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0)), myInjectionsTable);
|
||||
|
||||
if (myInfos.length > 1) {
|
||||
group.addSeparator();
|
||||
final AnAction shareAction = new AnAction("Make Global", null, IconLoader.getIcon("/actions/import.png")) {
|
||||
@Override
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
final List<InjInfo> injections = getSelectedInjections();
|
||||
final CfgInfo cfg = getTargetCfgInfo(injections);
|
||||
if (cfg == null) return;
|
||||
for (InjInfo info : injections) {
|
||||
if (info.cfgInfo == cfg) continue;
|
||||
if (info.bundled) continue;
|
||||
info.cfgInfo.injectionInfos.remove(info);
|
||||
cfg.addInjection(info.injection);
|
||||
}
|
||||
final int[] selectedRows = myInjectionsTable.getSelectedRows();
|
||||
myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos));
|
||||
TableUtil.selectRows(myInjectionsTable, selectedRows);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(final AnActionEvent e) {
|
||||
final CfgInfo cfg = getTargetCfgInfo(getSelectedInjections());
|
||||
e.getPresentation().setEnabled(cfg != null);
|
||||
e.getPresentation().setText(cfg == getDefaultCfgInfo() ? "Make Global" : "Move to Project");
|
||||
super.update(e);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private CfgInfo getTargetCfgInfo(final List<InjInfo> injections) {
|
||||
CfgInfo cfg = null;
|
||||
for (InjInfo info : injections) {
|
||||
if (info.bundled) {
|
||||
continue;
|
||||
}
|
||||
if (cfg == null) cfg = info.cfgInfo;
|
||||
else if (cfg != info.cfgInfo) return info.cfgInfo;
|
||||
}
|
||||
if (cfg == null) return cfg;
|
||||
for (CfgInfo info : myInfos) {
|
||||
if (info != cfg) return info;
|
||||
}
|
||||
throw new AssertionError();
|
||||
}
|
||||
};
|
||||
shareAction.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.SHIFT_DOWN_MASK)), myInjectionsTable);
|
||||
group.add(shareAction);
|
||||
}
|
||||
group.addSeparator();
|
||||
group.add(new AnAction("Import", "Import", IconLoader.getIcon("/actions/install.png")) {
|
||||
@Override
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
doImportAction(e.getDataContext());
|
||||
updateCountLabel();
|
||||
}
|
||||
});
|
||||
group.add(new AnAction("Export", "Export", IconLoader.getIcon("/actions/export.png")) {
|
||||
@Override
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
final List<BaseInjection> injections = getInjectionList(getSelectedInjections());
|
||||
final VirtualFileWrapper wrapper = FileChooserFactory.getInstance().createSaveFileDialog(
|
||||
new FileSaverDescriptor("Export Selected Injections to File...", "", "xml"), myProject).save(null, null);
|
||||
if (wrapper == null) return;
|
||||
final Configuration configuration = new Configuration();
|
||||
configuration.setInjections(injections);
|
||||
final Document document = new Document(configuration.getState());
|
||||
try {
|
||||
JDOMUtil.writeDocument(document, wrapper.getFile(), "\n");
|
||||
}
|
||||
catch (IOException ex) {
|
||||
final String msg = ex.getLocalizedMessage();
|
||||
Messages.showErrorDialog(myProject, msg != null && msg.length() > 0 ? msg : ex.toString(), "Export failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(final AnActionEvent e) {
|
||||
e.getPresentation().setEnabled(!getSelectedInjections().isEmpty());
|
||||
}
|
||||
});
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
|
||||
private void performEditAction(AnActionEvent e) {
|
||||
final AnAction action = getEditAction();
|
||||
if (action != null) {
|
||||
final int row = myInjectionsTable.getSelectedRow();
|
||||
action.actionPerformed(e);
|
||||
((ListTableModel)myInjectionsTable.getModel()).fireTableDataChanged();
|
||||
myInjectionsTable.getListTableModel().fireTableDataChanged();
|
||||
myInjectionsTable.getSelectionModel().setSelectionInterval(row, row);
|
||||
updateCountLabel();
|
||||
}
|
||||
@@ -253,15 +325,16 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
private void updateCountLabel() {
|
||||
int placesCount = 0;
|
||||
int enablePlacesCount = 0;
|
||||
for (BaseInjection injection : myInjections) {
|
||||
for (InjectionPlace place : injection.getInjectionPlaces()) {
|
||||
placesCount++;
|
||||
if (place.isEnabled()) enablePlacesCount++;
|
||||
final List<InjInfo> items = myInjectionsTable.getListTableModel().getItems();
|
||||
if (!items.isEmpty()) {
|
||||
for (InjInfo injection : items) {
|
||||
for (InjectionPlace place : injection.injection.getInjectionPlaces()) {
|
||||
placesCount++;
|
||||
if (place.isEnabled()) enablePlacesCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!myInjections.isEmpty()) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(myInjections.size()).append(" injection").append(myInjections.size() > 1 ? "s" : "").append(" (").append(enablePlacesCount)
|
||||
sb.append(items.size()).append(" injection").append(items.size() > 1 ? "s" : "").append(" (").append(enablePlacesCount)
|
||||
.append(" of ").append(placesCount).append(" place").append(placesCount > 1 ? "s" : "").append(" enabled) ");
|
||||
myCountLabel.setText(sb.toString());
|
||||
}
|
||||
@@ -272,20 +345,23 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
|
||||
@Nullable
|
||||
private AnAction getEditAction() {
|
||||
final BaseInjection injection = getSelectedInjection();
|
||||
final String supportId = injection == null? null : injection.getSupportId();
|
||||
final InjInfo info = getSelectedInjection();
|
||||
final String supportId = info == null? null : info.injection.getSupportId();
|
||||
return supportId == null? null : myEditActions.get(supportId);
|
||||
}
|
||||
|
||||
private void addInjection(final BaseInjection injection) {
|
||||
injection.initializePlaces(true);
|
||||
myInjections.add(injection);
|
||||
myInjectionsTable.getListTableModel().setItems(myInjections);
|
||||
final int index = myInjections.indexOf(injection);
|
||||
final InjInfo info = getDefaultCfgInfo().addInjection(injection);
|
||||
myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos));
|
||||
final int index = myInjectionsTable.convertRowIndexToView(myInjectionsTable.getListTableModel().getItems().indexOf(info));
|
||||
myInjectionsTable.getSelectionModel().setSelectionInterval(index, index);
|
||||
TableUtil.scrollSelectionToVisible(myInjectionsTable);
|
||||
}
|
||||
|
||||
private CfgInfo getDefaultCfgInfo() {
|
||||
return myInfos[0];
|
||||
}
|
||||
|
||||
private static void sortInjections(final List<BaseInjection> injections) {
|
||||
Collections.sort(injections, new Comparator<BaseInjection>() {
|
||||
public int compare(final BaseInjection o1, final BaseInjection o2) {
|
||||
@@ -302,12 +378,11 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
return myRoot;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
myInjections.clear();
|
||||
for (BaseInjection injection : myOriginalInjections) {
|
||||
myInjections.add(injection.copy());
|
||||
public void reset() {
|
||||
for (CfgInfo info : myInfos) {
|
||||
info.reset();
|
||||
}
|
||||
myInjectionsTable.getListTableModel().setItems(myInjections);
|
||||
myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos));
|
||||
updateCountLabel();
|
||||
}
|
||||
|
||||
@@ -315,33 +390,33 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
}
|
||||
|
||||
public void apply() {
|
||||
myConfiguration.replaceInjections(myInjections, myOriginalInjections);
|
||||
myOriginalInjections.clear();
|
||||
myOriginalInjections.addAll(myInjections);
|
||||
sortInjections(myOriginalInjections);
|
||||
for (CfgInfo info : myInfos) {
|
||||
info.apply();
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
final List<BaseInjection> copy = new ArrayList<BaseInjection>(myInjections);
|
||||
sortInjections(copy);
|
||||
return !myOriginalInjections.equals(copy);
|
||||
for (CfgInfo info : myInfos) {
|
||||
if (info.isModified()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void performSelectedInjectionsEnabled(final boolean enabled) {
|
||||
for (BaseInjection injection : getSelectedInjections()) {
|
||||
injection.setPlaceEnabled(null, enabled);
|
||||
for (InjInfo info : getSelectedInjections()) {
|
||||
info.injection.setPlaceEnabled(null, enabled);
|
||||
}
|
||||
myInjectionsTable.updateUI();
|
||||
updateCountLabel();
|
||||
}
|
||||
|
||||
private void performToggleAction() {
|
||||
final List<BaseInjection> selectedInjections = getSelectedInjections();
|
||||
final List<InjInfo> selectedInjections = getSelectedInjections();
|
||||
boolean enabledExists = false;
|
||||
boolean disabledExists = false;
|
||||
for (BaseInjection injection : selectedInjections) {
|
||||
if (injection.isEnabled()) enabledExists = true;
|
||||
for (InjInfo info : selectedInjections) {
|
||||
if (info.injection.isEnabled()) enabledExists = true;
|
||||
else disabledExists = true;
|
||||
if (enabledExists && disabledExists) break;
|
||||
}
|
||||
@@ -352,25 +427,20 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
private void performRemove() {
|
||||
final int selectedRow = myInjectionsTable.getSelectedRow();
|
||||
if (selectedRow < 0) return;
|
||||
final List<BaseInjection> selected = getSelectedInjections();
|
||||
main: for (Iterator<BaseInjection> it = myInjections.iterator(); it.hasNext(); ) {
|
||||
final BaseInjection injection = it.next();
|
||||
for (BaseInjection selectedInjection : selected) {
|
||||
if (injection == selectedInjection) {
|
||||
it.remove();
|
||||
continue main;
|
||||
}
|
||||
}
|
||||
final List<InjInfo> selected = getSelectedInjections();
|
||||
for (InjInfo info : selected) {
|
||||
if (info.bundled) continue;
|
||||
info.cfgInfo.injectionInfos.remove(info);
|
||||
}
|
||||
((ListTableModel)myInjectionsTable.getModel()).fireTableDataChanged();
|
||||
final int index = Math.min(myInjections.size() - 1, selectedRow);
|
||||
myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos));
|
||||
final int index = Math.min(myInjectionsTable.getListTableModel().getRowCount() - 1, selectedRow);
|
||||
myInjectionsTable.getSelectionModel().setSelectionInterval(index, index);
|
||||
TableUtil.scrollSelectionToVisible(myInjectionsTable);
|
||||
updateCountLabel();
|
||||
}
|
||||
|
||||
private List<BaseInjection> getSelectedInjections() {
|
||||
final ArrayList<BaseInjection> toRemove = new ArrayList<BaseInjection>();
|
||||
private List<InjInfo> getSelectedInjections() {
|
||||
final ArrayList<InjInfo> toRemove = new ArrayList<InjInfo>();
|
||||
for (int row : myInjectionsTable.getSelectedRows()) {
|
||||
toRemove.add(myInjectionsTable.getItems().get(myInjectionsTable.convertRowIndexToModel(row)));
|
||||
}
|
||||
@@ -378,7 +448,7 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BaseInjection getSelectedInjection() {
|
||||
private InjInfo getSelectedInjection() {
|
||||
final int row = myInjectionsTable.getSelectedRow();
|
||||
return row < 0? null : myInjectionsTable.getItems().get(myInjectionsTable.convertRowIndexToModel(row));
|
||||
}
|
||||
@@ -409,9 +479,9 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
return "reference.settings.injection.language.injection.settings";
|
||||
}
|
||||
|
||||
private class InjectionsTable extends TableView<BaseInjection> {
|
||||
private InjectionsTable(final List<BaseInjection> injections) {
|
||||
super(new ListTableModel<BaseInjection>(createInjectionColumnInfos(), injections, 1));
|
||||
private class InjectionsTable extends TableView<InjInfo> {
|
||||
private InjectionsTable(final List<InjInfo> injections) {
|
||||
super(new ListTableModel<InjInfo>(createInjectionColumnInfos(), injections, 1));
|
||||
setAutoResizeMode(AUTO_RESIZE_LAST_COLUMN);
|
||||
getColumnModel().getColumn(2).setCellRenderer(createLanguageCellRenderer());
|
||||
getColumnModel().getColumn(1).setCellRenderer(createDisplayNameCellRenderer());
|
||||
@@ -421,9 +491,9 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
setGridColor(getForeground());
|
||||
getColumnModel().getColumn(0).setMaxWidth(new JCheckBox().getPreferredSize().width);
|
||||
final int[] preffered = new int[] {0} ;
|
||||
ContainerUtil.process(myInjections, new Processor<BaseInjection>() {
|
||||
public boolean process(final BaseInjection injection) {
|
||||
final String languageId = injection.getInjectedLanguageId();
|
||||
ContainerUtil.process(injections, new Processor<InjInfo>() {
|
||||
public boolean process(final InjInfo injection) {
|
||||
final String languageId = injection.injection.getInjectedLanguageId();
|
||||
if (preffered[0] < languageId.length()) preffered[0] = languageId.length();
|
||||
return true;
|
||||
}
|
||||
@@ -456,7 +526,7 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
|
||||
@Override
|
||||
protected String getElementText(final Object element) {
|
||||
final BaseInjection injection = (BaseInjection)element;
|
||||
final BaseInjection injection = ((InjInfo)element).injection;
|
||||
return injection.getSupportId() + " " + injection.getInjectedLanguageId() + " " + injection.getDisplayName();
|
||||
}
|
||||
};
|
||||
@@ -468,74 +538,104 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
final TableCellRenderer booleanCellRenderer = createBooleanCellRenderer();
|
||||
final TableCellRenderer displayNameCellRenderer = createDisplayNameCellRenderer();
|
||||
final TableCellRenderer languageCellRenderer = createLanguageCellRenderer();
|
||||
final Comparator<BaseInjection> languageComparator = new Comparator<BaseInjection>() {
|
||||
public int compare(final BaseInjection o1, final BaseInjection o2) {
|
||||
return Comparing.compare(o1.getInjectedLanguageId(), o2.getInjectedLanguageId());
|
||||
final Comparator<InjInfo> languageComparator = new Comparator<InjInfo>() {
|
||||
public int compare(final InjInfo o1, final InjInfo o2) {
|
||||
return Comparing.compare(o1.injection.getInjectedLanguageId(), o2.injection.getInjectedLanguageId());
|
||||
}
|
||||
};
|
||||
final Comparator<BaseInjection> displayNameComparator = new Comparator<BaseInjection>() {
|
||||
public int compare(final BaseInjection o1, final BaseInjection o2) {
|
||||
final int support = Comparing.compare(o1.getSupportId(), o2.getSupportId());
|
||||
final Comparator<InjInfo> displayNameComparator = new Comparator<InjInfo>() {
|
||||
public int compare(final InjInfo o1, final InjInfo o2) {
|
||||
final int support = Comparing.compare(o1.injection.getSupportId(), o2.injection.getSupportId());
|
||||
if (support != 0) return support;
|
||||
return Comparing.compare(o1.getDisplayName(), o2.getDisplayName());
|
||||
return Comparing.compare(o1.injection.getDisplayName(), o2.injection.getDisplayName());
|
||||
}
|
||||
};
|
||||
return new ColumnInfo[]{new ColumnInfo<BaseInjection, Boolean>(" ") {
|
||||
final ColumnInfo[] columnInfos = {new ColumnInfo<InjInfo, Boolean>(" ") {
|
||||
@Override
|
||||
public Class getColumnClass() {
|
||||
return Boolean.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean valueOf(final BaseInjection o) {
|
||||
return o.isEnabled();
|
||||
public Boolean valueOf(final InjInfo o) {
|
||||
return o.injection.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(final BaseInjection injection) {
|
||||
public boolean isCellEditable(final InjInfo injection) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(final BaseInjection injection, final Boolean value) {
|
||||
injection.setPlaceEnabled(null, value.booleanValue());
|
||||
public void setValue(final InjInfo injection, final Boolean value) {
|
||||
injection.injection.setPlaceEnabled(null, value.booleanValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableCellRenderer getRenderer(final BaseInjection injection) {
|
||||
public TableCellRenderer getRenderer(final InjInfo injection) {
|
||||
return booleanCellRenderer;
|
||||
}
|
||||
}, new ColumnInfo<BaseInjection, BaseInjection>("Display Name") {
|
||||
}, new ColumnInfo<InjInfo, InjInfo>("Display Name") {
|
||||
@Override
|
||||
public BaseInjection valueOf(final BaseInjection injection) {
|
||||
return injection;
|
||||
public InjInfo valueOf(final InjInfo info) {
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<BaseInjection> getComparator() {
|
||||
public Comparator<InjInfo> getComparator() {
|
||||
return displayNameComparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableCellRenderer getRenderer(final BaseInjection injection) {
|
||||
public TableCellRenderer getRenderer(final InjInfo injection) {
|
||||
return displayNameCellRenderer;
|
||||
}
|
||||
}, new ColumnInfo<BaseInjection, BaseInjection>("Language") {
|
||||
}, new ColumnInfo<InjInfo, InjInfo>("Language") {
|
||||
@Override
|
||||
public BaseInjection valueOf(final BaseInjection injection) {
|
||||
return injection;
|
||||
public InjInfo valueOf(final InjInfo info) {
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<BaseInjection> getComparator() {
|
||||
public Comparator<InjInfo> getComparator() {
|
||||
return languageComparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableCellRenderer getRenderer(final BaseInjection injection) {
|
||||
public TableCellRenderer getRenderer(final InjInfo info) {
|
||||
return languageCellRenderer;
|
||||
}
|
||||
}};
|
||||
if (myInfos.length > 1) {
|
||||
final TableCellRenderer typeRenderer = createTypeRenderer();
|
||||
return ArrayUtil.append(columnInfos, new ColumnInfo<InjInfo, String>("Type") {
|
||||
@Override
|
||||
public String valueOf(final InjInfo info) {
|
||||
return info.bundled ? "bundled" : info.cfgInfo.title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableCellRenderer getRenderer(final InjInfo injInfo) {
|
||||
return typeRenderer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth(final JTable table) {
|
||||
return table.getFontMetrics(table.getFont()).stringWidth(StringUtil.repeatSymbol('m', 6));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<InjInfo> getComparator() {
|
||||
return new Comparator<InjInfo>() {
|
||||
@Override
|
||||
public int compare(final InjInfo o1, final InjInfo o2) {
|
||||
return Comparing.compare(valueOf(o1), valueOf(o2));
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
return columnInfos;
|
||||
}
|
||||
|
||||
private static BooleanTableCellRenderer createBooleanCellRenderer() {
|
||||
@@ -559,13 +659,14 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus,
|
||||
final int row,
|
||||
final int column) {
|
||||
final BaseInjection injection = (BaseInjection)value;
|
||||
final InjInfo injection = (InjInfo)value;
|
||||
// fix for a marvellous Swing peculiarity: AccessibleJTable likes to pass null here
|
||||
if (injection == null) return myLabel;
|
||||
final Language language = InjectedLanguage.findLanguageById(injection.getInjectedLanguageId());
|
||||
final String languageId = injection.injection.getInjectedLanguageId();
|
||||
final Language language = InjectedLanguage.findLanguageById(languageId);
|
||||
final FileType fileType = language == null ? null : language.getAssociatedFileType();
|
||||
myLabel.setIcon(fileType == null ? null : fileType.getIcon());
|
||||
myLabel.setText(language == null ? injection.getInjectedLanguageId() : language.getDisplayName());
|
||||
myLabel.setText(language == null ? languageId : language.getDisplayName());
|
||||
setLabelColors(myLabel, table, isSelected, row);
|
||||
return myLabel;
|
||||
}
|
||||
@@ -581,12 +682,13 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
final int row,
|
||||
final int column) {
|
||||
myLabel.clear();
|
||||
final BaseInjection injection = (BaseInjection)value;
|
||||
final InjInfo info = (InjInfo)value;
|
||||
// fix for a marvellous Swing peculiarity: AccessibleJTable likes to pass null here
|
||||
if (injection == null) return myLabel;
|
||||
if (info == null) return myLabel;
|
||||
final SimpleTextAttributes grayAttrs = isSelected ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES;
|
||||
myText.append(injection.getSupportId() + ": ", grayAttrs);
|
||||
mySupports.get(injection.getSupportId()).setupPresentation(injection, myText, isSelected);
|
||||
final String supportId = info.injection.getSupportId();
|
||||
myText.append(supportId + ": ", grayAttrs);
|
||||
mySupports.get(supportId).setupPresentation(info.injection, myText, isSelected);
|
||||
myText.appendToComponent(myLabel);
|
||||
myText.clear();
|
||||
setLabelColors(myLabel, table, isSelected, row);
|
||||
@@ -595,6 +697,24 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
};
|
||||
}
|
||||
|
||||
private static TableCellRenderer createTypeRenderer() {
|
||||
return new TableCellRenderer() {
|
||||
final SimpleColoredComponent myLabel = new SimpleColoredComponent();
|
||||
|
||||
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus,
|
||||
final int row,
|
||||
final int column) {
|
||||
myLabel.clear();
|
||||
final String info = (String)value;
|
||||
if (info == null) return myLabel;
|
||||
final SimpleTextAttributes grayAttrs = isSelected ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES;
|
||||
myLabel.append(info, grayAttrs);
|
||||
setLabelColors(myLabel, table, isSelected, row);
|
||||
return myLabel;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Component setLabelColors(final Component label, final JTable table, final boolean isSelected, final int row) {
|
||||
if (label instanceof JComponent) {
|
||||
((JComponent)label).setOpaque(true);
|
||||
@@ -635,10 +755,11 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
Messages.showWarningDialog(myProject, "The selected file does not contain any importable configuration.", "Nothing to Import");
|
||||
return;
|
||||
}
|
||||
final Map<String,Set<BaseInjection>> currentMap =
|
||||
ContainerUtil.classify(myInjections.iterator(), new Convertor<BaseInjection, String>() {
|
||||
public String convert(final BaseInjection o) {
|
||||
return o.getSupportId();
|
||||
final CfgInfo info = getDefaultCfgInfo();
|
||||
final Map<String,Set<InjInfo>> currentMap =
|
||||
ContainerUtil.classify(info.injectionInfos.iterator(), new Convertor<InjInfo, String>() {
|
||||
public String convert(final InjInfo o) {
|
||||
return o.injection.getSupportId();
|
||||
}
|
||||
});
|
||||
final List<BaseInjection> originalInjections = new ArrayList<BaseInjection>();
|
||||
@@ -655,7 +776,7 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
//myInjections.addAll(newInjections);
|
||||
|
||||
for (String supportId : InjectorUtils.getActiveInjectionSupportIds()) {
|
||||
final Set<BaseInjection> currentInjections = currentMap.get(supportId);
|
||||
final List<BaseInjection> currentInjections = getInjectionList(new ArrayList<InjInfo>(currentMap.get(supportId)));
|
||||
final List<BaseInjection> importingInjections = cfg.getInjections(supportId);
|
||||
if (currentInjections == null) {
|
||||
newInjections.addAll(importingInjections);
|
||||
@@ -664,12 +785,8 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
Configuration.importInjections(currentInjections, importingInjections, originalInjections, newInjections);
|
||||
}
|
||||
}
|
||||
myInjections.removeAll(originalInjections);
|
||||
myInjections.addAll(newInjections);
|
||||
for (BaseInjection injection : newInjections) {
|
||||
injection.initializePlaces(true);
|
||||
}
|
||||
myInjectionsTable.getListTableModel().setItems(myInjections);
|
||||
info.replace(originalInjections, newInjections);
|
||||
myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos));
|
||||
final int n = newInjections.size();
|
||||
if (n > 1) {
|
||||
Messages.showInfoMessage(myProject, n + " entries have been successfully imported", "Import Successful");
|
||||
@@ -681,11 +798,128 @@ public class InjectionsSettingsUI implements Configurable {
|
||||
Messages.showInfoMessage(myProject, "No new entries have been imported", "Import");
|
||||
}
|
||||
}
|
||||
catch (Exception e1) {
|
||||
Configuration.LOG.error("Unable to load Settings", e1);
|
||||
catch (Exception ex) {
|
||||
Configuration.LOG.error(ex);
|
||||
|
||||
final String msg = e1.getLocalizedMessage();
|
||||
Messages.showErrorDialog(myProject, msg != null && msg.length() > 0 ? msg : e1.toString(), "Could not load Settings");
|
||||
final String msg = ex.getLocalizedMessage();
|
||||
Messages.showErrorDialog(myProject, msg != null && msg.length() > 0 ? msg : ex.toString(), "Import failed");
|
||||
}
|
||||
}
|
||||
|
||||
private static class CfgInfo {
|
||||
final Configuration cfg;
|
||||
final List<BaseInjection> originalInjections;
|
||||
final List<InjInfo> injectionInfos = new ArrayList<InjInfo>();
|
||||
final THashSet<BaseInjection> bundledInjections = new THashSet<BaseInjection>(new SameParamsAndPlacesStrategy());
|
||||
final String title;
|
||||
|
||||
public CfgInfo(Configuration cfg, final String title) {
|
||||
this.cfg = cfg;
|
||||
this.title = title;
|
||||
bundledInjections.addAll(cfg.getDefaultInjections());
|
||||
originalInjections = ContainerUtil
|
||||
.concat(InjectorUtils.getActiveInjectionSupportIds(), new Function<String, Collection<? extends BaseInjection>>() {
|
||||
public Collection<? extends BaseInjection> fun(final String s) {
|
||||
return ContainerUtil.findAll(
|
||||
CfgInfo.this.cfg instanceof Configuration.Prj ? ((Configuration.Prj)CfgInfo.this.cfg).getOwnInjections(s) : CfgInfo.this.cfg
|
||||
.getInjections(s),
|
||||
new Condition<BaseInjection>() {
|
||||
public boolean value(final BaseInjection injection) {
|
||||
return InjectedLanguage.findLanguageById(injection.getInjectedLanguageId()) != null;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
sortInjections(originalInjections);
|
||||
reset();
|
||||
}
|
||||
|
||||
public void apply() {
|
||||
final List<BaseInjection> injectionList = getInjectionList(injectionInfos);
|
||||
cfg.replaceInjections(injectionList, originalInjections);
|
||||
originalInjections.clear();
|
||||
originalInjections.addAll(injectionList);
|
||||
sortInjections(originalInjections);
|
||||
FileContentUtil.reparseOpenedFiles();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
injectionInfos.clear();
|
||||
for (BaseInjection injection : originalInjections) {
|
||||
injectionInfos.add(new InjInfo(injection.copy(), this));
|
||||
}
|
||||
}
|
||||
|
||||
public InjInfo addInjection(final BaseInjection injection) {
|
||||
final InjInfo info = new InjInfo(injection, this);
|
||||
injectionInfos.add(info);
|
||||
return info;
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
final List<BaseInjection> copy = new ArrayList<BaseInjection>(getInjectionList(injectionInfos));
|
||||
sortInjections(copy);
|
||||
return !originalInjections.equals(copy);
|
||||
}
|
||||
|
||||
public void replace(final List<BaseInjection> originalInjections, final List<BaseInjection> newInjections) {
|
||||
for (Iterator<InjInfo> it = injectionInfos.iterator(); it.hasNext(); ) {
|
||||
final InjInfo info = it.next();
|
||||
if (originalInjections.contains(info.injection)) it.remove();
|
||||
}
|
||||
for (BaseInjection newInjection : newInjections) {
|
||||
injectionInfos.add(new InjInfo(newInjection, this));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class SameParamsAndPlacesStrategy implements TObjectHashingStrategy<BaseInjection> {
|
||||
@Override
|
||||
public int computeHashCode(final BaseInjection object) {
|
||||
return object.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final BaseInjection o1, final BaseInjection o2) {
|
||||
if (!o1.sameLanguageParameters(o2)) return false;
|
||||
if (!o1.getInjectionPlaces().equals(o2.getInjectionPlaces())) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class InjInfo {
|
||||
final BaseInjection injection;
|
||||
final CfgInfo cfgInfo;
|
||||
final boolean bundled;
|
||||
|
||||
private InjInfo(final BaseInjection injection, final CfgInfo cfgInfo) {
|
||||
this.injection = injection;
|
||||
this.cfgInfo = cfgInfo;
|
||||
bundled = cfgInfo.bundledInjections.contains(injection);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<InjInfo> getInjInfoList(final CfgInfo[] infos) {
|
||||
return ContainerUtil.concat(infos, new Function<CfgInfo, Collection<? extends InjInfo>>() {
|
||||
@Override
|
||||
public Collection<InjInfo> fun(final CfgInfo cfgInfo) {
|
||||
return cfgInfo.injectionInfos;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static List<BaseInjection> getInjectionList(final List<InjInfo> list) {
|
||||
return new AbstractList<BaseInjection>() {
|
||||
@Override
|
||||
public BaseInjection get(final int index) {
|
||||
return list.get(index).injection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,10 +43,10 @@ import java.awt.*;
|
||||
*/
|
||||
public class Settings implements SearchableConfigurable {
|
||||
|
||||
private final Configuration myConfiguration;
|
||||
private final Project myProject;
|
||||
|
||||
Settings(Configuration configuration) {
|
||||
myConfiguration = configuration;
|
||||
Settings(final Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
private SettingsUI mySettingsUI;
|
||||
@@ -69,32 +69,7 @@ public class Settings implements SearchableConfigurable {
|
||||
}
|
||||
|
||||
public JComponent createComponent() {
|
||||
final ProjectManager projectManager = ProjectManager.getInstance();
|
||||
final Project[] projects = projectManager.getOpenProjects();
|
||||
|
||||
Project project = null;
|
||||
if (projects.length == 0) {
|
||||
project = projectManager.getDefaultProject();
|
||||
}
|
||||
else {
|
||||
final WindowManagerEx windowManager = WindowManagerEx.getInstanceEx();
|
||||
final Window focusedWindow = windowManager.getMostRecentFocusedWindow();
|
||||
if (focusedWindow != null) {
|
||||
for (Project p : projects) {
|
||||
final Window w = windowManager.suggestParentWindow(p);
|
||||
if (w == focusedWindow || w.isAncestorOf(focusedWindow) || focusedWindow.isAncestorOf(w)) {
|
||||
project = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (project == null) {
|
||||
project = projectManager.getDefaultProject();
|
||||
}
|
||||
}
|
||||
|
||||
mySettingsUI = new SettingsUI(project, myConfiguration);
|
||||
|
||||
mySettingsUI = new SettingsUI(myProject, Configuration.getProjectInstance(myProject));
|
||||
return mySettingsUI.createComponent();
|
||||
}
|
||||
|
||||
|
||||
-2
@@ -87,7 +87,6 @@ public abstract class AbstractLanguageInjectionSupport extends LanguageInjection
|
||||
final BaseInjection newInjection = showDefaultInjectionUI(project, originalInjection.copy());
|
||||
if (newInjection != null) {
|
||||
originalInjection.copyFrom(newInjection);
|
||||
originalInjection.initializePlaces(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -134,7 +133,6 @@ public abstract class AbstractLanguageInjectionSupport extends LanguageInjection
|
||||
}
|
||||
});
|
||||
if (builder.show() == DialogWrapper.OK_EXIT_CODE) {
|
||||
injection.initializePlaces(false);
|
||||
return injection;
|
||||
}
|
||||
return null;
|
||||
|
||||
+5
-3
@@ -20,10 +20,12 @@ import com.intellij.lang.Language;
|
||||
import com.intellij.lang.injection.MultiHostInjector;
|
||||
import com.intellij.lang.injection.MultiHostRegistrar;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiLanguageInjectionHost;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.intellij.plugins.intelliLang.Configuration;
|
||||
import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -36,9 +38,11 @@ import java.util.Set;
|
||||
public final class DefaultLanguageInjector implements MultiHostInjector {
|
||||
|
||||
private final Configuration myInjectionConfiguration;
|
||||
private final LanguageInjectionSupport[] mySupports;
|
||||
|
||||
public DefaultLanguageInjector(Configuration configuration) {
|
||||
myInjectionConfiguration = configuration;
|
||||
mySupports = InjectorUtils.getActiveInjectionSupports();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -47,9 +51,7 @@ public final class DefaultLanguageInjector implements MultiHostInjector {
|
||||
}
|
||||
|
||||
public void getLanguagesToInject(@NotNull final MultiHostRegistrar registrar, @NotNull final PsiElement host) {
|
||||
final Set<String> allIds = myInjectionConfiguration.getAllInjectorIds();
|
||||
for (LanguageInjectionSupport support : Extensions.getExtensions(LanguageInjectionSupport.EP_NAME)) {
|
||||
if (!allIds.contains(support.getId())) continue;
|
||||
for (LanguageInjectionSupport support : mySupports) {
|
||||
if (!support.useDefaultInjector(host)) continue;
|
||||
for (BaseInjection injection : myInjectionConfiguration.getInjections(support.getId())) {
|
||||
if (injection.acceptsPsiElement(host)) {
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ public class EditInjectionSettingsAction implements IntentionAction, LowPriority
|
||||
if (support == null) return;
|
||||
try {
|
||||
if (!support.editInjectionInPlace(host)) {
|
||||
ShowSettingsUtil.getInstance().editConfigurable(project, new InjectionsSettingsUI(project, Configuration.getInstance()));
|
||||
ShowSettingsUtil.getInstance().editConfigurable(project, new InjectionsSettingsUI(project, Configuration.getProjectInstance(project)));
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
||||
+1
-1
@@ -115,7 +115,7 @@ public class InjectLanguageAction implements IntentionAction {
|
||||
}
|
||||
|
||||
private static boolean defaultFunctionalityWorked(final PsiLanguageInjectionHost host, final String languageId) {
|
||||
return Configuration.getInstance().setHostInjectionEnabled(host, Collections.singleton(languageId), true);
|
||||
return Configuration.getProjectInstance(host.getProject()).setHostInjectionEnabled(host, Collections.singleton(languageId), true);
|
||||
}
|
||||
|
||||
private static boolean doChooseLanguageToInject(Editor editor, final Processor<String> onChosen) {
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ public class UnInjectLanguageAction implements IntentionAction, LowPriorityActio
|
||||
}
|
||||
// todo there is a problem: host i.e. literal expression is confused with "target" i.e. parameter
|
||||
// todo therefore this part doesn't work for java
|
||||
return Configuration.getInstance().setHostInjectionEnabled(host, languages, false);
|
||||
return Configuration.getProjectInstance(host.getProject()).setHostInjectionEnabled(host, languages, false);
|
||||
}
|
||||
|
||||
public boolean startInWriteAction() {
|
||||
|
||||
+21
-47
@@ -161,7 +161,7 @@ public class BaseInjection implements Injection, PersistentStateComponent<Elemen
|
||||
public boolean intersectsWith(final BaseInjection template) {
|
||||
if (!Comparing.equal(getInjectedLanguageId(), template.getInjectedLanguageId())) return false;
|
||||
for (InjectionPlace other : template.getInjectionPlaces()) {
|
||||
if (findPlaceByText(other.getText()) != null) return true;
|
||||
if (myPlaces.contains(other)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -175,14 +175,6 @@ public class BaseInjection implements Injection, PersistentStateComponent<Elemen
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public InjectionPlace findPlaceByText(final String text) {
|
||||
for (InjectionPlace cur : myPlaces) {
|
||||
if (Comparing.equal(text, cur.getText())) return cur;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public BaseInjection copy() {
|
||||
return new BaseInjection(mySupportId).copyFrom(this);
|
||||
@@ -196,6 +188,13 @@ public class BaseInjection implements Injection, PersistentStateComponent<Elemen
|
||||
final BaseInjection that = (BaseInjection)o;
|
||||
|
||||
if (!sameLanguageParameters(that)) return false;
|
||||
if (myPlaces.size() != that.myPlaces.size()) return false;
|
||||
for (int i = 0, len = myPlaces.size(); i < len; i++) {
|
||||
if (myPlaces.get(i).isEnabled() != that.myPlaces.get(i).isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// enabled flag is not counted this way:
|
||||
if (!myPlaces.equals(that.myPlaces)) return false;
|
||||
return true;
|
||||
}
|
||||
@@ -227,6 +226,7 @@ public class BaseInjection implements Injection, PersistentStateComponent<Elemen
|
||||
}
|
||||
|
||||
public void loadState(Element element) {
|
||||
final PatternCompiler<PsiElement> helper = getCompiler();
|
||||
final Element e = element.getChild(getClass().getSimpleName());
|
||||
if (e != null) {
|
||||
myInjectedLanguageId = JDOMExternalizer.readString(e, "LANGUAGE");
|
||||
@@ -235,7 +235,6 @@ public class BaseInjection implements Injection, PersistentStateComponent<Elemen
|
||||
setValuePattern(JDOMExternalizer.readString(e, "VALUE_PATTERN"));
|
||||
mySingleFile = JDOMExternalizer.readBoolean(e, "SINGLE_FILE");
|
||||
readExternalImpl(e);
|
||||
initializePlaces(false);
|
||||
}
|
||||
else {
|
||||
myDisplayName = StringUtil.notNullize(element.getChildText("display-name"));
|
||||
@@ -248,41 +247,21 @@ public class BaseInjection implements Injection, PersistentStateComponent<Elemen
|
||||
for (Element placeElement : (List<Element>)element.getChildren("place")) {
|
||||
final boolean enabled = !Boolean.parseBoolean(placeElement.getAttributeValue("disabled"));
|
||||
final String text = placeElement.getText();
|
||||
myPlaces.add(new InjectionPlace(text, null, enabled));
|
||||
myPlaces.add(new InjectionPlace(helper.createElementPattern(text, getDisplayName()), enabled));
|
||||
}
|
||||
myPlaces.trimToSize();
|
||||
}
|
||||
}
|
||||
|
||||
public void initializePlaces(final boolean compile) {
|
||||
final PatternCompiler<PsiElement> helper =
|
||||
PatternCompilerFactory.getFactory().getPatternCompiler(InjectorUtils.findInjectionSupport(getSupportId()).getPatternClasses());
|
||||
if (myPlaces.isEmpty()) {
|
||||
for (String text : generatePlaces()) {
|
||||
myPlaces.add(new InjectionPlace(text, compile? helper.createElementPattern(text, getDisplayName()) : null, true));
|
||||
}
|
||||
}
|
||||
else if (compile) {
|
||||
boolean replace = false;
|
||||
final ArrayList<InjectionPlace> newPlaces = new ArrayList<InjectionPlace>();
|
||||
for (InjectionPlace place : myPlaces) {
|
||||
if (StringUtil.isNotEmpty(place.getText()) && place.getElementPattern() == null) {
|
||||
replace = true;
|
||||
newPlaces.add(new InjectionPlace(place.getText(), helper.createElementPattern(place.getText(), getDisplayName()), place.isEnabled()));
|
||||
}
|
||||
else {
|
||||
newPlaces.add(place);
|
||||
}
|
||||
}
|
||||
if (replace) {
|
||||
myPlaces.clear();
|
||||
myPlaces.addAll(newPlaces);
|
||||
}
|
||||
generatePlaces();
|
||||
}
|
||||
myPlaces.trimToSize();
|
||||
}
|
||||
|
||||
protected List<String> generatePlaces() {
|
||||
return Collections.emptyList();
|
||||
|
||||
public PatternCompiler<PsiElement> getCompiler() {
|
||||
return PatternCompilerFactory.getFactory().getPatternCompiler(InjectorUtils.findInjectionSupport(getSupportId()).getPatternClasses());
|
||||
}
|
||||
|
||||
public void generatePlaces() {
|
||||
}
|
||||
|
||||
protected void readExternalImpl(Element e) {}
|
||||
@@ -387,13 +366,8 @@ public class BaseInjection implements Injection, PersistentStateComponent<Elemen
|
||||
|
||||
public void mergeOriginalPlacesFrom(final BaseInjection injection, final boolean enabled) {
|
||||
for (InjectionPlace place : injection.getInjectionPlaces()) {
|
||||
if (findPlaceByText(place.getText()) == null) {
|
||||
if (enabled || !place.isEnabled()) {
|
||||
myPlaces.add(place);
|
||||
}
|
||||
else {
|
||||
myPlaces.add(new InjectionPlace(place.getText(), place.getElementPattern(), false));
|
||||
}
|
||||
if (!myPlaces.contains(place)) {
|
||||
myPlaces.add(enabled || !place.isEnabled() ? place : place.enabled(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -403,7 +377,7 @@ public class BaseInjection implements Injection, PersistentStateComponent<Elemen
|
||||
final InjectionPlace cur = myPlaces.get(i);
|
||||
if (text == null || Comparing.equal(text, cur.getText())) {
|
||||
if (cur.isEnabled() != enabled) {
|
||||
myPlaces.set(i, new InjectionPlace(cur.getText(), cur.getElementPattern(), enabled));
|
||||
myPlaces.set(i, cur.enabled(enabled));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -16,25 +16,28 @@
|
||||
|
||||
package org.intellij.plugins.intelliLang.inject.config;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
/**
|
||||
* @author Gregory.Shrago
|
||||
*/
|
||||
// todo inline class
|
||||
public class InjectionPlace {
|
||||
private final String myText;
|
||||
private final ElementPattern<PsiElement> myElementPattern;
|
||||
private final boolean myEnabled;
|
||||
|
||||
public InjectionPlace(final String myText, final ElementPattern<PsiElement> myElementPattern, final boolean enabled) {
|
||||
this.myText = myText;
|
||||
public InjectionPlace(final ElementPattern<PsiElement> myElementPattern, final boolean enabled) {
|
||||
this.myElementPattern = myElementPattern;
|
||||
myEnabled = enabled;
|
||||
}
|
||||
|
||||
public InjectionPlace enabled(final boolean enabled) {
|
||||
return new InjectionPlace(myElementPattern, enabled);
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return myText;
|
||||
return myElementPattern.toString();
|
||||
}
|
||||
|
||||
public ElementPattern<PsiElement> getElementPattern() {
|
||||
@@ -52,16 +55,13 @@ public class InjectionPlace {
|
||||
|
||||
final InjectionPlace place = (InjectionPlace)o;
|
||||
|
||||
if (myEnabled != place.myEnabled) return false;
|
||||
if (myText != null ? !myText.equals(place.myText) : place.myText != null) return false;
|
||||
if (!myElementPattern.equals(place.myElementPattern)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myText != null ? myText.hashCode() : 0;
|
||||
result = 31 * result + (myEnabled ? 1 : 0);
|
||||
return result;
|
||||
return myElementPattern.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ public abstract class AbstractInjectionPanel<T extends BaseInjection> implements
|
||||
for (Field panel : myOtherPanels) {
|
||||
getField(panel).apply();
|
||||
}
|
||||
|
||||
myOrigInjection.generatePlaces();
|
||||
myEditCopy.copyFrom(myOrigInjection);
|
||||
}
|
||||
|
||||
|
||||
+6
-4
@@ -93,12 +93,13 @@ public class BaseInjectionPanel extends AbstractInjectionPanel<BaseInjection> {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final ArrayList<InjectionPlace> places = new ArrayList<InjectionPlace>();
|
||||
for (String s : myTextArea.getText().split("\\s*\n\\s*")) {
|
||||
final boolean nextEnabled;
|
||||
if (s.startsWith("+")) {
|
||||
enabled = true;
|
||||
nextEnabled = true;
|
||||
s = s.substring(1).trim();
|
||||
}
|
||||
else if (s.startsWith("-")) {
|
||||
enabled = false;
|
||||
nextEnabled = false;
|
||||
s = s.substring(1).trim();
|
||||
}
|
||||
else {
|
||||
@@ -107,14 +108,15 @@ public class BaseInjectionPanel extends AbstractInjectionPanel<BaseInjection> {
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
final String text = sb.toString();
|
||||
places.add(new InjectionPlace(text, myHelper.compileElementPattern(text), enabled));
|
||||
places.add(new InjectionPlace(myHelper.compileElementPattern(text), enabled));
|
||||
sb.setLength(0);
|
||||
}
|
||||
sb.append(s);
|
||||
enabled = nextEnabled;
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
final String text = sb.toString();
|
||||
places.add(new InjectionPlace(text, myHelper.compileElementPattern(text), enabled));
|
||||
places.add(new InjectionPlace(myHelper.compileElementPattern(text), enabled));
|
||||
}
|
||||
other.getInjectionPlaces().clear();
|
||||
other.getInjectionPlaces().addAll(places);
|
||||
|
||||
+4
-2
@@ -17,6 +17,7 @@ package org.intellij.plugins.intelliLang.inject.config;
|
||||
|
||||
import com.intellij.openapi.util.JDOMExternalizer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.patterns.compiler.PatternCompiler;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.xml.XmlAttribute;
|
||||
import com.intellij.psi.xml.XmlAttributeValue;
|
||||
@@ -76,8 +77,9 @@ public class XmlAttributeInjection extends AbstractTagInjection {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> generatePlaces() {
|
||||
return Collections.singletonList(getPatternString(this));
|
||||
public void generatePlaces() {
|
||||
getInjectionPlaces().clear();
|
||||
getInjectionPlaces().add(new InjectionPlace(getCompiler().createElementPattern(getPatternString(this), getDisplayName()), true));
|
||||
}
|
||||
|
||||
private boolean matches(@NotNull XmlAttribute attr) {
|
||||
|
||||
+3
-2
@@ -51,8 +51,9 @@ public class XmlTagInjection extends AbstractTagInjection {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> generatePlaces() {
|
||||
return Collections.singletonList(getPatternString(this));
|
||||
public void generatePlaces() {
|
||||
getInjectionPlaces().clear();
|
||||
getInjectionPlaces().add(new InjectionPlace(getCompiler().createElementPattern(getPatternString(this), getDisplayName()), true));
|
||||
}
|
||||
|
||||
public static String getPatternString(final AbstractTagInjection injection) {
|
||||
|
||||
+16
-14
@@ -101,7 +101,8 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor
|
||||
|
||||
public boolean removeInjectionInPlace(final PsiLanguageInjectionHost host) {
|
||||
if (!isMine(host)) return false;
|
||||
final Configuration configuration = Configuration.getInstance();
|
||||
final Project project = host.getProject();
|
||||
final Configuration configuration = Configuration.getProjectInstance(project);
|
||||
final ArrayList<BaseInjection> injections = collectInjections(host, configuration);
|
||||
if (injections.isEmpty()) return false;
|
||||
final ArrayList<BaseInjection> newInjections = new ArrayList<BaseInjection>();
|
||||
@@ -109,23 +110,23 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor
|
||||
final BaseInjection newInjection = injection.copy();
|
||||
newInjection.setPlaceEnabled(null, false);
|
||||
}
|
||||
Configuration.getInstance().replaceInjectionsWithUndo(
|
||||
host.getProject(), newInjections, injections, Collections.<PsiElement>emptyList());
|
||||
configuration.replaceInjectionsWithUndo(
|
||||
project, newInjections, injections, Collections.<PsiElement>emptyList());
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean editInjectionInPlace(final PsiLanguageInjectionHost host) {
|
||||
if (!isMine(host)) return false;
|
||||
final Configuration configuration = Configuration.getInstance();
|
||||
final Project project = host.getProject();
|
||||
final Configuration configuration = Configuration.getProjectInstance(project);
|
||||
final ArrayList<BaseInjection> injections = collectInjections(host, configuration);
|
||||
if (injections.isEmpty()) return false;
|
||||
final Project project = host.getProject();
|
||||
final BaseInjection originalInjection = injections.get(0);
|
||||
final BaseInjection xmlInjection = createFrom(originalInjection, host);
|
||||
final BaseInjection newInjection =
|
||||
xmlInjection == null? showDefaultInjectionUI(project, originalInjection.copy()) : showInjectionUI(project, xmlInjection);
|
||||
if (newInjection != null) {
|
||||
Configuration.getInstance().replaceInjectionsWithUndo(
|
||||
configuration.replaceInjectionsWithUndo(
|
||||
project, Collections.singletonList(newInjection),
|
||||
Collections.singletonList(originalInjection),
|
||||
Collections.<PsiElement>emptyList());
|
||||
@@ -158,7 +159,6 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor
|
||||
}
|
||||
});
|
||||
if (builder.show() == DialogWrapper.OK_EXIT_CODE) {
|
||||
xmlInjection.initializePlaces(false);
|
||||
return new AbstractTagInjection().copyFrom(xmlInjection);
|
||||
}
|
||||
return null;
|
||||
@@ -166,7 +166,7 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor
|
||||
|
||||
@Nullable
|
||||
private static BaseInjection createFrom(final BaseInjection injection, final PsiLanguageInjectionHost host) {
|
||||
if (injection.getInjectionPlaces().size() > 1) return null;
|
||||
if (injection.getInjectionPlaces().isEmpty() || injection.getInjectionPlaces().size() > 1) return null;
|
||||
|
||||
AbstractTagInjection result;
|
||||
final InjectionPlace place = injection.getInjectionPlaces().get(0);
|
||||
@@ -218,6 +218,7 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
result.generatePlaces();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -265,6 +266,7 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor
|
||||
injection.setInjectedLanguageId(languageId);
|
||||
injection.setTagName(tag.getLocalName());
|
||||
injection.setTagNamespace(tag.getNamespace());
|
||||
injection.generatePlaces();
|
||||
doEditInjection(host.getProject(), injection);
|
||||
return true;
|
||||
}
|
||||
@@ -272,11 +274,12 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor
|
||||
}
|
||||
|
||||
private static void doEditInjection(final Project project, final XmlTagInjection template) {
|
||||
final AbstractTagInjection originalInjection = (AbstractTagInjection)Configuration.getInstance().findExistingInjection(template);
|
||||
final Configuration configuration = Configuration.getProjectInstance(project);
|
||||
final AbstractTagInjection originalInjection = (AbstractTagInjection)configuration.findExistingInjection(template);
|
||||
|
||||
final XmlTagInjection newInjection = originalInjection == null? template : new XmlTagInjection().copyFrom(originalInjection);
|
||||
if (InjectLanguageAction.doEditConfigurable(project, new XmlTagInjectionConfigurable(newInjection, null, project))) {
|
||||
Configuration.getInstance().replaceInjectionsWithUndo(
|
||||
configuration.replaceInjectionsWithUndo(
|
||||
project, Collections.singletonList(newInjection),
|
||||
ContainerUtil.createMaybeSingletonList(originalInjection),
|
||||
Collections.<PsiElement>emptyList());
|
||||
@@ -293,6 +296,7 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor
|
||||
injection.setAttributeNamespace(attribute.getNamespace());
|
||||
injection.setTagName(tag.getLocalName());
|
||||
injection.setTagNamespace(tag.getNamespace());
|
||||
injection.generatePlaces();
|
||||
doEditInjection(host.getProject(), injection);
|
||||
return true;
|
||||
}
|
||||
@@ -300,12 +304,11 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor
|
||||
}
|
||||
|
||||
private static void doEditInjection(final Project project, final XmlAttributeInjection template) {
|
||||
final Configuration configuration = Configuration.getInstance();
|
||||
template.initializePlaces(false);
|
||||
final Configuration configuration = Configuration.getProjectInstance(project);
|
||||
final BaseInjection originalInjection = configuration.findExistingInjection(template);
|
||||
final BaseInjection newInjection = originalInjection == null ? template : originalInjection.copy();
|
||||
if (InjectLanguageAction.doEditConfigurable(project, new XmlAttributeInjectionConfigurable((XmlAttributeInjection)newInjection, null, project))) {
|
||||
Configuration.getInstance().replaceInjectionsWithUndo(
|
||||
configuration.replaceInjectionsWithUndo(
|
||||
project, Collections.singletonList(newInjection),
|
||||
ContainerUtil.createMaybeSingletonList(originalInjection),
|
||||
Collections.<PsiElement>emptyList());
|
||||
@@ -356,7 +359,6 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor
|
||||
final BaseInjection newInjection = showInjectionUI(project, injection);
|
||||
if (newInjection != null) {
|
||||
originalInjection.copyFrom(newInjection);
|
||||
originalInjection.initializePlaces(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
<dom.fileDescription implementation="org.jetbrains.android.dom.drawable.LevelListDomFileDescription"/>
|
||||
<dom.fileDescription implementation="org.jetbrains.android.dom.drawable.InsetOrClipOrScaleDomFileDescription"/>
|
||||
<dom.fileDescription implementation="org.jetbrains.android.dom.drawable.ShapeDomFileDescription"/>
|
||||
<dom.fileDescription implementation="org.jetbrains.android.dom.drawable.AnimationListDomFileDescription"/>
|
||||
<dom.fileDescription implementation="org.jetbrains.android.dom.color.ColorDomFileDescription"/>
|
||||
|
||||
<dom.fileDescription implementation="org.jetbrains.android.dom.manifest.ManifestDomFileDescription"/>
|
||||
|
||||
@@ -574,6 +574,9 @@ public class AndroidDomExtender extends DomExtender<AndroidDomElement> {
|
||||
else if (element instanceof LevelListItem) {
|
||||
registerAttributes(facet, element, "LevelListDrawableItem", SYSTEM_RESOURCE_PACKAGE, registrar);
|
||||
}
|
||||
else if (element instanceof AnimationListItem) {
|
||||
registerAttributes(facet, element, "AnimationDrawableItem", SYSTEM_RESOURCE_PACKAGE, registrar);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -40,6 +40,7 @@ public class AndroidDrawableDomUtil {
|
||||
SPECIAL_STYLEABLE_NAMES.put("inset", "InsetDrawable");
|
||||
SPECIAL_STYLEABLE_NAMES.put("clip", "ClipDrawable");
|
||||
SPECIAL_STYLEABLE_NAMES.put("scale", "ScaleDrawable");
|
||||
SPECIAL_STYLEABLE_NAMES.put("animation-list", "AnimationDrawable");
|
||||
|
||||
SPECIAL_STYLEABLE_NAMES.put("shape", "GradientDrawable");
|
||||
SPECIAL_STYLEABLE_NAMES.put("corners", "DrawableCorners");
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.jetbrains.android.dom.drawable;
|
||||
|
||||
import com.intellij.util.xml.DefinesXml;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
@DefinesXml
|
||||
public interface AnimationList extends DrawableDomElement {
|
||||
List<AnimationListItem> getItems();
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package org.jetbrains.android.dom.drawable;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import org.jetbrains.android.dom.AndroidResourceDomFileDescription;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AnimationListDomFileDescription extends AndroidResourceDomFileDescription<AnimationList> {
|
||||
@NonNls static final String ANIMATION_LIST_TAG = "animation-list";
|
||||
|
||||
public AnimationListDomFileDescription() {
|
||||
super(AnimationList.class, ANIMATION_LIST_TAG, "drawable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptsOtherRootTagNames() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMyFile(@NotNull XmlFile file, @Nullable Module module) {
|
||||
if (!super.isMyFile(file, module)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final XmlTag rootTag = file.getRootTag();
|
||||
if (rootTag == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ANIMATION_LIST_TAG.equals(rootTag.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.jetbrains.android.dom.drawable;
|
||||
|
||||
import com.intellij.util.xml.Convert;
|
||||
import org.jetbrains.android.dom.AndroidAttributeValue;
|
||||
import org.jetbrains.android.dom.ResourceType;
|
||||
import org.jetbrains.android.dom.converters.ResourceReferenceConverter;
|
||||
import org.jetbrains.android.dom.resources.ResourceValue;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public interface AnimationListItem extends DrawableDomElement {
|
||||
@Convert(ResourceReferenceConverter.class)
|
||||
@ResourceType("drawable")
|
||||
AndroidAttributeValue<ResourceValue> getDrawable();
|
||||
}
|
||||
@@ -25,6 +25,9 @@ import com.android.sdklib.SdkManager;
|
||||
import com.android.sdklib.internal.avd.AvdManager;
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.execution.configurations.ParametersList;
|
||||
import com.intellij.execution.process.ProcessHandler;
|
||||
import com.intellij.execution.process.ProcessOutputTypes;
|
||||
import com.intellij.facet.Facet;
|
||||
import com.intellij.facet.FacetManager;
|
||||
import com.intellij.facet.FacetTypeId;
|
||||
@@ -318,7 +321,7 @@ public class AndroidFacet extends Facet<AndroidFacetConfiguration> {
|
||||
return myAvdManager;
|
||||
}
|
||||
|
||||
public void launchEmulator(@Nullable final String avdName, @NotNull final String commands) {
|
||||
public void launchEmulator(@Nullable final String avdName, @NotNull final String commands, @Nullable ProcessHandler handler) {
|
||||
AndroidPlatform platform = getConfiguration().getAndroidPlatform();
|
||||
if (platform != null) {
|
||||
final String emulatorPath = platform.getSdk().getLocation() + File.separator + AndroidUtils.toolPath(EMULATOR);
|
||||
@@ -328,13 +331,16 @@ public class AndroidFacet extends Facet<AndroidFacetConfiguration> {
|
||||
commandLine.addParameter("-avd");
|
||||
commandLine.addParameter(avdName);
|
||||
}
|
||||
String[] params = commands.split("\\s+");
|
||||
String[] params = ParametersList.parse(commands);
|
||||
for (String s : params) {
|
||||
if (s.length() > 0) {
|
||||
commandLine.addParameter(s);
|
||||
}
|
||||
}
|
||||
AndroidUtils.runExternalToolInSeparateThread(getModule().getProject(), commandLine);
|
||||
if (handler != null) {
|
||||
handler.notifyTextAvailable(commandLine.getCommandLineString() + '\n', ProcessOutputTypes.STDOUT);
|
||||
}
|
||||
AndroidUtils.runExternalToolInSeparateThread(getModule().getProject(), commandLine, handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,12 @@
|
||||
*/
|
||||
package org.jetbrains.android.inspections;
|
||||
|
||||
import com.intellij.util.xml.Converter;
|
||||
import com.intellij.util.xml.GenericDomValue;
|
||||
import com.intellij.util.xml.WrappingConverter;
|
||||
import com.intellij.util.xml.highlighting.BasicDomElementsInspection;
|
||||
import org.jetbrains.android.dom.AndroidDomElement;
|
||||
import org.jetbrains.android.dom.converters.AndroidPackageConverter;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -47,4 +51,10 @@ public class AndroidDomInspection extends BasicDomElementsInspection<AndroidDomE
|
||||
public String getShortName() {
|
||||
return "AndroidDomInspection";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldCheckResolveProblems(GenericDomValue value) {
|
||||
final Converter realConverter = WrappingConverter.getDeepestConverter(value.getConverter(), value);
|
||||
return !(realConverter instanceof AndroidPackageConverter);
|
||||
}
|
||||
}
|
||||
@@ -239,7 +239,7 @@ public class AndroidModuleBuilder extends JavaModuleBuilder {
|
||||
@Override
|
||||
public void run() {
|
||||
final Project project = module.getProject();
|
||||
AndroidUtils.runExternalTool(project, commandLine, true);
|
||||
AndroidUtils.runExternalTool(project, commandLine, true, null);
|
||||
|
||||
StartupManager.getInstance(project).runWhenProjectIsInitialized(new Runnable() {
|
||||
public void run() {
|
||||
|
||||
@@ -357,14 +357,14 @@ public abstract class AndroidRunningState implements RunProfileState, AndroidDeb
|
||||
chooseAvd();
|
||||
}
|
||||
if (myAvdName != null) {
|
||||
myFacet.launchEmulator(myAvdName, myCommandLine);
|
||||
myFacet.launchEmulator(myAvdName, myCommandLine, getProcessHandler());
|
||||
}
|
||||
else if (getProcessHandler().isStartNotified()) {
|
||||
getProcessHandler().destroyProcess();
|
||||
}
|
||||
}
|
||||
else {
|
||||
myFacet.launchEmulator(myAvdName, myCommandLine);
|
||||
myFacet.launchEmulator(myAvdName, myCommandLine, getProcessHandler());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ public class DeviceChooser extends DialogWrapper implements AndroidDebugBridge.I
|
||||
if (chooser.getExitCode() != OK_EXIT_CODE) return;
|
||||
if (avd == null) return;
|
||||
}
|
||||
myFacet.launchEmulator(avd != null ? avd.getName() : null, "");
|
||||
myFacet.launchEmulator(avd != null ? avd.getName() : null, "", null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,9 +27,7 @@ import com.intellij.execution.RunManagerEx;
|
||||
import com.intellij.execution.RunnerAndConfigurationSettings;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.execution.impl.ConsoleViewImpl;
|
||||
import com.intellij.execution.process.OSProcessHandler;
|
||||
import com.intellij.execution.process.ProcessAdapter;
|
||||
import com.intellij.execution.process.ProcessEvent;
|
||||
import com.intellij.execution.process.*;
|
||||
import com.intellij.execution.ui.ConsoleView;
|
||||
import com.intellij.execution.ui.ConsoleViewContentType;
|
||||
import com.intellij.facet.ProjectFacetManager;
|
||||
@@ -445,14 +443,23 @@ public class AndroidUtils {
|
||||
|
||||
public static void runExternalToolInSeparateThread(@NotNull final Project project,
|
||||
@NotNull final GeneralCommandLine commandLine) {
|
||||
runExternalToolInSeparateThread(project, commandLine, null);
|
||||
}
|
||||
|
||||
public static void runExternalToolInSeparateThread(@NotNull final Project project,
|
||||
@NotNull final GeneralCommandLine commandLine,
|
||||
@Nullable final ProcessHandler processHandler) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
public void run() {
|
||||
runExternalTool(project, commandLine, false);
|
||||
runExternalTool(project, commandLine, false, processHandler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void runExternalTool(final Project project, GeneralCommandLine commandLine, boolean printOutputToConsole) {
|
||||
public static void runExternalTool(final Project project,
|
||||
GeneralCommandLine commandLine,
|
||||
boolean printOutputToAndroidConsole,
|
||||
ProcessHandler processHandler) {
|
||||
String[] commands = commandLine.getCommands();
|
||||
String command = StringUtil.join(commands, " ");
|
||||
LOG.info("Execute: " + command);
|
||||
@@ -468,17 +475,22 @@ public class AndroidUtils {
|
||||
result = e.getMessage();
|
||||
}
|
||||
|
||||
if (result != null && printOutputToConsole) {
|
||||
final ConsoleViewContentType contentType = success ?
|
||||
ConsoleViewContentType.NORMAL_OUTPUT :
|
||||
ConsoleViewContentType.ERROR_OUTPUT;
|
||||
final String finalResult = result;
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
printMessageToConsole(project, finalResult, contentType);
|
||||
}
|
||||
});
|
||||
if (result != null) {
|
||||
if (printOutputToAndroidConsole) {
|
||||
final ConsoleViewContentType contentType = success ?
|
||||
ConsoleViewContentType.NORMAL_OUTPUT :
|
||||
ConsoleViewContentType.ERROR_OUTPUT;
|
||||
final String finalResult = result;
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
printMessageToConsole(project, finalResult, contentType);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (processHandler != null) {
|
||||
processHandler.notifyTextAvailable(result + '\n', ProcessOutputTypes.STDOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:one<caret>>
|
||||
<item android:drawable="@drawable/myDrawable" android:duration="400"/>
|
||||
</animation-list>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="">
|
||||
<item android:drawable="@drawable/myDrawable" android:duration="400"/>
|
||||
</animation-list>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/myDrawa<caret>" android:duration="400"/>
|
||||
</animation-list>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/myDrawable" android:duration="400"/>
|
||||
</animation-list>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:dur<caret>/>
|
||||
</animation-list>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:duration=""/>
|
||||
</animation-list>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
|
||||
<item android:drawable="@drawable/myDrawable" android:duration="400"/>
|
||||
</animation-list>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item/>
|
||||
</animation-list>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="<error>aba</error>">
|
||||
package="aba">
|
||||
<<error>permission</error>/>
|
||||
<permission android:name="a"/>
|
||||
<application android:icon="@drawable/picture1">
|
||||
|
||||
+20
@@ -213,6 +213,26 @@ public class AndroidDrawableResourcesDomTest extends AndroidDomTest {
|
||||
doTestCompletionVariants(getTestName(true) + ".xml", "gradient", "solid", "size", "stroke", "padding", "corners");
|
||||
}
|
||||
|
||||
public void testAnimationListHighlighting1() throws Throwable {
|
||||
doTestHighlighting();
|
||||
}
|
||||
|
||||
public void testAnimationListHighlighting2() throws Throwable {
|
||||
doTestHighlighting();
|
||||
}
|
||||
|
||||
public void testAnimationListCompletion1() throws Throwable {
|
||||
doTestCompletion();
|
||||
}
|
||||
|
||||
public void testAnimationListCompletion2() throws Throwable {
|
||||
doTestCompletion();
|
||||
}
|
||||
|
||||
public void testAnimationListCompletion3() throws Throwable {
|
||||
doTestCompletion();
|
||||
}
|
||||
|
||||
public void testIncorrectRootTag() throws Throwable {
|
||||
doTestHighlighting();
|
||||
}
|
||||
|
||||
+5
-1
@@ -109,7 +109,11 @@ public class EclipseWorkspaceRootStep extends ProjectImportWizardStep {
|
||||
public void updateStep() {
|
||||
String path = getContext().getRootDirectory();
|
||||
if (path == null) {
|
||||
path = PropertiesComponent.getInstance().isValueSet(_ECLIPSE_PROJECT_DIR) ? PropertiesComponent.getInstance().getValue(_ECLIPSE_PROJECT_DIR) : getWizardContext().getProjectFileDirectory();
|
||||
if (getWizardContext().isProjectFileDirectorySet() || !PropertiesComponent.getInstance().isValueSet(_ECLIPSE_PROJECT_DIR)) {
|
||||
path = getWizardContext().getProjectFileDirectory();
|
||||
} else {
|
||||
path = PropertiesComponent.getInstance().getValue(_ECLIPSE_PROJECT_DIR);
|
||||
}
|
||||
}
|
||||
myWorkspaceRootComponent.setText(path.replace('/', File.separatorChar));
|
||||
myWorkspaceRootComponent.getTextField().selectAll();
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -232,6 +233,9 @@ public class PsiUtil {
|
||||
if (type == null) {
|
||||
result.add(nullAsBottom ? PsiType.NULL : TypesUtil.getJavaLangObject(expression));
|
||||
} else {
|
||||
if (stopAt == expression) {
|
||||
type = TypeConversionUtil.erasure(type);
|
||||
}
|
||||
result.add(type);
|
||||
}
|
||||
if (stopAt == expression) {
|
||||
@@ -242,6 +246,9 @@ public class PsiUtil {
|
||||
for (GrClosableBlock closure : closures) {
|
||||
PsiType closureType = closure.getType();
|
||||
if (closureType != null) {
|
||||
if (stopAt == closure) {
|
||||
closureType = TypeConversionUtil.erasure(closureType);
|
||||
}
|
||||
result.add(closureType);
|
||||
}
|
||||
if (stopAt == closure) {
|
||||
|
||||
@@ -106,4 +106,26 @@ class GroovyStressTest extends LightCodeInsightFixtureTestCase {
|
||||
IdeaTestUtil.assertTiming "slow", 10000, { myFixture.doHighlighting() }
|
||||
}
|
||||
|
||||
public void testDeeplyNestedClosuresInGenericCalls() {
|
||||
String text = "println it"
|
||||
for (i in 1..10) {
|
||||
text = "foo(it) { $text }"
|
||||
}
|
||||
myFixture.configureByText("a.groovy", "def <T> foo(T t, Closure cl) {}\n" + text)
|
||||
myFixture.enableInspections(new MissingReturnInspection())
|
||||
IdeaTestUtil.assertTiming "slow", 10000, { myFixture.doHighlighting() }
|
||||
|
||||
}
|
||||
|
||||
public void testDeeplyNestedClosuresInGenericCalls2() {
|
||||
String text = "println it"
|
||||
for (i in 1..10) {
|
||||
text = "foo(it) { $text }"
|
||||
}
|
||||
myFixture.configureByText("a.groovy", "def <T> foo(T t, Closure<T> cl) {}\n" + text)
|
||||
myFixture.enableInspections(new MissingReturnInspection())
|
||||
IdeaTestUtil.assertTiming "slow", 10000, { myFixture.doHighlighting() }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -101,6 +101,9 @@ public class JUnit4TestResultsSender extends RunListener {
|
||||
if (!matcher.matches()) {
|
||||
matcher = Pattern.compile("expected same:<(.*)> was not:<(.*)>", Pattern.DOTALL).matcher(message);
|
||||
}
|
||||
if (!matcher.matches()) {
|
||||
matcher = Pattern.compile("expected:<(.*)> but was:<(.*)>", Pattern.DOTALL).matcher(message);
|
||||
}
|
||||
if (matcher.matches()) {
|
||||
return ComparisonDetailsExtractor
|
||||
.create(assertion, matcher.group(1).replaceAll("\\\\n", "\n"), matcher.group(2).replaceAll("\\\\n", "\n"));
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.jetbrains.idea.svn;
|
||||
|
||||
import com.intellij.lifecycle.AtomicSectionsAware;
|
||||
import com.intellij.lifecycle.PeriodicalTasksCloser;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.ProjectComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
@@ -40,7 +41,6 @@ import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.StringLenComparator;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -477,18 +477,9 @@ class SvnFileUrlMappingImpl implements SvnFileUrlMapping, PersistentStateCompone
|
||||
String convertedPath = currentPath.getAbsolutePath();
|
||||
convertedPath = (currentPath.isDirectory() && (! convertedPath.endsWith(File.separator))) ? convertedPath + File.separator :
|
||||
convertedPath;
|
||||
final List<String> paths;
|
||||
synchronized (myMonitor) {
|
||||
paths = new ArrayList<String>(myMapping.getFileRoots());
|
||||
return myMapping.getRootForPath(convertedPath);
|
||||
}
|
||||
Collections.sort(paths, StringLenComparator.getDescendingInstance());
|
||||
|
||||
for (String path : paths) {
|
||||
if (FileUtil.startsWith(convertedPath, path)) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public VirtualFile[] getNotFilteredRoots() {
|
||||
@@ -528,26 +519,30 @@ class SvnFileUrlMappingImpl implements SvnFileUrlMapping, PersistentStateCompone
|
||||
}
|
||||
|
||||
public void loadState(final SvnMappingSavedPart state) {
|
||||
final SvnMapping mapping = new SvnMapping();
|
||||
final SvnMapping realMapping = new SvnMapping();
|
||||
|
||||
((ProjectLevelVcsManagerImpl) ProjectLevelVcsManager.getInstance(myProject)).addInitializationRequest(
|
||||
VcsInitObject.AFTER_COMMON, new DumbAwareRunnable() {
|
||||
public void run() {
|
||||
try {
|
||||
fillMapping(mapping, state.getMappingRoots());
|
||||
fillMapping(realMapping, state.getMoreRealMappingRoots());
|
||||
} catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
LOG.info(t);
|
||||
return;
|
||||
}
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final SvnMapping mapping = new SvnMapping();
|
||||
final SvnMapping realMapping = new SvnMapping();
|
||||
try {
|
||||
fillMapping(mapping, state.getMappingRoots());
|
||||
fillMapping(realMapping, state.getMoreRealMappingRoots());
|
||||
} catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
LOG.info(t);
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (myMonitor) {
|
||||
myMapping.copyFrom(mapping);
|
||||
myMoreRealMapping.copyFrom(realMapping);
|
||||
}
|
||||
synchronized (myMonitor) {
|
||||
myMapping.copyFrom(mapping);
|
||||
myMoreRealMapping.copyFrom(realMapping);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,25 +15,25 @@
|
||||
*/
|
||||
package org.jetbrains.idea.svn;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
public class SvnMapping {
|
||||
private final List<VirtualFile> myLonelyRoots;
|
||||
private final Map<String, RootUrlInfo> myFile2UrlMap;
|
||||
private final TreeMap<String, RootUrlInfo> myFile2UrlMap;
|
||||
private final Map<String, RootUrlInfo> myUrl2FileMap;
|
||||
//private final List<VirtualFile> myPhysicalCopies;
|
||||
private boolean myRootsDifferFromSettings;
|
||||
// no additional info. for caching only (convert roots)
|
||||
private List<VirtualFile> myPreCalculatedUnderVcsRoots;
|
||||
|
||||
public SvnMapping() {
|
||||
myFile2UrlMap = new HashMap<String, RootUrlInfo>();
|
||||
myFile2UrlMap = new TreeMap<String, RootUrlInfo>(FilePathsComparator.getInstance());
|
||||
myUrl2FileMap = new HashMap<String, RootUrlInfo>();
|
||||
myLonelyRoots = new ArrayList<VirtualFile>();
|
||||
//myPhysicalCopies = new ArrayList<VirtualFile>();
|
||||
|
||||
myPreCalculatedUnderVcsRoots = null;
|
||||
|
||||
@@ -44,12 +44,10 @@ public class SvnMapping {
|
||||
myFile2UrlMap.clear();
|
||||
myUrl2FileMap.clear();
|
||||
myLonelyRoots.clear();
|
||||
//myPhysicalCopies.clear();
|
||||
|
||||
myFile2UrlMap.putAll(other.myFile2UrlMap);
|
||||
myUrl2FileMap.putAll(other.myUrl2FileMap);
|
||||
myLonelyRoots.addAll(other.myLonelyRoots);
|
||||
//myPhysicalCopies.addAll(other.myPhysicalCopies);
|
||||
myRootsDifferFromSettings = other.myRootsDifferFromSettings;
|
||||
myPreCalculatedUnderVcsRoots = null;
|
||||
}
|
||||
@@ -76,13 +74,6 @@ public class SvnMapping {
|
||||
myUrl2FileMap.put(rootInfo.getAbsoluteUrl(), rootInfo);
|
||||
}
|
||||
|
||||
/*
|
||||
// todo check called. dont forget
|
||||
public void setPhysicalCopies(final List<VirtualFile> roots) {
|
||||
myPhysicalCopies.clear();
|
||||
myPhysicalCopies.addAll(roots);
|
||||
}*/
|
||||
|
||||
public List<VirtualFile> getUnderVcsRoots() {
|
||||
if (myPreCalculatedUnderVcsRoots == null) {
|
||||
myPreCalculatedUnderVcsRoots = new ArrayList<VirtualFile>();
|
||||
@@ -97,8 +88,9 @@ public class SvnMapping {
|
||||
return new ArrayList<RootUrlInfo>(myFile2UrlMap.values());
|
||||
}
|
||||
|
||||
public Collection<String> getFileRoots() {
|
||||
return myFile2UrlMap.keySet();
|
||||
@Nullable
|
||||
public String getRootForPath(final String path) {
|
||||
return myFile2UrlMap.floorKey(path);
|
||||
}
|
||||
|
||||
public Collection<String> getUrls() {
|
||||
@@ -117,10 +109,6 @@ public class SvnMapping {
|
||||
return myUrl2FileMap.isEmpty();
|
||||
}
|
||||
|
||||
/*public List<VirtualFile> getPhysicalCopies() {
|
||||
return myPhysicalCopies;
|
||||
}*/
|
||||
|
||||
public boolean isRootsDifferFromSettings() {
|
||||
return myRootsDifferFromSettings;
|
||||
}
|
||||
@@ -132,4 +120,17 @@ public class SvnMapping {
|
||||
public List<VirtualFile> getLonelyRoots() {
|
||||
return myLonelyRoots;
|
||||
}
|
||||
|
||||
private static class FilePathsComparator implements Comparator<String> {
|
||||
private final static FilePathsComparator ourInstance = new FilePathsComparator();
|
||||
|
||||
public static FilePathsComparator getInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
return FileUtil.comparePaths(o1, o2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,17 +22,13 @@ import com.intellij.lang.Language;
|
||||
import com.intellij.lang.html.HTMLLanguage;
|
||||
import com.intellij.lang.xml.XMLLanguage;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.psi.XmlElementVisitor;
|
||||
import com.intellij.psi.html.HtmlTag;
|
||||
import com.intellij.psi.xml.XmlChildRole;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.xml.XmlBundle;
|
||||
@@ -119,15 +115,8 @@ public class CheckEmptyTagInspection extends XmlSuppressableInspectionTool {
|
||||
if (psiFile == null) return;
|
||||
ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(psiFile.getVirtualFile());
|
||||
|
||||
final StringBuilder builder = new StringBuilder(tag.getText());
|
||||
builder.replace(builder.length() - 2, builder.length(), "></" + tag.getLocalName() + ">");
|
||||
|
||||
try {
|
||||
final FileType fileType = psiFile.getFileType();
|
||||
PsiFile file = PsiFileFactory.getInstance(tag.getProject()).createFileFromText(
|
||||
"dummy." + (fileType == StdFileTypes.JSP || tag.getContainingFile().getLanguage() == HTMLLanguage.INSTANCE ? "html" : "xml"), builder.toString());
|
||||
|
||||
tag.replace(((XmlFile)file).getDocument().getRootTag());
|
||||
XmlUtil.expandTag(tag);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
|
||||
@@ -53,6 +53,8 @@ import com.intellij.psi.filters.ElementFilter;
|
||||
import com.intellij.psi.filters.XmlTagFilter;
|
||||
import com.intellij.psi.filters.position.FilterPattern;
|
||||
import com.intellij.psi.impl.source.html.HtmlDocumentImpl;
|
||||
import com.intellij.psi.impl.source.tree.CompositeElement;
|
||||
import com.intellij.psi.impl.source.tree.LeafElement;
|
||||
import com.intellij.psi.impl.source.xml.XmlEntityRefImpl;
|
||||
import com.intellij.psi.scope.processor.FilterElementProcessor;
|
||||
import com.intellij.psi.search.PsiElementProcessor;
|
||||
@@ -587,6 +589,37 @@ public class XmlUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void expandTag(@NotNull XmlTag tag) {
|
||||
XmlTag newTag = XmlElementFactory.getInstance(tag.getProject()).createTagFromText('<' + tag.getName() + "></" + tag.getName() + '>');
|
||||
|
||||
ASTNode node = tag.getNode();
|
||||
if (!(node instanceof CompositeElement)) return;
|
||||
CompositeElement compositeElement = (CompositeElement)node;
|
||||
|
||||
final LeafElement emptyTagEnd = (LeafElement)XmlChildRole.EMPTY_TAG_END_FINDER.findChild(compositeElement);
|
||||
if (emptyTagEnd == null) return;
|
||||
|
||||
compositeElement.removeChild(emptyTagEnd);
|
||||
PsiElement[] children = newTag.getChildren();
|
||||
|
||||
compositeElement.addChildren(children[2].getNode(), null, null);
|
||||
}
|
||||
//
|
||||
//public static void expandTag(@NotNull XmlTag tag) {
|
||||
// final LeafElement emptyTagEnd = (LeafElement)XmlChildRole.EMPTY_TAG_END_FINDER.findChild(tag.getNode());
|
||||
// if (emptyTagEnd == null) return;
|
||||
//
|
||||
// PsiFile file = tag.getContainingFile().getOriginalFile();
|
||||
//
|
||||
// TextRange textRange = emptyTagEnd.getTextRange();
|
||||
// Document document = file.getViewProvider().getDocument();
|
||||
// if (document == null) return;
|
||||
//
|
||||
// PsiDocumentManager.getInstance(file.getProject()).commitDocument(document);
|
||||
// document.replaceString(textRange.getStartOffset(), textRange.getEndOffset(), "></" + tag.getName() + '>');
|
||||
// PsiDocumentManager.getInstance(file.getProject()).commitDocument(document);
|
||||
//}
|
||||
|
||||
private static class XmlElementProcessor {
|
||||
private final PsiElementProcessor processor;
|
||||
private final PsiFile targetFile;
|
||||
|
||||
Reference in New Issue
Block a user