mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote branch 'origin/master'
This commit is contained in:
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.codeInspection.dataFlow;
|
||||
|
||||
/**
|
||||
* User: cdr
|
||||
*/
|
||||
public class InstructionFactory {
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.util.ProperTextRange;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.PsiFileImpl;
|
||||
@@ -35,14 +37,15 @@ class AnchorElementInfo extends SelfElementInfo {
|
||||
private IStubElementType myStubElementType;
|
||||
|
||||
AnchorElementInfo(@NotNull PsiElement anchor, @NotNull PsiFile containingFile) {
|
||||
super(containingFile.getProject(), anchor.getTextRange(), anchor.getClass(), containingFile, containingFile.getLanguage());
|
||||
super(containingFile.getProject(), ProperTextRange.create(anchor.getTextRange()), anchor.getClass(), containingFile,
|
||||
containingFile.getLanguage());
|
||||
}
|
||||
// will restore by stub index until file tree get loaded
|
||||
AnchorElementInfo(@NotNull PsiElement anchor,
|
||||
@NotNull PsiFileWithStubSupport containingFile,
|
||||
int stubId,
|
||||
@NotNull IStubElementType stubElementType) {
|
||||
super(containingFile.getProject(), new TextRange(0,0), anchor.getClass(), containingFile, containingFile.getLanguage());
|
||||
super(containingFile.getProject(), new ProperTextRange(0,0), anchor.getClass(), containingFile, containingFile.getLanguage());
|
||||
this.stubId = stubId;
|
||||
myStubElementType = stubElementType;
|
||||
IElementType contentElementType = ((PsiFileImpl)containingFile).getContentElementType();
|
||||
@@ -83,7 +86,7 @@ class AnchorElementInfo extends SelfElementInfo {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fastenBelt(int offset) {
|
||||
public void fastenBelt(int offset, RangeMarker cachedRangeMarker) {
|
||||
if (stubId != -1) {
|
||||
PsiElement element = restoreElement();
|
||||
if (element != null) {
|
||||
@@ -94,6 +97,6 @@ class AnchorElementInfo extends SelfElementInfo {
|
||||
setRange((anchor == null ? element : anchor).getTextRange());
|
||||
}
|
||||
}
|
||||
super.fastenBelt(offset);
|
||||
super.fastenBelt(offset, cachedRangeMarker);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-5
@@ -16,6 +16,7 @@
|
||||
package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
@@ -51,10 +52,6 @@ public class ImplicitVariableElementInfoFactory implements SmartPointerElementIn
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Document getDocumentToSynchronize() {
|
||||
return null;
|
||||
@@ -64,7 +61,7 @@ public class ImplicitVariableElementInfoFactory implements SmartPointerElementIn
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fastenBelt(int offset) {
|
||||
public void fastenBelt(int offset, RangeMarker cachedRangeMarker) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+7
-5
@@ -68,7 +68,7 @@ public class VariableInplaceIntroducer extends AbstractInplaceVariableIntroducer
|
||||
public VariableInplaceIntroducer(final Project project,
|
||||
final TypeExpression expression,
|
||||
final Editor editor,
|
||||
final @NotNull PsiVariable elementToRename,
|
||||
@NotNull final PsiVariable elementToRename,
|
||||
final boolean cantChangeFinalModifier,
|
||||
final boolean hasTypeSuggestion,
|
||||
final RangeMarker exprMarker,
|
||||
@@ -113,7 +113,7 @@ public class VariableInplaceIntroducer extends AbstractInplaceVariableIntroducer
|
||||
try {
|
||||
if (success) {
|
||||
final Document document = myEditor.getDocument();
|
||||
final @Nullable PsiVariable psiVariable = getVariable();
|
||||
@Nullable final PsiVariable psiVariable = getVariable();
|
||||
if (psiVariable == null) {
|
||||
return;
|
||||
}
|
||||
@@ -145,9 +145,11 @@ public class VariableInplaceIntroducer extends AbstractInplaceVariableIntroducer
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (getExprMarker() != null) {
|
||||
myEditor.getCaretModel().moveToOffset(getExprMarker().getStartOffset());
|
||||
}
|
||||
else {
|
||||
RangeMarker exprMarker = getExprMarker();
|
||||
if (exprMarker != null && exprMarker.isValid()) {
|
||||
myEditor.getCaretModel().moveToOffset(exprMarker.getStartOffset());
|
||||
myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
|
||||
}
|
||||
if (myExpressionText != null) {
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.List;
|
||||
|
||||
public class CompositeFilter implements Filter {
|
||||
private final List<Filter> myFilters = new ArrayList<Filter>();
|
||||
private DumbService myDumbService;
|
||||
private final DumbService myDumbService;
|
||||
|
||||
public CompositeFilter(Project project) {
|
||||
myDumbService = DumbService.getInstance(project);
|
||||
@@ -35,6 +35,7 @@ public class CompositeFilter implements Filter {
|
||||
final boolean dumb = myDumbService.isDumb();
|
||||
List<Filter> filters = myFilters;
|
||||
int count = filters.size();
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0; i < count; i++) {
|
||||
Filter filter = filters.get(i);
|
||||
if (!dumb || DumbService.isDumbAware(filter)) {
|
||||
|
||||
@@ -23,14 +23,20 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class OpenFileHyperlinkInfo implements FileHyperlinkInfo {
|
||||
private final OpenFileDescriptor myDescriptor;
|
||||
private final Project myProject;
|
||||
private final VirtualFile myFile;
|
||||
private final int myLine;
|
||||
private final int myColumn;
|
||||
|
||||
public OpenFileHyperlinkInfo(@NotNull OpenFileDescriptor descriptor) {
|
||||
myDescriptor = descriptor;
|
||||
this(descriptor.getProject(), descriptor.getFile(), descriptor.getLine(), descriptor.getColumn());
|
||||
}
|
||||
|
||||
public OpenFileHyperlinkInfo(Project project, @NotNull final VirtualFile file, final int line, final int column) {
|
||||
this (new OpenFileDescriptor(project, file, line, column));
|
||||
myProject = project;
|
||||
myFile = file;
|
||||
myLine = line;
|
||||
myColumn = column;
|
||||
}
|
||||
|
||||
public OpenFileHyperlinkInfo(Project project, @NotNull final VirtualFile file, final int line) {
|
||||
@@ -38,15 +44,15 @@ public final class OpenFileHyperlinkInfo implements FileHyperlinkInfo {
|
||||
}
|
||||
|
||||
public OpenFileDescriptor getDescriptor() {
|
||||
return myDescriptor;
|
||||
return new OpenFileDescriptor(myProject, myFile, myLine, myColumn);
|
||||
}
|
||||
|
||||
public void navigate(final Project project) {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
final VirtualFile file = myDescriptor.getFile();
|
||||
final VirtualFile file = myFile;
|
||||
if(file.isValid()) {
|
||||
FileEditorManager.getInstance(project).openTextEditor(myDescriptor, true);
|
||||
FileEditorManager.getInstance(project).openTextEditor(getDescriptor(), true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+8
-4
@@ -35,6 +35,7 @@ import com.intellij.openapi.components.ProjectComponent;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.ex.EditorMarkupModel;
|
||||
import com.intellij.openapi.editor.ex.MarkupModelEx;
|
||||
import com.intellij.openapi.editor.ex.RangeHighlighterEx;
|
||||
@@ -557,10 +558,13 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx
|
||||
int endOffset = highlighter.getEndOffset();
|
||||
if (startOffset > offset || offset > endOffset) {
|
||||
if (!includeFixRange) return false;
|
||||
if (info.fixMarker == null || !info.fixMarker.isValid()) return false;
|
||||
startOffset = info.fixMarker.getStartOffset();
|
||||
endOffset = info.fixMarker.getEndOffset();
|
||||
if (startOffset > offset || offset > endOffset) return false;
|
||||
RangeMarker fixMarker = info.fixMarker;
|
||||
if (fixMarker != null) { // null means its range is the same as highlighter
|
||||
if (!fixMarker.isValid()) return false;
|
||||
startOffset = fixMarker.getStartOffset();
|
||||
endOffset = fixMarker.getEndOffset();
|
||||
if (startOffset > offset || offset > endOffset) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -28,12 +28,14 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.containers.WeakHashMap;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import gnu.trove.TIntObjectProcedure;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
@@ -74,7 +76,7 @@ public class FileStatusMap implements Disposable {
|
||||
if (!errorFound) return;
|
||||
PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
|
||||
assert file != null : document;
|
||||
status = new FileStatus(file,document);
|
||||
status = new FileStatus(file.getProject());
|
||||
myDocumentToStatusMap.put(document, status);
|
||||
}
|
||||
status.errorFound = errorFound;
|
||||
@@ -90,29 +92,25 @@ public class FileStatusMap implements Disposable {
|
||||
|
||||
private static class FileStatus {
|
||||
public boolean defensivelyMarked; // file marked dirty without knowledge of specific dirty region. Subsequent markScopeDirty can refine dirty scope, not extend it
|
||||
private boolean wolfPassFinfished;
|
||||
private boolean wolfPassFinished;
|
||||
// if contains the special value "WHOLE_FILE_MARKER" than the corresponding range is (0, document length)
|
||||
private final TIntObjectHashMap<RangeMarker> dirtyScopes = new TIntObjectHashMap<RangeMarker>();
|
||||
private boolean errorFound;
|
||||
|
||||
private FileStatus(@NotNull PsiFile file, @NotNull Document document) {
|
||||
markWholeFile(file, document, file.getProject());
|
||||
private FileStatus(@NotNull Project project) {
|
||||
markWholeFile(project);
|
||||
}
|
||||
|
||||
private void markWholeFile(PsiFile file, Document document, Project project) {
|
||||
dirtyScopes.put(Pass.UPDATE_ALL, createWholeFileMarker(file, document));
|
||||
dirtyScopes.put(Pass.EXTERNAL_TOOLS, createWholeFileMarker(file, document));
|
||||
dirtyScopes.put(Pass.LOCAL_INSPECTIONS, createWholeFileMarker(file, document));
|
||||
private void markWholeFile(@NotNull Project project) {
|
||||
dirtyScopes.put(Pass.UPDATE_ALL, WHOLE_FILE_MARKER);
|
||||
dirtyScopes.put(Pass.EXTERNAL_TOOLS, WHOLE_FILE_MARKER);
|
||||
dirtyScopes.put(Pass.LOCAL_INSPECTIONS, WHOLE_FILE_MARKER);
|
||||
TextEditorHighlightingPassRegistrarImpl registrar = (TextEditorHighlightingPassRegistrarImpl) TextEditorHighlightingPassRegistrar.getInstance(project);
|
||||
for(DirtyScopeTrackingHighlightingPassFactory factory: registrar.getDirtyScopeTrackingFactories()) {
|
||||
dirtyScopes.put(factory.getPassId(), createWholeFileMarker(file, document));
|
||||
dirtyScopes.put(factory.getPassId(), WHOLE_FILE_MARKER);
|
||||
}
|
||||
}
|
||||
|
||||
private static RangeMarker createWholeFileMarker(PsiFile file, Document document) {
|
||||
int length = file == null ? -1 : Math.min(file.getTextLength(), document.getTextLength());
|
||||
return length == -1 ? null : document.createRangeMarker(0, length);
|
||||
}
|
||||
|
||||
public boolean allDirtyScopesAreNull() {
|
||||
for (Object o : dirtyScopes.getValues()) {
|
||||
if (o != null) return false;
|
||||
@@ -134,14 +132,14 @@ public class FileStatusMap implements Disposable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder s = new StringBuilder();
|
||||
s.append("defensivelyMarked = " + defensivelyMarked);
|
||||
s.append("; wolfPassFinfished = " + wolfPassFinfished);
|
||||
s.append("; errorFound = " + errorFound);
|
||||
@NonNls final StringBuilder s = new StringBuilder();
|
||||
s.append("defensivelyMarked = ").append(defensivelyMarked);
|
||||
s.append("; wolfPassFinfished = ").append(wolfPassFinished);
|
||||
s.append("; errorFound = ").append(errorFound);
|
||||
s.append("; dirtyScopes: (");
|
||||
dirtyScopes.forEachEntry(new TIntObjectProcedure<RangeMarker>() {
|
||||
public boolean execute(int passId, RangeMarker rangeMarker) {
|
||||
s.append(" pass: " + passId + " -> " + rangeMarker + ";");
|
||||
s.append(" pass: " + passId + " -> " + (rangeMarker == WHOLE_FILE_MARKER ? "Whole file" : rangeMarker)+ ";");
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@@ -171,17 +169,17 @@ public class FileStatusMap implements Disposable {
|
||||
synchronized(myDocumentToStatusMap){
|
||||
FileStatus status = myDocumentToStatusMap.get(document);
|
||||
if (status == null){
|
||||
status = new FileStatus(file,document);
|
||||
status = new FileStatus(file.getProject());
|
||||
myDocumentToStatusMap.put(document, status);
|
||||
}
|
||||
status.defensivelyMarked=false;
|
||||
if (passId == Pass.WOLF) {
|
||||
status.wolfPassFinfished = true;
|
||||
status.wolfPassFinished = true;
|
||||
}
|
||||
else if (status.dirtyScopes.containsKey(passId)) {
|
||||
RangeMarker marker = status.dirtyScopes.get(passId);
|
||||
if (marker != null) {
|
||||
marker.dispose();
|
||||
if (marker != WHOLE_FILE_MARKER) marker.dispose();
|
||||
status.dirtyScopes.put(passId, null);
|
||||
}
|
||||
}
|
||||
@@ -203,13 +201,12 @@ public class FileStatusMap implements Disposable {
|
||||
return file == null ? null : file.getTextRange();
|
||||
}
|
||||
if (status.defensivelyMarked) {
|
||||
//PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
|
||||
status.markWholeFile(file, document, myProject);
|
||||
status.markWholeFile(myProject);
|
||||
status.defensivelyMarked = false;
|
||||
}
|
||||
LOG.assertTrue(status.dirtyScopes.containsKey(passId), "Unknown pass " + passId);
|
||||
RangeMarker marker = status.dirtyScopes.get(passId);
|
||||
return marker == null ? null : marker.isValid() ? TextRange.create(marker) : new TextRange(0, document.getTextLength());
|
||||
return marker == null ? null : marker != WHOLE_FILE_MARKER && marker.isValid() ? TextRange.create(marker) : new TextRange(0, document.getTextLength());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,15 +218,15 @@ public class FileStatusMap implements Disposable {
|
||||
return;
|
||||
}
|
||||
if (passId == Pass.WOLF) {
|
||||
status.wolfPassFinfished = false;
|
||||
status.wolfPassFinished = false;
|
||||
}
|
||||
else {
|
||||
LOG.assertTrue(status.dirtyScopes.containsKey(passId));
|
||||
RangeMarker marker = status.dirtyScopes.get(passId);
|
||||
if (marker != null) {
|
||||
if (marker != null && marker != WHOLE_FILE_MARKER) {
|
||||
marker.dispose();
|
||||
}
|
||||
marker = document.createRangeMarker(0, document.getTextLength());
|
||||
marker = WHOLE_FILE_MARKER;
|
||||
status.dirtyScopes.put(passId, marker);
|
||||
}
|
||||
}
|
||||
@@ -269,8 +266,10 @@ public class FileStatusMap implements Disposable {
|
||||
private static RangeMarker combineScopes(RangeMarker old, TextRange scope, int textLength, @NotNull Document document) {
|
||||
if (scope == null) return old;
|
||||
if (old == null) {
|
||||
if (scope.equalsToRange(0, textLength)) return WHOLE_FILE_MARKER;
|
||||
return document.createRangeMarker(scope);
|
||||
}
|
||||
if (old == WHOLE_FILE_MARKER) return old;
|
||||
TextRange oldRange = TextRange.create(old);
|
||||
TextRange union = scope.union(oldRange);
|
||||
if (old.isValid() && union.equals(oldRange)) {
|
||||
@@ -280,6 +279,7 @@ public class FileStatusMap implements Disposable {
|
||||
union = union.intersection(new TextRange(0, textLength));
|
||||
}
|
||||
old.dispose();
|
||||
assert union != null;
|
||||
return document.createRangeMarker(union);
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ public class FileStatusMap implements Disposable {
|
||||
if (!ProblemHighlightFilter.shouldHighlightFile(file)) return true;
|
||||
|
||||
FileStatus status = myDocumentToStatusMap.get(document);
|
||||
return status != null && !status.defensivelyMarked && status.wolfPassFinfished && status.allDirtyScopesAreNull();
|
||||
return status != null && !status.defensivelyMarked && status.wolfPassFinished && status.allDirtyScopesAreNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ public class FileStatusMap implements Disposable {
|
||||
public void assertAllDirtyScopesAreNull(@NotNull Document document) {
|
||||
synchronized (myDocumentToStatusMap) {
|
||||
FileStatus status = myDocumentToStatusMap.get(document);
|
||||
assert status != null && !status.defensivelyMarked && status.wolfPassFinfished && status.allDirtyScopesAreNull() : status;
|
||||
assert status != null && !status.defensivelyMarked && status.wolfPassFinished && status.allDirtyScopesAreNull() : status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,4 +305,63 @@ public class FileStatusMap implements Disposable {
|
||||
public void allowDirt(boolean allow) {
|
||||
myAllowDirt = allow;
|
||||
}
|
||||
|
||||
private static final RangeMarker WHOLE_FILE_MARKER = new RangeMarker(){
|
||||
@NotNull
|
||||
@Override
|
||||
public Document getDocument() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStartOffset() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEndOffset() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGreedyToLeft(boolean greedy) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGreedyToRight(boolean greedy) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGreedyToRight() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGreedyToLeft() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getUserData(@NotNull Key<T> key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void putUserData(@NotNull Key<T> key, @Nullable T value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+3
-1
@@ -63,6 +63,7 @@ import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -545,6 +546,7 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP
|
||||
return new ArrayList<HighlightInfo>(myHighlights);
|
||||
}
|
||||
|
||||
private final Map<TextRange, RangeMarker> ranges2markersCache = new THashMap<TextRange, RangeMarker>();
|
||||
private void collectHighlights(@NotNull final List<PsiElement> elements1,
|
||||
@NotNull final Runnable after1,
|
||||
@NotNull final List<PsiElement> elements2,
|
||||
@@ -606,7 +608,7 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP
|
||||
final EditorColorsScheme colorsScheme = getColorsScheme();
|
||||
UpdateHighlightersUtil.addHighlighterToEditorIncrementally(myProject, myDocument, myFile, 0,
|
||||
myDocument.getTextLength(),
|
||||
info, colorsScheme, Pass.UPDATE_ALL);
|
||||
info, colorsScheme, Pass.UPDATE_ALL, ranges2markersCache);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+3
-1
@@ -34,6 +34,7 @@ import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.colors.CodeInsightColors;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||
@@ -375,6 +376,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass
|
||||
severity, problemDescriptor.isAfterEndOfLine(), null, isFileLevel);
|
||||
}
|
||||
|
||||
private final Map<TextRange, RangeMarker> ranges2markersCache = new THashMap<TextRange, RangeMarker>();
|
||||
private final TransferToEDTQueue<Trinity<ProblemDescriptor, LocalInspectionTool,ProgressIndicator>> myTransferToEDTQueue
|
||||
= new TransferToEDTQueue<Trinity<ProblemDescriptor, LocalInspectionTool,ProgressIndicator>>("Apply inspection results", new Processor<Trinity<ProblemDescriptor, LocalInspectionTool,ProgressIndicator>>() {
|
||||
private final InspectionProfile inspectionProfile = InspectionProjectProfileManager.getInstance(myProject).getInspectionProfile();
|
||||
@@ -402,7 +404,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass
|
||||
for (HighlightInfo info : infos) {
|
||||
final EditorColorsScheme colorsScheme = getColorsScheme();
|
||||
UpdateHighlightersUtil.addHighlighterToEditorIncrementally(myProject, myDocument, myFile, myStartOffset, myEndOffset,
|
||||
info, colorsScheme, getId());
|
||||
info, colorsScheme, getId(), ranges2markersCache);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+15
-10
@@ -159,7 +159,8 @@ public class UpdateHighlightersUtil {
|
||||
int endOffset,
|
||||
@NotNull final HighlightInfo info,
|
||||
@Nullable final EditorColorsScheme colorsScheme, // if null global scheme will be used
|
||||
final int group) {
|
||||
final int group,
|
||||
@NotNull Map<TextRange, RangeMarker> ranges2markersCache) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
if (info.isFileLevelAnnotation || info.getGutterIconRenderer() != null) return;
|
||||
|
||||
@@ -177,7 +178,7 @@ public class UpdateHighlightersUtil {
|
||||
|
||||
if (info.getStartOffset() < startOffset || info.getEndOffset() > endOffset) return;
|
||||
|
||||
createOrReuseHighlighterFor(info, colorsScheme, document, group, file, (MarkupModelEx)markup, null, null,
|
||||
createOrReuseHighlighterFor(info, colorsScheme, document, group, file, (MarkupModelEx)markup, null, ranges2markersCache,
|
||||
SeverityRegistrar.getInstance(project));
|
||||
|
||||
clearWhiteSpaceOptimizationFlag(document);
|
||||
@@ -388,7 +389,7 @@ public class UpdateHighlightersUtil {
|
||||
@NotNull final PsiFile psiFile,
|
||||
@NotNull MarkupModelEx markup,
|
||||
@Nullable HighlightersRecycler infosToRemove,
|
||||
@Nullable final Map<TextRange, RangeMarker> ranges2markersCache,
|
||||
@NotNull final Map<TextRange, RangeMarker> ranges2markersCache,
|
||||
SeverityRegistrar severityRegistrar) {
|
||||
final int infoStartOffset = info.startOffset;
|
||||
int infoEndOffset = info.endOffset;
|
||||
@@ -424,7 +425,7 @@ public class UpdateHighlightersUtil {
|
||||
GutterIconRenderer renderer = info.getGutterIconRenderer();
|
||||
finalHighlighter.setGutterIconRenderer(renderer);
|
||||
|
||||
if (ranges2markersCache != null) ranges2markersCache.put(new TextRange(infoStartOffset, finalInfoEndOffset), info.highlighter);
|
||||
ranges2markersCache.put(new TextRange(infoStartOffset, finalInfoEndOffset), info.highlighter);
|
||||
if (info.quickFixActionRanges != null) {
|
||||
List<Pair<HighlightInfo.IntentionActionDescriptor, RangeMarker>> list =
|
||||
new ArrayList<Pair<HighlightInfo.IntentionActionDescriptor, RangeMarker>>(info.quickFixActionRanges.size());
|
||||
@@ -435,7 +436,13 @@ public class UpdateHighlightersUtil {
|
||||
}
|
||||
info.quickFixActionMarkers = new CopyOnWriteArrayList<Pair<HighlightInfo.IntentionActionDescriptor, RangeMarker>>(list);
|
||||
}
|
||||
info.fixMarker = getOrCreate(document, ranges2markersCache, new TextRange(info.fixStartOffset, info.fixEndOffset));
|
||||
TextRange fixRange = new TextRange(info.fixStartOffset, info.fixEndOffset);
|
||||
if (fixRange.equalsToRange(infoStartOffset, finalInfoEndOffset)) {
|
||||
info.fixMarker = null; // null means it the same as highlighter'
|
||||
}
|
||||
else {
|
||||
info.fixMarker = getOrCreate(document, ranges2markersCache, fixRange);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -469,13 +476,11 @@ public class UpdateHighlightersUtil {
|
||||
return layer;
|
||||
}
|
||||
|
||||
private static RangeMarker getOrCreate(@NotNull Document document, @Nullable Map<TextRange, RangeMarker> ranges2markersCache, @NotNull TextRange textRange) {
|
||||
RangeMarker marker = ranges2markersCache == null ? null : ranges2markersCache.get(textRange);
|
||||
private static RangeMarker getOrCreate(@NotNull Document document, @NotNull Map<TextRange, RangeMarker> ranges2markersCache, @NotNull TextRange textRange) {
|
||||
RangeMarker marker = ranges2markersCache.get(textRange);
|
||||
if (marker == null) {
|
||||
marker = document.createRangeMarker(textRange);
|
||||
if (ranges2markersCache != null) {
|
||||
ranges2markersCache.put(textRange, marker);
|
||||
}
|
||||
ranges2markersCache.put(textRange, marker);
|
||||
}
|
||||
return marker;
|
||||
}
|
||||
|
||||
@@ -783,6 +783,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
checkValid();
|
||||
LOG.assertTrue(myLookupStartMarker.isValid(), "invalid lookup start");
|
||||
LOG.assertTrue(marker.isValid(), "invalid marker");
|
||||
marker.dispose();
|
||||
if (isVisible()) {
|
||||
updateLookupBounds();
|
||||
}
|
||||
@@ -814,7 +815,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
updateScrollbarVisibility();
|
||||
|
||||
Point p = calculatePosition(getComponent());
|
||||
HintManagerImpl.getInstanceImpl().showEditorHint(this, myEditor, p, HintManagerImpl.HIDE_BY_ESCAPE | HintManagerImpl.UPDATE_BY_SCROLLING, 0, false,
|
||||
HintManagerImpl.getInstanceImpl().showEditorHint(this, myEditor, p, HintManager.HIDE_BY_ESCAPE | HintManager.UPDATE_BY_SCROLLING, 0, false,
|
||||
HintManagerImpl.createHintHint(myEditor, p, this, HintManager.UNDER).setAwtTooltip(false));
|
||||
LOG.assertTrue(isVisible(), "!visible, disposed=" + myDisposed);
|
||||
LOG.assertTrue(myList.isShowing(), "!showing, disposed=" + myDisposed);
|
||||
@@ -955,6 +956,12 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
? myEditor.getSelectionModel().getSelectionStart()
|
||||
: myEditor.getCaretModel().getOffset();
|
||||
int start = Math.max(offset - myMinPrefixLength - myAdditionalPrefix.length(), 0);
|
||||
if (myLookupStartMarker != null) {
|
||||
if (myLookupStartMarker.isValid() && myLookupStartMarker.getStartOffset() == start && myLookupStartMarker.getEndOffset() == start) {
|
||||
return start;
|
||||
}
|
||||
myLookupStartMarker.dispose();
|
||||
}
|
||||
myLookupStartMarker = myEditor.getDocument().createRangeMarker(start, start);
|
||||
myLookupStartMarker.setGreedyToLeft(true);
|
||||
return start;
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
@@ -125,18 +126,18 @@ public class DocumentCommitThread implements Runnable, Disposable {
|
||||
useIndicator(null);
|
||||
}
|
||||
|
||||
public boolean queueCommit(@NonNls String reason, @NotNull Document document, @NotNull Project project) {
|
||||
public boolean queueCommit(@NonNls @NotNull String reason, @NotNull Document document, @NotNull Project project, @Nullable DocumentEvent event) {
|
||||
assert !isDisposed : "already disposed";
|
||||
|
||||
if (!project.isInitialized()) return false;
|
||||
PsiFile psiFile = PsiDocumentManager.getInstance(project).getCachedPsiFile(document);
|
||||
if (psiFile == null) return false;
|
||||
|
||||
doQueue(document, project, getCommitStage(document), reason);
|
||||
doQueue(document, project, getCommitStage(document), reason, event);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void doQueue(@NotNull Document document, @NotNull Project project, CommitStage start, @NonNls String reason) {
|
||||
private void doQueue(@NotNull Document document, @NotNull Project project, CommitStage start, @NonNls @NotNull String reason, @Nullable DocumentEvent event) {
|
||||
synchronized (documentsToCommit) {
|
||||
if (!changeCommitStage(document, start, CommitStage.QUEUED_TO_COMMIT, false)) return;
|
||||
|
||||
@@ -156,7 +157,7 @@ public class DocumentCommitThread implements Runnable, Disposable {
|
||||
}
|
||||
ProgressIndicator indicator = new ProgressIndicatorBase();
|
||||
indicator.start();
|
||||
documentsToCommit.addLast(new CommitTask(document, project, indicator));
|
||||
documentsToCommit.addLast(new CommitTask(document, project, indicator, reason, event));
|
||||
log("Queued", document, false, reason);
|
||||
}
|
||||
}
|
||||
@@ -204,13 +205,21 @@ public class DocumentCommitThread implements Runnable, Disposable {
|
||||
private final Document document;
|
||||
private final Project project;
|
||||
private final ProgressIndicator indicator; // progress to commit this doc under.
|
||||
private final String reason;
|
||||
@Nullable private final DocumentEvent event;
|
||||
// running = false means document was removed from the queue, should ignore.
|
||||
// canceled = true means commit was canceled, should reschedule for later.
|
||||
|
||||
private CommitTask(@NotNull Document document, @NotNull Project project, @NotNull ProgressIndicator indicator) {
|
||||
private CommitTask(@NotNull Document document,
|
||||
@NotNull Project project,
|
||||
@NotNull ProgressIndicator indicator,
|
||||
@NotNull String reason,
|
||||
@Nullable DocumentEvent event) {
|
||||
this.document = document;
|
||||
this.project = project;
|
||||
this.indicator = indicator;
|
||||
this.reason = reason;
|
||||
this.event = event;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,12 +248,13 @@ public class DocumentCommitThread implements Runnable, Disposable {
|
||||
Project project = null;
|
||||
ProgressIndicator indicator = null;
|
||||
try {
|
||||
CommitTask task;
|
||||
synchronized (documentsToCommit) {
|
||||
if (!myEnabled || documentsToCommit.isEmpty()) {
|
||||
documentsToCommit.wait();
|
||||
continue;
|
||||
}
|
||||
CommitTask task = documentsToCommit.pullFirst();
|
||||
task = documentsToCommit.pullFirst();
|
||||
document = task.document;
|
||||
indicator = task.indicator;
|
||||
project = task.project;
|
||||
@@ -267,7 +277,7 @@ public class DocumentCommitThread implements Runnable, Disposable {
|
||||
Runnable finishRunnable = null;
|
||||
if (!success && !indicator.isCanceled()) {
|
||||
try {
|
||||
finishRunnable = commit(document, project, null, indicator, false);
|
||||
finishRunnable = commit(document, project, null, indicator, false, task.reason, task.event);
|
||||
success = finishRunnable != null;
|
||||
log("Committed", document, false, finishRunnable, indicator);
|
||||
}
|
||||
@@ -304,7 +314,7 @@ public class DocumentCommitThread implements Runnable, Disposable {
|
||||
cancel(e);
|
||||
}
|
||||
if (!success && indicator.isRunning()) { // running means sync commit has not intervened
|
||||
doQueue(document, project, CommitStage.QUEUED_TO_COMMIT, "re-added on failure");
|
||||
doQueue(document, project, CommitStage.QUEUED_TO_COMMIT, "re-added on failure", null);
|
||||
}
|
||||
}
|
||||
catch(Throwable e) {
|
||||
@@ -340,7 +350,7 @@ public class DocumentCommitThread implements Runnable, Disposable {
|
||||
ProgressIndicatorBase indicator = new ProgressIndicatorBase();
|
||||
indicator.start();
|
||||
log("About to commit sync", document, true, indicator);
|
||||
Runnable finish = commit(document, project, excludeFile, indicator, true);
|
||||
Runnable finish = commit(document, project, excludeFile, indicator, true, "Sync commit", null);
|
||||
log("Committed sync", document, true, finish, indicator);
|
||||
|
||||
assert finish != null;
|
||||
@@ -351,12 +361,14 @@ public class DocumentCommitThread implements Runnable, Disposable {
|
||||
@NotNull final Project project,
|
||||
final PsiFile excludeFile,
|
||||
@NotNull final ProgressIndicator indicator,
|
||||
final boolean synchronously) {
|
||||
final boolean synchronously,
|
||||
@NotNull final String reason,
|
||||
@Nullable final DocumentEvent event) {
|
||||
final Runnable[] success = new Runnable[1];
|
||||
((ProgressManagerImpl)ProgressManager.getInstance()).executeProcessUnderProgress(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
success[0] = commitUnderProgress(document, project, excludeFile, indicator, synchronously);
|
||||
success[0] = commitUnderProgress(document, project, excludeFile, indicator, synchronously, reason, event);
|
||||
}
|
||||
}, indicator);
|
||||
return success[0];
|
||||
@@ -374,10 +386,12 @@ public class DocumentCommitThread implements Runnable, Disposable {
|
||||
|
||||
// returns finish commit Runnable (to be invoked later in EDT), or null on failure
|
||||
private Runnable commitUnderProgress(@NotNull final Document document,
|
||||
@NotNull final Project project,
|
||||
final PsiFile excludeFile,
|
||||
@NotNull final ProgressIndicator indicator,
|
||||
final boolean synchronously) {
|
||||
@NotNull final Project project,
|
||||
final PsiFile excludeFile,
|
||||
@NotNull final ProgressIndicator indicator,
|
||||
final boolean synchronously,
|
||||
@NotNull final String reason,
|
||||
@Nullable final DocumentEvent event) {
|
||||
final List<Processor<Document>> finishRunnables = new ArrayList<Processor<Document>>();
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
@@ -436,7 +450,7 @@ public class DocumentCommitThread implements Runnable, Disposable {
|
||||
|
||||
boolean success = false;
|
||||
try {
|
||||
success = documentManager.finishCommit(document, finishRunnables, synchronously);
|
||||
success = documentManager.finishCommit(document, finishRunnables, synchronously, reason, event);
|
||||
log("Finished", document, synchronously, success, Arrays.asList(documentManager.getUncommittedDocuments()));
|
||||
if (synchronously) {
|
||||
assert success;
|
||||
@@ -456,7 +470,7 @@ public class DocumentCommitThread implements Runnable, Disposable {
|
||||
if (!success) {
|
||||
// add document back to the queue
|
||||
log("Re-adding back", document, synchronously, success, documentManager.isCommitted(document), Arrays.asList(documentManager.getUncommittedDocuments()));
|
||||
queueCommit("Re-added back", document, project);
|
||||
queueCommit("Re-added back", document, project, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -469,7 +483,8 @@ public class DocumentCommitThread implements Runnable, Disposable {
|
||||
private Processor<Document> doCommit(@NotNull final Document document,
|
||||
@NotNull final PsiFile file,
|
||||
@NotNull ProgressIndicator indicator,
|
||||
final boolean synchronously, PsiDocumentManager documentManager) {
|
||||
final boolean synchronously,
|
||||
@NotNull PsiDocumentManager documentManager) {
|
||||
((PsiDocumentManagerImpl)documentManager).clearTreeHardRef(document);
|
||||
final TextBlock textBlock = PsiDocumentManagerImpl.getTextBlock(file);
|
||||
if (textBlock.isEmpty()) return null;
|
||||
|
||||
@@ -309,7 +309,11 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
|
||||
}
|
||||
}
|
||||
|
||||
boolean finishCommit(@NotNull final Document document, final List<Processor<Document>> finishRunnables, boolean synchronously) {
|
||||
boolean finishCommit(@NotNull final Document document,
|
||||
final List<Processor<Document>> finishRunnables,
|
||||
boolean synchronously,
|
||||
@NotNull String reason,
|
||||
@Nullable DocumentEvent event) {
|
||||
if (myProject.isDisposed()) return false;
|
||||
ApplicationManager.getApplication().assertWriteAccessAllowed();
|
||||
|
||||
@@ -343,10 +347,27 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
|
||||
|
||||
if (success) {
|
||||
runAfterCommitActions(document);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
checkAllElementsValid(document, reason, event);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
private void checkAllElementsValid(@NotNull Document document, @NotNull final String reason, @Nullable final DocumentEvent event) {
|
||||
final PsiFile psiFile = getCachedPsiFile(document);
|
||||
if (psiFile != null) {
|
||||
psiFile.accept(new PsiRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (!element.isValid()) {
|
||||
LOG.error("Commit to '"+psiFile.getVirtualFile()+"' lead to invalid element: "+element+ "; Reason: '"+reason+"'; Doc change event: "+event);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void doCommit(@NotNull final Document document, final PsiFile excludeFile) {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
public void run() {
|
||||
@@ -538,7 +559,7 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
|
||||
if (file == null) continue;
|
||||
|
||||
if (file.isPhysical() && mySmartPointerManager != null) { // mock tests
|
||||
SmartPointerManagerImpl.fastenBelts(file, event.getOffset());
|
||||
SmartPointerManagerImpl.fastenBelts(file, event.getOffset(), null);
|
||||
}
|
||||
|
||||
final TextBlock textBlock = getTextBlock(file);
|
||||
@@ -591,7 +612,7 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
|
||||
if (commitNecessary) {
|
||||
myUncommittedDocuments.add(document);
|
||||
|
||||
myDocumentCommitThread.queueCommit("Document changed", document, myProject);
|
||||
myDocumentCommitThread.queueCommit("Document changed", document, myProject, event);
|
||||
}
|
||||
|
||||
// Consider that it's worth to perform complete re-parse instead of merge if the whole document text is replaced and
|
||||
|
||||
@@ -873,7 +873,7 @@ public class FileManagerImpl implements FileManager {
|
||||
}
|
||||
|
||||
if (oldPsiFile != null && oldPsiFile.isPhysical()) {
|
||||
SmartPointerManagerImpl.fastenBelts(oldPsiFile, 0);
|
||||
SmartPointerManagerImpl.fastenBelts(oldPsiFile, 0, null);
|
||||
}
|
||||
ApplicationManager.getApplication().runWriteAction(
|
||||
new ExternalChangeAction() {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
@@ -40,7 +41,7 @@ public class ClsElementInfo implements SmartPointerElementInfo {
|
||||
|
||||
// before change
|
||||
@Override
|
||||
public void fastenBelt(int offset) {
|
||||
public void fastenBelt(int offset, RangeMarker cachedRangeMarker) {
|
||||
}
|
||||
|
||||
// after change
|
||||
@@ -56,10 +57,6 @@ public class ClsElementInfo implements SmartPointerElementInfo {
|
||||
return myStubIndexReference.retrieve();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int elementHashCode() {
|
||||
return myStubIndexReference.hashCode();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
@@ -48,7 +49,7 @@ class FileElementInfo implements SmartPointerElementInfo {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fastenBelt(int offset) {
|
||||
public void fastenBelt(int offset, RangeMarker cachedRangeMarker) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,10 +60,6 @@ class FileElementInfo implements SmartPointerElementInfo {
|
||||
return SelfElementInfo.restoreFileFromVirtual(myVirtualFile, myProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int elementHashCode() {
|
||||
return myVirtualFile.hashCode();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
@@ -44,7 +45,7 @@ class HardElementInfo implements SmartPointerElementInfo {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fastenBelt(int offset) {
|
||||
public void fastenBelt(int offset, RangeMarker cachedRangeMarker) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,10 +56,6 @@ class HardElementInfo implements SmartPointerElementInfo {
|
||||
return myElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int elementHashCode() {
|
||||
return myElement.hashCode();
|
||||
|
||||
+9
-9
@@ -38,13 +38,13 @@ class InjectedSelfElementInfo extends SelfElementInfo {
|
||||
private final Class<? extends PsiElement> anchorClass;
|
||||
private final Language anchorLanguage;
|
||||
|
||||
InjectedSelfElementInfo(@NotNull Project project, @NotNull PsiElement anchor, @NotNull PsiElement context) {
|
||||
super(project, context);
|
||||
InjectedSelfElementInfo(@NotNull Project project, @NotNull PsiElement element, @NotNull PsiElement hostContext) {
|
||||
super(project, hostContext);
|
||||
SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(project);
|
||||
TextRange range = InjectedLanguageManager.getInstance(project).injectedToHost(anchor, anchor.getTextRange());
|
||||
myInjectedFileRangeInHostFile = smartPointerManager.createSmartPsiFileRangePointer(context.getContainingFile(), range);
|
||||
anchorClass = anchor.getClass();
|
||||
anchorLanguage = anchor.getContainingFile().getLanguage();
|
||||
TextRange range = InjectedLanguageManager.getInstance(project).injectedToHost(element, element.getTextRange());
|
||||
myInjectedFileRangeInHostFile = smartPointerManager.createSmartPsiFileRangePointer(hostContext.getContainingFile(), range);
|
||||
anchorClass = element.getClass();
|
||||
anchorLanguage = element.getContainingFile().getLanguage();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,8 +56,8 @@ class InjectedSelfElementInfo extends SelfElementInfo {
|
||||
|
||||
@Override
|
||||
public PsiElement restoreElement() {
|
||||
PsiElement host = super.restoreElement();
|
||||
if (host == null) return null;
|
||||
PsiElement hostContext = super.restoreElement();
|
||||
if (hostContext == null) return null;
|
||||
|
||||
Segment segment = myInjectedFileRangeInHostFile.getRange();
|
||||
if (segment == null) return null;
|
||||
@@ -65,7 +65,7 @@ class InjectedSelfElementInfo extends SelfElementInfo {
|
||||
final Ref<PsiElement> result = new Ref<PsiElement>();
|
||||
|
||||
final InjectedLanguageManager manager = InjectedLanguageManager.getInstance(getProject());
|
||||
InjectedLanguageUtil.enumerate(host, host.getContainingFile(), new PsiLanguageInjectionHost.InjectedPsiVisitor() {
|
||||
InjectedLanguageUtil.enumerate(hostContext, hostContext.getContainingFile(), new PsiLanguageInjectionHost.InjectedPsiVisitor() {
|
||||
@Override
|
||||
public void visit(@NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) {
|
||||
if (result.get() != null) return;
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.ProperTextRange;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
*/
|
||||
public class MultiRootSelfElementInfo extends SelfElementInfo {
|
||||
public MultiRootSelfElementInfo(@NotNull Project project,
|
||||
@NotNull TextRange anchor,
|
||||
@NotNull ProperTextRange anchor,
|
||||
@NotNull Class anchorClass,
|
||||
@NotNull PsiFile containingFile,
|
||||
@NotNull Language language) {
|
||||
|
||||
@@ -21,10 +21,7 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -49,10 +46,11 @@ public class SelfElementInfo implements SmartPointerElementInfo {
|
||||
protected final Language myLanguage;
|
||||
|
||||
protected SelfElementInfo(@NotNull Project project, @NotNull PsiElement anchor) {
|
||||
this(project, anchor.getTextRange(), anchor.getClass(), anchor.getContainingFile(), anchor.getContainingFile().getLanguage());
|
||||
this(project, ProperTextRange.create(anchor.getTextRange()), anchor.getClass(), anchor.getContainingFile(),
|
||||
anchor.getContainingFile().getLanguage());
|
||||
}
|
||||
public SelfElementInfo(@NotNull Project project,
|
||||
@NotNull TextRange anchor,
|
||||
@NotNull ProperTextRange anchor,
|
||||
@NotNull Class anchorClass,
|
||||
@NotNull PsiFile containingFile,
|
||||
@NotNull Language language) {
|
||||
@@ -104,7 +102,7 @@ public class SelfElementInfo implements SmartPointerElementInfo {
|
||||
|
||||
// before change
|
||||
@Override
|
||||
public void fastenBelt(int offset) {
|
||||
public void fastenBelt(int offset, @Nullable RangeMarker cachedRangeMarker) {
|
||||
if (!mySyncMarkerIsValid) return;
|
||||
RangeMarker marker = getMarker();
|
||||
int actualEndOffset = marker == null || !marker.isValid() ? getSyncEndOffset() : marker.getEndOffset();
|
||||
@@ -117,15 +115,19 @@ public class SelfElementInfo implements SmartPointerElementInfo {
|
||||
mySyncMarkerIsValid = false;
|
||||
return;
|
||||
}
|
||||
//PsiToDocumentSynchronizer synchronizer = ((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(myProject)).getSynchronizer();
|
||||
//boolean inSynchronization = synchronizer.isInSynchronization(document);
|
||||
|
||||
//if (!inSynchronization) { // otherwise doc offsets are incorrect
|
||||
int start = Math.min(getSyncStartOffset(), document.getTextLength());
|
||||
int end = Math.min(Math.max(getSyncEndOffset(), start), document.getTextLength());
|
||||
int start = Math.min(getSyncStartOffset(), document.getTextLength());
|
||||
int end = Math.min(Math.max(getSyncEndOffset(), start), document.getTextLength());
|
||||
// use supplied cached markers if available
|
||||
if (cachedRangeMarker != null &&
|
||||
cachedRangeMarker.isValid() &&
|
||||
cachedRangeMarker.getStartOffset() == start &&
|
||||
cachedRangeMarker.getEndOffset() == end) {
|
||||
marker = cachedRangeMarker;
|
||||
}
|
||||
else {
|
||||
marker = document.createRangeMarker(start, end, true);
|
||||
setMarker(marker);
|
||||
//}
|
||||
}
|
||||
setMarker(marker);
|
||||
}
|
||||
else if (!marker.isValid()) {
|
||||
mySyncMarkerIsValid = false;
|
||||
@@ -151,7 +153,7 @@ public class SelfElementInfo implements SmartPointerElementInfo {
|
||||
mySyncMarkerIsValid = false;
|
||||
}
|
||||
}
|
||||
myRangeMarker = null;
|
||||
myRangeMarker = null; // clear hard ref to avoid leak, hold soft ref for not recreating marker later
|
||||
}
|
||||
|
||||
// commit
|
||||
@@ -196,16 +198,7 @@ public class SelfElementInfo implements SmartPointerElementInfo {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
RangeMarker marker = getMarker();
|
||||
if (marker != null) {
|
||||
marker.dispose();
|
||||
setMarker(null);
|
||||
}
|
||||
}
|
||||
|
||||
private RangeMarker getMarker() {
|
||||
RangeMarker getMarker() {
|
||||
Reference<RangeMarker> ref = myMarkerRef;
|
||||
return ref == null ? null : ref.get();
|
||||
}
|
||||
|
||||
+2
-2
@@ -17,6 +17,7 @@
|
||||
package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -29,14 +30,13 @@ interface SmartPointerElementInfo {
|
||||
Document getDocumentToSynchronize();
|
||||
|
||||
void documentAndPsiInSync();
|
||||
void fastenBelt(int offset);
|
||||
void fastenBelt(int offset, RangeMarker cachedRangeMarker);
|
||||
|
||||
void unfastenBelt(int offset);
|
||||
|
||||
@Nullable
|
||||
PsiElement restoreElement();
|
||||
|
||||
void dispose();
|
||||
int elementHashCode(); // must be immutable
|
||||
boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other);
|
||||
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.SmartPsiElementPointer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface SmartPointerEx<E extends PsiElement> extends SmartPsiElementPointer<E> {
|
||||
void fastenBelt(int offset);
|
||||
void fastenBelt(int offset, @Nullable RangeMarker cachedRangeMarker);
|
||||
void documentAndPsiInSync();
|
||||
|
||||
void unfastenBelt(int offset);
|
||||
|
||||
+31
-10
@@ -16,18 +16,22 @@
|
||||
|
||||
package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.injected.editor.DocumentWindow;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.impl.DocumentImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.ProperTextRange;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import com.intellij.reference.SoftReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
@@ -47,7 +51,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
public static void fastenBelts(@NotNull PsiFile file, int offset) {
|
||||
public static void fastenBelts(@NotNull PsiFile file, int offset, @Nullable RangeMarker cachedRangeMarker) {
|
||||
synchronized (file) {
|
||||
if (areBeltsFastened(file)) return;
|
||||
|
||||
@@ -66,15 +70,16 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
WeakReference<SmartPointerEx> reference = pointers.get(i);
|
||||
SmartPointerEx pointer = reference.get();
|
||||
if (pointer != null) {
|
||||
pointer.fastenBelt(offset);
|
||||
pointer.fastenBelt(offset, cachedRangeMarker);
|
||||
pointers.set(index++, reference);
|
||||
}
|
||||
}
|
||||
|
||||
for (Document injectedDoc : InjectedLanguageUtil.getCachedInjectedDocuments(file)) {
|
||||
for (DocumentWindow injectedDoc : InjectedLanguageUtil.getCachedInjectedDocuments(file)) {
|
||||
PsiFile injectedFile = psiDocumentManager.getPsiFile(injectedDoc);
|
||||
if (injectedFile == null) continue;
|
||||
fastenBelts(injectedFile, 0);
|
||||
RangeMarker cachedMarker = getCachedRangeMarkerToInjectedFragment(injectedFile);
|
||||
fastenBelts(injectedFile, 0, cachedMarker);
|
||||
}
|
||||
|
||||
int size = pointers.size();
|
||||
@@ -84,6 +89,19 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
}
|
||||
}
|
||||
|
||||
private static RangeMarker getCachedRangeMarkerToInjectedFragment(PsiFile injectedFile) {
|
||||
PsiElement hostContext = injectedFile.getContext();
|
||||
RangeMarker cachedMarker = null;
|
||||
if (hostContext != null) {
|
||||
SmartPsiElementPointer<PsiElement> cachedPointer = getCachedPointer(hostContext);
|
||||
SmartPointerElementInfo info = cachedPointer == null ? null : ((SmartPsiElementPointerImpl)cachedPointer).getElementInfo();
|
||||
if (info instanceof SelfElementInfo) {
|
||||
cachedMarker = ((SelfElementInfo)info).getMarker();
|
||||
}
|
||||
}
|
||||
return cachedMarker;
|
||||
}
|
||||
|
||||
public static void unfastenBelts(@NotNull PsiFile file, int offset) {
|
||||
synchronized (file) {
|
||||
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(file.getProject());
|
||||
@@ -107,7 +125,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
}
|
||||
}
|
||||
|
||||
for (Document injectedDoc : InjectedLanguageUtil.getCachedInjectedDocuments(file)) {
|
||||
for (DocumentWindow injectedDoc : InjectedLanguageUtil.getCachedInjectedDocuments(file)) {
|
||||
PsiFile injectedFile = psiDocumentManager.getPsiFile(injectedDoc);
|
||||
if (injectedFile == null) continue;
|
||||
unfastenBelts(injectedFile, 0);
|
||||
@@ -168,8 +186,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
if (containingFile != null && !containingFile.isValid() || containingFile == null && !element.isValid()) {
|
||||
LOG.error("Invalid element:" + element);
|
||||
}
|
||||
Reference<SmartPsiElementPointer> data = element.getUserData(CACHED_SMART_POINTER_KEY);
|
||||
SmartPsiElementPointer cachedPointer = data == null ? null : data.get();
|
||||
SmartPsiElementPointer<E> cachedPointer = getCachedPointer(element);
|
||||
if (cachedPointer != null) {
|
||||
return cachedPointer;
|
||||
}
|
||||
@@ -180,14 +197,18 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
return pointer;
|
||||
}
|
||||
|
||||
private static <E extends PsiElement> SmartPsiElementPointer<E> getCachedPointer(E element) {
|
||||
Reference<SmartPsiElementPointer> data = element.getUserData(CACHED_SMART_POINTER_KEY);
|
||||
return data == null ? null : data.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public SmartPsiFileRange createSmartPsiFileRangePointer(@NotNull PsiFile file, @NotNull TextRange range) {
|
||||
if (!file.isValid()) {
|
||||
LOG.error("Invalid element:" + file);
|
||||
}
|
||||
|
||||
SmartPsiFileRangePointerImpl pointer = new SmartPsiFileRangePointerImpl(file, range);
|
||||
SmartPsiFileRangePointerImpl pointer = new SmartPsiFileRangePointerImpl(file, ProperTextRange.create(range));
|
||||
initPointer(pointer, file);
|
||||
|
||||
return pointer;
|
||||
@@ -215,7 +236,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
pointers.add(new WeakReference<SmartPointerEx>(pointer));
|
||||
|
||||
if (areBeltsFastened(containingFile)) {
|
||||
pointer.fastenBelt(0);
|
||||
pointer.fastenBelt(0, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-6
@@ -19,8 +19,10 @@ package com.intellij.psi.impl.smartPointers;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.ProperTextRange;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -157,8 +159,8 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
|
||||
|
||||
FileViewProvider viewProvider = containingFile.getViewProvider();
|
||||
if (viewProvider instanceof InjectedFileViewProvider) {
|
||||
PsiElement context = containingFile.getContext();
|
||||
if (context != null) return new InjectedSelfElementInfo(project, element, context);
|
||||
PsiElement hostContext = containingFile.getContext();
|
||||
if (hostContext != null) return new InjectedSelfElementInfo(project, element, hostContext);
|
||||
}
|
||||
|
||||
if (element instanceof PsiFile) {
|
||||
@@ -169,6 +171,7 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
|
||||
if (elementRange == null) {
|
||||
return new HardElementInfo(project, element);
|
||||
}
|
||||
ProperTextRange proper = ProperTextRange.create(elementRange);
|
||||
|
||||
LOG.assertTrue(element.isPhysical());
|
||||
LOG.assertTrue(element.isValid());
|
||||
@@ -177,9 +180,9 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
|
||||
VirtualFile virtualFile = containingFile.getVirtualFile();
|
||||
boolean isElementInMainRoot = virtualFile == null || containingFile.getManager().findFile(virtualFile) == containingFile;
|
||||
if (isMultiRoot && !isElementInMainRoot) {
|
||||
return new MultiRootSelfElementInfo(project, elementRange, element.getClass(), containingFile, containingFile.getLanguage());
|
||||
return new MultiRootSelfElementInfo(project, proper, element.getClass(), containingFile, containingFile.getLanguage());
|
||||
}
|
||||
return new SelfElementInfo(project, elementRange, element.getClass(), containingFile, containingFile.getLanguage());
|
||||
return new SelfElementInfo(project, proper, element.getClass(), containingFile, containingFile.getLanguage());
|
||||
}
|
||||
|
||||
public void documentAndPsiInSync() {
|
||||
@@ -191,8 +194,8 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
|
||||
myElementInfo.unfastenBelt(offset);
|
||||
}
|
||||
|
||||
public void fastenBelt(int offset) {
|
||||
myElementInfo.fastenBelt(offset);
|
||||
public void fastenBelt(int offset, @Nullable RangeMarker cachedRangeMarker) {
|
||||
myElementInfo.fastenBelt(offset, cachedRangeMarker);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+3
-3
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.ProperTextRange;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.SmartPsiFileRange;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -24,12 +24,12 @@ import org.jetbrains.annotations.NotNull;
|
||||
* User: cdr
|
||||
*/
|
||||
public class SmartPsiFileRangePointerImpl extends SmartPsiElementPointerImpl<PsiFile> implements SmartPsiFileRange {
|
||||
public SmartPsiFileRangePointerImpl(@NotNull PsiFile containingFile, @NotNull TextRange range) {
|
||||
public SmartPsiFileRangePointerImpl(@NotNull PsiFile containingFile, @NotNull ProperTextRange range) {
|
||||
super(containingFile, createElementInfo(containingFile, range), PsiFile.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static SmartPointerElementInfo createElementInfo(@NotNull PsiFile containingFile, @NotNull TextRange range) {
|
||||
private static SmartPointerElementInfo createElementInfo(@NotNull PsiFile containingFile, @NotNull ProperTextRange range) {
|
||||
return new SelfElementInfo(containingFile.getProject(), range, PsiFile.class, containingFile, containingFile.getLanguage());
|
||||
}
|
||||
|
||||
|
||||
+18
-6
@@ -292,7 +292,7 @@ public class PostprocessReformattingAspect implements PomModelAspect, Disposable
|
||||
// process all roots in viewProvider to find marked for reformat before elements and create appropriate ragge markers
|
||||
handleReformatMarkers(key, postprocessTasks);
|
||||
|
||||
// then we create ranges by changed nodes. One per node. There ranges can instersect. Ranges are sorted by end offset.
|
||||
// then we create ranges by changed nodes. One per node. There ranges can intersect. Ranges are sorted by end offset.
|
||||
if (astNodes != null) createActionsMap(astNodes, key, postprocessTasks);
|
||||
|
||||
if ("true".equals(System.getProperty("check.psi.is.valid")) && ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
@@ -358,8 +358,8 @@ public class PostprocessReformattingAspect implements PomModelAspect, Disposable
|
||||
iterator.remove();
|
||||
}
|
||||
else if (accumulatedTask.getStartOffset() > currentTask.getEndOffset() ||
|
||||
(accumulatedTask.getStartOffset() == currentTask.getEndOffset() &&
|
||||
!canStickActionsTogether(accumulatedTask, currentTask))) {
|
||||
accumulatedTask.getStartOffset() == currentTask.getEndOffset() &&
|
||||
!canStickActionsTogether(accumulatedTask, currentTask)) {
|
||||
// action can be pushed
|
||||
if (accumulatedTask instanceof ReindentTask) {
|
||||
indentActions.add((ReindentTask) accumulatedTask);
|
||||
@@ -391,7 +391,7 @@ public class PostprocessReformattingAspect implements PomModelAspect, Disposable
|
||||
if (!(accumulatedTask instanceof ReindentTask)) {
|
||||
iterator.remove();
|
||||
|
||||
boolean withLeadingWhitespace = (accumulatedTask instanceof ReformatWithHeadingWhitespaceTask);
|
||||
boolean withLeadingWhitespace = accumulatedTask instanceof ReformatWithHeadingWhitespaceTask;
|
||||
if (accumulatedTask instanceof ReformatTask &&
|
||||
currentTask instanceof ReformatWithHeadingWhitespaceTask &&
|
||||
accumulatedTask.getStartOffset() == currentTask.getStartOffset()) {
|
||||
@@ -402,8 +402,20 @@ public class PostprocessReformattingAspect implements PomModelAspect, Disposable
|
||||
accumulatedTask.getStartOffset() < currentTask.getStartOffset()) {
|
||||
withLeadingWhitespace = false;
|
||||
}
|
||||
RangeMarker rangeMarker = document.createRangeMarker(Math.min(accumulatedTask.getStartOffset(), currentTask.getStartOffset()),
|
||||
Math.max(accumulatedTask.getEndOffset(), currentTask.getEndOffset()));
|
||||
int newStart = Math.min(accumulatedTask.getStartOffset(), currentTask.getStartOffset());
|
||||
int newEnd = Math.max(accumulatedTask.getEndOffset(), currentTask.getEndOffset());
|
||||
RangeMarker rangeMarker;
|
||||
|
||||
if (accumulatedTask.getStartOffset() == newStart && accumulatedTask.getEndOffset() == newEnd) {
|
||||
rangeMarker = accumulatedTask.getRange();
|
||||
}
|
||||
else if (currentTask.getStartOffset() == newStart && currentTask.getEndOffset() == newEnd) {
|
||||
rangeMarker = currentTask.getRange();
|
||||
}
|
||||
else {
|
||||
rangeMarker = document.createRangeMarker(newStart, newEnd);
|
||||
}
|
||||
|
||||
if (withLeadingWhitespace) {
|
||||
accumulatedTask = new ReformatWithHeadingWhitespaceTask(rangeMarker);
|
||||
}
|
||||
|
||||
+1
@@ -284,6 +284,7 @@ public class VariableInplaceRenamer {
|
||||
}
|
||||
|
||||
public void templateCancelled(Template template) {
|
||||
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
|
||||
finish();
|
||||
moveOffsetAfter(false);
|
||||
}
|
||||
|
||||
@@ -1183,10 +1183,12 @@ public class JBTabsImpl extends JComponent
|
||||
public void setPaintBlocked(boolean blocked, final boolean takeSnapshot) {
|
||||
if (blocked && !myPaintBlocked) {
|
||||
if (takeSnapshot) {
|
||||
myImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
final Graphics2D g = myImage.createGraphics();
|
||||
super.paint(g);
|
||||
g.dispose();
|
||||
if (getWidth() > 0 && getHeight() > 0) {
|
||||
myImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
final Graphics2D g = myImage.createGraphics();
|
||||
super.paint(g);
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
protected final List<Getable<T>> intervals;
|
||||
protected int maxEnd; // max of all intervalEnd()s among all children.
|
||||
protected int delta; // delta of startOffset. getStartOffset() = myStartOffset + Sum of deltas up to root
|
||||
private IntervalNode next; // node following this in the in-order tree traversal. used for optimised tree iteration
|
||||
|
||||
public IntervalNode(@NotNull T key, int start, int end) {
|
||||
// maxEnd == 0 so to not disrupt existing maxes
|
||||
@@ -383,14 +382,13 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
return Math.max(start, startOffset) <= Math.min(end, endOffset);
|
||||
}
|
||||
|
||||
// next node in inorder traversal
|
||||
private IntervalNode nextNode(@NotNull IntervalNode root,
|
||||
int startOffset, int endOffset,
|
||||
@NotNull int[] newDeltaUpToRootExclusive) {
|
||||
assert root.isValid();
|
||||
int deltaUpToRootExclusive = newDeltaUpToRootExclusive[0];
|
||||
int delta = deltaUpToRootExclusive + root.delta;
|
||||
//int myStartOffset = root.intervalStart() + delta;
|
||||
//int myEndOffset = root.intervalEnd() + delta;
|
||||
int myMaxEnd = maxEndOf(root, deltaUpToRootExclusive);
|
||||
assert startOffset <= myMaxEnd;
|
||||
|
||||
@@ -603,16 +601,6 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
assert ids.add(((RangeMarkerImpl)t).getId()) : t;
|
||||
}
|
||||
|
||||
if (assertInvalid) {
|
||||
IntervalNode next = root.next;
|
||||
if (next != null) {
|
||||
assert previous(next) == root;
|
||||
int nextStart = next.intervalStart() + next.computeDeltaUpToRoot();
|
||||
int myStart = root.intervalStart() + deltaUpToRootExclusive + root.delta;
|
||||
assert nextStart >= myStart;
|
||||
}
|
||||
}
|
||||
|
||||
keyCounter.addAndGet(root.intervals.size());
|
||||
nodeCounter.incrementAndGet();
|
||||
int delta = deltaUpToRootExclusive + (root.isValid() ? root.delta : 0);
|
||||
|
||||
+1
-1
@@ -196,6 +196,6 @@ class RangeHighlighterImpl extends RangeMarkerImpl implements RangeHighlighterEx
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RangeHighlighter: ("+getStartOffset()+","+getEndOffset()+"); layer="+getLayer();
|
||||
return "RangeHighlighter: ("+getStartOffset()+","+getEndOffset()+"); layer="+getLayer()+"; tooltip: "+getData().getErrorStripeTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,12 +21,11 @@ import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.editor.ex.RangeMarkerEx;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.util.DistributedCounter;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx, MutableInterval {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.RangeMarkerImpl");
|
||||
|
||||
@@ -34,8 +33,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
|
||||
protected RangeMarkerTree.RMNode myNode;
|
||||
|
||||
private final long myId;
|
||||
//private static long counter;
|
||||
private static final AtomicLong counter = new AtomicLong();
|
||||
private static final DistributedCounter counter = new DistributedCounter();
|
||||
|
||||
protected RangeMarkerImpl(@NotNull DocumentEx document, int start, int end, boolean register) {
|
||||
this(document, start, end, register, false, false);
|
||||
@@ -52,7 +50,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
|
||||
}
|
||||
|
||||
myDocument = document;
|
||||
myId = counter.getAndIncrement();
|
||||
myId = counter.next();
|
||||
if (register) {
|
||||
registerInTree(start, end, greedyToLeft, greedyToRight, 0);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package com.intellij.openapi.editor.impl;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.ex.MarkupModelEx;
|
||||
@@ -25,13 +28,17 @@ import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* User: cdr
|
||||
*/
|
||||
public class RangeMarkerTree<T extends RangeMarkerEx> extends IntervalTreeImpl<T> {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.RangeMarkerTree");
|
||||
private static final boolean DEBUG = LOG.isDebugEnabled() || ApplicationManager.getApplication().isUnitTestMode() || ApplicationManagerEx.getApplicationEx().isInternal();
|
||||
|
||||
private final PrioritizedDocumentListener myListener;
|
||||
final Document myDocument;
|
||||
private final Document myDocument;
|
||||
private final EqualStartIntervalComparator<IntervalNode> myEqualStartIntervalComparator = new EqualStartIntervalComparator<IntervalNode>() {
|
||||
@Override
|
||||
public int compare(IntervalNode i1, IntervalNode i2) {
|
||||
@@ -81,6 +88,7 @@ public class RangeMarkerTree<T extends RangeMarkerEx> extends IntervalTreeImpl<T
|
||||
myDocument.removeDocumentListener(myListener);
|
||||
}
|
||||
|
||||
private static final int DUPLICATE_LIMIT = 30; // assertion: no more than DUPLICATE_LIMIT range markers are allowed to be registered at given (start, end)
|
||||
@Override
|
||||
public RangeMarkerTree<T>.RMNode addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) {
|
||||
RangeMarkerImpl marker = (RangeMarkerImpl)interval;
|
||||
@@ -88,7 +96,23 @@ public class RangeMarkerTree<T extends RangeMarkerEx> extends IntervalTreeImpl<T
|
||||
RangeMarkerTree<T>.RMNode node = (RMNode)super.addInterval(interval, start, end, greedyToLeft, greedyToRight, layer);
|
||||
|
||||
checkBelongsToTheTree(interval, true);
|
||||
|
||||
if (DEBUG && node.intervals.size() > DUPLICATE_LIMIT) {
|
||||
System.gc();System.gc();System.gc();
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
final AtomicInteger alive = new AtomicInteger();
|
||||
node.processAliveKeys(new Processor<T>() {
|
||||
@Override
|
||||
public boolean process(T t) {
|
||||
msg.append(t).append("\n");
|
||||
alive.incrementAndGet();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (alive.get() > DUPLICATE_LIMIT) {
|
||||
msg.insert(0, "Too many range markers (" + alive +") registered at ("+start+","+end+") in "+this+":\n");
|
||||
LOG.error(msg);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -319,7 +319,7 @@ final class EditorTabbedContainer implements Disposable, CloseAction.CloseTarget
|
||||
}
|
||||
|
||||
public void setPaintBlocked(boolean blocked) {
|
||||
((JBTabsImpl)myTabs).setPaintBlocked(blocked, false);
|
||||
((JBTabsImpl)myTabs).setPaintBlocked(blocked, true);
|
||||
}
|
||||
|
||||
private class MyQueryable implements Queryable {
|
||||
|
||||
@@ -969,8 +969,7 @@ public class RangeMarkerTest extends LightPlatformTestCase {
|
||||
|
||||
public void testRangeMarkersAreWeakReferenced_NoVerify() throws Exception {
|
||||
final Document document = EditorFactory.getInstance().createDocument("[xxxxxxxxxxxxxx]");
|
||||
int COUNT = 100;
|
||||
for (int i = 0; i < COUNT; i++) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
document.createRangeMarker(0, document.getTextLength());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.util;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Low-contention counter.
|
||||
* Repeated calls to {@link #next()} return numbers which are unique across all calling threads, and which are increasing over calls within one thread.
|
||||
*/
|
||||
public class DistributedCounter {
|
||||
private static final int CHUNK_SIZE = 1000;
|
||||
private final AtomicLong nextChunkStart = new AtomicLong();
|
||||
// must not ne static
|
||||
private final ThreadLocal<NextPair> localCounter = new ThreadLocal<NextPair>();
|
||||
private static class NextPair {
|
||||
long nextId;
|
||||
final long limit;
|
||||
|
||||
private NextPair(long nextId, long limit) {
|
||||
this.nextId = nextId;
|
||||
this.limit = limit;
|
||||
}
|
||||
}
|
||||
|
||||
public long next() {
|
||||
NextPair nextPair = localCounter.get();
|
||||
if (nextPair == null || nextPair.nextId == nextPair.limit) {
|
||||
long start = nextChunkStart.getAndAdd(CHUNK_SIZE);
|
||||
nextPair = new NextPair(start, start + CHUNK_SIZE);
|
||||
localCounter.set(nextPair);
|
||||
}
|
||||
long result = nextPair.nextId;
|
||||
nextPair.nextId++;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import com.intellij.execution.process.ProcessHandler;
|
||||
import com.intellij.execution.process.ProcessOutputTypes;
|
||||
import com.intellij.execution.ui.ConsoleView;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
@@ -172,8 +171,7 @@ public final class PlainTextView implements AntOutputView {
|
||||
int highlightStartOffset = textStartOffset + placeInfo.getLinkStartIndex();
|
||||
int highlightEndOffset = textStartOffset + placeInfo.getLinkEndIndex() + 1;
|
||||
|
||||
OpenFileDescriptor descriptor = new OpenFileDescriptor(myProject, placeInfo.getFile(), placeInfo.getLine(), placeInfo.getColumn());
|
||||
OpenFileHyperlinkInfo info = new OpenFileHyperlinkInfo(descriptor);
|
||||
OpenFileHyperlinkInfo info = new OpenFileHyperlinkInfo(myProject, placeInfo.getFile(), placeInfo.getLine(), placeInfo.getColumn());
|
||||
return new Result(highlightStartOffset, highlightEndOffset, info);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user