Merge branch 'master' of git@git.labs.intellij.net:idea/community

This commit is contained in:
Kirill Kalishev
2011-05-17 19:53:22 +04:00
96 changed files with 1771 additions and 761 deletions
@@ -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;
@@ -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();
}
@@ -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;
}
@@ -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);
@@ -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;
}
}
@@ -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);
}
}
}
@@ -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));
}
@@ -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;
}
}
}
@@ -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;
}
@@ -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);
@@ -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();
@@ -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());
}
}
}
}
}
}
@@ -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;
@@ -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() {
@@ -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);
@@ -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) {
@@ -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) {
@@ -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"})
@@ -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");
@@ -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 {
@@ -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) {
@@ -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) {
}
@@ -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);
@@ -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) {
}
@@ -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) {
}
@@ -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) {
}
@@ -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);
}
@@ -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);
}
}
@@ -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");
}
+6 -9
View File
@@ -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));
}
}
}
@@ -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();
}
@@ -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;
@@ -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)) {
@@ -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 {
@@ -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) {
@@ -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() {
@@ -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));
}
}
}
@@ -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();
}
}
@@ -94,7 +94,7 @@ public abstract class AbstractInjectionPanel<T extends BaseInjection> implements
for (Field panel : myOtherPanels) {
getField(panel).apply();
}
myOrigInjection.generatePlaces();
myEditCopy.copyFrom(myOrigInjection);
}
@@ -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);
@@ -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) {
@@ -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) {
@@ -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 {
+1
View File
@@ -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();
}
@@ -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">
@@ -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();
}
@@ -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;