mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' of git@git.labs.intellij.net:idea/community
This commit is contained in:
+3
-1
@@ -97,7 +97,9 @@ public class SmartStepIntoActionHandler extends DebuggerActionHandler {
|
||||
}
|
||||
|
||||
final Document doc = FileDocumentManager.getInstance().getDocument(vFile);
|
||||
|
||||
if (line >= doc.getLineCount()) {
|
||||
return Collections.emptyList(); // the document has been changed
|
||||
}
|
||||
final int startOffset = doc.getLineStartOffset(line);
|
||||
final TextRange lineRange = new TextRange(startOffset, doc.getLineEndOffset(line));
|
||||
final int offset = CharArrayUtil.shiftForward(doc.getCharsSequence(), startOffset, " \t");
|
||||
|
||||
@@ -505,7 +505,7 @@ public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvi
|
||||
|
||||
if (thisObjectReference != null && evaluationContext.getDebugProcess().getVirtualMachineProxy().canGetSyntheticAttribute()) {
|
||||
final ReferenceType thisRefType = thisObjectReference.referenceType();
|
||||
if (thisRefType instanceof ClassType && thisRefType.name().contains("$")) { // makes sense for nested classes only
|
||||
if (thisRefType instanceof ClassType && thisRefType.equals(location.declaringType()) && thisRefType.name().contains("$")) { // makes sense for nested classes only
|
||||
final ClassType clsType = (ClassType)thisRefType;
|
||||
for (Field field : clsType.fields()) {
|
||||
if (field.isSynthetic() && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) {
|
||||
|
||||
@@ -21,12 +21,14 @@ import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
|
||||
import com.intellij.debugger.engine.DebuggerUtils;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContext;
|
||||
import com.intellij.debugger.engine.jdi.StackFrameProxy;
|
||||
import com.intellij.debugger.ui.impl.watch.FieldDescriptorImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.MessageDescriptor;
|
||||
import com.intellij.debugger.ui.impl.watch.NodeManagerImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
|
||||
import com.intellij.debugger.ui.tree.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.DefaultJDOMExternalizer;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
@@ -171,8 +173,16 @@ public class ClassRenderer extends NodeRendererImpl{
|
||||
return false;
|
||||
}
|
||||
if (isSynthetic) {
|
||||
if (objInstance.equals(context.getThisObject()) && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) {
|
||||
return false;
|
||||
try {
|
||||
final StackFrameProxy frameProxy = context.getFrameProxy();
|
||||
if (frameProxy != null) {
|
||||
final Location location = frameProxy.location();
|
||||
if (location != null && objInstance.equals(context.getThisObject()) && Comparing.equal(objInstance.referenceType(), location.declaringType()) && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (EvaluateException ignored) {
|
||||
}
|
||||
}
|
||||
if(!SHOW_STATIC && field.isStatic()) {
|
||||
|
||||
+14
-17
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.roots.ui.configuration;
|
||||
|
||||
import com.intellij.ide.ui.ListCellRendererWrapper;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
@@ -22,7 +23,6 @@ import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
@@ -34,30 +34,27 @@ public class LanguageLevelCombo extends ComboBox {
|
||||
for (LanguageLevel level : LanguageLevel.values()) {
|
||||
addItem(level);
|
||||
}
|
||||
setRenderer(new MyDefaultListCellRenderer());
|
||||
setRenderer(new ListCellRendererWrapper(getRenderer()) {
|
||||
@Override
|
||||
public void customize(final JList list, final Object value, final int index, final boolean selected, final boolean hasFocus) {
|
||||
if (value instanceof LanguageLevel) {
|
||||
setText(((LanguageLevel)value).getPresentableText());
|
||||
}
|
||||
else if (value instanceof String) {
|
||||
setText((String)value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void reset(Project project){
|
||||
public void reset(Project project) {
|
||||
setSelectedItem(LanguageLevelProjectExtension.getInstance(project).getLanguageLevel());
|
||||
}
|
||||
|
||||
public void setSelectedItem(Object anObject) {
|
||||
if (anObject == null){
|
||||
if (anObject == null) {
|
||||
anObject = USE_PROJECT_LANGUAGE_LEVEL;
|
||||
}
|
||||
super.setSelectedItem(anObject);
|
||||
}
|
||||
|
||||
private static class MyDefaultListCellRenderer extends DefaultListCellRenderer {
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
if (value instanceof LanguageLevel) {
|
||||
setText(((LanguageLevel)value).getPresentableText());
|
||||
}
|
||||
else if (value instanceof String) {
|
||||
setText((String)value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -108,7 +108,6 @@ public class ProjectJdkConfigurable implements UnnamedConfigurable {
|
||||
myCbProjectJdk.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (myFreeze) return;
|
||||
final Sdk oldJdk = myJdksModel.getProjectSdk();
|
||||
myJdksModel.setProjectSdk(myCbProjectJdk.getSelectedJdk());
|
||||
clearCaches();
|
||||
}
|
||||
|
||||
+7
-13
@@ -20,8 +20,6 @@ import com.intellij.codeInsight.lookup.*;
|
||||
import com.intellij.codeInsight.template.SmartCompletionContextType;
|
||||
import com.intellij.codeInsight.template.impl.TemplateImpl;
|
||||
import com.intellij.codeInsight.template.impl.TemplateSettings;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.patterns.PsiJavaPatterns;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.filters.getters.ClassLiteralGetter;
|
||||
@@ -52,17 +50,13 @@ public class BasicExpressionCompletionContributor extends ExpressionSmartComplet
|
||||
}
|
||||
|
||||
public static LookupElement createKeywordLookupItem(final PsiElement element, final String s) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<LookupItem>() {
|
||||
public LookupItem compute() {
|
||||
try {
|
||||
final PsiKeyword keyword = JavaPsiFacade.getInstance(element.getProject()).getElementFactory().createKeyword(s);
|
||||
return new KeywordLookupItem(keyword, element).setAutoCompletionPolicy(AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
try {
|
||||
final PsiKeyword keyword = JavaPsiFacade.getInstance(element.getProject()).getElementFactory().createKeyword(s);
|
||||
return new KeywordLookupItem(keyword, element).setAutoCompletionPolicy(AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+57
-6
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupItem;
|
||||
import com.intellij.codeInsight.lookup.LookupItemUtil;
|
||||
import com.intellij.codeInsight.lookup.TailTypeDecorator;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.filters.ContextGetter;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
@@ -32,6 +33,45 @@ import java.util.Set;
|
||||
*/
|
||||
public class JavaAwareCompletionData extends CompletionData{
|
||||
|
||||
@NotNull
|
||||
static TailType analyzeItem(final Object completion, final PsiElement position) {
|
||||
if(completion instanceof PsiKeyword){
|
||||
final String text = ((PsiKeyword)completion).getText();
|
||||
if(PsiKeyword.BREAK.equals(text) || PsiKeyword.CONTINUE.equals(text)) {
|
||||
PsiElement scope = position;
|
||||
while(true){
|
||||
if (scope instanceof PsiFile || scope instanceof PsiMethod || scope instanceof PsiClassInitializer){
|
||||
return TailType.SEMICOLON;
|
||||
}
|
||||
|
||||
if (scope instanceof PsiLabeledStatement){
|
||||
return TailType.NONE;
|
||||
}
|
||||
scope = scope.getParent();
|
||||
}
|
||||
}
|
||||
if(PsiKeyword.RETURN.equals(text)){
|
||||
PsiElement scope = position;
|
||||
while(true){
|
||||
if (scope instanceof PsiFile || scope instanceof PsiClassInitializer){
|
||||
return TailType.NONE;
|
||||
}
|
||||
|
||||
if (scope instanceof PsiMethod){
|
||||
final PsiMethod method = (PsiMethod)scope;
|
||||
if(method.isConstructor() || PsiType.VOID.equals(method.getReturnType())) {
|
||||
return TailType.SEMICOLON;
|
||||
}
|
||||
|
||||
return TailType.SPACE;
|
||||
}
|
||||
scope = scope.getParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
return TailType.NONE;
|
||||
}
|
||||
|
||||
protected void addLookupItem(Set<LookupElement> set, TailType tailType, @NotNull Object completion, final PsiFile file, final CompletionVariant variant) {
|
||||
if (completion instanceof LookupElement && !(completion instanceof LookupItem)) {
|
||||
set.add((LookupElement)completion);
|
||||
@@ -44,18 +84,29 @@ public class JavaAwareCompletionData extends CompletionData{
|
||||
LookupItem ret = (LookupItem)_ret;
|
||||
final InsertHandler insertHandler = variant.getInsertHandler();
|
||||
if(insertHandler != null && ret.getInsertHandler() == null) {
|
||||
ret.setInsertHandler(insertHandler);
|
||||
ret.setTailType(TailType.UNKNOWN);
|
||||
}
|
||||
else if (tailType != TailType.NONE) {
|
||||
ret.setTailType(tailType);
|
||||
}
|
||||
ret.setInsertHandler(new InsertHandler<LookupElement>() {
|
||||
@Override
|
||||
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||
final TailType type = analyzeItem(item.getObject(), context.getFile().findElementAt(context.getStartOffset()));
|
||||
new DefaultInsertHandler().handleInsert(context, item);
|
||||
if (type != TailType.NONE) {
|
||||
context.setAddCompletionChar(false);
|
||||
type.processTail(context.getEditor(), context.getTailOffset());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
final Map<Object, Object> itemProperties = variant.getItemProperties();
|
||||
for (final Object key : itemProperties.keySet()) {
|
||||
ret.setAttribute(key, itemProperties.get(key));
|
||||
}
|
||||
set.add(ret);
|
||||
|
||||
if ((insertHandler == null || ret.getInsertHandler() != null) && tailType != TailType.NONE) {
|
||||
set.add(TailTypeDecorator.withTail(ret, tailType));
|
||||
} else {
|
||||
set.add(ret);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addKeywords(final Set<LookupElement> set, final PsiElement position, final PrefixMatcher matcher, final PsiFile file,
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.TailTypes;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFix;
|
||||
import com.intellij.codeInsight.hint.ShowParameterInfoHandler;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
@@ -250,15 +249,6 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
completionData.fillCompletions(parameters, result);
|
||||
|
||||
for (final LookupElement item : lookupSet) {
|
||||
if (item instanceof LookupItem && ((LookupItem)item).getInsertHandler() == null) {
|
||||
((LookupItem)item).setInsertHandler(new InsertHandler() {
|
||||
public void handleInsert(final InsertionContext context, final LookupElement item) {
|
||||
analyzeItem((LookupItem)item, item.getObject(), parameters.getPosition());
|
||||
new DefaultInsertHandler().handleInsert(context, item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
result.addElement(item);
|
||||
}
|
||||
|
||||
@@ -469,54 +459,6 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
return parent.getParent() instanceof PsiTypeElement || parent.getParent() instanceof PsiExpressionStatement || parent.getParent() instanceof PsiReferenceList;
|
||||
}
|
||||
|
||||
public static void analyzeItem(final LookupItem item, final Object completion, final PsiElement position) {
|
||||
if(completion instanceof PsiKeyword){
|
||||
if(PsiKeyword.BREAK.equals(((PsiKeyword)completion).getText())
|
||||
|| PsiKeyword.CONTINUE.equals(((PsiKeyword)completion).getText())){
|
||||
PsiElement scope = position;
|
||||
while(true){
|
||||
if (scope instanceof PsiFile
|
||||
|| scope instanceof PsiMethod
|
||||
|| scope instanceof PsiClassInitializer){
|
||||
item.setTailType(TailType.SEMICOLON);
|
||||
break;
|
||||
}
|
||||
else if (scope instanceof PsiLabeledStatement){
|
||||
item.setTailType(TailType.NONE);
|
||||
break;
|
||||
}
|
||||
scope = scope.getParent();
|
||||
}
|
||||
}
|
||||
if(PsiKeyword.RETURN.equals(((PsiKeyword)completion).getText())){
|
||||
PsiElement scope = position;
|
||||
while(true){
|
||||
if (scope instanceof PsiFile
|
||||
|| scope instanceof PsiClassInitializer){
|
||||
item.setTailType(TailType.NONE);
|
||||
break;
|
||||
}
|
||||
else if (scope instanceof PsiMethod){
|
||||
final PsiMethod method = (PsiMethod)scope;
|
||||
if(method.isConstructor() || PsiType.VOID.equals(method.getReturnType())) {
|
||||
item.setTailType(TailType.SEMICOLON);
|
||||
}
|
||||
else item.setTailType(TailType.SPACE);
|
||||
|
||||
break;
|
||||
}
|
||||
scope = scope.getParent();
|
||||
}
|
||||
}
|
||||
if(PsiKeyword.SYNCHRONIZED.equals(((PsiKeyword)completion).getText())){
|
||||
if (PsiTreeUtil.getParentOfType(position, PsiMember.class, PsiCodeBlock.class) instanceof PsiCodeBlock){
|
||||
item.setTailType(TailTypes.SYNCHRONIZED_LPARENTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void beforeCompletion(@NotNull final CompletionInitializationContext context) {
|
||||
final PsiFile file = context.getFile();
|
||||
|
||||
|
||||
@@ -541,6 +541,7 @@ public class JavaCompletionData extends JavaAwareCompletionData{
|
||||
variant.addCompletion(PsiKeyword.RETURN, TailType.SPACE);
|
||||
variant.addCompletion(PsiKeyword.NEW, TailType.SPACE);
|
||||
variant.addCompletion(PsiKeyword.ASSERT, TailType.SPACE);
|
||||
variant.addCompletion(PsiKeyword.SYNCHRONIZED, TailTypes.SYNCHRONIZED_LPARENTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -68,7 +68,7 @@ public class ModifierChooser
|
||||
});
|
||||
|
||||
myMap.put(new OrFilter(new ClassFilter(PsiStatement.class), new ClassFilter(PsiCodeBlock.class)), new String[][]{
|
||||
new String[]{"final", "synchronized"}
|
||||
new String[]{"final"}
|
||||
});
|
||||
|
||||
myMap.put(new ClassFilter(PsiParameterList.class), new String[][]{
|
||||
|
||||
+3
-3
@@ -399,7 +399,7 @@ public class HighlightClassUtil {
|
||||
|
||||
static HighlightInfo checkExtendsClassAndImplementsInterface(PsiReferenceList referenceList,
|
||||
JavaResolveResult resolveResult,
|
||||
PsiJavaCodeReferenceElement context) {
|
||||
PsiJavaCodeReferenceElement ref) {
|
||||
PsiClass aClass = (PsiClass)referenceList.getParent();
|
||||
boolean isImplements = referenceList.equals(aClass.getImplementsList());
|
||||
boolean isInterface = aClass.isInterface();
|
||||
@@ -409,10 +409,10 @@ public class HighlightClassUtil {
|
||||
PsiClass extendFrom = (PsiClass)resolveResult.getElement();
|
||||
if (extendFrom.isInterface() != mustBeInterface) {
|
||||
errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR,
|
||||
context,
|
||||
ref,
|
||||
mustBeInterface ? INTERFACE_EXPECTED : NO_INTERFACE_EXPECTED);
|
||||
PsiClassType type =
|
||||
JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(extendFrom, resolveResult.getSubstitutor());
|
||||
JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(ref);
|
||||
QuickFixAction.registerQuickFixAction(errorResult, new ChangeExtendsToImplementsFix(aClass, type));
|
||||
}
|
||||
return errorResult;
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ public abstract class CreateConstructorFromThisOrSuperFix extends CreateFromUsag
|
||||
|
||||
targetClass = constructor.getContainingClass();
|
||||
myMethodCall = CodeInsightUtil.findElementInRange(psiFile, rangeMarker.getStartOffset(), rangeMarker.getEndOffset(), myMethodCall.getClass());
|
||||
((RangeMarkerEx)rangeMarker).dispose();
|
||||
rangeMarker.dispose();
|
||||
|
||||
Template template = templateBuilder.buildTemplate();
|
||||
final Editor editor = positionCursor(project, targetClass.getContainingFile(), targetClass);
|
||||
|
||||
+1
-1
@@ -229,7 +229,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix {
|
||||
Template template = builder.buildTemplate();
|
||||
newEditor.getCaretModel().moveToOffset(rangeMarker.getStartOffset());
|
||||
newEditor.getDocument().deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset());
|
||||
((RangeMarkerEx)rangeMarker).dispose();
|
||||
rangeMarker.dispose();
|
||||
|
||||
if (!shouldBeAbstract) {
|
||||
startTemplate(newEditor, template, project, new TemplateEditingAdapter() {
|
||||
|
||||
@@ -357,9 +357,9 @@ public class DeclarationParser {
|
||||
|
||||
@NotNull
|
||||
private static PsiBuilder.Marker parseTypeNotNull(final PsiBuilder builder) {
|
||||
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder);
|
||||
assert typeInfo != null : builder.getOriginalText();
|
||||
return typeInfo.marker;
|
||||
final PsiBuilder.Marker type = ReferenceParser.parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
|
||||
assert type != null : builder.getOriginalText();
|
||||
return type;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -399,14 +399,7 @@ public class DeclarationParser {
|
||||
final boolean anno, final boolean constructor) {
|
||||
parseParameterList(builder);
|
||||
|
||||
if (constructor && builder.getTokenType() == JavaTokenType.LBRACKET) {
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
eatBrackets(builder, false);
|
||||
marker.error(JavaErrorMessages.message("expected.semicolon"));
|
||||
}
|
||||
else {
|
||||
eatBrackets(builder, true);
|
||||
}
|
||||
eatBrackets(builder, constructor, JavaErrorMessages.message("expected.semicolon"));
|
||||
|
||||
if (areTypeAnnotationsSupported(builder)) {
|
||||
final PsiBuilder.Marker receiver = builder.mark();
|
||||
@@ -544,21 +537,23 @@ public class DeclarationParser {
|
||||
final PsiBuilder.Marker param = builder.mark();
|
||||
|
||||
final Pair<PsiBuilder.Marker, Boolean> modListInfo = parseModifierList(builder);
|
||||
final PsiBuilder.Marker type = ellipsis ? ReferenceParser.parseTypeWithEllipsis(builder, true, true) :
|
||||
ReferenceParser.parseType(builder, true, true, false);
|
||||
|
||||
if (type == null && modListInfo.second) {
|
||||
int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD;
|
||||
if (ellipsis) flags |= ReferenceParser.ELLIPSIS;
|
||||
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseTypeInfo(builder, flags);
|
||||
|
||||
if (typeInfo == null && modListInfo.second) {
|
||||
param.rollbackTo();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
if (typeInfo == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.type"));
|
||||
emptyElement(builder, JavaElementType.TYPE);
|
||||
}
|
||||
|
||||
if (expect(builder, JavaTokenType.IDENTIFIER)) {
|
||||
eatBrackets(builder, true);
|
||||
eatBrackets(builder, typeInfo != null && typeInfo.isVarArg, JavaErrorMessages.message("expected.rparen"));
|
||||
done(param, JavaElementType.PARAMETER);
|
||||
return param;
|
||||
}
|
||||
@@ -593,7 +588,7 @@ public class DeclarationParser {
|
||||
while (true) {
|
||||
shouldRollback = true;
|
||||
|
||||
if (!eatBrackets(builder, true)) {
|
||||
if (!eatBrackets(builder, false, null)) {
|
||||
unclosed = true;
|
||||
}
|
||||
|
||||
@@ -655,14 +650,25 @@ public class DeclarationParser {
|
||||
return declaration;
|
||||
}
|
||||
|
||||
private static boolean eatBrackets(final PsiBuilder builder, final boolean withError) {
|
||||
private static boolean eatBrackets(final PsiBuilder builder, final boolean isError, @Nullable final String error) {
|
||||
if (builder.getTokenType() != JavaTokenType.LBRACKET) return true;
|
||||
|
||||
final PsiBuilder.Marker marker = isError ? builder.mark() : null;
|
||||
|
||||
boolean result = true;
|
||||
while (expect(builder, JavaTokenType.LBRACKET)) {
|
||||
if (!expect(builder, JavaTokenType.RBRACKET)) {
|
||||
if (withError) error(builder, JavaErrorMessages.message("expected.rbracket"));
|
||||
return false;
|
||||
if (!isError) error(builder, JavaErrorMessages.message("expected.rbracket"));
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
if (marker != null) {
|
||||
marker.error(error);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -161,8 +161,7 @@ public class ExpressionParser {
|
||||
return parseUnary(builder);
|
||||
|
||||
case TYPE:
|
||||
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder);
|
||||
return typeInfo != null ? typeInfo.marker : null;
|
||||
return ReferenceParser.parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
|
||||
|
||||
default:
|
||||
assert false : "Unexpected type: " + type;
|
||||
@@ -255,7 +254,7 @@ public class ExpressionParser {
|
||||
final PsiBuilder.Marker typeCast = builder.mark();
|
||||
builder.advanceLexer();
|
||||
|
||||
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseType(builder);
|
||||
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseTypeInfo(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
|
||||
|
||||
if (typeInfo == null || builder.getTokenType() != JavaTokenType.RPARENTH) {
|
||||
typeCast.rollbackTo();
|
||||
@@ -733,8 +732,7 @@ public class ExpressionParser {
|
||||
private static PsiBuilder.Marker parseClassObjectAccess(final PsiBuilder builder) {
|
||||
final PsiBuilder.Marker expr = builder.mark();
|
||||
|
||||
final PsiBuilder.Marker type = ReferenceParser.parseType(builder, false, false, false);
|
||||
if (type == null) {
|
||||
if (ReferenceParser.parseType(builder, 0) == null) {
|
||||
expr.drop();
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -32,10 +32,16 @@ import static com.intellij.lang.java.parser.JavaParserUtil.emptyElement;
|
||||
|
||||
|
||||
public class ReferenceParser {
|
||||
public static final int EAT_LAST_DOT = 0x01;
|
||||
public static final int ELLIPSIS = 0x02;
|
||||
public static final int WILDCARD = 0x04;
|
||||
public static final int DIAMONDS = 0x08;
|
||||
|
||||
public static class TypeInfo {
|
||||
public boolean isPrimitive = false;
|
||||
public boolean isParameterized = false;
|
||||
public boolean isArray = false;
|
||||
public boolean isVarArg = false;
|
||||
public boolean hasErrors = false;
|
||||
public PsiBuilder.Marker marker = null;
|
||||
}
|
||||
@@ -45,33 +51,19 @@ public class ReferenceParser {
|
||||
private ReferenceParser() { }
|
||||
|
||||
@Nullable
|
||||
public static TypeInfo parseType(final PsiBuilder builder) {
|
||||
return parseTypeWithInfo(builder, true, true, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiBuilder.Marker parseType(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard, final boolean diamonds) {
|
||||
final TypeInfo typeInfo = parseTypeWithInfo(builder, eatLastDot, wildcard, diamonds);
|
||||
public static PsiBuilder.Marker parseType(final PsiBuilder builder, final int flags) {
|
||||
final TypeInfo typeInfo = parseTypeInfo(builder, flags);
|
||||
return typeInfo != null ? typeInfo.marker : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiBuilder.Marker parseTypeWithEllipsis(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard) {
|
||||
final TypeInfo typeInfo = parseTypeWithInfo(builder, eatLastDot, wildcard, false);
|
||||
if (typeInfo == null) return null;
|
||||
|
||||
PsiBuilder.Marker type = typeInfo.marker;
|
||||
if (builder.getTokenType() == JavaTokenType.ELLIPSIS) {
|
||||
type = typeInfo.marker.precede();
|
||||
builder.advanceLexer();
|
||||
type.done(JavaElementType.TYPE);
|
||||
}
|
||||
|
||||
return type;
|
||||
public static TypeInfo parseTypeInfo(final PsiBuilder builder, final int flags) {
|
||||
return parseTypeInfo(builder, isSet(flags, EAT_LAST_DOT), isSet(flags, WILDCARD), isSet(flags, DIAMONDS), isSet(flags, ELLIPSIS));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TypeInfo parseTypeWithInfo(final PsiBuilder builder, final boolean eatLastDot, final boolean wildcard, final boolean diamonds) {
|
||||
private static TypeInfo parseTypeInfo(final PsiBuilder builder,
|
||||
final boolean eatLastDot, final boolean wildcard, final boolean diamonds, final boolean ellipsis) {
|
||||
if (builder.getTokenType() == null) return null;
|
||||
|
||||
final TypeInfo typeInfo = new TypeInfo();
|
||||
@@ -126,18 +118,28 @@ public class ReferenceParser {
|
||||
type = type.precede();
|
||||
}
|
||||
|
||||
if (ellipsis && builder.getTokenType() == JavaTokenType.ELLIPSIS) {
|
||||
type = type.precede();
|
||||
builder.advanceLexer();
|
||||
type.done(JavaElementType.TYPE);
|
||||
typeInfo.isVarArg = true;
|
||||
}
|
||||
|
||||
typeInfo.marker = type;
|
||||
return typeInfo;
|
||||
}
|
||||
|
||||
private static boolean isSet(final int mask, final int flag) {
|
||||
return (mask & flag) != 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiBuilder.Marker parseWildcardType(final PsiBuilder builder) {
|
||||
final PsiBuilder.Marker type = builder.mark();
|
||||
builder.advanceLexer();
|
||||
|
||||
if (expect(builder, WILDCARD_KEYWORD_SET)) {
|
||||
final PsiBuilder.Marker boundType = parseType(builder, true, false, false);
|
||||
if (boundType == null) {
|
||||
if (parseTypeInfo(builder, EAT_LAST_DOT) == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.type"));
|
||||
}
|
||||
}
|
||||
@@ -248,8 +250,7 @@ public class ReferenceParser {
|
||||
|
||||
boolean isOk = true;
|
||||
while (true) {
|
||||
final PsiBuilder.Marker type = parseType(builder, true, wildcard, diamonds);
|
||||
if (type == null) {
|
||||
if (parseTypeInfo(builder, true, wildcard, diamonds, false) == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.identifier"));
|
||||
}
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ public class StatementParser {
|
||||
final PsiBuilder.Marker declStatement = builder.mark();
|
||||
final PsiBuilder.Marker decl = DeclarationParser.parse(builder, DeclarationParser.Context.CODE_BLOCK);
|
||||
if (decl == null) {
|
||||
ReferenceParser.parseType(builder, false, false, false);
|
||||
ReferenceParser.parseType(builder, 0);
|
||||
error(builder, JavaErrorMessages.message("expected.identifier"));
|
||||
}
|
||||
done(declStatement, JavaElementType.DECLARATION_STATEMENT);
|
||||
|
||||
@@ -253,8 +253,8 @@ public interface JavaElementType {
|
||||
return JavaParserUtil.parseFragment(chameleon,
|
||||
new JavaParserUtil.ParserWrapper() {
|
||||
public void parse(final PsiBuilder builder) {
|
||||
ReferenceParser.parseType(builder);
|
||||
expect(builder, JavaTokenType.ELLIPSIS);
|
||||
ReferenceParser.parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
|
||||
expect(builder, JavaTokenType.ELLIPSIS); // todo[r.sh] parse ellipsis and fix PsiTypeCodeFragmentImpl.getType()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+6
-3
@@ -26,8 +26,10 @@ package com.intellij.refactoring.introduceVariable;
|
||||
import com.intellij.codeInsight.CodeInsightUtil;
|
||||
import com.intellij.codeInsight.completion.JavaCompletionUtil;
|
||||
import com.intellij.codeInsight.highlighting.HighlightManager;
|
||||
import com.intellij.codeInsight.intention.impl.TypeExpression;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.codeInsight.template.TemplateBuilderImpl;
|
||||
import com.intellij.codeInsight.template.*;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.lang.LanguageRefactoringSupport;
|
||||
@@ -463,6 +465,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
|
||||
getSettings(project, editor, expr, occurrences, typeSelectorManager, inFinalContext, hasWriteAccess, validator, choice);
|
||||
if (!settings.isOK()) return;
|
||||
typeSelectorManager.setAllOccurences(choice != OccurrencesChooser.ReplaceChoice.NO);
|
||||
final TypeExpression expression = new TypeExpression(project, typeSelectorManager.getTypesForAll());
|
||||
final RangeMarker exprMarker = editor.getDocument().createRangeMarker(expr.getTextRange());
|
||||
final SuggestedNameInfo suggestedName = getSuggestedName(settings.getSelectedType(), expr);
|
||||
final Runnable runnable =
|
||||
@@ -482,8 +485,8 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
|
||||
@Override
|
||||
protected void addAdditionalVariables(TemplateBuilderImpl builder) {
|
||||
final PsiTypeElement typeElement = elementToRename.getTypeElement();
|
||||
builder.replaceElement(typeElement, "Variable_Type", ReassignVariableUtil
|
||||
.createExpression(typeSelectorManager, typeElement.getText()), false, true);
|
||||
builder.replaceElement(typeElement, "Variable_Type",
|
||||
ReassignVariableUtil.createExpression(expression, typeElement.getText()), false, true);
|
||||
}
|
||||
};
|
||||
renamer.setAdvertisementText(
|
||||
|
||||
+21
-24
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
package com.intellij.refactoring.introduceVariable;
|
||||
|
||||
import com.intellij.codeInsight.intention.impl.TypeExpression;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.codeInsight.lookup.PsiTypeLookupItem;
|
||||
@@ -29,6 +30,7 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.VisualPosition;
|
||||
import com.intellij.openapi.keymap.Keymap;
|
||||
import com.intellij.openapi.keymap.KeymapManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.*;
|
||||
@@ -151,30 +153,6 @@ public class ReassignVariableUtil {
|
||||
}
|
||||
}
|
||||
|
||||
static Expression createExpression(final TypeSelectorManagerImpl typeSelectorManager, final String defaultText) {
|
||||
final PsiType[] types = typeSelectorManager.getTypesForAll();
|
||||
return new Expression() {
|
||||
@Override
|
||||
public com.intellij.codeInsight.template.Result calculateResult(ExpressionContext context) {
|
||||
return new TextResult(defaultText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.intellij.codeInsight.template.Result calculateQuickResult(ExpressionContext context) {
|
||||
return new TextResult(defaultText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LookupElement[] calculateLookupItems(ExpressionContext context) {
|
||||
LookupElement[] result = new LookupElement[types.length];
|
||||
for (int i = 0, typesLength = types.length; i < typesLength; i++) {
|
||||
result[i] = PsiTypeLookupItem.createLookupItem(types[i], null);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static String getAdvertisementText(Editor editor, PsiDeclarationStatement declaration, PsiType type, PsiType[] typesForAll) {
|
||||
final VariablesProcessor processor = findVariablesOfType(editor, declaration, type);
|
||||
@@ -187,4 +165,23 @@ public class ReassignVariableUtil {
|
||||
}
|
||||
return typesForAll.length > 1 ? "Press Shift Tab to change type" : null;
|
||||
}
|
||||
|
||||
public static Expression createExpression(final TypeExpression expression, final String defaultType) {
|
||||
return new Expression() {
|
||||
@Override
|
||||
public com.intellij.codeInsight.template.Result calculateResult(ExpressionContext context) {
|
||||
return new TextResult(defaultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.intellij.codeInsight.template.Result calculateQuickResult(ExpressionContext context) {
|
||||
return new TextResult(defaultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LookupElement[] calculateLookupItems(ExpressionContext context) {
|
||||
return expression.calculateLookupItems(context);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +124,33 @@ public class PullUpHelper extends BaseRefactoringProcessor{
|
||||
if (info.isToAbstract() || willBeUsedInSubclass(modifierListOwner, movedMembers, myTargetSuperClass, mySourceClass)) {
|
||||
PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PROTECTED, true);
|
||||
}
|
||||
if (modifierListOwner instanceof PsiClass) {
|
||||
modifierListOwner.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitMethod(PsiMethod method) {
|
||||
check(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitField(PsiField field) {
|
||||
check(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {
|
||||
check(aClass);
|
||||
super.visitClass(aClass);
|
||||
}
|
||||
|
||||
private void check(PsiMember member) {
|
||||
if (member.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
if (willBeUsedInSubclass(member, movedMembers, myTargetSuperClass, mySourceClass)) {
|
||||
PsiUtil.setModifierProperty(member, PsiModifier.PROTECTED, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
ChangeContextUtil.encodeContextInfo(info.getMember(), true);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import java.util.*;
|
||||
* @author dsl
|
||||
*/
|
||||
public class TypeSelectorManagerImpl implements TypeSelectorManager {
|
||||
private SmartTypePointer myPointer;
|
||||
private PsiType myDefaultType;
|
||||
private final PsiExpression myMainOccurence;
|
||||
private final PsiExpression[] myOccurrences;
|
||||
@@ -46,6 +47,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
|
||||
private final boolean myIsOneSuggestion;
|
||||
private TypeSelector myTypeSelector;
|
||||
private final PsiElementFactory myFactory;
|
||||
private final SmartTypePointerManager mySmartTypePointerManager;
|
||||
private ExpectedTypesProvider.ExpectedClassProvider myOccurrenceClassProvider;
|
||||
private ExpectedTypesProvider myExpectedTypesProvider;
|
||||
|
||||
@@ -59,7 +61,8 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
|
||||
|
||||
public TypeSelectorManagerImpl(Project project, PsiType type, PsiExpression[] occurrences, boolean areTypesDirected) {
|
||||
myFactory = JavaPsiFacade.getInstance(project).getElementFactory();
|
||||
myDefaultType = type;
|
||||
mySmartTypePointerManager = SmartTypePointerManager.getInstance(project);
|
||||
setDefaultType(type);
|
||||
myMainOccurence = null;
|
||||
myOccurrences = occurrences;
|
||||
myExpectedTypesProvider = ExpectedTypesProvider.getInstance(project);
|
||||
@@ -83,7 +86,8 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
|
||||
PsiExpression mainOccurence,
|
||||
PsiExpression[] occurrences) {
|
||||
myFactory = JavaPsiFacade.getInstance(project).getElementFactory();
|
||||
myDefaultType = type;
|
||||
mySmartTypePointerManager = SmartTypePointerManager.getInstance(project);
|
||||
setDefaultType(type);
|
||||
myMainOccurence = mainOccurence;
|
||||
myOccurrences = occurrences;
|
||||
myExpectedTypesProvider = ExpectedTypesProvider.getInstance(project);
|
||||
@@ -94,7 +98,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
|
||||
|
||||
if (containingMethod != null) {
|
||||
if (PsiUtil.resolveClassInType(type) != null) {
|
||||
myDefaultType = checkIfTypeAccessible(type, project, containingMethod);
|
||||
setDefaultType(checkIfTypeAccessible(type, project, containingMethod));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +136,15 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
|
||||
}
|
||||
|
||||
public PsiType getDefaultType() {
|
||||
return myDefaultType;
|
||||
if (myDefaultType.isValid()) {
|
||||
return myDefaultType;
|
||||
}
|
||||
return myPointer.getType();
|
||||
}
|
||||
|
||||
public void setDefaultType(PsiType defaultType) {
|
||||
myDefaultType = defaultType;
|
||||
myPointer = mySmartTypePointerManager.createSmartTypePointer(defaultType);
|
||||
}
|
||||
|
||||
private ExpectedTypesProvider.ExpectedClassProvider createOccurrenceClassProvider() {
|
||||
@@ -151,7 +163,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
|
||||
final ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes(myMainOccurence, false, myOccurrenceClassProvider,
|
||||
false);
|
||||
final ArrayList<PsiType> allowedTypes = new ArrayList<PsiType>();
|
||||
RefactoringHierarchyUtil.processSuperTypes(myDefaultType, new RefactoringHierarchyUtil.SuperTypeVisitor() {
|
||||
RefactoringHierarchyUtil.processSuperTypes(getDefaultType(), new RefactoringHierarchyUtil.SuperTypeVisitor() {
|
||||
public void visitType(PsiType aType) {
|
||||
checkIfAllowed(aType);
|
||||
}
|
||||
@@ -193,7 +205,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
|
||||
}
|
||||
|
||||
final ArrayList<PsiType> allowedTypes = new ArrayList<PsiType>();
|
||||
RefactoringHierarchyUtil.processSuperTypes(myDefaultType, new RefactoringHierarchyUtil.SuperTypeVisitor() {
|
||||
RefactoringHierarchyUtil.processSuperTypes(getDefaultType(), new RefactoringHierarchyUtil.SuperTypeVisitor() {
|
||||
public void visitType(PsiType aType) {
|
||||
checkIfAllowed(aType);
|
||||
}
|
||||
@@ -234,18 +246,18 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
|
||||
|
||||
for (int index = 0; index < result.size(); index++) {
|
||||
PsiType psiType = result.get(index);
|
||||
if (psiType.equals(myDefaultType)) {
|
||||
if (psiType.equals(getDefaultType())) {
|
||||
result.remove(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(myDefaultType);
|
||||
final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(getDefaultType());
|
||||
if (unboxedType != null) {
|
||||
result.remove(unboxedType);
|
||||
result.add(0, unboxedType);
|
||||
}
|
||||
result.add(0, myDefaultType);
|
||||
result.add(0, getDefaultType());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -292,7 +304,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
|
||||
}
|
||||
|
||||
private String getStatsKey() {
|
||||
return "IntroduceVariable##" + serialize(myDefaultType);
|
||||
return "IntroduceVariable##" + serialize(getDefaultType());
|
||||
}
|
||||
|
||||
private String serialize(PsiType type) {
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
public class Foooo {
|
||||
|
||||
{
|
||||
int intaaaa;
|
||||
for (in<caret>)
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
public class Foooo {
|
||||
|
||||
{
|
||||
int intaaaa;
|
||||
for (int <caret>)
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Change 'implements b' to 'extends b'" "true"
|
||||
class a extends b<C.D> {
|
||||
}
|
||||
|
||||
class b<T> {}
|
||||
|
||||
class C {
|
||||
static class D {}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Change 'implements b' to 'extends b'" "true"
|
||||
class a implements <caret>b<C.D> {
|
||||
}
|
||||
|
||||
class b<T> {}
|
||||
|
||||
class C {
|
||||
static class D {}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
PsiJavaFile:VarArgBrackets.java
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiMethod:foo
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeParameterList
|
||||
<empty list>
|
||||
PsiTypeElement:void
|
||||
PsiKeyword:void('void')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:foo('foo')
|
||||
PsiParameterList:(int... x[])
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:x
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:int...
|
||||
PsiTypeElement:int
|
||||
PsiKeyword:int('int')
|
||||
PsiJavaToken:ELLIPSIS('...')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:x('x')
|
||||
PsiErrorElement:')' expected
|
||||
PsiJavaToken:LBRACKET('[')
|
||||
PsiJavaToken:RBRACKET(']')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiJavaToken:SEMICOLON(';')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
public class B extends A {
|
||||
private void f(){
|
||||
new C();
|
||||
}
|
||||
<caret>
|
||||
private static class C{
|
||||
private C(){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//A.java
|
||||
class A {
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
public class B extends A {
|
||||
private void f(){
|
||||
new C();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//A.java
|
||||
class A {
|
||||
protected static class C{
|
||||
protected C(){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -620,6 +620,12 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase {
|
||||
public void testPrimitiveTypesInForLoop5() throws Throwable { doPrimitiveTypeTest() }
|
||||
public void testPrimitiveTypesInForLoop6() throws Throwable { doPrimitiveTypeTest() }
|
||||
|
||||
public void testPrimitiveTypesInForLoopSpace() throws Throwable {
|
||||
configure()
|
||||
myFixture.type ' '
|
||||
checkResultByFile(getTestName(false) + "_after.java")
|
||||
}
|
||||
|
||||
public void testSecondInvocationToFillCommonPrefix() throws Throwable {
|
||||
configure()
|
||||
type('a');
|
||||
|
||||
+1
@@ -90,6 +90,7 @@ public class DeclarationParserTest extends JavaParsingTestCase {
|
||||
public void testUnclosed4() { doParserTest("{ void f(int a,, }", false, false); }
|
||||
public void testUnclosed5() { doParserTest("{ void f(int a,); }", false, false); }
|
||||
public void testConstructorBrackets() { doParserTest("{ A() [] { } }", false, false); }
|
||||
public void testVarArgBrackets() { doParserTest("{ void foo(int... x[]); }", false, false); }
|
||||
|
||||
public void testGenericMethod() { doParserTest("{ public static <E> test();\n" +
|
||||
" <E> void test1();\n" +
|
||||
|
||||
+10
-13
@@ -30,18 +30,18 @@ public class ReferenceParserTest extends JavaParsingTestCase {
|
||||
public void testReference1() { doRefParserTest("a.", true); }
|
||||
public void testReference2() { doRefParserTest("a.b", false); }
|
||||
|
||||
public void testType0() { doTypeParserTest("int", false); }
|
||||
public void testType1() { doTypeParserTest("a.b", false); }
|
||||
public void testType2() { doTypeParserTest("int[]", false); }
|
||||
public void testType3() { doTypeParserTest("int[][", false); }
|
||||
public void testType4() { doTypeParserTest("Map<String,List<String>>", false); }
|
||||
public void testType5() { doTypeParserTest("Object[]...", false); }
|
||||
public void testType0() { doTypeParserTest("int"); }
|
||||
public void testType1() { doTypeParserTest("a.b"); }
|
||||
public void testType2() { doTypeParserTest("int[]"); }
|
||||
public void testType3() { doTypeParserTest("int[]["); }
|
||||
public void testType4() { doTypeParserTest("Map<String,List<String>>"); }
|
||||
public void testType5() { doTypeParserTest("Object[]..."); }
|
||||
public void testType6() {
|
||||
withLevel(LanguageLevel.JDK_1_7,
|
||||
new Runnable() { @Override
|
||||
public void run() { doTypeParserTest("@English String @NonEmpty []", false); } });
|
||||
public void run() { doTypeParserTest("@English String @NonEmpty []"); } });
|
||||
}
|
||||
public void testType7() { doTypeParserTest("Diamond<>", true); }
|
||||
public void testType7() { doTypeParserTest("Diamond<>"); }
|
||||
|
||||
public void testTypeParams0() { doTypeParamsParserTest("<T>"); }
|
||||
public void testTypeParams1() { doTypeParamsParserTest("<T, U>"); }
|
||||
@@ -61,14 +61,11 @@ public class ReferenceParserTest extends JavaParsingTestCase {
|
||||
});
|
||||
}
|
||||
|
||||
private void doTypeParserTest(final String text, final boolean diamonds) {
|
||||
private void doTypeParserTest(final String text) {
|
||||
doParserTest(text, new TestParser() {
|
||||
@Override
|
||||
public void parse(final PsiBuilder builder) {
|
||||
if (diamonds)
|
||||
ReferenceParser.parseType(builder, false, false, true);
|
||||
else
|
||||
ReferenceParser.parseTypeWithEllipsis(builder, false, false);
|
||||
ReferenceParser.parseType(builder, ReferenceParser.DIAMONDS | ReferenceParser.ELLIPSIS);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -42,6 +42,10 @@ public class PullUpTest extends LightCodeInsightTestCase {
|
||||
doTest(new RefactoringTestUtil.MemberDescriptor("C", PsiClass.class),
|
||||
new RefactoringTestUtil.MemberDescriptor("D", PsiClass.class));
|
||||
}
|
||||
|
||||
public void testPullUpPrivateInnerClassWithPrivateConstructor() throws Exception {
|
||||
doTest(new RefactoringTestUtil.MemberDescriptor("C", PsiClass.class));
|
||||
}
|
||||
|
||||
public void testPullUpAndAbstractize() throws Exception {
|
||||
doTest(new RefactoringTestUtil.MemberDescriptor("a", PsiMethod.class),
|
||||
|
||||
@@ -140,13 +140,9 @@ public abstract class CompletionService {
|
||||
|
||||
getVariantsFromContributors(parameters, null, new Consumer<LookupElement>() {
|
||||
public void consume(final LookupElement lookupElement) {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
if (lookupSet.add(lookupElement)) {
|
||||
consumer.consume(lookupElement);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (lookupSet.add(lookupElement)) {
|
||||
consumer.consume(lookupElement);
|
||||
}
|
||||
}
|
||||
});
|
||||
return lookupSet.toArray(new LookupElement[lookupSet.size()]);
|
||||
|
||||
@@ -230,7 +230,8 @@ public class PsiTreeUtil {
|
||||
}
|
||||
};
|
||||
|
||||
PsiTreeUtil.processElements(element, processor);
|
||||
processElements(element, processor);
|
||||
//noinspection unchecked
|
||||
return (T)processor.getFoundElement();
|
||||
}
|
||||
|
||||
@@ -238,7 +239,8 @@ public class PsiTreeUtil {
|
||||
public static <T extends PsiElement> T getChildOfType(@Nullable PsiElement element, @NotNull Class<T> aClass) {
|
||||
if (element == null) return null;
|
||||
for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (instanceOf(child, aClass)) {
|
||||
if (aClass.isInstance(child)) {
|
||||
//noinspection unchecked
|
||||
return (T)child;
|
||||
}
|
||||
}
|
||||
@@ -258,8 +260,9 @@ public class PsiTreeUtil {
|
||||
|
||||
List<T> result = null;
|
||||
for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (instanceOf(child, aClass)) {
|
||||
if (aClass.isInstance(child)) {
|
||||
if (result == null) result = new SmartList<T>();
|
||||
//noinspection unchecked
|
||||
result.add((T)child);
|
||||
}
|
||||
}
|
||||
@@ -272,29 +275,16 @@ public class PsiTreeUtil {
|
||||
|
||||
List<T> result = new SmartList<T>();
|
||||
for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (instanceOf(child, aClass)) {
|
||||
if (aClass.isInstance(child)) {
|
||||
//noinspection unchecked
|
||||
result.add((T)child);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static boolean instanceOf(final PsiElement child, final Class... classes) {
|
||||
/*
|
||||
if (aClass == PsiClass.class) return child instanceof PsiClass;
|
||||
else if (aClass == PsiMethod.class) return child instanceof PsiMethod;
|
||||
else if (aClass == PsiField.class) return child instanceof PsiField;
|
||||
else if (aClass == PsiMember.class) return child instanceof PsiMember;
|
||||
else if (aClass == PsiDocCommentOwner.class) return child instanceof PsiDocCommentOwner;
|
||||
else if (aClass == PsiStatement.class) return child instanceof PsiStatement;
|
||||
else if (aClass == PsiCodeBlock.class) return child instanceof PsiCodeBlock;
|
||||
else if (aClass == PsiClassInitializer.class) return child instanceof PsiClassInitializer;
|
||||
else if (aClass == XmlTag.class) return child instanceof XmlTag;
|
||||
else if (aClass == XmlDocument.class) return child instanceof XmlDocument;
|
||||
*/
|
||||
|
||||
for (Class each : classes) {
|
||||
private static boolean instanceOf(final PsiElement child, final Class<?>... classes) {
|
||||
for (final Class<?> each : classes) {
|
||||
if (each.isInstance(child)) return true;
|
||||
}
|
||||
return false;
|
||||
@@ -313,7 +303,10 @@ public class PsiTreeUtil {
|
||||
if (element == null) return null;
|
||||
for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
for (Class<? extends T> aClass : classes) {
|
||||
if (instanceOf(child, aClass)) return (T)child;
|
||||
if (aClass.isInstance(child)) {
|
||||
//noinspection unchecked
|
||||
return (T)child;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -323,7 +316,10 @@ public class PsiTreeUtil {
|
||||
public static <T extends PsiElement> T getNextSiblingOfType(@Nullable PsiElement sibling, @NotNull Class<T> aClass) {
|
||||
if (sibling == null) return null;
|
||||
for (PsiElement child = sibling.getNextSibling(); child != null; child = child.getNextSibling()) {
|
||||
if (instanceOf(child, aClass)) return (T)child;
|
||||
if (aClass.isInstance(child)) {
|
||||
//noinspection unchecked
|
||||
return (T)child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -332,7 +328,10 @@ public class PsiTreeUtil {
|
||||
public static <T extends PsiElement> T getPrevSiblingOfType(@Nullable PsiElement sibling, @NotNull Class<T> aClass) {
|
||||
if (sibling == null) return null;
|
||||
for (PsiElement child = sibling.getPrevSibling(); child != null; child = child.getPrevSibling()) {
|
||||
if (instanceOf(child, aClass)) return (T)child;
|
||||
if (aClass.isInstance(child)) {
|
||||
//noinspection unchecked
|
||||
return (T)child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -391,11 +390,12 @@ public class PsiTreeUtil {
|
||||
element = element.getContext();
|
||||
}
|
||||
|
||||
while (element != null && !instanceOf(element, aClass)) {
|
||||
while (element != null && !aClass.isInstance(element)) {
|
||||
if (instanceOf(element, stopAt)) return null;
|
||||
element = element.getContext();
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return (T)element;
|
||||
}
|
||||
|
||||
@@ -424,6 +424,7 @@ public class PsiTreeUtil {
|
||||
element = element.getContext();
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return (T)element;
|
||||
}
|
||||
|
||||
@@ -435,7 +436,8 @@ public class PsiTreeUtil {
|
||||
}
|
||||
|
||||
while (element != null) {
|
||||
if (instanceOf(element, aClass)) {
|
||||
if (aClass.isInstance(element)) {
|
||||
//noinspection unchecked
|
||||
return (T)element;
|
||||
}
|
||||
if (element instanceof PsiFile) return null;
|
||||
@@ -455,12 +457,13 @@ public class PsiTreeUtil {
|
||||
element = element.getParent();
|
||||
}
|
||||
|
||||
while (element != null && !instanceOf(element, aClass)) {
|
||||
while (element != null && !aClass.isInstance(element)) {
|
||||
if (instanceOf(element, stopAt)) return null;
|
||||
if (element instanceof PsiFile) return null;
|
||||
element = element.getParent();
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return (T)element;
|
||||
}
|
||||
|
||||
@@ -509,7 +512,10 @@ public class PsiTreeUtil {
|
||||
public static <T extends PsiElement> T getNonStrictParentOfType(@NotNull PsiElement element, @NotNull Class<? extends T>... classes) {
|
||||
PsiElement run = element;
|
||||
while (run != null) {
|
||||
if (instanceOf(run, classes)) return (T)run;
|
||||
if (instanceOf(run, classes)) {
|
||||
//noinspection unchecked
|
||||
return (T)run;
|
||||
}
|
||||
if (run instanceof PsiFile) break;
|
||||
run = run.getParent();
|
||||
}
|
||||
@@ -546,6 +552,7 @@ public class PsiTreeUtil {
|
||||
|
||||
public static boolean processElements(@Nullable PsiElement element, @NotNull PsiElementProcessor processor) {
|
||||
if (element == null) return true;
|
||||
//noinspection unchecked
|
||||
if (!processor.execute(element)) return false;
|
||||
for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (!processElements(child, processor)) return false;
|
||||
@@ -832,11 +839,13 @@ public class PsiTreeUtil {
|
||||
TextRange injectionRange = outerLanguageElement.getTextRange();
|
||||
List<PsiElement> res = Lists.newArrayList();
|
||||
|
||||
assert psi != null : outerLanguageElement;
|
||||
for (PsiElement element = psi.findElementAt(injectionRange.getStartOffset());
|
||||
element != null && injectionRange.intersectsStrict(element.getTextRange());
|
||||
element = element.getNextSibling()) {
|
||||
res.add(element);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ public class CodeInsightUtilBase {
|
||||
T elementInRange = findElementInRange(psiFile, rangeMarker.getStartOffset(), rangeMarker.getEndOffset(),
|
||||
(Class<? extends T>)element.getClass(),
|
||||
language);
|
||||
((RangeMarkerEx)rangeMarker).dispose();
|
||||
rangeMarker.dispose();
|
||||
return elementInRange;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,10 +19,8 @@ package com.intellij.codeInsight.completion;
|
||||
import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.lookup.*;
|
||||
import com.intellij.codeInsight.template.Template;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.paths.PsiDynaReference;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
@@ -104,21 +102,17 @@ public class CompletionData {
|
||||
public void completeReference(final PsiReference reference, final Set<LookupElement> set, @NotNull final PsiElement position, final PsiFile file,
|
||||
final int offset){
|
||||
final CompletionVariant[] variants = findVariants(position, file);
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
boolean hasApplicableVariants = false;
|
||||
for (CompletionVariant variant : variants) {
|
||||
if (variant.hasReferenceFilter()) {
|
||||
variant.addReferenceCompletions(reference, position, set, file, CompletionData.this);
|
||||
hasApplicableVariants = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasApplicableVariants) {
|
||||
myGenericVariant.addReferenceCompletions(reference, position, set, file, CompletionData.this);
|
||||
}
|
||||
boolean hasApplicableVariants = false;
|
||||
for (CompletionVariant variant : variants) {
|
||||
if (variant.hasReferenceFilter()) {
|
||||
variant.addReferenceCompletions(reference, position, set, file, CompletionData.this);
|
||||
hasApplicableVariants = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!hasApplicableVariants) {
|
||||
myGenericVariant.addReferenceCompletions(reference, position, set, file, CompletionData.this);
|
||||
}
|
||||
}
|
||||
|
||||
public void addKeywordVariants(Set<CompletionVariant> set, PsiElement position, final PsiFile file) {
|
||||
@@ -129,11 +123,7 @@ public class CompletionData {
|
||||
final PrefixMatcher matcher,
|
||||
final PsiFile file){
|
||||
for (final CompletionVariant variant : variants) {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
variant.addKeywords(set, position, matcher, file, CompletionData.this);
|
||||
}
|
||||
});
|
||||
variant.addKeywords(set, position, matcher, file, CompletionData.this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,34 +132,30 @@ public class CompletionData {
|
||||
}
|
||||
|
||||
public CompletionVariant[] findVariants(final PsiElement position, final PsiFile file){
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<CompletionVariant[]>() {
|
||||
public CompletionVariant[] compute() {
|
||||
final List<CompletionVariant> variants = new ArrayList<CompletionVariant>();
|
||||
PsiElement scope = position;
|
||||
if(scope == null){
|
||||
scope = file;
|
||||
}
|
||||
while (scope != null) {
|
||||
boolean breakFlag = false;
|
||||
if (isScopeAcceptable(scope)){
|
||||
final List<CompletionVariant> variants = new ArrayList<CompletionVariant>();
|
||||
PsiElement scope = position;
|
||||
if(scope == null){
|
||||
scope = file;
|
||||
}
|
||||
while (scope != null) {
|
||||
boolean breakFlag = false;
|
||||
if (isScopeAcceptable(scope)){
|
||||
|
||||
for (final CompletionVariant variant : myCompletionVariants) {
|
||||
if (variant.isVariantApplicable(position, scope) && !variants.contains(variant)) {
|
||||
variants.add(variant);
|
||||
if (variant.isScopeFinal(scope)) {
|
||||
breakFlag = true;
|
||||
}
|
||||
for (final CompletionVariant variant : myCompletionVariants) {
|
||||
if (variant.isVariantApplicable(position, scope) && !variants.contains(variant)) {
|
||||
variants.add(variant);
|
||||
if (variant.isScopeFinal(scope)) {
|
||||
breakFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(breakFlag || isScopeFinal(scope.getClass()))
|
||||
break;
|
||||
scope = scope.getContext();
|
||||
if (scope instanceof PsiDirectory) break;
|
||||
}
|
||||
return variants.toArray(new CompletionVariant[variants.size()]);
|
||||
if(breakFlag || isScopeFinal(scope.getClass()))
|
||||
break;
|
||||
scope = scope.getContext();
|
||||
if (scope instanceof PsiDirectory) break;
|
||||
}
|
||||
});
|
||||
return variants.toArray(new CompletionVariant[variants.size()]);
|
||||
}
|
||||
|
||||
protected final CompletionVariant myGenericVariant = new CompletionVariant() {
|
||||
@@ -207,14 +193,7 @@ public class CompletionData {
|
||||
public static String findPrefixStatic(final PsiElement insertedElement, final int offsetInFile, ElementPattern<Character> prefixStartTrim) {
|
||||
if(insertedElement == null) return "";
|
||||
|
||||
final String prefix = ApplicationManager.getApplication().runReadAction(new Computable<String>() {
|
||||
public String compute() {
|
||||
if (!insertedElement.isValid()) {
|
||||
return "";
|
||||
}
|
||||
return getReferencePrefix(insertedElement, offsetInFile);
|
||||
}
|
||||
});
|
||||
final String prefix = getReferencePrefix(insertedElement, offsetInFile);
|
||||
if (prefix != null) return prefix;
|
||||
|
||||
if (insertedElement instanceof PsiPlainText || insertedElement instanceof PsiComment) {
|
||||
|
||||
+9
-3
@@ -88,7 +88,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
|
||||
};
|
||||
private LightweightHint myHint;
|
||||
private final Semaphore myFreezeSemaphore;
|
||||
private boolean myToRestart;
|
||||
private Boolean myToRestart;
|
||||
|
||||
private boolean myModifiersReleased;
|
||||
|
||||
@@ -436,6 +436,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
|
||||
}
|
||||
|
||||
private void finishCompletionProcess() {
|
||||
myToRestart = false;
|
||||
cancel();
|
||||
|
||||
assert !myDisposed;
|
||||
@@ -474,7 +475,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
|
||||
invokeLaterIfNotDispatch(new Runnable() {
|
||||
public void run() {
|
||||
if (isOutdated()) return;
|
||||
if (isCanceled() && !myToRestart) return; // otherwise
|
||||
if (isCanceled() && myToRestart != Boolean.TRUE) return;
|
||||
|
||||
//what if a new completion was invoked by the user before this 'later'?
|
||||
if (CompletionProgressIndicator.this != CompletionServiceImpl.getCompletionService().getCurrentCompletion()) return;
|
||||
@@ -528,6 +529,11 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
|
||||
}
|
||||
|
||||
public void cancelByWriteAction() {
|
||||
if (myToRestart != null) {
|
||||
LOG.assertTrue(myToRestart == Boolean.FALSE); //explicit completionFinished was invoked before this write action
|
||||
return;
|
||||
}
|
||||
|
||||
myToRestart = true;
|
||||
cancel();
|
||||
|
||||
@@ -605,7 +611,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
|
||||
}
|
||||
|
||||
public void prefixUpdated() {
|
||||
if (myToRestart) {
|
||||
if (myToRestart == Boolean.TRUE) {
|
||||
scheduleRestart();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.filters.ContextGetter;
|
||||
import com.intellij.psi.filters.ElementFilter;
|
||||
import com.intellij.psi.filters.position.PatternFilter;
|
||||
import com.intellij.util.PairConsumer;
|
||||
import com.intellij.util.ReflectionCache;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -192,14 +191,6 @@ public class CompletionVariant {
|
||||
}
|
||||
}
|
||||
|
||||
public void processReferenceCompletions(PairConsumer<ElementFilter, TailType> consumer) {
|
||||
for (final CompletionVariantItem ce : myCompletionsList) {
|
||||
if(ce.myCompletion instanceof ElementFilter){
|
||||
consumer.consume((ElementFilter)ce.myCompletion, ce.myTailType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addKeywords(Set<LookupElement> set, PsiElement position, final PrefixMatcher matcher, final PsiFile file,
|
||||
final CompletionData completionData){
|
||||
|
||||
|
||||
+7
-20
@@ -17,15 +17,12 @@ package com.intellij.codeInsight.completion.impl;
|
||||
|
||||
import com.intellij.codeInsight.completion.*;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -56,21 +53,11 @@ public class CompletionServiceImpl extends CompletionService{
|
||||
}
|
||||
|
||||
public CompletionResultSet createResultSet(final CompletionParameters parameters, final Consumer<LookupElement> consumer,
|
||||
@NotNull final CompletionContributor contributor) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<CompletionResultSet>() {
|
||||
public CompletionResultSet compute() {
|
||||
final PsiElement position = parameters.getPosition();
|
||||
if (!position.isValid()) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
|
||||
final String prefix = CompletionData.findPrefixStatic(position, parameters.getOffset());
|
||||
|
||||
final String textBeforePosition = parameters.getPosition().getContainingFile().getText().substring(0, parameters.getOffset());
|
||||
|
||||
return new CompletionResultSetImpl(consumer, textBeforePosition, new CamelHumpMatcher(prefix), contributor);
|
||||
}
|
||||
});
|
||||
@NotNull final CompletionContributor contributor) {
|
||||
final PsiElement position = parameters.getPosition();
|
||||
final String prefix = CompletionData.findPrefixStatic(position, parameters.getOffset());
|
||||
final String textBeforePosition = parameters.getPosition().getContainingFile().getText().substring(0, parameters.getOffset());
|
||||
return new CompletionResultSetImpl(consumer, textBeforePosition, new CamelHumpMatcher(prefix), contributor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -171,7 +171,7 @@ public class FileStatusMap implements Disposable {
|
||||
else if (status.dirtyScopes.containsKey(passId)) {
|
||||
RangeMarker marker = status.dirtyScopes.get(passId);
|
||||
if (marker != null) {
|
||||
((RangeMarkerEx)marker).dispose();
|
||||
marker.dispose();
|
||||
status.dirtyScopes.put(passId, null);
|
||||
}
|
||||
}
|
||||
@@ -217,7 +217,7 @@ public class FileStatusMap implements Disposable {
|
||||
LOG.assertTrue(status.dirtyScopes.containsKey(passId));
|
||||
RangeMarker marker = status.dirtyScopes.get(passId);
|
||||
if (marker != null) {
|
||||
((RangeMarkerEx)marker).dispose();
|
||||
marker.dispose();
|
||||
}
|
||||
marker = document.createRangeMarker(0, document.getTextLength());
|
||||
status.dirtyScopes.put(passId, marker);
|
||||
@@ -269,7 +269,7 @@ public class FileStatusMap implements Disposable {
|
||||
if (union.getEndOffset() > textLength) {
|
||||
union = union.intersection(new TextRange(0, textLength));
|
||||
}
|
||||
((RangeMarkerEx)old).dispose();
|
||||
old.dispose();
|
||||
return document.createRangeMarker(union);
|
||||
}
|
||||
|
||||
|
||||
@@ -266,7 +266,13 @@ public class TypedHandler implements TypedActionHandler {
|
||||
for (DocumentWindow documentWindow : InjectedLanguageUtil.getCachedInjectedDocuments(oldFile)) {
|
||||
if (documentWindow.isValid() && documentWindow.containsRange(offset, offset)) {
|
||||
PsiFile injectedFile = PsiDocumentManager.getInstance(oldFile.getProject()).getPsiFile(documentWindow);
|
||||
return InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
|
||||
final Editor injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
|
||||
// IDEA-52375 fix: last quote sign should be handled by outer language quote handler
|
||||
if (injectedEditor.getCaretModel().getOffset() == injectedEditor.getDocument().getTextLength() &&
|
||||
charTyped == editor.getDocument().getCharsSequence().charAt(offset)) {
|
||||
return editor;
|
||||
}
|
||||
return injectedEditor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public abstract class TailTypeDecorator<T extends LookupElement> extends LookupE
|
||||
|
||||
final LookupItem lookupItem = delegate.as(LookupItem.class);
|
||||
if (lookupItem != null && tailType != null) {
|
||||
lookupItem.setTailType(TailType.NONE);
|
||||
lookupItem.setTailType(TailType.UNKNOWN);
|
||||
}
|
||||
delegate.handleInsert(context);
|
||||
if (tailType != null && tailType.isApplicable(context)) {
|
||||
|
||||
@@ -77,7 +77,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
|
||||
|
||||
private int myMinPrefixLength;
|
||||
private int myPreferredItemsCount;
|
||||
private long myShownStamp = -1;
|
||||
private String myInitialPrefix;
|
||||
private LookupArranger myArranger;
|
||||
|
||||
@@ -493,10 +492,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
|
||||
}
|
||||
|
||||
public void finishLookup(final char completionChar) {
|
||||
if (justShown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final LookupElement item = (LookupElement)myList.getSelectedValue();
|
||||
doHide(false, true);
|
||||
if (item == null ||
|
||||
@@ -537,10 +532,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
|
||||
fireItemSelected(item, completionChar);
|
||||
}
|
||||
|
||||
public boolean justShown() {
|
||||
return myShownStamp > 0 && System.currentTimeMillis() - myShownStamp < 42 && !ApplicationManager.getApplication().isUnitTestMode();
|
||||
}
|
||||
|
||||
public int getLookupStart() {
|
||||
if (myLookupStartMarker == null) {
|
||||
final int start = calcLookupStart();
|
||||
@@ -581,8 +572,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
|
||||
hintManager.showEditorHint(this, myEditor, p, HintManagerImpl.HIDE_BY_ESCAPE | HintManagerImpl.UPDATE_BY_SCROLLING, 0, false);
|
||||
|
||||
getComponent().getRootPane().getLayeredPane().add(myIconPanel, 42, 0);
|
||||
|
||||
myShownStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
private void addListeners() {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.intellij.codeInsight.lookup.impl;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.codeInsight.completion.CompletionProcess;
|
||||
import com.intellij.codeInsight.completion.CompletionService;
|
||||
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher;
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
||||
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
|
||||
@@ -119,7 +121,10 @@ public class LookupManagerImpl extends LookupManager {
|
||||
final Runnable request = new Runnable() {
|
||||
public void run() {
|
||||
if (myActiveLookup == lookup) {
|
||||
DocumentationManager.getInstance(myProject).showJavaDocInfo(editor, psiFile, false);
|
||||
final CompletionProcess completion = CompletionService.getCompletionService().getCurrentCompletion();
|
||||
if (completion == null || !completion.isAutopopupCompletion()) {
|
||||
DocumentationManager.getInstance(myProject).showJavaDocInfo(editor, psiFile, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+4
-1
@@ -19,6 +19,7 @@ package com.intellij.codeInsight.lookup.impl.actions;
|
||||
import com.intellij.codeInsight.lookup.Lookup;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl;
|
||||
import com.intellij.codeInsight.template.impl.TemplateSettings;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
@@ -33,6 +34,7 @@ public class ChooseItemAction extends EditorAction {
|
||||
private static class Handler extends EditorActionHandler {
|
||||
public void execute(final Editor editor, final DataContext dataContext) {
|
||||
LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor);
|
||||
assert lookup != null;
|
||||
lookup.finishLookup(Lookup.NORMAL_SELECT_CHAR);
|
||||
}
|
||||
}
|
||||
@@ -41,7 +43,8 @@ public class ChooseItemAction extends EditorAction {
|
||||
LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor);
|
||||
if (lookup != null) {
|
||||
lookup.refreshUi(); // to bring the list model up to date
|
||||
presentation.setEnabled(!lookup.justShown() && (lookup.isFocused() || lookup.isCompletion() && !lookup.getItems().isEmpty()));
|
||||
presentation.setEnabled(lookup.isFocused() &&
|
||||
!ChooseItemReplaceAction.hasTemplatePrefix(lookup, TemplateSettings.ENTER_CHAR));
|
||||
} else {
|
||||
presentation.setEnabled(false);
|
||||
}
|
||||
|
||||
+20
-1
@@ -17,15 +17,21 @@
|
||||
package com.intellij.codeInsight.lookup.impl.actions;
|
||||
|
||||
import com.intellij.codeInsight.completion.CodeCompletionFeatures;
|
||||
import com.intellij.codeInsight.completion.CompletionUtil;
|
||||
import com.intellij.codeInsight.lookup.Lookup;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl;
|
||||
import com.intellij.codeInsight.template.impl.LiveTemplateCompletionContributor;
|
||||
import com.intellij.codeInsight.template.impl.TemplateImpl;
|
||||
import com.intellij.codeInsight.template.impl.TemplateSettings;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorAction;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
|
||||
public class ChooseItemReplaceAction extends EditorAction {
|
||||
public ChooseItemReplaceAction(){
|
||||
@@ -36,15 +42,28 @@ public class ChooseItemReplaceAction extends EditorAction {
|
||||
public void executeWriteAction(Editor editor, DataContext dataContext) {
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_REPLACE);
|
||||
LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor);
|
||||
assert lookup != null;
|
||||
lookup.finishLookup(Lookup.REPLACE_SELECT_CHAR);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean hasTemplatePrefix(LookupImpl lookup, char shortcutChar) {
|
||||
final PsiFile file = lookup.getPsiFile();
|
||||
final Editor editor = lookup.getEditor();
|
||||
PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument());
|
||||
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
final String prefix = CompletionUtil.findJavaIdentifierPrefix(file, offset);
|
||||
final TemplateImpl template = LiveTemplateCompletionContributor.findApplicableTemplate(file, offset, prefix);
|
||||
return template != null && shortcutChar == TemplateSettings.getInstance().getShortcutChar(template);
|
||||
}
|
||||
|
||||
public void update(Editor editor, Presentation presentation, DataContext dataContext){
|
||||
LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor);
|
||||
if (lookup != null) {
|
||||
lookup.refreshUi(); // to bring the list model up to date
|
||||
presentation.setEnabled(!lookup.justShown() && (lookup.isFocused() || lookup.isCompletion() && !lookup.getItems().isEmpty()));
|
||||
presentation.setEnabled((lookup.isFocused() || lookup.isCompletion() && !lookup.getItems().isEmpty()) &&
|
||||
!hasTemplatePrefix(lookup, TemplateSettings.TAB_CHAR));
|
||||
} else {
|
||||
presentation.setEnabled(false);
|
||||
}
|
||||
|
||||
+40
-14
@@ -19,10 +19,17 @@ import com.intellij.codeInsight.completion.*;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.codeInsight.template.TemplateManager;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.patterns.PlatformPatterns;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.containers.CollectionFactory;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
@@ -39,23 +46,42 @@ public class LiveTemplateCompletionContributor extends CompletionContributor {
|
||||
final PsiFile file = parameters.getOriginalFile();
|
||||
final int offset = parameters.getOffset();
|
||||
final String prefix = result.getPrefixMatcher().getPrefix();
|
||||
for (final TemplateImpl template : TemplateSettings.getInstance().getTemplates()) {
|
||||
final String key = template.getKey();
|
||||
if (!template.isDeactivated() && !template.isSelectionTemplate() && TemplateManagerImpl.isApplicable(file, offset, template)) {
|
||||
if (prefix.equals(key)) {
|
||||
result.addElement(LookupElementBuilder.create(key).setTypeText(template.getDescription()).setInsertHandler(new InsertHandler<LookupElement>() {
|
||||
@Override
|
||||
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||
context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset());
|
||||
context.setAddCompletionChar(false);
|
||||
TemplateManager.getInstance(context.getProject()).startTemplate(context.getEditor(), template);
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
result.restartCompletionOnPrefixChange(key);
|
||||
final TemplateImpl template = findApplicableTemplate(file, offset, prefix);
|
||||
if (template != null) {
|
||||
result.addElement(LookupElementBuilder.create(prefix).setTypeText(template.getDescription()).setInsertHandler(new InsertHandler<LookupElement>() {
|
||||
@Override
|
||||
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||
context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset());
|
||||
context.setAddCompletionChar(false);
|
||||
TemplateManager.getInstance(context.getProject()).startTemplate(context.getEditor(), template);
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
for (final TemplateImpl possible : listApplicableTemplates(file, offset)) {
|
||||
result.restartCompletionOnPrefixChange(possible.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static List<TemplateImpl> listApplicableTemplates(PsiFile file, int offset) {
|
||||
final ArrayList<TemplateImpl> result = CollectionFactory.arrayList();
|
||||
for (final TemplateImpl template : TemplateSettings.getInstance().getTemplates()) {
|
||||
if (!template.isDeactivated() && !template.isSelectionTemplate() && TemplateManagerImpl.isApplicable(file, offset, template)) {
|
||||
result.add(template);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TemplateImpl findApplicableTemplate(PsiFile file, int offset, final String key) {
|
||||
return ContainerUtil.find(listApplicableTemplates(file, offset), new Condition<TemplateImpl>() {
|
||||
@Override
|
||||
public boolean value(TemplateImpl template) {
|
||||
return key.equals(template.getKey());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class TemplateSegments {
|
||||
|
||||
public void replaceSegmentAt(int index, int start, int end) {
|
||||
RangeMarker rangeMarker = mySegments.get(index);
|
||||
((RangeMarkerEx)rangeMarker).dispose();
|
||||
rangeMarker.dispose();
|
||||
Document doc = myEditor.getDocument();
|
||||
rangeMarker = doc.createRangeMarker(start, end);
|
||||
rangeMarker.setGreedyToLeft(true);
|
||||
|
||||
@@ -690,7 +690,7 @@ public class TemplateSettings implements PersistentStateComponent<Element>, Expo
|
||||
return candidates;
|
||||
}
|
||||
|
||||
private char getShortcutChar(TemplateImpl template) {
|
||||
public char getShortcutChar(TemplateImpl template) {
|
||||
char c = template.getShortcutChar();
|
||||
if (c == DEFAULT_CHAR) {
|
||||
return getDefaultShortcutChar();
|
||||
|
||||
@@ -73,6 +73,7 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable,
|
||||
|
||||
private List<Element> myUnloadedElements = null;
|
||||
private JDOMExternalizableStringList myOrder = new JDOMExternalizableStringList();
|
||||
private boolean myOrdered = true;
|
||||
|
||||
private final EventDispatcher<RunManagerListener> myDispatcher = EventDispatcher.create(RunManagerListener.class);
|
||||
|
||||
@@ -286,7 +287,7 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable,
|
||||
|
||||
@Override
|
||||
public Collection<RunnerAndConfigurationSettings> getSortedConfigurations() {
|
||||
if (myOrder != null && !myOrder.isEmpty()) { //compatibility
|
||||
if (!myOrdered && !myOrder.isEmpty()) { //compatibility
|
||||
final HashMap<String, RunnerAndConfigurationSettings> settings =
|
||||
new HashMap<String, RunnerAndConfigurationSettings>(myConfigurations); //sort shared and local configurations
|
||||
myConfigurations.clear();
|
||||
@@ -299,7 +300,7 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable,
|
||||
for (String configName : order) {
|
||||
myConfigurations.put(configName, settings.get(configName));
|
||||
}
|
||||
myOrder = null;
|
||||
myOrdered = true;
|
||||
}
|
||||
return myConfigurations.values();
|
||||
}
|
||||
@@ -474,9 +475,8 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable,
|
||||
}
|
||||
}
|
||||
|
||||
if (myOrder != null) {
|
||||
myOrder.readExternal(parentNode);
|
||||
}
|
||||
myOrder.readExternal(parentNode);
|
||||
myOrdered = false;
|
||||
|
||||
mySelectedConfig = parentNode.getAttributeValue(SELECTED_ATTR);
|
||||
fireBeforeRunTasksUpdated();
|
||||
@@ -799,7 +799,6 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable,
|
||||
}
|
||||
|
||||
public void shareConfiguration(final RunConfiguration runConfiguration, final boolean shareConfiguration) {
|
||||
if (shareConfiguration && isTemporary(runConfiguration)) makeStable(runConfiguration);
|
||||
mySharedConfigurations.put(runConfiguration.getUniqueID(), shareConfiguration);
|
||||
}
|
||||
|
||||
|
||||
@@ -222,6 +222,7 @@ public class FileTemplateUtil{
|
||||
Velocity.setProperty("class.resource.loader.class", MyClasspathResourceLoader.class.getName());
|
||||
Velocity.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, modifiedPatternsPath.getAbsolutePath());
|
||||
Velocity.setProperty(RuntimeConstants.INPUT_ENCODING, FileTemplate.ourEncoding);
|
||||
Velocity.setProperty(RuntimeConstants.PARSER_POOL_SIZE, 3);
|
||||
Velocity.init();
|
||||
ourVelocityInitialized = true;
|
||||
}
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.ide.projectView.actions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class MarkExcludeRootAction extends MarkRootAction {
|
||||
public MarkExcludeRootAction() {
|
||||
super(false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
VirtualFile[] vFiles = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
|
||||
String message = vFiles.length == 1 ? FileUtil.toSystemDependentName(vFiles [0].getPath()) : vFiles.length + " selected files";
|
||||
final int rc = Messages.showOkCancelDialog(e.getData(PlatformDataKeys.PROJECT),
|
||||
"Are you sure you would you like to exclude " + message +
|
||||
" from the project?\nYou can restore excluded folders later using the Project Structure dialog.",
|
||||
"Mark as Excluded", Messages.getQuestionIcon());
|
||||
if (rc != 0) {
|
||||
return;
|
||||
}
|
||||
super.actionPerformed(e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.ide.projectView.actions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.LangDataKeys;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.roots.*;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class MarkRootAction extends AnAction {
|
||||
private final boolean myMarkAsTestSources;
|
||||
private final boolean myMarkAsExcluded;
|
||||
|
||||
public MarkRootAction() {
|
||||
myMarkAsTestSources = false;
|
||||
myMarkAsExcluded = false;
|
||||
}
|
||||
|
||||
protected MarkRootAction(boolean markAsTestSources, boolean markAsExcluded) {
|
||||
myMarkAsTestSources = markAsTestSources;
|
||||
myMarkAsExcluded = markAsExcluded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
Module module = e.getData(LangDataKeys.MODULE);
|
||||
VirtualFile[] vFiles = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
|
||||
assert vFiles != null;
|
||||
final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
|
||||
for (VirtualFile vFile : vFiles) {
|
||||
ContentEntry entry = findContentEntry(model, vFile);
|
||||
if (entry != null) {
|
||||
final SourceFolder[] sourceFolders = entry.getSourceFolders();
|
||||
for (SourceFolder sourceFolder : sourceFolders) {
|
||||
if (sourceFolder.getFile() == vFile) {
|
||||
entry.removeSourceFolder(sourceFolder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (myMarkAsExcluded) {
|
||||
entry.addExcludeFolder(vFile);
|
||||
}
|
||||
else {
|
||||
entry.addSourceFolder(vFile, myMarkAsTestSources);
|
||||
}
|
||||
}
|
||||
}
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
model.commit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ContentEntry findContentEntry(ModifiableRootModel model, VirtualFile vFile) {
|
||||
final ContentEntry[] contentEntries = model.getContentEntries();
|
||||
for (ContentEntry contentEntry : contentEntries) {
|
||||
final VirtualFile contentEntryFile = contentEntry.getFile();
|
||||
if (contentEntryFile != null && VfsUtil.isAncestor(contentEntryFile, vFile, false)) {
|
||||
return contentEntry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
boolean enabled = canMark(e, myMarkAsTestSources || myMarkAsExcluded, !myMarkAsTestSources || myMarkAsExcluded);
|
||||
e.getPresentation().setVisible(enabled);
|
||||
e.getPresentation().setEnabled(enabled);
|
||||
}
|
||||
|
||||
public static boolean canMark(AnActionEvent e, boolean acceptSourceRoot, boolean acceptTestSourceRoot) {
|
||||
Module module = e.getData(LangDataKeys.MODULE);
|
||||
VirtualFile[] vFiles = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
|
||||
if (module == null || vFiles == null) {
|
||||
return false;
|
||||
}
|
||||
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(module.getProject()).getFileIndex();
|
||||
for (VirtualFile vFile : vFiles) {
|
||||
if (!vFile.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
if (!fileIndex.isInContent(vFile)) {
|
||||
return false;
|
||||
}
|
||||
if (fileIndex.getSourceRootForFile(vFile) == vFile) {
|
||||
boolean isTestSourceRoot = fileIndex.isInTestSourceContent(vFile);
|
||||
if (acceptSourceRoot && !isTestSourceRoot) return true;
|
||||
if (acceptTestSourceRoot && isTestSourceRoot) return true;
|
||||
}
|
||||
if (fileIndex.isInSourceContent(vFile)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.ide.projectView.actions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class MarkRootGroup extends DefaultActionGroup {
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setVisible(MarkRootAction.canMark(e, true, true));
|
||||
}
|
||||
}
|
||||
+8
-9
@@ -13,14 +13,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.ide.util.gotoByName.matchers;
|
||||
package com.intellij.ide.projectView.actions;
|
||||
|
||||
import com.intellij.openapi.util.Computable;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface EntityMatcher {
|
||||
boolean nameMatches(String shortPattern, String shortName);
|
||||
|
||||
Set<Object> getElementsByPattern(String fullPattern, String shortName, boolean checkboxState, Computable<Boolean> isCancelled);
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class MarkTestSourceRootAction extends MarkRootAction {
|
||||
public MarkTestSourceRootAction() {
|
||||
super(true, false);
|
||||
}
|
||||
}
|
||||
@@ -1497,6 +1497,10 @@ public final class ProjectViewImpl extends ProjectView implements PersistentStat
|
||||
return getPaneOptionValue(myShowMembers, paneId, ourShowMembersDefaults);
|
||||
}
|
||||
|
||||
public void setShowMembers(boolean showMembers, String paneId) {
|
||||
setPaneOption(myShowMembers, showMembers, paneId, true);
|
||||
}
|
||||
|
||||
public boolean isHideEmptyMiddlePackages(String paneId) {
|
||||
return getPaneOptionValue(myHideEmptyPackages, paneId, ourHideEmptyPackagesDefaults);
|
||||
}
|
||||
|
||||
+2
-1
@@ -39,7 +39,7 @@ public abstract class LangScriptingContextConfigurable implements Configurable,
|
||||
public LangScriptingContextConfigurable(Project project, LangScriptingContextProvider provider) {
|
||||
myLibManager = new ScriptingLibraryManager(project, provider.getLibraryType());
|
||||
myPanel = useDedicatedLibraryUI() ? new ScriptingLibrariesPanel(provider, project, myLibManager) : new ScriptingLibrariesPanelStub();
|
||||
myContextsConfigurable = new ScriptingContextsConfigurable(project, provider);
|
||||
myContextsConfigurable = new ScriptingContextsConfigurable(project, provider.getLibraryMappings(project));
|
||||
}
|
||||
|
||||
private boolean useDedicatedLibraryUI() {
|
||||
@@ -70,6 +70,7 @@ public abstract class LangScriptingContextConfigurable implements Configurable,
|
||||
public void run() {
|
||||
myLibManager.commitChanges();
|
||||
myPanel.resetTable();
|
||||
myContextsConfigurable.resetMappings();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+5
@@ -17,9 +17,11 @@ package com.intellij.ide.scriptingContext;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.libraries.LibraryType;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Rustam Vishnyakov
|
||||
@@ -37,4 +39,7 @@ public abstract class LangScriptingContextProvider {
|
||||
|
||||
public abstract boolean isCompact(VirtualFile file);
|
||||
|
||||
@Nullable
|
||||
public abstract String getLibraryTypeName(OrderRootType rootType);
|
||||
|
||||
}
|
||||
|
||||
+12
-10
@@ -47,6 +47,10 @@ public class ScriptingLibraryMappings extends LanguagePerFileMappings<ScriptingL
|
||||
return library.getName();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
myLibraryManager.reset();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getValueAttribute() {
|
||||
@@ -75,7 +79,6 @@ public class ScriptingLibraryMappings extends LanguagePerFileMappings<ScriptingL
|
||||
|
||||
@Override
|
||||
public Collection<ScriptingLibraryTable.LibraryModel> getAvailableValues(VirtualFile file) {
|
||||
myLibraryManager.reset();
|
||||
List<ScriptingLibraryTable.LibraryModel> libraries = getSingleLibraries();
|
||||
if (myCompoundLibMap.containsKey(file)) {
|
||||
libraries.add(myCompoundLibMap.get(file));
|
||||
@@ -127,7 +130,7 @@ public class ScriptingLibraryMappings extends LanguagePerFileMappings<ScriptingL
|
||||
}
|
||||
|
||||
public static class CompoundLibrary extends ScriptingLibraryTable.LibraryModel {
|
||||
private List<ScriptingLibraryTable.LibraryModel> myLibraries = new ArrayList<ScriptingLibraryTable.LibraryModel>();
|
||||
private final Map<String, ScriptingLibraryTable.LibraryModel> myLibraries = new TreeMap<String, ScriptingLibraryTable.LibraryModel>();
|
||||
|
||||
public CompoundLibrary() {
|
||||
super(null);
|
||||
@@ -138,20 +141,19 @@ public class ScriptingLibraryMappings extends LanguagePerFileMappings<ScriptingL
|
||||
}
|
||||
|
||||
public void toggleLibrary(@NotNull ScriptingLibraryTable.LibraryModel library) {
|
||||
for (ScriptingLibraryTable.LibraryModel lib : myLibraries) {
|
||||
if (lib == library) {
|
||||
myLibraries.remove(library);
|
||||
return;
|
||||
}
|
||||
String libName = library.getName();
|
||||
if (myLibraries.containsKey(libName)) {
|
||||
myLibraries.remove(libName);
|
||||
return;
|
||||
}
|
||||
myLibraries.add(library);
|
||||
myLibraries.put(libName, library);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
StringBuffer allNames = new StringBuffer();
|
||||
boolean isFirst = true;
|
||||
for (ScriptingLibraryTable.LibraryModel library : myLibraries) {
|
||||
for (ScriptingLibraryTable.LibraryModel library : myLibraries.values()) {
|
||||
allNames.append(isFirst ? "" : ", ");
|
||||
allNames.append(library.getName());
|
||||
isFirst = false;
|
||||
@@ -161,7 +163,7 @@ public class ScriptingLibraryMappings extends LanguagePerFileMappings<ScriptingL
|
||||
|
||||
@Override
|
||||
public boolean containsFile(VirtualFile file) {
|
||||
for (ScriptingLibraryTable.LibraryModel library : myLibraries) {
|
||||
for (ScriptingLibraryTable.LibraryModel library : myLibraries.values()) {
|
||||
if (library.containsFile(file)) return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.intellij.ide.scriptingContext.LangScriptingContextProvider;
|
||||
import com.intellij.openapi.fileChooser.FileChooser;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.libraries.scripting.ScriptingLibraryTable;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
@@ -42,8 +43,8 @@ public class EditLibraryDialog extends DialogWrapper {
|
||||
private static final int FILE_LOCATION_COL = 0;
|
||||
private static final int FILE_TYPE_COL = 1;
|
||||
|
||||
private static final String SOURCE_TYPE = "Source";
|
||||
private static final String COMPACT_TYPE = "Compact";
|
||||
private final String mySourceTypeName;
|
||||
private final String myCompactTypeName;
|
||||
|
||||
private JPanel contentPane;
|
||||
private JTextField myLibName;
|
||||
@@ -60,6 +61,8 @@ public class EditLibraryDialog extends DialogWrapper {
|
||||
super(true);
|
||||
setTitle(title);
|
||||
myProvider = provider;
|
||||
mySourceTypeName = provider.getLibraryTypeName(OrderRootType.SOURCES);
|
||||
myCompactTypeName = provider.getLibraryTypeName(OrderRootType.CLASSES);
|
||||
myAddFileButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
@@ -95,7 +98,7 @@ public class EditLibraryDialog extends DialogWrapper {
|
||||
|
||||
TableColumn typeCol = myFileTable.getColumnModel().getColumn(FILE_TYPE_COL);
|
||||
typeCol.setMaxWidth(80);
|
||||
MyTableCellEditor cellEditor = new MyTableCellEditor(new JComboBox(new String[] {SOURCE_TYPE, COMPACT_TYPE}), myFileTableModel);
|
||||
MyTableCellEditor cellEditor = new MyTableCellEditor(new JComboBox(new String[] {mySourceTypeName, myCompactTypeName}), myFileTableModel);
|
||||
typeCol.setCellEditor(cellEditor);
|
||||
}
|
||||
|
||||
@@ -105,7 +108,7 @@ public class EditLibraryDialog extends DialogWrapper {
|
||||
myFileTableModel.setFiles(lib.getSourceFiles(), lib.getCompactFiles());
|
||||
}
|
||||
|
||||
private static class MyTableCellEditor extends DefaultCellEditor {
|
||||
private class MyTableCellEditor extends DefaultCellEditor {
|
||||
|
||||
private FileTableModel myFileTableModel;
|
||||
private VirtualFile myFile;
|
||||
@@ -119,7 +122,7 @@ public class EditLibraryDialog extends DialogWrapper {
|
||||
public boolean stopCellEditing() {
|
||||
if (myFile != null) {
|
||||
Object value = getCellEditorValue();
|
||||
myFileTableModel.setFileType(myFile, value.equals(COMPACT_TYPE));
|
||||
myFileTableModel.setFileType(myFile, value.equals(myCompactTypeName));
|
||||
}
|
||||
return super.stopCellEditing();
|
||||
}
|
||||
@@ -254,7 +257,7 @@ public class EditLibraryDialog extends DialogWrapper {
|
||||
case FILE_LOCATION_COL:
|
||||
return file;
|
||||
case FILE_TYPE_COL:
|
||||
return myCompactFiles.contains(file) ? COMPACT_TYPE : SOURCE_TYPE;
|
||||
return myCompactFiles.contains(file) ? myCompactTypeName : mySourceTypeName;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
+16
-3
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.intellij.ide.scriptingContext.ui;
|
||||
|
||||
import com.intellij.ide.scriptingContext.LangScriptingContextProvider;
|
||||
import com.intellij.ide.scriptingContext.ScriptingLibraryMappings;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.libraries.scripting.ScriptingLibraryTable;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
@@ -30,10 +30,23 @@ import javax.swing.*;
|
||||
*/
|
||||
public class ScriptingContextsConfigurable extends LanguagePerFileConfigurable<ScriptingLibraryTable.LibraryModel> {
|
||||
|
||||
public ScriptingContextsConfigurable(final Project project, final LangScriptingContextProvider provider) {
|
||||
super(project, ScriptingLibraryTable.LibraryModel.class, provider.getLibraryMappings(project),
|
||||
private final ScriptingLibraryMappings myScriptingLibraryMappings;
|
||||
|
||||
public ScriptingContextsConfigurable(final Project project, final ScriptingLibraryMappings mappings) {
|
||||
super(project, ScriptingLibraryTable.LibraryModel.class, mappings,
|
||||
"Specify which libraries are used in specific files and/or directories.", "Library",
|
||||
"Override library settings for child directories and files?", "Override Library Settings");
|
||||
myScriptingLibraryMappings = mappings;
|
||||
}
|
||||
|
||||
public void resetMappings() {
|
||||
myScriptingLibraryMappings.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
resetMappings();
|
||||
super.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,12 +20,11 @@ import com.intellij.Patches;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.actions.CopyReferenceAction;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.ide.util.gotoByName.matchers.DefaultMatcher;
|
||||
import com.intellij.ide.util.gotoByName.matchers.EntityMatcher;
|
||||
import com.intellij.openapi.MnemonicHelper;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.keymap.KeymapManager;
|
||||
@@ -33,15 +32,19 @@ import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.*;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.openapi.wm.ex.WindowManagerEx;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.codeStyle.NameUtil;
|
||||
import com.intellij.psi.statistics.StatisticsInfo;
|
||||
import com.intellij.psi.statistics.StatisticsManager;
|
||||
import com.intellij.psi.util.proximity.PsiProximityComparator;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.ListScrollingUtil;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
@@ -49,6 +52,9 @@ import com.intellij.ui.components.JBList;
|
||||
import com.intellij.ui.popup.PopupOwner;
|
||||
import com.intellij.ui.popup.PopupUpdateProcessor;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.diff.Diff;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -62,14 +68,19 @@ import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.text.DefaultEditorKit;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ChooseByNameBase {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.gotoByName.ChooseByNameBase");
|
||||
|
||||
protected final Project myProject;
|
||||
protected final ChooseByNameModel myModel;
|
||||
protected final String myInitialText;
|
||||
private boolean myPreselectInitialText;
|
||||
private final Reference<PsiElement> myContext;
|
||||
|
||||
protected Component myPreviouslyFocusedComponent;
|
||||
|
||||
@@ -104,14 +115,10 @@ public abstract class ChooseByNameBase {
|
||||
private static int VISIBLE_LIST_SIZE_LIMIT = 10;
|
||||
private static final int MAXIMUM_LIST_SIZE_LIMIT = 30;
|
||||
private int myMaximumListSizeLimit = MAXIMUM_LIST_SIZE_LIMIT;
|
||||
@NonNls
|
||||
private static final String NOT_FOUND_IN_PROJECT_CARD = "syslib";
|
||||
@NonNls
|
||||
private static final String NOT_FOUND_CARD = "nfound";
|
||||
@NonNls
|
||||
private static final String CHECK_BOX_CARD = "chkbox";
|
||||
@NonNls
|
||||
private static final String SEARCHING_CARD = "searching";
|
||||
@NonNls private static final String NOT_FOUND_IN_PROJECT_CARD = "syslib";
|
||||
@NonNls private static final String NOT_FOUND_CARD = "nfound";
|
||||
@NonNls private static final String CHECK_BOX_CARD = "chkbox";
|
||||
@NonNls private static final String SEARCHING_CARD = "searching";
|
||||
private static final int REBUILD_DELAY = 300;
|
||||
|
||||
private final Alarm myHideAlarm = new Alarm();
|
||||
@@ -119,26 +126,32 @@ public abstract class ChooseByNameBase {
|
||||
protected JBPopup myTextPopup;
|
||||
protected JBPopup myDropdownPopup;
|
||||
|
||||
private EntityMatcher myMatcher;
|
||||
private static class MatchesComparator implements Comparator<String> {
|
||||
private final String myOriginalPattern;
|
||||
|
||||
private MatchesComparator(final String originalPattern) {
|
||||
myOriginalPattern = originalPattern.trim();
|
||||
}
|
||||
|
||||
public int compare(final String a, final String b) {
|
||||
boolean aStarts = a.startsWith(myOriginalPattern);
|
||||
boolean bStarts = b.startsWith(myOriginalPattern);
|
||||
if (aStarts && bStarts) return a.compareToIgnoreCase(b);
|
||||
if (aStarts && !bStarts) return -1;
|
||||
if (bStarts && !aStarts) return 1;
|
||||
return a.compareToIgnoreCase(b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param initialText initial text which will be in the lookup text field
|
||||
* @param context
|
||||
*/
|
||||
protected ChooseByNameBase(Project project, ChooseByNameModel model, String initialText, final PsiElement context) {
|
||||
this(project, model, initialText);
|
||||
myMatcher = new DefaultMatcher(model, context);
|
||||
}
|
||||
|
||||
protected ChooseByNameBase(Project project, ChooseByNameModel model, String initialText, EntityMatcher matcher) {
|
||||
this(project, model, initialText);
|
||||
myMatcher = matcher;
|
||||
}
|
||||
|
||||
private ChooseByNameBase(Project project, ChooseByNameModel model, String initialText) {
|
||||
myProject = project;
|
||||
myModel = model;
|
||||
myInitialText = initialText;
|
||||
myContext = new WeakReference<PsiElement>(context);
|
||||
}
|
||||
|
||||
public boolean isPreselectInitialText() {
|
||||
@@ -259,7 +272,7 @@ public abstract class ChooseByNameBase {
|
||||
|
||||
/**
|
||||
* @param callback
|
||||
* @param modalityState - if not null rebuilds list in given {@link com.intellij.openapi.application.ModalityState}
|
||||
* @param modalityState - if not null rebuilds list in given {@link ModalityState}
|
||||
* @param allowMultipleSelection
|
||||
*/
|
||||
protected void initUI(final ChooseByNamePopupComponent.Callback callback,
|
||||
@@ -284,8 +297,7 @@ public abstract class ChooseByNameBase {
|
||||
|
||||
GridBagLayout gb = new GridBagLayout();
|
||||
JPanel eastWrapper = new JPanel(gb);
|
||||
gb.setConstraints(hBox, new GridBagConstraints(0, 0, 0, 0, 1, 1, GridBagConstraints.SOUTHEAST, GridBagConstraints.NONE,
|
||||
new Insets(0, 0, 0, 0), 0, 0));
|
||||
gb.setConstraints(hBox, new GridBagConstraints(0, 0, 0, 0, 1, 1, GridBagConstraints.SOUTHEAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
eastWrapper.add(hBox);
|
||||
|
||||
caption2Tools.add(eastWrapper, BorderLayout.CENTER);
|
||||
@@ -435,7 +447,8 @@ public abstract class ChooseByNameBase {
|
||||
myListModel = new DefaultListModel();
|
||||
myList = new JBList(myListModel);
|
||||
myList.setFocusable(false);
|
||||
myList.setSelectionMode(allowMultipleSelection ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION : ListSelectionModel.SINGLE_SELECTION);
|
||||
myList.setSelectionMode(allowMultipleSelection ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION :
|
||||
ListSelectionModel.SINGLE_SELECTION);
|
||||
myList.addMouseListener(new MouseAdapter() {
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (!myTextField.hasFocus()) {
|
||||
@@ -577,8 +590,8 @@ public abstract class ChooseByNameBase {
|
||||
final int paneHeight = layeredPane.getHeight();
|
||||
final int y = paneHeight / 3 - preferredTextFieldPanelSize.height / 2;
|
||||
|
||||
VISIBLE_LIST_SIZE_LIMIT =
|
||||
Math.max(10, (paneHeight - (y + preferredTextFieldPanelSize.height)) / (preferredTextFieldPanelSize.height / 2) - 1);
|
||||
VISIBLE_LIST_SIZE_LIMIT = Math.max
|
||||
(10, (paneHeight - (y + preferredTextFieldPanelSize.height)) / (preferredTextFieldPanelSize.height / 2) - 1);
|
||||
|
||||
ComponentPopupBuilder builder = JBPopupFactory.getInstance().createComponentPopupBuilder(myTextFieldPanel, myTextField);
|
||||
builder.setCancelCallback(new Computable<Boolean>() {
|
||||
@@ -614,11 +627,9 @@ public abstract class ChooseByNameBase {
|
||||
layeredPane = ((JDialog)parent).getLayeredPane();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("cannot find parent window: project=" +
|
||||
myProject +
|
||||
throw new IllegalStateException("cannot find parent window: project=" + myProject +
|
||||
(myProject != null ? "; open=" + myProject.isOpen() : "") +
|
||||
"; window=" +
|
||||
window);
|
||||
"; window=" + window);
|
||||
}
|
||||
return layeredPane;
|
||||
}
|
||||
@@ -639,7 +650,8 @@ public abstract class ChooseByNameBase {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
final String text = myTextField.getText();
|
||||
if (!canShowListForEmptyPattern() && (text == null || text.trim().length() == 0)) {
|
||||
if (!canShowListForEmptyPattern() &&
|
||||
(text == null || text.trim().length() == 0)) {
|
||||
myListModel.clear();
|
||||
hideList();
|
||||
myCard.show(myCardContainer, CHECK_BOX_CARD);
|
||||
@@ -779,12 +791,17 @@ public abstract class ChooseByNameBase {
|
||||
return "choose_by_name#" + myModel.getPromptText() + "#" + myCheckBox.isSelected() + "#" + myTextField.getText();
|
||||
}
|
||||
|
||||
public String getNamePattern(String pattern) {
|
||||
return getNamePattern_static(myModel, pattern);
|
||||
private String getQualifierPattern(String pattern) {
|
||||
final String[] separators = myModel.getSeparators();
|
||||
int lastSeparatorOccurence = 0;
|
||||
for (String separator : separators) {
|
||||
lastSeparatorOccurence = Math.max(lastSeparatorOccurence, pattern.lastIndexOf(separator));
|
||||
}
|
||||
return pattern.substring(0, lastSeparatorOccurence);
|
||||
}
|
||||
|
||||
public static String getNamePattern_static(ChooseByNameModel model, String pattern) {
|
||||
final String[] separators = model.getSeparators();
|
||||
public String getNamePattern(String pattern) {
|
||||
final String[] separators = myModel.getSeparators();
|
||||
int lastSeparatorOccurence = 0;
|
||||
for (String separator : separators) {
|
||||
final int idx = pattern.lastIndexOf(separator);
|
||||
@@ -970,7 +987,7 @@ public abstract class ChooseByNameBase {
|
||||
|
||||
protected void processKeyEvent(KeyEvent e) {
|
||||
final KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e);
|
||||
|
||||
|
||||
if (myCompletionKeyStroke != null && keyStroke.equals(myCompletionKeyStroke)) {
|
||||
completionKeyStrokeHappened = true;
|
||||
e.consume();
|
||||
@@ -1021,7 +1038,8 @@ public abstract class ChooseByNameBase {
|
||||
}
|
||||
|
||||
private void fillInCommonPrefix(final String pattern) {
|
||||
final List<String> list = getNamesByPattern(pattern, getNames());
|
||||
final ArrayList<String> list = new ArrayList<String>();
|
||||
getNamesByPattern(myCheckBox.isSelected(), null, list, pattern);
|
||||
|
||||
if (isComplexPattern(pattern)) return; //TODO: support '*'
|
||||
final String oldText = myTextField.getText();
|
||||
@@ -1087,34 +1105,6 @@ public abstract class ChooseByNameBase {
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getNamesByPattern(String pattern, String[] names) {
|
||||
if (pattern.startsWith("@")) {
|
||||
pattern = pattern.substring(1);
|
||||
}
|
||||
|
||||
boolean empty = pattern.length() == 0;
|
||||
if (empty) {
|
||||
if (!canShowListForEmptyPattern()) return Collections.emptyList();
|
||||
return Arrays.asList(names);
|
||||
}
|
||||
|
||||
ArrayList<String> result = new ArrayList<String>();
|
||||
try {
|
||||
for (String name : names) {
|
||||
if (myCalcElementsThread.myCancelled) {
|
||||
break;
|
||||
}
|
||||
if (myMatcher.nameMatches(pattern, name)) {
|
||||
result.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Do nothing. No matches appears valid result for "bad" pattern
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final String EXTRA_ELEM = "...";
|
||||
|
||||
private class CalcElementsThread implements Runnable {
|
||||
@@ -1203,31 +1193,55 @@ public abstract class ChooseByNameBase {
|
||||
}
|
||||
|
||||
private void addElementsByPattern(Set<Object> elementsArray, String pattern) {
|
||||
String[] names = myCheckboxState ? myNames[1] : myNames[0];
|
||||
String namePattern = getNamePattern(pattern);
|
||||
String qualifierPattern = getQualifierPattern(pattern);
|
||||
|
||||
List<String> namesList = getNamesByPattern(namePattern, names);
|
||||
boolean empty = namePattern.length() == 0 || namePattern.equals("@"); // TODO[yole]: remove implicit dependency
|
||||
if (empty && !canShowListForEmptyPattern()) return;
|
||||
|
||||
List<String> namesList = new ArrayList<String>();
|
||||
getNamesByPattern(myCheckboxState, this, namesList, namePattern);
|
||||
if (myCancelled) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
// Here we sort using namePattern to have similar logic with empty qualified patten case
|
||||
Collections.sort(namesList, new MatchesComparator(namePattern));
|
||||
|
||||
boolean overflow = false;
|
||||
List<Object> sameNameElements = new SmartList<Object>();
|
||||
All:
|
||||
for (String name : namesList) {
|
||||
Set<Object> elems = myMatcher.getElementsByPattern(namePattern, name, myCheckboxState,new Computable<Boolean>() {
|
||||
public Boolean compute() {
|
||||
return myCancelled;
|
||||
}
|
||||
});
|
||||
if (elementsArray.size() + elems.size() <= myMaximumListSizeLimit) {
|
||||
elementsArray.addAll(elems);
|
||||
if (myCancelled) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
else {
|
||||
Iterator<Object> iter = elems.iterator();
|
||||
while (elementsArray.size() < myMaximumListSizeLimit) {
|
||||
elementsArray.add(iter.next());
|
||||
final Object[] elements = myModel.getElementsByName(name, myCheckboxState, namePattern);
|
||||
if (elements.length > 1) {
|
||||
sameNameElements.clear();
|
||||
for (final Object element : elements) {
|
||||
if (matchesQualifier(element, qualifierPattern)) {
|
||||
sameNameElements.add(element);
|
||||
}
|
||||
}
|
||||
sortByProximity(sameNameElements);
|
||||
for (Object element : sameNameElements) {
|
||||
elementsArray.add(element);
|
||||
if (elementsArray.size() >= myMaximumListSizeLimit) {
|
||||
overflow = true;
|
||||
break All;
|
||||
}
|
||||
}
|
||||
elementsArray.add(EXTRA_ELEM);
|
||||
break;
|
||||
}
|
||||
else if (elements.length == 1 && matchesQualifier(elements[0], qualifierPattern)) {
|
||||
elementsArray.add(elements[0]);
|
||||
if (elementsArray.size() >= myMaximumListSizeLimit) {
|
||||
overflow = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (overflow) {
|
||||
elementsArray.add(EXTRA_ELEM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1238,8 +1252,92 @@ public abstract class ChooseByNameBase {
|
||||
}
|
||||
}
|
||||
|
||||
private String[] getNames() {
|
||||
return myCheckBox.isSelected() ? myNames[1] : myNames[0];
|
||||
private void sortByProximity(final List<Object> sameNameElements) {
|
||||
Collections.sort(sameNameElements, new PathProximityComparator(myModel, myContext.get()));
|
||||
}
|
||||
|
||||
private List<String> split(String s) {
|
||||
List<String> answer = new ArrayList<String>();
|
||||
for (String token : StringUtil.tokenize(s, StringUtil.join(myModel.getSeparators(), ""))) {
|
||||
if (token.length() > 0) {
|
||||
answer.add(token);
|
||||
}
|
||||
}
|
||||
|
||||
return answer.isEmpty() ? Collections.singletonList(s) : answer;
|
||||
}
|
||||
|
||||
private boolean matchesQualifier(final Object element, final String qualifierPattern) {
|
||||
final String name = myModel.getFullName(element);
|
||||
if (name == null) return false;
|
||||
|
||||
final List<String> suspects = split(name);
|
||||
final List<Pair<String, NameUtil.Matcher>> patternsAndMatchers =
|
||||
ContainerUtil.map2List(split(qualifierPattern), new Function<String, Pair<String, NameUtil.Matcher>>() {
|
||||
public Pair<String, NameUtil.Matcher> fun(String s) {
|
||||
final String pattern = getNamePattern(s);
|
||||
final NameUtil.Matcher matcher = buildPatternMatcher(pattern);
|
||||
|
||||
return new Pair<String, NameUtil.Matcher>(pattern, matcher);
|
||||
}
|
||||
});
|
||||
|
||||
int matchPosition = 0;
|
||||
|
||||
try {
|
||||
patterns:
|
||||
for (Pair<String, NameUtil.Matcher> patternAndMatcher : patternsAndMatchers) {
|
||||
final String pattern = patternAndMatcher.first;
|
||||
final NameUtil.Matcher matcher = patternAndMatcher.second;
|
||||
if (pattern.length() > 0) {
|
||||
for (int j = matchPosition; j < suspects.size() - 1; j++) {
|
||||
String suspect = suspects.get(j);
|
||||
if (matches(pattern, matcher, suspect)) {
|
||||
matchPosition = j + 1;
|
||||
continue patterns;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Do nothing. No matches appears valid result for "bad" pattern
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void getNamesByPattern(final boolean checkboxState,
|
||||
CalcElementsThread calcElementsThread,
|
||||
final List<String> list,
|
||||
String pattern) throws ProcessCanceledException {
|
||||
if (!canShowListForEmptyPattern()) {
|
||||
LOG.assertTrue(pattern.length() > 0);
|
||||
}
|
||||
|
||||
if (pattern.startsWith("@")) {
|
||||
pattern = pattern.substring(1);
|
||||
}
|
||||
|
||||
final String[] names = checkboxState ? myNames[1] : myNames[0];
|
||||
final NameUtil.Matcher matcher = buildPatternMatcher(pattern);
|
||||
|
||||
try {
|
||||
for (String name : names) {
|
||||
if (calcElementsThread != null && calcElementsThread.myCancelled) {
|
||||
break;
|
||||
}
|
||||
if (matches(pattern, matcher, name)) {
|
||||
list.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Do nothing. No matches appears valid result for "bad" pattern
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canShowListForEmptyPattern() {
|
||||
@@ -1247,27 +1345,46 @@ public abstract class ChooseByNameBase {
|
||||
}
|
||||
|
||||
protected boolean lastKeyStrokeIsCompletion() {
|
||||
return myTextField.isCompletionKeyStroke();
|
||||
return myTextField.isCompletionKeyStroke();
|
||||
}
|
||||
|
||||
private boolean matches(String pattern, NameUtil.Matcher matcher, String name) {
|
||||
boolean matches = false;
|
||||
if (name != null) {
|
||||
if (myModel instanceof CustomMatcherModel) {
|
||||
if (((CustomMatcherModel)myModel).matches(name, pattern)) {
|
||||
matches = true;
|
||||
}
|
||||
}
|
||||
else if (pattern.length() == 0 || matcher.matches(name)) {
|
||||
matches = true;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
private NameUtil.Matcher buildPatternMatcher(String pattern) {
|
||||
return NameUtil.buildMatcher(pattern, 0, true, true, pattern.toLowerCase().equals(pattern));
|
||||
}
|
||||
|
||||
private interface CalcElementsCallback {
|
||||
void run(Set<?> elements);
|
||||
}
|
||||
|
||||
private static class MatchesComparator implements Comparator<String> {
|
||||
private final String myOriginalPattern;
|
||||
private static class PathProximityComparator implements Comparator<Object> {
|
||||
private final ChooseByNameModel myModel;
|
||||
private final PsiProximityComparator myProximityComparator;
|
||||
|
||||
private MatchesComparator(final String originalPattern) {
|
||||
myOriginalPattern = originalPattern.trim();
|
||||
private PathProximityComparator(final ChooseByNameModel model, final PsiElement context) {
|
||||
myModel = model;
|
||||
myProximityComparator = new PsiProximityComparator(context);
|
||||
}
|
||||
|
||||
public int compare(final String a, final String b) {
|
||||
boolean aStarts = a.startsWith(myOriginalPattern);
|
||||
boolean bStarts = b.startsWith(myOriginalPattern);
|
||||
if (aStarts && bStarts) return a.compareToIgnoreCase(b);
|
||||
if (aStarts && !bStarts) return -1;
|
||||
if (bStarts && !aStarts) return 1;
|
||||
return a.compareToIgnoreCase(b);
|
||||
public int compare(final Object o1, final Object o2) {
|
||||
int rc = myProximityComparator.compare(o1, o2);
|
||||
if (rc != 0) return rc;
|
||||
|
||||
return Comparing.compare(myModel.getFullName(o1), myModel.getFullName(o2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.intellij.ide.util.gotoByName;
|
||||
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.ide.util.gotoByName.matchers.EntityMatcher;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.ComponentPopupBuilder;
|
||||
@@ -43,7 +42,7 @@ import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNamePopupComponent {
|
||||
public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNamePopupComponent{
|
||||
private static final Key<ChooseByNamePopup> CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY = new Key<ChooseByNamePopup>("ChooseByNamePopup");
|
||||
private Component myOldFocusOwner = null;
|
||||
private boolean myShowListForEmptyPattern = false;
|
||||
@@ -59,17 +58,6 @@ public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNameP
|
||||
}
|
||||
}
|
||||
|
||||
private ChooseByNamePopup(final Project project, final ChooseByNameModel model, final ChooseByNamePopup oldPopup,
|
||||
EntityMatcher matcher,@Nullable final String predefinedText) {
|
||||
super(project, model, oldPopup != null ? oldPopup.getEnteredText() : predefinedText, matcher);
|
||||
if (oldPopup == null && predefinedText != null) {
|
||||
setPreselectInitialText(true);
|
||||
}
|
||||
if (oldPopup != null) { //inherit old focus owner
|
||||
myOldFocusOwner = oldPopup.myPreviouslyFocusedComponent;
|
||||
}
|
||||
}
|
||||
|
||||
public String getEnteredText() {
|
||||
return myTextField.getText();
|
||||
}
|
||||
@@ -215,22 +203,6 @@ public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNameP
|
||||
public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, final PsiElement context) {
|
||||
return createPopup(project, model, context, null);
|
||||
}
|
||||
public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, EntityMatcher matcher) {
|
||||
return createPopup(project, model, matcher, null);
|
||||
}
|
||||
|
||||
public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, EntityMatcher matcher,
|
||||
@Nullable final String predefinedText) {
|
||||
final ChooseByNamePopup oldPopup = project.getUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY);
|
||||
if (oldPopup != null) {
|
||||
oldPopup.close(false);
|
||||
}
|
||||
ChooseByNamePopup newPopup = new ChooseByNamePopup(project, model, oldPopup, matcher, predefinedText);
|
||||
|
||||
project.putUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, newPopup);
|
||||
return newPopup;
|
||||
}
|
||||
|
||||
public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, final PsiElement context,
|
||||
@Nullable final String predefinedText) {
|
||||
final ChooseByNamePopup oldPopup = project.getUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY);
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.ide.util.gotoByName.matchers;
|
||||
|
||||
import com.intellij.ide.util.gotoByName.ChooseByNameBase;
|
||||
import com.intellij.ide.util.gotoByName.ChooseByNameModel;
|
||||
import com.intellij.ide.util.gotoByName.CustomMatcherModel;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.codeStyle.NameUtil;
|
||||
import com.intellij.psi.util.proximity.PsiProximityComparator;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.*;
|
||||
|
||||
public class DefaultMatcher implements EntityMatcher {
|
||||
private ChooseByNameModel myModel;
|
||||
private WeakReference<PsiElement> myContext;
|
||||
|
||||
private String myPattern = null;
|
||||
private NameUtil.Matcher myMatcher = null;
|
||||
|
||||
public DefaultMatcher(ChooseByNameModel model, PsiElement context) {
|
||||
myModel = model;
|
||||
myContext = new WeakReference<PsiElement>(context);
|
||||
}
|
||||
|
||||
public boolean nameMatches(String shortPattern, String shortName) {
|
||||
if (myPattern == null || !myPattern.equals(shortPattern)) {
|
||||
myMatcher = buildPatternMatcher(shortPattern);
|
||||
myPattern = shortPattern;
|
||||
}
|
||||
|
||||
return matches(shortPattern, myMatcher, shortName);
|
||||
}
|
||||
|
||||
public Set<Object> getElementsByPattern(String fullPattern, String shortName, boolean checkboxState, Computable<Boolean> isCancelled) {
|
||||
String namePattern = getShortNamePattern(fullPattern);
|
||||
String qualifierPattern = getQualifierPattern(fullPattern);
|
||||
|
||||
//todo this is a code duplicate - remove it
|
||||
String newPattern = namePattern.startsWith("@") ? namePattern.substring(1) : namePattern;
|
||||
if (!nameMatches(newPattern, shortName)) return Collections.emptySet();
|
||||
|
||||
List<Object> sameNameElements = new SmartList<Object>();
|
||||
final Object[] elements = myModel.getElementsByName(shortName, checkboxState, namePattern);
|
||||
|
||||
Set<Object> result = new HashSet<Object>();
|
||||
if (elements.length == 1) {
|
||||
if (matchesQualifier(elements[0], qualifierPattern)) {
|
||||
result.add(elements[0]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
sameNameElements.clear();
|
||||
for (final Object element : elements) {
|
||||
if (isCancelled.compute()) return result;
|
||||
if (matchesQualifier(element, qualifierPattern)) {
|
||||
sameNameElements.add(element);
|
||||
}
|
||||
}
|
||||
sortByProximity(sameNameElements);
|
||||
result.addAll(sameNameElements);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void sortByProximity(final List<Object> sameNameElements) {
|
||||
Collections.sort(sameNameElements, new PathProximityComparator(myModel, myContext.get()));
|
||||
}
|
||||
|
||||
private boolean matchesQualifier(final Object element, final String qualifierPattern) {
|
||||
final String name = myModel.getFullName(element);
|
||||
if (name == null) return false;
|
||||
|
||||
final List<String> suspects = split(name);
|
||||
final List<Pair<String, NameUtil.Matcher>> patternsAndMatchers =
|
||||
ContainerUtil.map2List(split(qualifierPattern), new Function<String, Pair<String, NameUtil.Matcher>>() {
|
||||
public Pair<String, NameUtil.Matcher> fun(String s) {
|
||||
final String pattern = getShortNamePattern(s);
|
||||
final NameUtil.Matcher matcher = buildPatternMatcher(pattern);
|
||||
|
||||
return new Pair<String, NameUtil.Matcher>(pattern, matcher);
|
||||
}
|
||||
});
|
||||
|
||||
int matchPosition = 0;
|
||||
|
||||
try {
|
||||
patterns:
|
||||
for (Pair<String, NameUtil.Matcher> patternAndMatcher : patternsAndMatchers) {
|
||||
final String pattern = patternAndMatcher.first;
|
||||
final NameUtil.Matcher matcher = patternAndMatcher.second;
|
||||
if (pattern.length() > 0) {
|
||||
for (int j = matchPosition; j < suspects.size() - 1; j++) {
|
||||
String suspect = suspects.get(j);
|
||||
if (matches(pattern, matcher, suspect)) {
|
||||
matchPosition = j + 1;
|
||||
continue patterns;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Do nothing. No matches appears valid result for "bad" pattern
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getShortNamePattern(String s) {
|
||||
return ChooseByNameBase.getNamePattern_static(myModel, s);
|
||||
}
|
||||
|
||||
private String getQualifierPattern(String pattern) {
|
||||
final String[] separators = myModel.getSeparators();
|
||||
int lastSeparatorOccurence = 0;
|
||||
for (String separator : separators) {
|
||||
lastSeparatorOccurence = Math.max(lastSeparatorOccurence, pattern.lastIndexOf(separator));
|
||||
}
|
||||
return pattern.substring(0, lastSeparatorOccurence);
|
||||
}
|
||||
|
||||
private boolean matches(String pattern, NameUtil.Matcher matcher, String name) {
|
||||
boolean matches = false;
|
||||
if (name != null) {
|
||||
if (myModel instanceof CustomMatcherModel) {
|
||||
if (((CustomMatcherModel)myModel).matches(name, pattern)) {
|
||||
matches = true;
|
||||
}
|
||||
}
|
||||
else if (pattern.length() == 0 || matcher.matches(name)) {
|
||||
matches = true;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
private static NameUtil.Matcher buildPatternMatcher(String pattern) {
|
||||
return NameUtil.buildMatcher(pattern, 0, true, true, pattern.toLowerCase().equals(pattern));
|
||||
}
|
||||
|
||||
private List<String> split(String s) {
|
||||
List<String> answer = new ArrayList<String>();
|
||||
for (String token : StringUtil.tokenize(s, StringUtil.join(myModel.getSeparators(), ""))) {
|
||||
if (token.length() > 0) {
|
||||
answer.add(token);
|
||||
}
|
||||
}
|
||||
|
||||
return answer.isEmpty() ? Collections.singletonList(s) : answer;
|
||||
}
|
||||
|
||||
private static class PathProximityComparator implements Comparator<Object> {
|
||||
private final ChooseByNameModel myModel;
|
||||
private final PsiProximityComparator myProximityComparator;
|
||||
|
||||
private PathProximityComparator(final ChooseByNameModel model, final PsiElement context) {
|
||||
myModel = model;
|
||||
myProximityComparator = new PsiProximityComparator(context);
|
||||
}
|
||||
|
||||
public int compare(final Object o1, final Object o2) {
|
||||
int rc = myProximityComparator.compare(o1, o2);
|
||||
if (rc != 0) return rc;
|
||||
|
||||
return Comparing.compare(myModel.getFullName(o1), myModel.getFullName(o2));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -758,7 +758,7 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
public void dispose() {
|
||||
for (PsiLanguageInjectionHost.Shred shred : myShreds) {
|
||||
RangeMarker rangeMarker = shred.getHostRangeMarker();
|
||||
((RangeMarkerEx)rangeMarker).dispose();
|
||||
rangeMarker.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.internal.psiView;
|
||||
|
||||
import com.intellij.ide.ui.ListCellRendererWrapper;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.LanguageUtil;
|
||||
@@ -357,13 +358,10 @@ public class PsiViewerDialog extends DialogWrapper implements DataProvider {
|
||||
|
||||
updateDialectsCombo();
|
||||
updateExtentionsCombo();
|
||||
myDialectsComboBox.setRenderer(new DefaultListCellRenderer() {
|
||||
myDialectsComboBox.setRenderer(new ListCellRendererWrapper<Language>(myDialectsComboBox.getRenderer()) {
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index,
|
||||
boolean isSelected, boolean cellHasFocus) {
|
||||
final Component result = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
if (value == null) setText("<no dialect>");
|
||||
return result;
|
||||
public void customize(final JList list, final Language value, final int index, final boolean selected, final boolean hasFocus) {
|
||||
setText(value != null ? value.getDisplayName() : "<no dialect>");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+5
-10
@@ -27,6 +27,7 @@ import com.intellij.codeInsight.daemon.impl.SeverityRegistrar;
|
||||
import com.intellij.codeInspection.ModifiableModel;
|
||||
import com.intellij.codeInspection.ex.InspectionProfileImpl;
|
||||
import com.intellij.codeInspection.ex.InspectionToolRegistrar;
|
||||
import com.intellij.ide.ui.ListCellRendererWrapper;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.colors.CodeInsightColors;
|
||||
@@ -259,19 +260,13 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable imple
|
||||
}
|
||||
|
||||
public JComponent createComponent() {
|
||||
myProfiles.setRenderer(new DefaultListCellRenderer(){
|
||||
myProfiles.setRenderer(new ListCellRendererWrapper<Profile>(myProfiles.getRenderer()) {
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
final Component rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
final String profileName = ((Profile)value).getName();
|
||||
public void customize(final JList list, final Profile value, final int index, final boolean selected, final boolean hasFocus) {
|
||||
final String profileName = value.getName();
|
||||
setText(profileName);
|
||||
final SingleInspectionProfilePanel panel = myPanels.get(profileName);
|
||||
if (panel != null && panel.isProfileShared()) {
|
||||
setIcon(Profile.PROJECT_PROFILE);
|
||||
} else {
|
||||
setIcon(Profile.LOCAL_PROFILE);
|
||||
}
|
||||
return rendererComponent;
|
||||
setIcon(panel != null && panel.isProfileShared() ? Profile.PROJECT_PROFILE : Profile.LOCAL_PROFILE);
|
||||
}
|
||||
});
|
||||
myProfiles.addActionListener(new ActionListener() {
|
||||
|
||||
@@ -50,11 +50,9 @@ import com.intellij.psi.impl.source.PsiFileImpl;
|
||||
import com.intellij.psi.impl.source.resolve.FileContextUtil;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.util.ConcurrencyUtil;
|
||||
import com.intellij.util.FileContentUtil;
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap;
|
||||
import com.intellij.util.containers.ConcurrentHashMap;
|
||||
import com.intellij.util.containers.ConcurrentWeakValueHashMap;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
@@ -81,6 +79,21 @@ public class FileManagerImpl implements FileManager {
|
||||
private final ConcurrentMap<VirtualFile, PsiDirectory> myVFileToPsiDirMap = new ConcurrentHashMap<VirtualFile, PsiDirectory>();
|
||||
private final ConcurrentWeakValueHashMap<VirtualFile, FileViewProvider> myVFileToViewProviderMap = new ConcurrentWeakValueHashMap<VirtualFile, FileViewProvider>();
|
||||
|
||||
private final Map<VirtualFile, GlobalSearchScope> myDefaultUseScopesCache = new ConcurrentFactoryMap<VirtualFile, GlobalSearchScope>() {
|
||||
@Override
|
||||
protected GlobalSearchScope create(VirtualFile key) {
|
||||
GlobalSearchScope scope = getInherentResolveScope(key);
|
||||
for (ResolveScopeEnlarger enlarger : ResolveScopeEnlarger.EP_NAME.getExtensions()) {
|
||||
final SearchScope extra = enlarger.getAdditionalResolveScope(key, myManager.getProject());
|
||||
if (extra != null) {
|
||||
scope = scope.union(extra);
|
||||
}
|
||||
}
|
||||
|
||||
return scope;
|
||||
}
|
||||
};
|
||||
|
||||
private boolean myInitialized = false;
|
||||
private boolean myDisposed = false;
|
||||
|
||||
@@ -108,6 +121,13 @@ public class FileManagerImpl implements FileManager {
|
||||
recalcAllViewProviders();
|
||||
}
|
||||
});
|
||||
|
||||
manager.registerRunnableToRunOnChange(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myDefaultUseScopesCache.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void processQueue() {
|
||||
@@ -394,19 +414,7 @@ public class FileManagerImpl implements FileManager {
|
||||
}
|
||||
|
||||
private GlobalSearchScope getDefaultResolveScope(@NotNull final Project project, @NotNull PsiFile psiFile, @NotNull final VirtualFile vFile) {
|
||||
return CachedValuesManager.getManager(project).getCachedValue(psiFile, new CachedValueProvider<GlobalSearchScope>() {
|
||||
@Override
|
||||
public Result<GlobalSearchScope> compute() {
|
||||
GlobalSearchScope scope = getInherentResolveScope(vFile);
|
||||
for (ResolveScopeEnlarger enlarger : ResolveScopeEnlarger.EP_NAME.getExtensions()) {
|
||||
final SearchScope extra = enlarger.getAdditionalResolveScope(vFile, project);
|
||||
if (extra != null) {
|
||||
scope = scope.union(extra);
|
||||
}
|
||||
}
|
||||
return Result.create(scope, PsiModificationTracker.MODIFICATION_COUNT, ProjectRootManager.getInstance(project));
|
||||
}
|
||||
});
|
||||
return myDefaultUseScopesCache.get(vFile);
|
||||
}
|
||||
|
||||
private GlobalSearchScope getInherentResolveScope(VirtualFile vFile) {
|
||||
|
||||
+4
@@ -82,6 +82,10 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar {
|
||||
cleared = true;
|
||||
}
|
||||
|
||||
public List<Pair<Place, PsiFile>> getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MultiHostRegistrar startInjecting(@NotNull Language language) {
|
||||
escapers = new SmartList<LiteralTextEscaper<? extends PsiLanguageInjectionHost>>();
|
||||
|
||||
@@ -437,7 +437,7 @@ public class FileBasedIndex implements ApplicationComponent {
|
||||
return index;
|
||||
}
|
||||
|
||||
private static <K> PersistentHashMap<Integer, Collection<K>> createIdToDataKeysIndex(ID<K, ?> indexId,
|
||||
private static <K> PersistentHashMap<Integer, Collection<K>> createIdToDataKeysIndex(final ID<K, ?> indexId,
|
||||
final KeyDescriptor<K> keyDescriptor,
|
||||
MemoryIndexStorage<K, ?> storage) throws IOException {
|
||||
final File indexStorageFile = IndexInfrastructure.getInputIndexStorageFile(indexId);
|
||||
@@ -446,19 +446,35 @@ public class FileBasedIndex implements ApplicationComponent {
|
||||
|
||||
final DataExternalizer<Collection<K>> dataExternalizer = new DataExternalizer<Collection<K>>() {
|
||||
public void save(DataOutput out, Collection<K> value) throws IOException {
|
||||
DataInputOutputUtil.writeINT(out, value.size());
|
||||
for (K key : value) {
|
||||
keyDescriptor.save(out, key);
|
||||
try {
|
||||
DataInputOutputUtil.writeINT(out, value.size());
|
||||
for (K key : value) {
|
||||
keyDescriptor.save(out, key);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new IOException("Error saving data for index " + indexId, e);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<K> read(DataInput in) throws IOException {
|
||||
final int size = DataInputOutputUtil.readINT(in);
|
||||
final List<K> list = new ArrayList<K>();
|
||||
for (int idx = 0; idx < size; idx++) {
|
||||
list.add(keyDescriptor.read(in));
|
||||
try {
|
||||
final int size = DataInputOutputUtil.readINT(in);
|
||||
final List<K> list = new ArrayList<K>();
|
||||
for (int idx = 0; idx < size; idx++) {
|
||||
list.add(keyDescriptor.read(in));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new IOException("Error reading data for index " + indexId, e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.openapi.components;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.UserDataHolder;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -98,4 +99,11 @@ public interface ComponentManager extends UserDataHolder, Disposable {
|
||||
<T> T[] getExtensions(ExtensionPointName<T> extensionPointName);
|
||||
|
||||
ComponentConfig getConfig(Class componentImplementation);
|
||||
|
||||
/**
|
||||
* @return condition for this component being disposed.
|
||||
* see {@link com.intellij.openapi.application.Application#invokeLater(Runnable, Condition)} for the usage example.
|
||||
*/
|
||||
@NotNull
|
||||
Condition getDisposed();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ package com.intellij.openapi.project;
|
||||
|
||||
import com.intellij.openapi.components.ComponentManager;
|
||||
import com.intellij.openapi.extensions.AreaInstance;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -61,8 +60,6 @@ public interface Project extends ComponentManager, AreaInstance {
|
||||
|
||||
void save();
|
||||
|
||||
Condition getDisposed();
|
||||
|
||||
boolean isOpen();
|
||||
|
||||
boolean isInitialized();
|
||||
|
||||
@@ -33,7 +33,7 @@ public class ComboBoxWithWidePopup extends JComboBox {
|
||||
if (SystemInfo.isMac && UIUtil.isUnderAquaLookAndFeel()) setMaximumRowCount(25);
|
||||
}
|
||||
|
||||
public ComboBoxWithWidePopup(final Object items[]) {
|
||||
public ComboBoxWithWidePopup(final Object[] items) {
|
||||
super(items);
|
||||
|
||||
if (SystemInfo.isMac && UIUtil.isUnderAquaLookAndFeel()) setMaximumRowCount(25);
|
||||
|
||||
+12
-6
@@ -16,6 +16,7 @@
|
||||
package com.intellij.codeInsight.hint;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
@@ -35,11 +36,13 @@ import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class EditorFragmentComponent extends JPanel {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.hint.EditorFragmentComponent");
|
||||
|
||||
private EditorFragmentComponent(EditorEx editor, int startLine, int endLine, boolean showFolding, boolean showGutter) {
|
||||
Document doc = editor.getDocument();
|
||||
final int endOffset = endLine < doc.getLineCount() ? doc.getLineEndOffset(endLine) : doc.getTextLength();
|
||||
int textWidth = Math.min(editor.getMaxWidthInRange(doc.getLineStartOffset(startLine), endOffset), ScreenUtil.getScreenRectangle(1, 1).width);
|
||||
LOG.assertTrue(textWidth > 0, "TextWidth: "+textWidth+"; startLine:" + startLine + "; endLine:" + endLine + ";");
|
||||
|
||||
FoldingModelEx foldingModel = editor.getFoldingModel();
|
||||
boolean isFoldingEnabled = foldingModel.isFoldingEnabled();
|
||||
@@ -51,6 +54,8 @@ public class EditorFragmentComponent extends JPanel {
|
||||
Point p2 = editor.logicalPositionToXY(new LogicalPosition(Math.max(endLine, startLine + 1), 0));
|
||||
int y1 = p1.y;
|
||||
int y2 = p2.y;
|
||||
int height = y2 - y1;
|
||||
LOG.assertTrue(height > 0, "Height: " + height + "; startLine:" + startLine + "; endLine:" + endLine + "; p1:" + p1 + "; p2:" + p2);
|
||||
|
||||
int savedScrollOffset = editor.getScrollingModel().getHorizontalScrollOffset();
|
||||
if (savedScrollOffset > 0) {
|
||||
@@ -58,20 +63,20 @@ public class EditorFragmentComponent extends JPanel {
|
||||
editor.getScrollingModel().scrollHorizontally(0);
|
||||
}
|
||||
|
||||
final Image textImage = new BufferedImage(textWidth, y2 - y1, BufferedImage.TYPE_INT_RGB);
|
||||
final Image textImage = new BufferedImage(textWidth, height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics textGraphics = textImage.getGraphics();
|
||||
|
||||
final JComponent rowHeader;
|
||||
final Image markersImage;
|
||||
if (showGutter) {
|
||||
rowHeader = editor.getGutterComponentEx();
|
||||
markersImage = new BufferedImage(Math.max(1, rowHeader.getWidth()), y2 - y1, BufferedImage.TYPE_INT_RGB);
|
||||
markersImage = new BufferedImage(Math.max(1, rowHeader.getWidth()), height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics markerGraphics = markersImage.getGraphics();
|
||||
|
||||
markerGraphics.translate(0, -y1);
|
||||
markerGraphics.setClip(0, y1, rowHeader.getWidth(), y2 - y1);
|
||||
markerGraphics.setClip(0, y1, rowHeader.getWidth(), height);
|
||||
markerGraphics.setColor(getBackgroundColor(editor));
|
||||
markerGraphics.fillRect(0, y1, rowHeader.getWidth(), y2 - y1);
|
||||
markerGraphics.fillRect(0, y1, rowHeader.getWidth(), height);
|
||||
rowHeader.paint(markerGraphics);
|
||||
}
|
||||
else {
|
||||
@@ -80,7 +85,7 @@ public class EditorFragmentComponent extends JPanel {
|
||||
}
|
||||
|
||||
textGraphics.translate(0, -y1);
|
||||
textGraphics.setClip(0, y1, textWidth, y2 - y1);
|
||||
textGraphics.setClip(0, y1, textWidth, height);
|
||||
final boolean wasVisible = editor.setCaretVisible(false);
|
||||
editor.getContentComponent().paint(textGraphics);
|
||||
if (wasVisible) {
|
||||
@@ -153,7 +158,8 @@ public class EditorFragmentComponent extends JPanel {
|
||||
|
||||
Point p = new Point(x, y);
|
||||
LightweightHint hint = new MyComponentHint(fragmentComponent);
|
||||
HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, p, (hideByAnyKey ? HintManagerImpl.HIDE_BY_ANY_KEY : 0) | HintManagerImpl.HIDE_BY_TEXT_CHANGE, 0, false, new HintHint(editor, p));
|
||||
HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, p, (hideByAnyKey ? HintManager.HIDE_BY_ANY_KEY : 0) |
|
||||
HintManager.HIDE_BY_TEXT_CHANGE, 0, false, new HintHint(editor, p));
|
||||
return hint;
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -44,11 +44,9 @@ public class ApplicationManagerEx extends ApplicationManager {
|
||||
final Application old = ourApplication;
|
||||
Disposer.register(parent, new Disposable() {
|
||||
public void dispose() {
|
||||
ourApplication = old;
|
||||
CachedSingletonsRegistry.cleanupCachedFields();
|
||||
setApplication(old);
|
||||
}
|
||||
});
|
||||
ourApplication = instance;
|
||||
CachedSingletonsRegistry.cleanupCachedFields();
|
||||
setApplication(instance);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-2
@@ -87,7 +87,7 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application
|
||||
|
||||
private final EventDispatcher<ApplicationListener> myDispatcher = EventDispatcher.create(ApplicationListener.class);
|
||||
|
||||
private final boolean myTestModeFlag;
|
||||
private boolean myTestModeFlag;
|
||||
private final boolean myHeadlessMode;
|
||||
private final boolean myCommandLineMode;
|
||||
|
||||
@@ -357,6 +357,10 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application
|
||||
return myTestModeFlag;
|
||||
}
|
||||
|
||||
public void setUnitTestMode(boolean testModeFlag) {
|
||||
myTestModeFlag = testModeFlag;
|
||||
}
|
||||
|
||||
public boolean isHeadlessEnvironment() {
|
||||
return myHeadlessMode;
|
||||
}
|
||||
@@ -689,7 +693,10 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application
|
||||
|
||||
if (!canExit()) return;
|
||||
|
||||
if (disposeSelf()) System.exit(myExitCode);
|
||||
boolean success = disposeSelf();
|
||||
if (success && !isUnitTestMode()) {
|
||||
System.exit(myExitCode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+3
-3
@@ -19,16 +19,16 @@
|
||||
*/
|
||||
package com.intellij.openapi.application.impl;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityInvokator;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Conditions;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ModalityInvokatorImpl implements ModalityInvokator {
|
||||
public ActionCallback invokeLater(Runnable runnable) {
|
||||
return invokeLater(runnable, Conditions.FALSE);
|
||||
return invokeLater(runnable, ApplicationManager.getApplication().getDisposed());
|
||||
}
|
||||
|
||||
public ActionCallback invokeLater(final Runnable runnable, @NotNull final Condition expired) {
|
||||
@@ -40,6 +40,6 @@ public class ModalityInvokatorImpl implements ModalityInvokator {
|
||||
}
|
||||
|
||||
public ActionCallback invokeLater(Runnable runnable, @NotNull ModalityState state) {
|
||||
return invokeLater(runnable, state, Conditions.FALSE);
|
||||
return invokeLater(runnable, state, ApplicationManager.getApplication().getDisposed());
|
||||
}
|
||||
}
|
||||
@@ -124,6 +124,7 @@ public class DummyProject extends UserDataHolderBase implements Project {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Condition getDisposed() {
|
||||
return new Condition() {
|
||||
public boolean value(final Object o) {
|
||||
|
||||
+11
@@ -30,6 +30,7 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
@@ -75,6 +76,11 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
|
||||
private Boolean myHeadless;
|
||||
private ComponentsRegistry myComponentsRegistry = new ComponentsRegistry();
|
||||
private boolean myHaveProgressManager = false;
|
||||
private final Condition myDisposedCondition = new Condition() {
|
||||
public boolean value(final Object o) {
|
||||
return isDisposed();
|
||||
}
|
||||
};
|
||||
|
||||
protected ComponentManagerImpl(ComponentManager parentComponentManager) {
|
||||
myParentComponentManager = parentComponentManager;
|
||||
@@ -431,6 +437,11 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
|
||||
return myComponentsRegistry.getConfig(componentImplementation);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Condition getDisposed() {
|
||||
return myDisposedCondition;
|
||||
}
|
||||
|
||||
private class ComponentsRegistry {
|
||||
private final Map<Class, Object> myInterfaceToLockMap = new HashMap<Class, Object>();
|
||||
private final Map<Class, Class> myInterfaceToClassMap = new HashMap<Class, Class>();
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
*/
|
||||
package com.intellij.openapi.editor.actions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorModificationUtil;
|
||||
@@ -36,6 +38,14 @@ public class SimplePasteAction extends EditorAction {
|
||||
super(new Handler());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
super.update(e);
|
||||
if (ActionPlaces.isPopupPlace(e.getPlace())) {
|
||||
e.getPresentation().setVisible(e.getPresentation().isEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
private static class Handler extends EditorWriteActionHandler {
|
||||
public void executeWriteAction(Editor editor, DataContext dataContext) {
|
||||
if (editor.isColumnMode()) {
|
||||
|
||||
@@ -87,7 +87,7 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
|
||||
|
||||
private void releaseBulkCaretMarker() {
|
||||
if (savedBeforeBulkCaretMarker != null) {
|
||||
((RangeMarkerEx)savedBeforeBulkCaretMarker).dispose();
|
||||
savedBeforeBulkCaretMarker.dispose();
|
||||
savedBeforeBulkCaretMarker = null;
|
||||
}
|
||||
}
|
||||
|
||||
+21
-12
@@ -221,6 +221,14 @@ public class EditorsSplitters extends JPanel {
|
||||
}
|
||||
mySplittersElement = null;
|
||||
}
|
||||
// clear empty splitters
|
||||
for (EditorWindow window : getWindows()) {
|
||||
if (window.getEditors().length == 0) {
|
||||
for (EditorWindow sibling : window.findSiblings()) {
|
||||
sibling.unsplit(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,6 +236,7 @@ public class EditorsSplitters extends JPanel {
|
||||
mySplittersElement = element;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public JPanel readExternalPanel(final Element element, @Nullable JPanel panel) {
|
||||
final Element splitterElement = element.getChild("splitter");
|
||||
@@ -263,11 +272,11 @@ public class EditorsSplitters extends JPanel {
|
||||
} else {
|
||||
window = findWindowWith(panel);
|
||||
}
|
||||
try {
|
||||
//noinspection unchecked
|
||||
final List<Element> children = leaf.getChildren("file");
|
||||
VirtualFile currentFile = null;
|
||||
for (final Element file : children) {
|
||||
//noinspection unchecked
|
||||
final List<Element> children = leaf.getChildren("file");
|
||||
VirtualFile currentFile = null;
|
||||
for (final Element file : children) {
|
||||
try {
|
||||
final HistoryEntry entry = new HistoryEntry(getManager().getProject(), file.getChild(HistoryEntry.TAG));
|
||||
boolean isCurrent = Boolean.valueOf(file.getAttributeValue("current")).booleanValue();
|
||||
getManager().openFileImpl3(window, entry.myFile, false, entry, isCurrent);
|
||||
@@ -281,15 +290,15 @@ public class EditorsSplitters extends JPanel {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentFile != null) {
|
||||
final EditorComposite editor = window.findFileComposite(currentFile);
|
||||
if (editor != null) {
|
||||
window.setSelectedEditor(editor, true);
|
||||
}
|
||||
catch (InvalidDataException e) {
|
||||
// OK
|
||||
}
|
||||
}
|
||||
catch (InvalidDataException e) {
|
||||
// OK
|
||||
if (currentFile != null) {
|
||||
final EditorComposite editor = window.findFileComposite(currentFile);
|
||||
if (editor != null) {
|
||||
window.setSelectedEditor(editor, true);
|
||||
}
|
||||
}
|
||||
return window.myPanel;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ import com.intellij.openapi.project.ex.ProjectEx;
|
||||
import com.intellij.openapi.project.ex.ProjectManagerEx;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.ex.MessagesEx;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -83,12 +82,6 @@ public class ProjectImpl extends ComponentManagerImpl implements ProjectEx {
|
||||
public boolean myOptimiseTestLoadSpeed;
|
||||
@NonNls public static final String TEMPLATE_PROJECT_NAME = "Default (Template) Project";
|
||||
|
||||
private final Condition myDisposedCondition = new Condition() {
|
||||
public boolean value(final Object o) {
|
||||
return isDisposed();
|
||||
}
|
||||
};
|
||||
|
||||
private String myName;
|
||||
private String myOldName;
|
||||
|
||||
@@ -174,10 +167,6 @@ public class ProjectImpl extends ComponentManagerImpl implements ProjectEx {
|
||||
return ProjectManagerEx.getInstanceEx().isProjectOpened(this);
|
||||
}
|
||||
|
||||
public Condition getDisposed() {
|
||||
return myDisposedCondition;
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return isOpen() && !isDisposed() && StartupManagerEx.getInstanceEx(this).startupActivityPassed();
|
||||
}
|
||||
|
||||
@@ -75,13 +75,13 @@ public class FileStatusManagerImpl extends FileStatusManager implements ProjectC
|
||||
}
|
||||
|
||||
public FileStatus calcStatus(@NotNull VirtualFile virtualFile) {
|
||||
if (virtualFile.isInLocalFileSystem() && myFileStatusProvider != null) {
|
||||
for (FileStatusProvider extension : myExtensions.getValue()) {
|
||||
FileStatus status = extension.getFileStatus(virtualFile);
|
||||
if (status != null) {
|
||||
return status;
|
||||
}
|
||||
for (FileStatusProvider extension : myExtensions.getValue()) {
|
||||
FileStatus status = extension.getFileStatus(virtualFile);
|
||||
if (status != null) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
if (virtualFile.isInLocalFileSystem() && myFileStatusProvider != null) {
|
||||
return myFileStatusProvider.getFileStatus(virtualFile);
|
||||
} else {
|
||||
return FileStatus.NOT_CHANGED;
|
||||
@@ -114,7 +114,7 @@ public class FileStatusManagerImpl extends FileStatusManager implements ProjectC
|
||||
|
||||
public void initComponent() { }
|
||||
|
||||
public void addFileStatusListener(FileStatusListener listener) {
|
||||
public void addFileStatusListener(@NotNull FileStatusListener listener) {
|
||||
myListeners.add(listener);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.wm.impl;
|
||||
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -76,7 +77,8 @@ public final class CommandProcessor implements Runnable {
|
||||
// max. I'm not actually quite sure this should have NON_MODAL modality but it should
|
||||
// definitely have some since runnables in command list may (and do) request some PSI activity
|
||||
final boolean queueNext = myCommandCount > 0;
|
||||
ApplicationManager.getApplication().getInvokator().invokeLater(command, ModalityState.NON_MODAL, expire == null ? Condition.FALSE : expire).doWhenDone(new Runnable() {
|
||||
Application application = ApplicationManager.getApplication();
|
||||
application.getInvokator().invokeLater(command, ModalityState.NON_MODAL, expire == null ? application.getDisposed() : expire).doWhenDone(new Runnable() {
|
||||
public void run() {
|
||||
if (queueNext) {
|
||||
CommandProcessor.this.run();
|
||||
|
||||
@@ -1823,7 +1823,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
|
||||
|
||||
@Nullable
|
||||
public Condition getExpireCondition() {
|
||||
return Condition.FALSE;
|
||||
return ApplicationManager.getApplication().getDisposed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,9 +24,6 @@ import com.intellij.openapi.util.ModificationTracker;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.reference.SoftReference;
|
||||
import com.intellij.util.concurrency.JBLock;
|
||||
import com.intellij.util.concurrency.JBReentrantReadWriteLock;
|
||||
import com.intellij.util.concurrency.LockFactory;
|
||||
import gnu.trove.TLongArrayList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -35,23 +32,12 @@ import java.lang.ref.Reference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.*;
|
||||
|
||||
/**
|
||||
* @author Dmitry Avdeev
|
||||
*/
|
||||
public abstract class CachedValueBase<T> {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.CachedValueImpl");
|
||||
|
||||
private final MyTimedReference<T> myData = new MyTimedReference<T>();
|
||||
private final JBLock r;
|
||||
private final JBLock w;
|
||||
|
||||
public CachedValueBase() {
|
||||
JBReentrantReadWriteLock rw = LockFactory.createReadWriteLock();
|
||||
r = rw.readLock();
|
||||
w = rw.writeLock();
|
||||
}
|
||||
|
||||
protected Data<T> computeData(T value, Object[] dependencies) {
|
||||
if (dependencies == null) {
|
||||
@@ -66,7 +52,7 @@ public abstract class CachedValueBase<T> {
|
||||
}
|
||||
|
||||
protected void setValue(final T value, final CachedValueProvider.Result<T> result) {
|
||||
myData.setData(computeData(value == null ? (T)NULL : value, getDependencies(result)));
|
||||
myData.setData(computeData(value == null ? (T)ObjectUtils.NULL : value, getDependencies(result)));
|
||||
myData.setIsLocked(result != null && result.isLockValue());
|
||||
}
|
||||
|
||||
@@ -82,7 +68,8 @@ public abstract class CachedValueBase<T> {
|
||||
}
|
||||
else {
|
||||
Object[] items = result.getDependencyItems();
|
||||
return result.getValue() == null ? items : items == null ? new Object[] {result.getValue()}: ArrayUtil.append(items, result.getValue());
|
||||
T value = result.getValue();
|
||||
return value == null ? items : items == null ? new Object[] {value}: ArrayUtil.append(items, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +120,7 @@ public abstract class CachedValueBase<T> {
|
||||
|
||||
protected void collectDependencies(TLongArrayList timeStamps, List<Object> resultingDeps, Object[] dependencies) {
|
||||
for (Object dependency : dependencies) {
|
||||
if (dependency == null || dependency == NULL) continue;
|
||||
if (dependency == null || dependency == ObjectUtils.NULL) continue;
|
||||
if (dependency instanceof Object[]) {
|
||||
collectDependencies(timeStamps, resultingDeps, (Object[])dependency);
|
||||
}
|
||||
@@ -168,16 +155,9 @@ public abstract class CachedValueBase<T> {
|
||||
}
|
||||
|
||||
public T setValue(final CachedValueProvider.Result<T> result) {
|
||||
w.lock();
|
||||
|
||||
try {
|
||||
T value = result.getValue();
|
||||
setValue(value, result);
|
||||
return value;
|
||||
}
|
||||
finally {
|
||||
w.unlock();
|
||||
}
|
||||
T value = result == null ? null : result.getValue();
|
||||
setValue(value, result);
|
||||
return value;
|
||||
}
|
||||
|
||||
public abstract boolean isFromMyProject(Project project);
|
||||
@@ -202,34 +182,15 @@ public abstract class CachedValueBase<T> {
|
||||
|
||||
@Nullable
|
||||
protected <P> T getValueWithLock(P param) {
|
||||
r.lock();
|
||||
try {
|
||||
T value = getUpToDateOrNull(true);
|
||||
if (value != null) {
|
||||
return value == NULL ? null : value;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
r.unlock();
|
||||
T value = getUpToDateOrNull(true);
|
||||
if (value != null) {
|
||||
return value == ObjectUtils.NULL ? null : value;
|
||||
}
|
||||
|
||||
// compute outside lock to avoid deadlock
|
||||
CachedValueProvider.Result<T> result = doCompute(param);
|
||||
T computed = result == null ? null : result.getValue();
|
||||
|
||||
w.lock();
|
||||
try {
|
||||
//T value = getUpToDateOrNull(false);
|
||||
//if (value != null) {
|
||||
// return value == NULL ? null : value;
|
||||
//}
|
||||
|
||||
setValue(computed, result);
|
||||
return computed;
|
||||
}
|
||||
finally {
|
||||
w.unlock();
|
||||
}
|
||||
return setValue(result);
|
||||
}
|
||||
|
||||
protected abstract <P> CachedValueProvider.Result<T> doCompute(P param);
|
||||
@@ -237,16 +198,15 @@ public abstract class CachedValueBase<T> {
|
||||
private static class MyTimedReference<T> extends TimedReference<SoftReference<Data<T>>> {
|
||||
private boolean myIsLocked;
|
||||
|
||||
|
||||
public MyTimedReference() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
public void setIsLocked(final boolean isLocked) {
|
||||
public synchronized void setIsLocked(final boolean isLocked) {
|
||||
myIsLocked = isLocked;
|
||||
}
|
||||
|
||||
protected boolean isLocked() {
|
||||
protected synchronized boolean isLocked() {
|
||||
return super.isLocked() || myIsLocked;
|
||||
}
|
||||
|
||||
|
||||
@@ -1192,3 +1192,7 @@ action.ConvertIndentsToTabs.description=Convert the indentation in the file or s
|
||||
group.Vcs.Import.text=Import into Version Control
|
||||
group.Vcs.Browse.text=Browse VCS Repository
|
||||
action.Graph.print.reset=Reset
|
||||
action.MarkSourceRoot.text=Source Root
|
||||
action.MarkTestSourceRoot.text=Test Source Root
|
||||
action.MarkExcludeRoot.text=Excluded
|
||||
group.MarkRootGroup.text=Mark Directory As
|
||||
|
||||
@@ -402,6 +402,11 @@
|
||||
</group>
|
||||
|
||||
<group id="ProjectViewPopupMenuSettingsGroup">
|
||||
<group id="MarkRootGroup" class="com.intellij.ide.projectView.actions.MarkRootGroup" popup="true">
|
||||
<action id="MarkSourceRoot" class="com.intellij.ide.projectView.actions.MarkRootAction"/>
|
||||
<action id="MarkTestSourceRoot" class="com.intellij.ide.projectView.actions.MarkTestSourceRootAction"/>
|
||||
<action id="MarkExcludeRoot" class="com.intellij.ide.projectView.actions.MarkExcludeRootAction"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group id="ProjectViewPopupMenu">
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.components.BaseComponent;
|
||||
import com.intellij.openapi.components.ComponentConfig;
|
||||
import com.intellij.openapi.components.ComponentManager;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
@@ -149,4 +150,10 @@ public class MockComponentManager extends UserDataHolderBase implements Componen
|
||||
public ComponentConfig getConfig(Class componentImplementation) {
|
||||
throw new UnsupportedOperationException("Method getConfig not implemented in " + getClass());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Condition getDisposed() {
|
||||
return Condition.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ public class MockProject extends MockComponentManager implements ProjectEx {
|
||||
return ServiceManager.getService(this, PomModel.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Condition getDisposed() {
|
||||
return new Condition() {
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.intellij.util.io;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
@@ -34,7 +36,7 @@ public class EnumeratorStringDescriptor implements KeyDescriptor<String> {
|
||||
return val1.equals(val2);
|
||||
}
|
||||
|
||||
public void save(final DataOutput storage, final String value) throws IOException {
|
||||
public void save(final DataOutput storage, @NotNull final String value) throws IOException {
|
||||
IOUtil.writeUTFFast(buffer, storage, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,14 +20,13 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.undo.UndoManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.impl.DocumentImpl;
|
||||
import com.intellij.openapi.editor.markup.*;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
@@ -46,6 +45,7 @@ import java.util.ListIterator;
|
||||
*/
|
||||
public class LineStatusTracker {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.ex.LineStatusTracker");
|
||||
private final Object myLock = new Object();
|
||||
// true -> have contents
|
||||
private BaseLoadState myBaseLoaded;
|
||||
|
||||
@@ -72,36 +72,36 @@ public class LineStatusTracker {
|
||||
}
|
||||
|
||||
public void initialize(@NotNull final String upToDateContent) {
|
||||
ApplicationManager.getApplication().isReadAccessAllowed();
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
LOG.assertTrue(BaseLoadState.LOADING == myBaseLoaded);
|
||||
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
myUpToDateDocument.setReadOnly(false);
|
||||
myUpToDateDocument.replaceString(0, myUpToDateDocument.getTextLength(), upToDateContent);
|
||||
myUpToDateDocument.setReadOnly(true);
|
||||
reinstallRanges();
|
||||
synchronized (myLock) {
|
||||
try {
|
||||
myUpToDateDocument.setReadOnly(false);
|
||||
myUpToDateDocument.replaceString(0, myUpToDateDocument.getTextLength(), upToDateContent);
|
||||
myUpToDateDocument.setReadOnly(true);
|
||||
reinstallRanges();
|
||||
|
||||
if (myDocumentListener == null) {
|
||||
myDocumentListener = new MyDocumentListener();
|
||||
myDocument.addDocumentListener(myDocumentListener);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
myBaseLoaded = BaseLoadState.LOADED;
|
||||
if (myDocumentListener == null) {
|
||||
myDocumentListener = new MyDocumentListener();
|
||||
myDocument.addDocumentListener(myDocumentListener);
|
||||
}
|
||||
}
|
||||
});
|
||||
finally {
|
||||
myBaseLoaded = BaseLoadState.LOADED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void reinstallRanges() {
|
||||
myApplication.assertWriteAccessAllowed();
|
||||
myApplication.assertReadAccessAllowed();
|
||||
|
||||
removeHighlightersFromMarkupModel();
|
||||
myRanges = new RangesBuilder(myDocument, myUpToDateDocument).getRanges();
|
||||
for (final Range range : myRanges) {
|
||||
range.setHighlighter(createHighlighter(range));
|
||||
synchronized (myLock) {
|
||||
removeHighlightersFromMarkupModel();
|
||||
myRanges = new RangesBuilder(myDocument, myUpToDateDocument).getRanges();
|
||||
for (final Range range : myRanges) {
|
||||
range.setHighlighter(createHighlighter(range));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,16 +137,13 @@ public class LineStatusTracker {
|
||||
}
|
||||
|
||||
public void release() {
|
||||
myApplication.runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (myDocumentListener != null) {
|
||||
myDocument.removeDocumentListener(myDocumentListener);
|
||||
}
|
||||
removeHighlightersFromMarkupModel();
|
||||
myRanges.clear();
|
||||
synchronized (myLock) {
|
||||
if (myDocumentListener != null) {
|
||||
myDocument.removeDocumentListener(myDocumentListener);
|
||||
}
|
||||
});
|
||||
removeHighlightersFromMarkupModel();
|
||||
myRanges.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public Document getDocument() {
|
||||
@@ -160,39 +157,38 @@ public class LineStatusTracker {
|
||||
public List<Range> getRanges() {
|
||||
myApplication.assertReadAccessAllowed();
|
||||
|
||||
return myRanges;
|
||||
synchronized (myLock) {
|
||||
return myRanges;
|
||||
}
|
||||
}
|
||||
|
||||
public Document getUpToDateDocument() {
|
||||
myApplication.assertIsDispatchThread();
|
||||
return myUpToDateDocument;
|
||||
}
|
||||
|
||||
public void startBulkUpdate() {
|
||||
myApplication.runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myBulkUpdate = true;
|
||||
removeHighlightersFromMarkupModel();
|
||||
myRanges.clear();
|
||||
}
|
||||
});
|
||||
synchronized (myLock) {
|
||||
myBulkUpdate = true;
|
||||
removeHighlightersFromMarkupModel();
|
||||
myRanges.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void removeHighlightersFromMarkupModel() {
|
||||
final MarkupModel markupModel = myDocument.getMarkupModel(myProject);
|
||||
for (Range range : myRanges) {
|
||||
markupModel.removeHighlighter(range.getHighlighter());
|
||||
synchronized (myLock) {
|
||||
for (Range range : myRanges) {
|
||||
markupModel.removeHighlighter(range.getHighlighter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void finishBulkUpdate() {
|
||||
myApplication.runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myBulkUpdate = false;
|
||||
reinstallRanges();
|
||||
}
|
||||
});
|
||||
synchronized (myLock) {
|
||||
myBulkUpdate = false;
|
||||
reinstallRanges();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,24 +196,18 @@ public class LineStatusTracker {
|
||||
* false -> load was already started; after contents is loaded,
|
||||
*/
|
||||
public boolean resetForBaseRevisionLoad() {
|
||||
return myApplication.runReadAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
if (BaseLoadState.LOADING == myBaseLoaded) return false;
|
||||
return myApplication.runWriteAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
myUpToDateDocument.setReadOnly(false);
|
||||
myUpToDateDocument.setText("");
|
||||
myUpToDateDocument.setReadOnly(true);
|
||||
removeHighlightersFromMarkupModel();
|
||||
myRanges.clear();
|
||||
myBaseLoaded = BaseLoadState.LOADING;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
myApplication.assertReadAccessAllowed();
|
||||
|
||||
synchronized (myLock) {
|
||||
if (BaseLoadState.LOADING == myBaseLoaded) return false;
|
||||
myUpToDateDocument.setReadOnly(false);
|
||||
myUpToDateDocument.setText("");
|
||||
myUpToDateDocument.setReadOnly(true);
|
||||
removeHighlightersFromMarkupModel();
|
||||
myRanges.clear();
|
||||
myBaseLoaded = BaseLoadState.LOADING;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyDocumentListener extends DocumentAdapter {
|
||||
@@ -231,39 +221,41 @@ public class LineStatusTracker {
|
||||
if (myBulkUpdate || (BaseLoadState.LOADED != myBaseLoaded)) return;
|
||||
myApplication.assertWriteAccessAllowed();
|
||||
|
||||
try {
|
||||
myFirstChangedLine = myDocument.getLineNumber(e.getOffset());
|
||||
myLastChangedLine = myDocument.getLineNumber(e.getOffset() + e.getOldLength());
|
||||
if (StringUtil.endsWithChar(e.getOldFragment(), '\n')) myLastChangedLine++;
|
||||
synchronized (myLock) {
|
||||
try {
|
||||
myFirstChangedLine = myDocument.getLineNumber(e.getOffset());
|
||||
myLastChangedLine = myDocument.getLineNumber(e.getOffset() + e.getOldLength());
|
||||
if (StringUtil.endsWithChar(e.getOldFragment(), '\n')) myLastChangedLine++;
|
||||
|
||||
myLinesBeforeChange = myDocument.getLineNumber(e.getOffset() + e.getOldLength()) - myDocument.getLineNumber(e.getOffset());
|
||||
myLinesBeforeChange = myDocument.getLineNumber(e.getOffset() + e.getOldLength()) - myDocument.getLineNumber(e.getOffset());
|
||||
|
||||
Range firstChangedRange = getLastRangeBeforeLine(myFirstChangedLine);
|
||||
Range firstChangedRange = getLastRangeBeforeLine(myFirstChangedLine);
|
||||
|
||||
if (firstChangedRange == null) {
|
||||
myUpToDateFirstLine = myFirstChangedLine;
|
||||
}
|
||||
else if (firstChangedRange.containsLine(myFirstChangedLine)) {
|
||||
myFirstChangedLine = firstChangedRange.getOffset1();
|
||||
myUpToDateFirstLine = firstChangedRange.getUOffset1();
|
||||
}
|
||||
else {
|
||||
myUpToDateFirstLine = firstChangedRange.getUOffset2() + (myFirstChangedLine - firstChangedRange.getOffset2());
|
||||
}
|
||||
if (firstChangedRange == null) {
|
||||
myUpToDateFirstLine = myFirstChangedLine;
|
||||
}
|
||||
else if (firstChangedRange.containsLine(myFirstChangedLine)) {
|
||||
myFirstChangedLine = firstChangedRange.getOffset1();
|
||||
myUpToDateFirstLine = firstChangedRange.getUOffset1();
|
||||
}
|
||||
else {
|
||||
myUpToDateFirstLine = firstChangedRange.getUOffset2() + (myFirstChangedLine - firstChangedRange.getOffset2());
|
||||
}
|
||||
|
||||
Range myLastChangedRange = getLastRangeBeforeLine(myLastChangedLine);
|
||||
Range myLastChangedRange = getLastRangeBeforeLine(myLastChangedLine);
|
||||
|
||||
if (myLastChangedRange == null) {
|
||||
myUpToDateLastLine = myLastChangedLine;
|
||||
if (myLastChangedRange == null) {
|
||||
myUpToDateLastLine = myLastChangedLine;
|
||||
}
|
||||
else if (myLastChangedRange.containsLine(myLastChangedLine)) {
|
||||
myUpToDateLastLine = myLastChangedRange.getUOffset2();
|
||||
myLastChangedLine = myLastChangedRange.getOffset2();
|
||||
}
|
||||
else {
|
||||
myUpToDateLastLine = myLastChangedRange.getUOffset2() + (myLastChangedLine - myLastChangedRange.getOffset2());
|
||||
}
|
||||
} catch (ProcessCanceledException ignore) {
|
||||
}
|
||||
else if (myLastChangedRange.containsLine(myLastChangedLine)) {
|
||||
myUpToDateLastLine = myLastChangedRange.getUOffset2();
|
||||
myLastChangedLine = myLastChangedRange.getOffset2();
|
||||
}
|
||||
else {
|
||||
myUpToDateLastLine = myLastChangedRange.getUOffset2() + (myLastChangedLine - myLastChangedRange.getOffset2());
|
||||
}
|
||||
} catch (ProcessCanceledException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,47 +273,49 @@ public class LineStatusTracker {
|
||||
if (myBulkUpdate || (BaseLoadState.LOADED != myBaseLoaded)) return;
|
||||
myApplication.assertWriteAccessAllowed();
|
||||
|
||||
try {
|
||||
synchronized (myLock) {
|
||||
try {
|
||||
|
||||
int line = myDocument.getLineNumber(e.getOffset() + e.getNewLength());
|
||||
int linesAfterChange = line - myDocument.getLineNumber(e.getOffset());
|
||||
int linesShift = linesAfterChange - myLinesBeforeChange;
|
||||
int line = myDocument.getLineNumber(e.getOffset() + e.getNewLength());
|
||||
int linesAfterChange = line - myDocument.getLineNumber(e.getOffset());
|
||||
int linesShift = linesAfterChange - myLinesBeforeChange;
|
||||
|
||||
List<Range> rangesAfterChange = getRangesAfter(myRanges, myLastChangedLine);
|
||||
List<Range> rangesBeforeChange = getRangesBefore(myRanges, myFirstChangedLine);
|
||||
List<Range> rangesAfterChange = getRangesAfter(myRanges, myLastChangedLine);
|
||||
List<Range> rangesBeforeChange = getRangesBefore(myRanges, myFirstChangedLine);
|
||||
|
||||
List<Range> changedRanges = getChangedRanges(myFirstChangedLine, myLastChangedLine);
|
||||
List<Range> changedRanges = getChangedRanges(myFirstChangedLine, myLastChangedLine);
|
||||
|
||||
int newSize = rangesBeforeChange.size() + changedRanges.size() + rangesAfterChange.size();
|
||||
if (myRanges.size() != newSize) {
|
||||
LOG.info("Ranges: " + myRanges + "; first changed line: " + myFirstChangedLine + "; last changed line: " + myLastChangedLine);
|
||||
LOG.assertTrue(false);
|
||||
}
|
||||
|
||||
|
||||
myLastChangedLine += linesShift;
|
||||
|
||||
|
||||
List<Range> newChangedRanges = getNewChangedRanges();
|
||||
|
||||
shiftRanges(rangesAfterChange, linesShift);
|
||||
|
||||
if (!changedRanges.equals(newChangedRanges)) {
|
||||
replaceRanges(changedRanges, newChangedRanges);
|
||||
|
||||
myRanges = new ArrayList<Range>();
|
||||
|
||||
myRanges.addAll(rangesBeforeChange);
|
||||
myRanges.addAll(newChangedRanges);
|
||||
myRanges.addAll(rangesAfterChange);
|
||||
|
||||
myRanges = mergeRanges(myRanges);
|
||||
|
||||
for (Range range : myRanges) {
|
||||
if (!range.hasHighlighter()) range.setHighlighter(createHighlighter(range));
|
||||
int newSize = rangesBeforeChange.size() + changedRanges.size() + rangesAfterChange.size();
|
||||
if (myRanges.size() != newSize) {
|
||||
LOG.info("Ranges: " + myRanges + "; first changed line: " + myFirstChangedLine + "; last changed line: " + myLastChangedLine);
|
||||
LOG.assertTrue(false);
|
||||
}
|
||||
|
||||
|
||||
myLastChangedLine += linesShift;
|
||||
|
||||
|
||||
List<Range> newChangedRanges = getNewChangedRanges();
|
||||
|
||||
shiftRanges(rangesAfterChange, linesShift);
|
||||
|
||||
if (!changedRanges.equals(newChangedRanges)) {
|
||||
replaceRanges(changedRanges, newChangedRanges);
|
||||
|
||||
myRanges = new ArrayList<Range>();
|
||||
|
||||
myRanges.addAll(rangesBeforeChange);
|
||||
myRanges.addAll(newChangedRanges);
|
||||
myRanges.addAll(rangesAfterChange);
|
||||
|
||||
myRanges = mergeRanges(myRanges);
|
||||
|
||||
for (Range range : myRanges) {
|
||||
if (!range.hasHighlighter()) range.setHighlighter(createHighlighter(range));
|
||||
}
|
||||
}
|
||||
} catch (ProcessCanceledException ignore) {
|
||||
}
|
||||
} catch (ProcessCanceledException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,49 +384,57 @@ public class LineStatusTracker {
|
||||
|
||||
@Nullable
|
||||
Range getNextRange(final Range range) {
|
||||
final int index = myRanges.indexOf(range);
|
||||
if (index == myRanges.size() - 1) return null;
|
||||
return myRanges.get(index + 1);
|
||||
synchronized (myLock) {
|
||||
final int index = myRanges.indexOf(range);
|
||||
if (index == myRanges.size() - 1) return null;
|
||||
return myRanges.get(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Range getPrevRange(final Range range) {
|
||||
final int index = myRanges.indexOf(range);
|
||||
if (index <= 0) return null;
|
||||
return myRanges.get(index - 1);
|
||||
synchronized (myLock) {
|
||||
final int index = myRanges.indexOf(range);
|
||||
if (index <= 0) return null;
|
||||
return myRanges.get(index - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Range getNextRange(final int line) {
|
||||
final Range currentRange = getRangeForLine(line);
|
||||
if (currentRange != null) {
|
||||
return getNextRange(currentRange);
|
||||
}
|
||||
|
||||
for (final Range range : myRanges) {
|
||||
if (line > range.getOffset1() || line > range.getOffset2()) {
|
||||
continue;
|
||||
synchronized (myLock) {
|
||||
final Range currentRange = getRangeForLine(line);
|
||||
if (currentRange != null) {
|
||||
return getNextRange(currentRange);
|
||||
}
|
||||
return range;
|
||||
|
||||
for (final Range range : myRanges) {
|
||||
if (line > range.getOffset1() || line > range.getOffset2()) {
|
||||
continue;
|
||||
}
|
||||
return range;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Range getPrevRange(final int line) {
|
||||
final Range currentRange = getRangeForLine(line);
|
||||
if (currentRange != null) {
|
||||
return getPrevRange(currentRange);
|
||||
}
|
||||
|
||||
for (ListIterator<Range> iterator = myRanges.listIterator(myRanges.size()); iterator.hasPrevious();) {
|
||||
final Range range = iterator.previous();
|
||||
if (range.getOffset1() > line) {
|
||||
continue;
|
||||
synchronized (myLock) {
|
||||
final Range currentRange = getRangeForLine(line);
|
||||
if (currentRange != null) {
|
||||
return getPrevRange(currentRange);
|
||||
}
|
||||
return range;
|
||||
|
||||
for (ListIterator<Range> iterator = myRanges.listIterator(myRanges.size()); iterator.hasPrevious();) {
|
||||
final Range range = iterator.previous();
|
||||
if (range.getOffset1() > line) {
|
||||
continue;
|
||||
}
|
||||
return range;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<Range> getRangesBefore(List<Range> ranges, int line) {
|
||||
@@ -455,43 +457,49 @@ public class LineStatusTracker {
|
||||
|
||||
@Nullable
|
||||
public Range getRangeForLine(final int line) {
|
||||
for (final Range range : myRanges) {
|
||||
if (range.getType() == Range.DELETED && line == range.getOffset1()) {
|
||||
return range;
|
||||
}
|
||||
else if (line >= range.getOffset1() && line < range.getOffset2()) {
|
||||
return range;
|
||||
synchronized (myLock) {
|
||||
for (final Range range : myRanges) {
|
||||
if (range.getType() == Range.DELETED && line == range.getOffset1()) {
|
||||
return range;
|
||||
}
|
||||
else if (line >= range.getOffset1() && line < range.getOffset2()) {
|
||||
return range;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void rollbackChanges(final Range range) {
|
||||
myApplication.assertWriteAccessAllowed();
|
||||
|
||||
TextRange currentTextRange = getCurrentTextRange(range);
|
||||
synchronized (myLock) {
|
||||
TextRange currentTextRange = getCurrentTextRange(range);
|
||||
|
||||
if (range.getType() == Range.INSERTED) {
|
||||
myDocument
|
||||
.replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()), "");
|
||||
}
|
||||
else if (range.getType() == Range.DELETED) {
|
||||
String upToDateContent = getUpToDateContent(range);
|
||||
myDocument.insertString(currentTextRange.getStartOffset(), upToDateContent);
|
||||
}
|
||||
else {
|
||||
if (range.getType() == Range.INSERTED) {
|
||||
myDocument
|
||||
.replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()), "");
|
||||
}
|
||||
else if (range.getType() == Range.DELETED) {
|
||||
String upToDateContent = getUpToDateContent(range);
|
||||
myDocument.insertString(currentTextRange.getStartOffset(), upToDateContent);
|
||||
}
|
||||
else {
|
||||
|
||||
String upToDateContent = getUpToDateContent(range);
|
||||
myDocument.replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()),
|
||||
upToDateContent);
|
||||
String upToDateContent = getUpToDateContent(range);
|
||||
myDocument.replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()),
|
||||
upToDateContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getUpToDateContent(Range range) {
|
||||
TextRange textRange = getUpToDateRange(range);
|
||||
final int startOffset = textRange.getStartOffset();
|
||||
final int endOffset = Math.min(textRange.getEndOffset() + 1, myUpToDateDocument.getTextLength());
|
||||
return myUpToDateDocument.getCharsSequence().subSequence(startOffset, endOffset).toString();
|
||||
synchronized (myLock) {
|
||||
TextRange textRange = getUpToDateRange(range);
|
||||
final int startOffset = textRange.getStartOffset();
|
||||
final int endOffset = Math.min(textRange.getEndOffset() + 1, myUpToDateDocument.getTextLength());
|
||||
return myUpToDateDocument.getCharsSequence().subSequence(startOffset, endOffset).toString();
|
||||
}
|
||||
}
|
||||
|
||||
Project getProject() {
|
||||
@@ -539,7 +547,7 @@ public class LineStatusTracker {
|
||||
}
|
||||
|
||||
public static LineStatusTracker createOn(final Document doc, final Project project) {
|
||||
final Document document = EditorFactory.getInstance().createDocument("");
|
||||
final Document document = new DocumentImpl(true);
|
||||
return new LineStatusTracker(doc, document, project);
|
||||
}
|
||||
|
||||
@@ -548,8 +556,9 @@ public class LineStatusTracker {
|
||||
}
|
||||
|
||||
public void baseRevisionLoadFailed() {
|
||||
myApplication.assertWriteAccessAllowed();
|
||||
myBaseLoaded = BaseLoadState.FAILED;
|
||||
synchronized (myLock) {
|
||||
myBaseLoaded = BaseLoadState.FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum BaseLoadState {
|
||||
|
||||
@@ -42,7 +42,6 @@ import com.intellij.openapi.editor.ex.DocumentBulkUpdateListener;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -68,6 +67,7 @@ import java.util.Map;
|
||||
|
||||
public class LineStatusTrackerManager implements ProjectComponent, LineStatusTrackerManagerI {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.impl.LineStatusTrackerManager");
|
||||
public final Object myLock = new Object();
|
||||
|
||||
public static LineStatusTrackerManagerI getInstance(final Project project) {
|
||||
if (System.getProperty(IGNORE_CHANGEMARKERS_KEY) != null) {
|
||||
@@ -116,15 +116,17 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
|
||||
myDisposable = new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
final Collection<LineStatusTracker> trackers = myLineStatusTrackers.values();
|
||||
final LineStatusTracker[] lineStatusTrackers = trackers.toArray(new LineStatusTracker[trackers.size()]);
|
||||
for (final LineStatusTracker tracker : lineStatusTrackers) {
|
||||
releaseTracker(tracker.getDocument());
|
||||
}
|
||||
synchronized (myLock) {
|
||||
final Collection<LineStatusTracker> trackers = myLineStatusTrackers.values();
|
||||
final LineStatusTracker[] lineStatusTrackers = trackers.toArray(new LineStatusTracker[trackers.size()]);
|
||||
for (final LineStatusTracker tracker : lineStatusTrackers) {
|
||||
releaseTracker(tracker.getDocument());
|
||||
}
|
||||
|
||||
myLineStatusTrackers.clear();
|
||||
assert myLineStatusUpdateAlarms.isEmpty();
|
||||
myLineStatusUpdateAlarms.clear();
|
||||
myLineStatusTrackers.clear();
|
||||
assert myLineStatusUpdateAlarms.isEmpty();
|
||||
myLineStatusUpdateAlarms.clear();
|
||||
}
|
||||
}
|
||||
};
|
||||
Disposer.register(myProject, myDisposable);
|
||||
@@ -178,12 +180,15 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
|
||||
@Override
|
||||
public LineStatusTracker getLineStatusTracker(final Document document) {
|
||||
myApplication.assertReadAccessAllowed();
|
||||
|
||||
if ((! myProject.isOpen()) || myProject.isDisposed()) return null;
|
||||
return myLineStatusTrackers.get(document);
|
||||
|
||||
synchronized (myLock) {
|
||||
return myLineStatusTrackers.get(document);
|
||||
}
|
||||
}
|
||||
|
||||
private void resetTracker(@NotNull final VirtualFile virtualFile) {
|
||||
myApplication.assertReadAccessAllowed();
|
||||
if ((! myProject.isOpen()) || myProject.isDisposed()) return;
|
||||
|
||||
final Document document = FileDocumentManager.getInstance().getCachedDocument(virtualFile);
|
||||
@@ -194,49 +199,43 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
|
||||
|
||||
log("resetting tracker for file " + virtualFile.getPath());
|
||||
|
||||
final LineStatusTracker tracker = myLineStatusTrackers.get(document);
|
||||
final boolean editorOpened = myFileEditorManager.isFileOpen(virtualFile);
|
||||
final boolean shouldBeInstalled = shouldBeInstalled(virtualFile) && editorOpened;
|
||||
|
||||
if (tracker == null && (! shouldBeInstalled)) return;
|
||||
synchronized (myLock) {
|
||||
final LineStatusTracker tracker = myLineStatusTrackers.get(document);
|
||||
|
||||
myApplication.runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// remove ?
|
||||
if (tracker != null) {
|
||||
if (! shouldBeInstalled) {
|
||||
releaseTracker(document);
|
||||
return;
|
||||
} else if ((LineStatusTracker.BaseLoadState.LOADING == tracker.getBaseLoaded())) {
|
||||
return; // will be recalculated
|
||||
} else {
|
||||
tracker.resetForBaseRevisionLoad();
|
||||
startAlarm(document, virtualFile);
|
||||
}
|
||||
} else if (shouldBeInstalled) {
|
||||
installTracker(virtualFile, document);
|
||||
if (tracker == null && (! shouldBeInstalled)) return;
|
||||
|
||||
if (tracker != null) {
|
||||
if (! shouldBeInstalled) {
|
||||
releaseTracker(document);
|
||||
return;
|
||||
} else if ((LineStatusTracker.BaseLoadState.LOADING == tracker.getBaseLoaded())) {
|
||||
return; // will be recalculated
|
||||
} else {
|
||||
tracker.resetForBaseRevisionLoad();
|
||||
startAlarm(document, virtualFile);
|
||||
}
|
||||
} else if (shouldBeInstalled) {
|
||||
installTracker(virtualFile, document);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseTracker(final Document document) {
|
||||
if ((! myProject.isOpen()) || myProject.isDisposed()) return;
|
||||
|
||||
myApplication.runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Alarm alarm = myLineStatusUpdateAlarms.remove(document);
|
||||
if (alarm != null) {
|
||||
alarm.cancelAllRequests();
|
||||
}
|
||||
final LineStatusTracker tracker = myLineStatusTrackers.remove(document);
|
||||
if (tracker != null) {
|
||||
tracker.release();
|
||||
}
|
||||
synchronized (myLock) {
|
||||
final Alarm alarm = myLineStatusUpdateAlarms.remove(document);
|
||||
if (alarm != null) {
|
||||
alarm.cancelAllRequests();
|
||||
}
|
||||
});
|
||||
final LineStatusTracker tracker = myLineStatusTrackers.remove(document);
|
||||
if (tracker != null) {
|
||||
tracker.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldBeInstalled(final VirtualFile virtualFile) {
|
||||
@@ -261,25 +260,24 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
|
||||
}
|
||||
|
||||
private void installTracker(final VirtualFile virtualFile, final Document document) {
|
||||
myApplication.runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (myLineStatusTrackers.containsKey(document)) return;
|
||||
assert !myLineStatusUpdateAlarms.containsKey(document);
|
||||
synchronized (myLock) {
|
||||
if (myLineStatusTrackers.containsKey(document)) return;
|
||||
assert !myLineStatusUpdateAlarms.containsKey(document);
|
||||
|
||||
final LineStatusTracker tracker = LineStatusTracker.createOn(document, myProject);
|
||||
myLineStatusTrackers.put(document, tracker);
|
||||
final LineStatusTracker tracker = LineStatusTracker.createOn(document, myProject);
|
||||
myLineStatusTrackers.put(document, tracker);
|
||||
|
||||
startAlarm(document, virtualFile);
|
||||
}
|
||||
});
|
||||
startAlarm(document, virtualFile);
|
||||
}
|
||||
}
|
||||
|
||||
private void startAlarm(final Document document, final VirtualFile virtualFile) {
|
||||
myApplication.assertWriteAccessAllowed();
|
||||
myApplication.assertReadAccessAllowed();
|
||||
|
||||
final Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
|
||||
myLineStatusUpdateAlarms.put(document, alarm);
|
||||
synchronized (myLock) {
|
||||
myLineStatusUpdateAlarms.put(document, alarm);
|
||||
}
|
||||
alarm.addRequest(new BaseRevisionLoader(alarm, document, virtualFile), 10);
|
||||
}
|
||||
|
||||
@@ -297,14 +295,12 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
|
||||
@Override
|
||||
public void run() {
|
||||
myAlarm.cancelAllRequests();
|
||||
final Boolean removed = myApplication.runReadAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
final Alarm removed = myLineStatusUpdateAlarms.remove(myDocument);
|
||||
return removed != null;
|
||||
synchronized (myLock) {
|
||||
final Alarm removed = myLineStatusUpdateAlarms.remove(myDocument);
|
||||
if (removed == null) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (! Boolean.TRUE.equals(removed)) return;
|
||||
}
|
||||
if ((! myProject.isOpen()) || myProject.isDisposed()) return;
|
||||
|
||||
if (! myVirtualFile.isValid()) {
|
||||
@@ -323,15 +319,13 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
|
||||
final String converted = StringUtil.convertLineSeparators(lastUpToDateContent);
|
||||
myApplication.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
public void run() {
|
||||
log("initializing tracker for file " + myVirtualFile.getPath());
|
||||
final LineStatusTracker tracker = myLineStatusTrackers.get(myDocument);
|
||||
if (tracker != null) {
|
||||
tracker.initialize(converted);
|
||||
}
|
||||
synchronized (myLock) {
|
||||
log("initializing tracker for file " + myVirtualFile.getPath());
|
||||
final LineStatusTracker tracker = myLineStatusTrackers.get(myDocument);
|
||||
if (tracker != null) {
|
||||
tracker.initialize(converted);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, new Condition() {
|
||||
@Override
|
||||
@@ -342,24 +336,13 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
|
||||
}
|
||||
|
||||
private void reportTrackerBaseLoadFailed() {
|
||||
myApplication.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
public void run() {
|
||||
log("base revision load failed for file " + myVirtualFile.getPath());
|
||||
final LineStatusTracker tracker = myLineStatusTrackers.get(myDocument);
|
||||
if (tracker != null) {
|
||||
tracker.baseRevisionLoadFailed();
|
||||
}
|
||||
}
|
||||
});
|
||||
synchronized (myLock) {
|
||||
log("base revision load failed for file " + myVirtualFile.getPath());
|
||||
final LineStatusTracker tracker = myLineStatusTrackers.get(myDocument);
|
||||
if (tracker != null) {
|
||||
tracker.baseRevisionLoadFailed();
|
||||
}
|
||||
}, new Condition() {
|
||||
@Override
|
||||
public boolean value(final Object ignore) {
|
||||
return (! myProject.isOpen()) || myProject.isDisposed();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,7 +352,6 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra
|
||||
|
||||
final VirtualFile[] openFiles = myFileEditorManager.getOpenFiles();
|
||||
for(final VirtualFile openFile: openFiles) {
|
||||
// write action inside is sufficient level
|
||||
resetTracker(openFile);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2010 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,22 +27,26 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class InfiniteLoopStatementInspection extends BaseInspection {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"infinite.loop.statement.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"infinite.loop.statement.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new InfiniteLoopStatementsVisitor();
|
||||
}
|
||||
@@ -50,12 +54,14 @@ public class InfiniteLoopStatementInspection extends BaseInspection {
|
||||
private static class InfiniteLoopStatementsVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override public void visitForStatement(@NotNull PsiForStatement statement) {
|
||||
@Override public void visitForStatement(
|
||||
@NotNull PsiForStatement statement) {
|
||||
super.visitForStatement(statement);
|
||||
checkStatement(statement);
|
||||
}
|
||||
|
||||
@Override public void visitWhileStatement(@NotNull PsiWhileStatement statement) {
|
||||
@Override public void visitWhileStatement(
|
||||
@NotNull PsiWhileStatement statement) {
|
||||
super.visitWhileStatement(statement);
|
||||
checkStatement(statement);
|
||||
}
|
||||
|
||||
@@ -103,14 +103,16 @@ public class ControlFlowUtils{
|
||||
final PsiExpression test = loopStatement.getCondition();
|
||||
final PsiStatement body = loopStatement.getBody();
|
||||
return statementMayCompleteNormally(body) && !BoolUtils.isTrue(test)
|
||||
|| statementIsBreakTarget(loopStatement);
|
||||
|| statementIsBreakTarget(loopStatement)
|
||||
|| statementContainsContinueToAncestor(loopStatement);
|
||||
}
|
||||
|
||||
private static boolean whileStatementMayReturnNormally(
|
||||
@NotNull PsiWhileStatement loopStatement){
|
||||
final PsiExpression test = loopStatement.getCondition();
|
||||
return !BoolUtils.isTrue(test)
|
||||
|| statementIsBreakTarget(loopStatement);
|
||||
|| statementIsBreakTarget(loopStatement)
|
||||
|| statementContainsContinueToAncestor(loopStatement);
|
||||
}
|
||||
|
||||
private static boolean forStatementMayReturnNormally(
|
||||
@@ -119,6 +121,9 @@ public class ControlFlowUtils{
|
||||
if(statementIsBreakTarget(loopStatement)){
|
||||
return true;
|
||||
}
|
||||
if (statementContainsContinueToAncestor(loopStatement)) {
|
||||
return true;
|
||||
}
|
||||
if(test == null){
|
||||
return false;
|
||||
}
|
||||
@@ -276,6 +281,19 @@ public class ControlFlowUtils{
|
||||
return breakFinder.breakFound();
|
||||
}
|
||||
|
||||
private static boolean statementContainsContinueToAncestor(
|
||||
@NotNull PsiStatement statement){
|
||||
PsiElement parent = statement.getParent();
|
||||
while (parent instanceof PsiLabeledStatement) {
|
||||
statement = (PsiStatement) parent;
|
||||
parent = parent.getParent();
|
||||
}
|
||||
final ContinueToAncestorFinder continueToAncestorFinder =
|
||||
new ContinueToAncestorFinder(statement);
|
||||
statement.accept(continueToAncestorFinder);
|
||||
return continueToAncestorFinder.continueToAncestorFound();
|
||||
}
|
||||
|
||||
public static boolean statementContainsReturn(
|
||||
@NotNull PsiStatement statement){
|
||||
final ReturnFinder returnFinder = new ReturnFinder();
|
||||
@@ -693,4 +711,41 @@ public class ControlFlowUtils{
|
||||
containsCallToMethod = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ContinueToAncestorFinder
|
||||
extends JavaRecursiveElementVisitor {
|
||||
|
||||
private final PsiStatement statement;
|
||||
private boolean found = false;
|
||||
|
||||
public ContinueToAncestorFinder(PsiStatement statement) {
|
||||
this.statement = statement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitContinueStatement(
|
||||
PsiContinueStatement continueStatement) {
|
||||
if (found) {
|
||||
return;
|
||||
}
|
||||
super.visitContinueStatement(continueStatement);
|
||||
final PsiIdentifier labelIdentifier =
|
||||
continueStatement.getLabelIdentifier();
|
||||
if (labelIdentifier == null) {
|
||||
return;
|
||||
}
|
||||
final PsiStatement continuedStatement =
|
||||
continueStatement.findContinuedStatement();
|
||||
if (continuedStatement == null) {
|
||||
return;
|
||||
}
|
||||
if (PsiTreeUtil.isAncestor(continuedStatement, statement, true)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean continueToAncestorFound() {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -94,13 +94,13 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
super.visitReferenceExpression(expression);
|
||||
final PsiElement parent = expression.getParent();
|
||||
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
|
||||
super.visitReferenceElement(reference);
|
||||
final PsiElement parent = reference.getParent();
|
||||
if (parent instanceof PsiImportStatement) {
|
||||
return;
|
||||
}
|
||||
final PsiElement qualifier = expression.getQualifier();
|
||||
final PsiElement qualifier = reference.getQualifier();
|
||||
if (!(qualifier instanceof PsiJavaCodeReferenceElement)) {
|
||||
return;
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection
|
||||
if (!(qualifierTarget instanceof PsiClass)) {
|
||||
return;
|
||||
}
|
||||
final PsiElement target = expression.resolve();
|
||||
final PsiElement target = reference.resolve();
|
||||
if (!(target instanceof PsiClass)) {
|
||||
return;
|
||||
}
|
||||
@@ -123,7 +123,7 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection
|
||||
return;
|
||||
}
|
||||
final String shortName = aClass.getName();
|
||||
if (!isReferenceToTargetClass(shortName, aClass, expression)) {
|
||||
if (!isReferenceToTargetClass(shortName, aClass, reference)) {
|
||||
return;
|
||||
}
|
||||
registerError(qualifier, aClass);
|
||||
|
||||
+6
-6
@@ -261,13 +261,13 @@ public class UnqualifiedInnerClassAccessInspection extends BaseInspection {
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(
|
||||
PsiReferenceExpression expression) {
|
||||
super.visitReferenceExpression(expression);
|
||||
if (expression.isQualified()) {
|
||||
public void visitReferenceElement(
|
||||
PsiJavaCodeReferenceElement reference) {
|
||||
super.visitReferenceElement(reference);
|
||||
if (reference.isQualified()) {
|
||||
return;
|
||||
}
|
||||
final PsiElement target = expression.resolve();
|
||||
final PsiElement target = reference.resolve();
|
||||
if (!(target instanceof PsiClass)) {
|
||||
return;
|
||||
}
|
||||
@@ -276,7 +276,7 @@ public class UnqualifiedInnerClassAccessInspection extends BaseInspection {
|
||||
if (containingClass == null) {
|
||||
return;
|
||||
}
|
||||
registerError(expression, containingClass.getName());
|
||||
registerError(reference, containingClass.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user