mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
range markers optimisations: create fewer markers in OpenFileDescriptor and LazyMarkerFactory
This commit is contained in:
@@ -174,7 +174,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
* @deprecated should be replaced with {@link #stripTrailingSpaces(com.intellij.openapi.project.Project, boolean, boolean, java.util.List)}
|
||||
* once multicaret logic will become unconditional (not controlled by configuration flag)
|
||||
*/
|
||||
public boolean stripTrailingSpaces(@Nullable final Project project,
|
||||
boolean stripTrailingSpaces(@Nullable final Project project,
|
||||
boolean inChangedLinesOnly,
|
||||
boolean virtualSpaceEnabled,
|
||||
int caretLine,
|
||||
@@ -230,7 +230,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
/**
|
||||
* @return true if stripping was completed successfully, false if the document prevented stripping by e.g. caret(s) being in the way
|
||||
*/
|
||||
public boolean stripTrailingSpaces(@Nullable final Project project,
|
||||
boolean stripTrailingSpaces(@Nullable final Project project,
|
||||
boolean inChangedLinesOnly,
|
||||
boolean virtualSpaceEnabled,
|
||||
@NotNull List<Integer> caretOffsets) {
|
||||
|
||||
@@ -15,276 +15,19 @@
|
||||
*/
|
||||
package com.intellij.openapi.editor;
|
||||
|
||||
import com.intellij.codeStyle.CodeStyleFacade;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.WeakList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LazyRangeMarkerFactory {
|
||||
private final Project myProject;
|
||||
private static final Key<WeakList<LazyMarker>> LAZY_MARKERS_KEY = Key.create("LAZY_MARKERS_KEY");
|
||||
|
||||
public abstract class LazyRangeMarkerFactory {
|
||||
public static LazyRangeMarkerFactory getInstance(Project project) {
|
||||
return ServiceManager.getService(project, LazyRangeMarkerFactory.class);
|
||||
}
|
||||
|
||||
public LazyRangeMarkerFactory(@NotNull Project project, @NotNull final FileDocumentManager fileDocumentManager) {
|
||||
myProject = project;
|
||||
|
||||
EditorFactory.getInstance().getEventMulticaster().addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
public void beforeDocumentChange(DocumentEvent e) {
|
||||
transformRangeMarkers(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void documentChanged(DocumentEvent e) {
|
||||
transformRangeMarkers(e);
|
||||
}
|
||||
|
||||
private void transformRangeMarkers(@NotNull DocumentEvent e) {
|
||||
Document document = e.getDocument();
|
||||
VirtualFile file = fileDocumentManager.getFile(document);
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
WeakList<LazyMarker> lazyMarkers = file.getUserData(LAZY_MARKERS_KEY);
|
||||
if (lazyMarkers == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<LazyMarker> markers = lazyMarkers.toStrongList();
|
||||
List<LazyMarker> markersToRemove = null;
|
||||
for (LazyMarker marker : markers) {
|
||||
if (file.equals(marker.getFile()) && marker.documentChanged(document) != null) {
|
||||
if (markersToRemove == null) {
|
||||
markersToRemove = new SmartList<LazyMarker>();
|
||||
}
|
||||
markersToRemove.add(marker);
|
||||
}
|
||||
}
|
||||
if (markersToRemove != null) {
|
||||
lazyMarkers.removeAll(markersToRemove);
|
||||
}
|
||||
}
|
||||
}, project);
|
||||
}
|
||||
|
||||
private static void addToLazyMarkersList(@NotNull LazyMarker marker, @NotNull VirtualFile file) {
|
||||
WeakList<LazyMarker> markers = file.getUserData(LAZY_MARKERS_KEY);
|
||||
|
||||
if (markers == null) {
|
||||
markers = file.putUserDataIfAbsent(LAZY_MARKERS_KEY, new WeakList<LazyMarker>());
|
||||
}
|
||||
markers.add(marker);
|
||||
}
|
||||
@NotNull
|
||||
public abstract RangeMarker createRangeMarker(@NotNull final VirtualFile file, final int offset);
|
||||
|
||||
@NotNull
|
||||
public RangeMarker createRangeMarker(@NotNull final VirtualFile file, final int offset) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<RangeMarker>() {
|
||||
@Override
|
||||
public RangeMarker compute() {
|
||||
// even for already loaded document do not create range marker yet - wait until it really needed when e.g. user clicked to jump to OpenFileDescriptor
|
||||
final LazyMarker marker = new OffsetLazyMarker(file, offset);
|
||||
addToLazyMarkersList(marker, file);
|
||||
return marker;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public RangeMarker createRangeMarker(@NotNull final VirtualFile file, final int line, final int column, final boolean persistent) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<RangeMarker>() {
|
||||
@Override
|
||||
public RangeMarker compute() {
|
||||
final Document document = FileDocumentManager.getInstance().getCachedDocument(file);
|
||||
if (document != null) {
|
||||
final int offset = calculateOffset(myProject, file, document, line, column);
|
||||
return document.createRangeMarker(offset, offset, persistent);
|
||||
}
|
||||
|
||||
final LazyMarker marker = new LineColumnLazyMarker(file, line, column);
|
||||
addToLazyMarkersList(marker, file);
|
||||
return marker;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private abstract static class LazyMarker extends UserDataHolderBase implements RangeMarker {
|
||||
private RangeMarker myDelegate;
|
||||
private final VirtualFile myFile;
|
||||
protected final int myInitialOffset;
|
||||
|
||||
private LazyMarker(@NotNull VirtualFile file, int offset) {
|
||||
myFile = file;
|
||||
myInitialOffset = offset;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public VirtualFile getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected final RangeMarker getOrCreateDelegate() {
|
||||
if (myDelegate == null) {
|
||||
Document document = FileDocumentManager.getInstance().getDocument(myFile);
|
||||
if (document == null) {
|
||||
return null;
|
||||
}
|
||||
myDelegate = createDelegate(myFile, document);
|
||||
}
|
||||
return myDelegate;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected final RangeMarker documentChanged(@NotNull Document document) {
|
||||
if (myDelegate == null) {
|
||||
myDelegate = createDelegate(myFile, document);
|
||||
}
|
||||
return myDelegate;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract RangeMarker createDelegate(@NotNull VirtualFile file, @NotNull Document document);
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Document getDocument() {
|
||||
RangeMarker delegate = getOrCreateDelegate();
|
||||
if (delegate == null) {
|
||||
//noinspection ConstantConditions
|
||||
return FileDocumentManager.getInstance().getDocument(myFile);
|
||||
}
|
||||
return delegate.getDocument();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStartOffset() {
|
||||
return myDelegate == null ? myInitialOffset : myDelegate.getStartOffset();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getEndOffset() {
|
||||
return myDelegate == null ? myInitialOffset : myDelegate.getEndOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
RangeMarker delegate = getOrCreateDelegate();
|
||||
return delegate != null && delegate.isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGreedyToLeft(boolean greedy) {
|
||||
getOrCreateDelegate().setGreedyToLeft(greedy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGreedyToRight(boolean greedy) {
|
||||
getOrCreateDelegate().setGreedyToRight(greedy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGreedyToRight() {
|
||||
return getOrCreateDelegate().isGreedyToRight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGreedyToLeft() {
|
||||
return getOrCreateDelegate().isGreedyToLeft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
RangeMarker delegate = getOrCreateDelegate();
|
||||
if (delegate != null) {
|
||||
delegate.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class OffsetLazyMarker extends LazyMarker {
|
||||
private OffsetLazyMarker(@NotNull VirtualFile file, int offset) {
|
||||
super(file, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public RangeMarker createDelegate(@NotNull VirtualFile file, @NotNull final Document document) {
|
||||
final int offset = Math.min(myInitialOffset, document.getTextLength());
|
||||
return document.createRangeMarker(offset, offset);
|
||||
}
|
||||
}
|
||||
|
||||
private class LineColumnLazyMarker extends LazyMarker {
|
||||
private final int myLine;
|
||||
private final int myColumn;
|
||||
|
||||
private LineColumnLazyMarker(@NotNull VirtualFile file, int line, int column) {
|
||||
super(file, -1);
|
||||
myLine = line;
|
||||
myColumn = column;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public RangeMarker createDelegate(@NotNull VirtualFile file, @NotNull Document document) {
|
||||
if (document.getTextLength() == 0 && !(myLine == 0 && myColumn == 0)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int offset = calculateOffset(myProject, file, document, myLine, myColumn);
|
||||
return document.createRangeMarker(offset, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStartOffset() {
|
||||
getOrCreateDelegate();
|
||||
return super.getStartOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEndOffset() {
|
||||
getOrCreateDelegate();
|
||||
return super.getEndOffset();
|
||||
}
|
||||
}
|
||||
|
||||
private static int calculateOffset(@NotNull Project project, @NotNull VirtualFile file, @NotNull Document document, final int line, final int column) {
|
||||
int offset;
|
||||
if (line < document.getLineCount()) {
|
||||
final int lineStart = document.getLineStartOffset(line);
|
||||
final int lineEnd = document.getLineEndOffset(line);
|
||||
final CharSequence docText = document.getCharsSequence();
|
||||
final int tabSize = CodeStyleFacade.getInstance(project).getTabSize(file.getFileType());
|
||||
|
||||
offset = lineStart;
|
||||
int col = 0;
|
||||
while (offset < lineEnd && col < column) {
|
||||
col += docText.charAt(offset) == '\t' ? tabSize : 1;
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
offset = document.getTextLength();
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
public abstract RangeMarker createRangeMarker(@NotNull final VirtualFile file, final int line, final int column, final boolean persistent);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2014 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.
|
||||
@@ -115,7 +115,7 @@ public class DelayedDocumentWatcher {
|
||||
public void documentChanged(DocumentEvent event) {
|
||||
if (myDocumentSavingInProgress) {
|
||||
/** When {@link FileDocumentManager#saveAllDocuments} is called,
|
||||
* {@link com.intellij.openapi.fileEditor.impl.TrailingSpacesStripper} can change a document.
|
||||
* {@link com.intellij.openapi.editor.impl.TrailingSpacesStripper} can change a document.
|
||||
* These needless 'documentChanged' events should be filtered out.
|
||||
*/
|
||||
return;
|
||||
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.openapi.editor.impl;
|
||||
|
||||
import com.intellij.codeStyle.CodeStyleFacade;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.LazyRangeMarkerFactory;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.WeakList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LazyRangeMarkerFactoryImpl extends LazyRangeMarkerFactory {
|
||||
private final Project myProject;
|
||||
private static final Key<WeakList<LazyMarker>> LAZY_MARKERS_KEY = Key.create("LAZY_MARKERS_KEY");
|
||||
|
||||
public LazyRangeMarkerFactoryImpl(@NotNull Project project, @NotNull final FileDocumentManager fileDocumentManager) {
|
||||
myProject = project;
|
||||
|
||||
EditorFactory.getInstance().getEventMulticaster().addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
public void beforeDocumentChange(DocumentEvent e) {
|
||||
transformRangeMarkers(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void documentChanged(DocumentEvent e) {
|
||||
transformRangeMarkers(e);
|
||||
}
|
||||
|
||||
private void transformRangeMarkers(@NotNull DocumentEvent e) {
|
||||
Document document = e.getDocument();
|
||||
VirtualFile file = fileDocumentManager.getFile(document);
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
WeakList<LazyMarker> lazyMarkers = getMarkers(file);
|
||||
if (lazyMarkers == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<LazyMarker> markers = lazyMarkers.toStrongList();
|
||||
for (LazyMarker marker : markers) {
|
||||
if (file.equals(marker.getFile())) {
|
||||
marker.getOrCreateDelegate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, project);
|
||||
}
|
||||
|
||||
static WeakList<LazyMarker> getMarkers(@NotNull VirtualFile file) {
|
||||
return file.getUserData(LazyRangeMarkerFactoryImpl.LAZY_MARKERS_KEY);
|
||||
}
|
||||
|
||||
private static void addToLazyMarkersList(@NotNull LazyMarker marker, @NotNull VirtualFile file) {
|
||||
WeakList<LazyMarker> markers = getMarkers(file);
|
||||
|
||||
if (markers == null) {
|
||||
markers = file.putUserDataIfAbsent(LAZY_MARKERS_KEY, new WeakList<LazyMarker>());
|
||||
}
|
||||
markers.add(marker);
|
||||
}
|
||||
|
||||
private static void removeFromLazyMarkersList(@NotNull LazyMarker marker, @NotNull VirtualFile file) {
|
||||
WeakList<LazyMarker> markers = getMarkers(file);
|
||||
|
||||
if (markers != null) {
|
||||
markers.remove(marker);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public RangeMarker createRangeMarker(@NotNull final VirtualFile file, final int offset) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<RangeMarker>() {
|
||||
@Override
|
||||
public RangeMarker compute() {
|
||||
// even for already loaded document do not create range marker yet - wait until it really needed when e.g. user clicked to jump to OpenFileDescriptor
|
||||
final LazyMarker marker = new OffsetLazyMarker(file, offset);
|
||||
addToLazyMarkersList(marker, file);
|
||||
return marker;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public RangeMarker createRangeMarker(@NotNull final VirtualFile file, final int line, final int column, final boolean persistent) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<RangeMarker>() {
|
||||
@Override
|
||||
public RangeMarker compute() {
|
||||
final Document document = FileDocumentManager.getInstance().getCachedDocument(file);
|
||||
if (document != null) {
|
||||
final int offset = calculateOffset(myProject, file, document, line, column);
|
||||
return document.createRangeMarker(offset, offset, persistent);
|
||||
}
|
||||
|
||||
final LazyMarker marker = new LineColumnLazyMarker(file, line, column);
|
||||
addToLazyMarkersList(marker, file);
|
||||
return marker;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
abstract static class LazyMarker extends UserDataHolderBase implements RangeMarker {
|
||||
protected RangeMarker myDelegate; // the real range marker which is created only when document is opened, or (this) which means it's disposed
|
||||
protected final VirtualFile myFile;
|
||||
protected final int myInitialOffset;
|
||||
|
||||
private LazyMarker(@NotNull VirtualFile file, int offset) {
|
||||
myFile = file;
|
||||
myInitialOffset = offset;
|
||||
}
|
||||
|
||||
boolean isDelegated() {
|
||||
return myDelegate != null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public VirtualFile getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected final RangeMarker getOrCreateDelegate() {
|
||||
if (myDelegate == null) {
|
||||
Document document = FileDocumentManager.getInstance().getDocument(myFile);
|
||||
if (document == null) {
|
||||
return null;
|
||||
}
|
||||
myDelegate = createDelegate(myFile, document);
|
||||
removeFromLazyMarkersList(this, myFile);
|
||||
}
|
||||
return isDisposed() ? null : myDelegate;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract RangeMarker createDelegate(@NotNull VirtualFile file, @NotNull Document document);
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Document getDocument() {
|
||||
RangeMarker delegate = getOrCreateDelegate();
|
||||
if (delegate == null) {
|
||||
//noinspection ConstantConditions
|
||||
return FileDocumentManager.getInstance().getDocument(myFile);
|
||||
}
|
||||
return delegate.getDocument();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStartOffset() {
|
||||
return myDelegate == null || isDisposed() ? myInitialOffset : myDelegate.getStartOffset();
|
||||
}
|
||||
|
||||
public boolean isDisposed() {
|
||||
return myDelegate == this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getEndOffset() {
|
||||
return myDelegate == null || isDisposed() ? myInitialOffset : myDelegate.getEndOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
RangeMarker delegate = getOrCreateDelegate();
|
||||
return delegate != null && !isDisposed() && delegate.isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGreedyToLeft(boolean greedy) {
|
||||
getOrCreateDelegate().setGreedyToLeft(greedy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGreedyToRight(boolean greedy) {
|
||||
getOrCreateDelegate().setGreedyToRight(greedy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGreedyToRight() {
|
||||
return getOrCreateDelegate().isGreedyToRight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGreedyToLeft() {
|
||||
return getOrCreateDelegate().isGreedyToLeft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
assert !isDisposed();
|
||||
RangeMarker delegate = myDelegate;
|
||||
if (delegate == null) {
|
||||
removeFromLazyMarkersList(this, myFile);
|
||||
myDelegate = this; // mark of disposed marker
|
||||
}
|
||||
else {
|
||||
delegate.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class OffsetLazyMarker extends LazyMarker {
|
||||
private OffsetLazyMarker(@NotNull VirtualFile file, int offset) {
|
||||
super(file, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
RangeMarker delegate = myDelegate;
|
||||
if (delegate == null) {
|
||||
Document document = FileDocumentManager.getInstance().getDocument(myFile);
|
||||
return document != null;
|
||||
}
|
||||
|
||||
return super.isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public RangeMarker createDelegate(@NotNull VirtualFile file, @NotNull final Document document) {
|
||||
final int offset = Math.min(myInitialOffset, document.getTextLength());
|
||||
return document.createRangeMarker(offset, offset);
|
||||
}
|
||||
}
|
||||
|
||||
private class LineColumnLazyMarker extends LazyMarker {
|
||||
private final int myLine;
|
||||
private final int myColumn;
|
||||
|
||||
private LineColumnLazyMarker(@NotNull VirtualFile file, int line, int column) {
|
||||
super(file, -1);
|
||||
myLine = line;
|
||||
myColumn = column;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public RangeMarker createDelegate(@NotNull VirtualFile file, @NotNull Document document) {
|
||||
if (document.getTextLength() == 0 && !(myLine == 0 && myColumn == 0)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int offset = calculateOffset(myProject, file, document, myLine, myColumn);
|
||||
return document.createRangeMarker(offset, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
RangeMarker delegate = myDelegate;
|
||||
if (delegate == null) {
|
||||
Document document = FileDocumentManager.getInstance().getDocument(myFile);
|
||||
return document != null && (document.getTextLength() != 0 || myLine == 0 && myColumn == 0);
|
||||
}
|
||||
|
||||
return super.isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStartOffset() {
|
||||
getOrCreateDelegate();
|
||||
return super.getStartOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEndOffset() {
|
||||
getOrCreateDelegate();
|
||||
return super.getEndOffset();
|
||||
}
|
||||
}
|
||||
|
||||
private static int calculateOffset(@NotNull Project project, @NotNull VirtualFile file, @NotNull Document document, final int line, final int column) {
|
||||
int offset;
|
||||
if (line < document.getLineCount()) {
|
||||
final int lineStart = document.getLineStartOffset(line);
|
||||
final int lineEnd = document.getLineEndOffset(line);
|
||||
final CharSequence docText = document.getCharsSequence();
|
||||
final int tabSize = CodeStyleFacade.getInstance(project).getTabSize(file.getFileType());
|
||||
|
||||
offset = lineStart;
|
||||
int col = 0;
|
||||
while (offset < lineEnd && col < column) {
|
||||
col += docText.charAt(offset) == '\t' ? tabSize : 1;
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
offset = document.getTextLength();
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
}
|
||||
+6
-6
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.fileEditor.impl;
|
||||
package com.intellij.openapi.editor.impl;
|
||||
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.injected.editor.DocumentWindow;
|
||||
@@ -23,7 +23,6 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
|
||||
import com.intellij.openapi.editor.impl.DocumentImpl;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -37,11 +36,12 @@ import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public final class TrailingSpacesStripper extends FileDocumentManagerAdapter {
|
||||
|
||||
public static final Key<String> OVERRIDE_STRIP_TRAILING_SPACES_KEY = Key.create("OVERRIDE_TRIM_TRAILING_SPACES_KEY");
|
||||
public static final Key<Boolean> OVERRIDE_ENSURE_NEWLINE_KEY = Key.create("OVERRIDE_ENSURE_NEWLINE_KEY");
|
||||
|
||||
@@ -61,7 +61,7 @@ public final class TrailingSpacesStripper extends FileDocumentManagerAdapter {
|
||||
strip(document);
|
||||
}
|
||||
|
||||
private void strip(final Document document) {
|
||||
private void strip(@NotNull final Document document) {
|
||||
if (!document.isWritable()) return;
|
||||
FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
|
||||
VirtualFile file = fileDocumentManager.getFile(document);
|
||||
@@ -149,7 +149,7 @@ public final class TrailingSpacesStripper extends FileDocumentManagerAdapter {
|
||||
((DocumentImpl)document).clearLineModificationFlagsExcept(caretLines);
|
||||
}
|
||||
|
||||
public static boolean stripIfNotCurrentLine(Document document, boolean inChangedLinesOnly) {
|
||||
public static boolean stripIfNotCurrentLine(@NotNull Document document, boolean inChangedLinesOnly) {
|
||||
if (document instanceof DocumentWindow) {
|
||||
document = ((DocumentWindow)document).getDelegate();
|
||||
}
|
||||
+1
@@ -37,6 +37,7 @@ import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
|
||||
import com.intellij.openapi.editor.impl.EditorFactoryImpl;
|
||||
import com.intellij.openapi.editor.impl.TrailingSpacesStripper;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.fileEditor.*;
|
||||
import com.intellij.openapi.fileEditor.impl.text.TextEditorImpl;
|
||||
|
||||
@@ -190,7 +190,8 @@
|
||||
<projectService serviceInterface="com.intellij.openapi.vcs.VcsFileListenerContextHelper"
|
||||
serviceImplementation="com.intellij.openapi.vcs.VcsFileListenerContextHelper"/>
|
||||
|
||||
<projectService serviceImplementation="com.intellij.openapi.editor.LazyRangeMarkerFactory"/>
|
||||
<projectService serviceInterface="com.intellij.openapi.editor.LazyRangeMarkerFactory"
|
||||
serviceImplementation="com.intellij.openapi.editor.impl.LazyRangeMarkerFactoryImpl"/>
|
||||
|
||||
<!-- General -->
|
||||
<applicationConfigurable groupId="appearance" key="title.general" bundle="messages.IdeBundle" id="preferences.general" instance="com.intellij.ide.GeneralSettingsConfigurable"/>
|
||||
|
||||
+41
-3
@@ -34,6 +34,7 @@ import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.PsiDocumentManagerImpl;
|
||||
@@ -44,6 +45,7 @@ import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.testFramework.Timings;
|
||||
import com.intellij.util.CommonProcessors;
|
||||
import com.intellij.util.ThrowableRunnable;
|
||||
import com.intellij.util.containers.WeakList;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -1077,13 +1079,13 @@ public class RangeMarkerTest extends LightPlatformTestCase {
|
||||
|
||||
public void testRangeHighlighterLinesInRangeForLongLinePerformance() throws Exception {
|
||||
final int N = 50000;
|
||||
Document document = EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol('x', 2*N));
|
||||
Document document = EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol('x', 2 * N));
|
||||
|
||||
final MarkupModelEx markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(document, ourProject, true);
|
||||
for (int i=0; i<N-1;i++) {
|
||||
markupModel.addRangeHighlighter(2*i, 2*i+1, 0, null, HighlighterTargetArea.EXACT_RANGE);
|
||||
}
|
||||
markupModel.addRangeHighlighter(N/2, N/2+1, 0, null, HighlighterTargetArea.LINES_IN_RANGE);
|
||||
markupModel.addRangeHighlighter(N / 2, N / 2 + 1, 0, null, HighlighterTargetArea.LINES_IN_RANGE);
|
||||
|
||||
PlatformTestUtil.startPerformanceTest("slow highlighters lookup", (int)(N*Math.log(N)/1000), new ThrowableRunnable() {
|
||||
@Override
|
||||
@@ -1107,6 +1109,42 @@ public class RangeMarkerTest extends LightPlatformTestCase {
|
||||
RangeHighlighter line = markupModel.addRangeHighlighter(4, 5, 0, null, HighlighterTargetArea.LINES_IN_RANGE);
|
||||
List<RangeHighlighter> list = new ArrayList<RangeHighlighter>();
|
||||
markupModel.processRangeHighlightersOverlappingWith(2, 9, new CommonProcessors.CollectProcessor<RangeHighlighter>(list));
|
||||
assertEquals(Arrays.asList(line,exact), list);
|
||||
assertEquals(Arrays.asList(line, exact), list);
|
||||
}
|
||||
|
||||
public void testLazyRangeMarkers() {
|
||||
psiFile = createFile("x.txt", "xxx");
|
||||
|
||||
LazyRangeMarkerFactoryImpl factory = (LazyRangeMarkerFactoryImpl)LazyRangeMarkerFactory.getInstance(getProject());
|
||||
VirtualFile virtualFile = psiFile.getVirtualFile();
|
||||
LazyRangeMarkerFactoryImpl.LazyMarker marker = (LazyRangeMarkerFactoryImpl.LazyMarker)factory.createRangeMarker(virtualFile, 0);
|
||||
WeakList<LazyRangeMarkerFactoryImpl.LazyMarker> markers = LazyRangeMarkerFactoryImpl.getMarkers(virtualFile);
|
||||
assertSame(marker, assertOneElement(markers));
|
||||
|
||||
assertFalse(marker.isDelegated());
|
||||
assertTrue(marker.isValid());
|
||||
assertEquals(0, marker.getStartOffset());
|
||||
assertFalse(marker.isDelegated());
|
||||
|
||||
marker.dispose();
|
||||
assertFalse(marker.isValid());
|
||||
assertEmpty(LazyRangeMarkerFactoryImpl.getMarkers(virtualFile));
|
||||
|
||||
|
||||
marker = (LazyRangeMarkerFactoryImpl.LazyMarker)factory.createRangeMarker(virtualFile, 0);
|
||||
assertFalse(marker.isDelegated());
|
||||
assertTrue(marker.isValid());
|
||||
assertEquals(0, marker.getStartOffset());
|
||||
assertFalse(marker.isDelegated());
|
||||
|
||||
Document document = marker.getDocument();
|
||||
document.insertString(2, "yyy");
|
||||
assertTrue(marker.isDelegated());
|
||||
assertTrue(marker.isValid());
|
||||
assertEquals(0, marker.getStartOffset());
|
||||
|
||||
assertEmpty(LazyRangeMarkerFactoryImpl.getMarkers(virtualFile));
|
||||
marker.dispose();
|
||||
assertEmpty(LazyRangeMarkerFactoryImpl.getMarkers(virtualFile));
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -13,15 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.editor;
|
||||
package com.intellij.openapi.editor.impl;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.impl.ApplicationImpl;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.impl.TrailingSpacesStripper;
|
||||
import com.intellij.testFramework.LightPlatformCodeInsightTestCase;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
+1
-1
@@ -35,10 +35,10 @@ import com.intellij.openapi.editor.actionSystem.EditorActionManager;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
import com.intellij.openapi.editor.impl.DocumentImpl;
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.editor.impl.TrailingSpacesStripper;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.fileEditor.impl.TrailingSpacesStripper;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
|
||||
Reference in New Issue
Block a user