import com.intellij.openapi.editor.actionSystem.EditorActionManager;
import com.intellij.openapi.editor.actionSystem.TypedAction;
import com.intellij.openapi.editor.ex.DocumentEx;
+import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileEditor.TextEditor;
protected Editor createEditor(VirtualFile file) {
final FileEditorManager instance = FileEditorManager.getInstance(myProject);
- if (file.getFileType().isBinary()) {
- return null;
- }
+ if (file.getFileType().isBinary()) return null;
- return instance.openTextEditor(new OpenFileDescriptor(myProject, file, 0), false);
+ Editor editor = instance.openTextEditor(new OpenFileDescriptor(myProject, file, 0), false);
+ ((EditorImpl)editor).setCaretActive();
+ return editor;
}
protected void tearDown() throws Exception {
checkResultByFile(filePath, false);
}
- protected void checkResultByFile(String filePath, boolean stripTrailingSpaces) throws Exception {
+ protected void checkResultByFile(@NonNls String filePath, boolean stripTrailingSpaces) throws Exception {
getProject().getComponent(PostprocessReformattingAspect.class).doPostponedFormatting();
if (stripTrailingSpaces) {
((DocumentEx)myEditor.getDocument()).stripTrailingSpaces(false);
import com.intellij.codeInsight.intention.impl.IntentionHintComponent;
import com.intellij.concurrency.Job;
import com.intellij.ide.PowerSaveMode;
+import com.intellij.injected.editor.EditorWindow;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
public void updateVisibleHighlighters(@NotNull Editor editor) {
ApplicationManager.getApplication().assertIsDispatchThread();
if (!myUpdateByTimerEnabled) return;
- //if (ApplicationManager.getApplication().isUnitTestMode()) return;
+ if (editor instanceof EditorWindow) editor = ((EditorWindow)editor).getDelegate();
final TextEditor textEditor = TextEditorProvider.getInstance().getTextEditor(editor);
BackgroundEditorHighlighter highlighter = textEditor.getBackgroundHighlighter();
return new RangeMarkerWindow(this, (RangeMarkerEx)hostMarker);
}
- public void stripTrailingSpaces(final boolean inChangedLinesOnly) {
- myDelegate.stripTrailingSpaces(inChangedLinesOnly);
+ public boolean stripTrailingSpaces(final boolean inChangedLinesOnly) {
+ return myDelegate.stripTrailingSpaces(inChangedLinesOnly);
}
public void setStripTrailingSpacesEnabled(final boolean isEnabled) {
return new LogicalPosition(lineNumber, column);
}
+ @Override
+ public boolean isCaretActive() {
+ return myDelegate.isCaretActive();
+ }
+
@NotNull
public LogicalPosition xyToLogicalPosition(@NotNull final Point p) {
assert isValid();
import java.util.List;
public interface DocumentEx extends Document {
- void stripTrailingSpaces(boolean inChangedLinesOnly);
+ /**
+ * @return true if stripping was completed successfully, false if the document prevented stripping by e.g. caret being in the way
+ */
+ boolean stripTrailingSpaces(boolean inChangedLinesOnly);
void setStripTrailingSpacesEnabled(boolean isEnabled);
@NotNull LineIterator createLineIterator();
import com.intellij.ide.PasteProvider;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.FoldingModel;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.VisualPosition;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
-import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeListener;
LogicalPosition visualToLogicalPosition(@NotNull VisualPosition visiblePos, boolean softWrapAware);
@NotNull LogicalPosition offsetToLogicalPosition(int offset, boolean softWrapAware);
+
+ /**
+ * @return true if caret cursor is blinking in this editor
+ */
+ boolean isCaretActive();
}
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.LocalTimeCounter;
import com.intellij.util.containers.ConcurrentHashMap;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
isStripTrailingSpacesEnabled = isEnabled;
}
- public void stripTrailingSpaces(boolean inChangedLinesOnly) {
- Editor[] editors = EditorFactory.getInstance().getEditors(this, null);
- VisualPosition[] visualCarets = new VisualPosition[editors.length];
- int[] caretLines = new int[editors.length];
- for (int i = 0; i < editors.length; i++) {
- visualCarets[i] = editors[i].getCaretModel().getVisualPosition();
- caretLines[i] = editors[i].getCaretModel().getLogicalPosition().line;
- }
-
+ public boolean stripTrailingSpaces(boolean inChangedLinesOnly) {
if (!isStripTrailingSpacesEnabled) {
- return;
+ return true;
}
- boolean isTestMode = ApplicationManager.getApplication().isUnitTestMode();
+ Editor editor = ContainerUtil.find(EditorFactory.getInstance().getEditors(this), new Condition<Editor>() {
+ @Override
+ public boolean value(Editor editor) {
+ return ((EditorEx)editor).isCaretActive();
+ }
+ });
- lines:
- for (int i = 0; i < myLineSet.getLineCount(); i++) {
- if (!isTestMode) {
- for (int caretLine : caretLines) {
- if (caretLine == i) continue lines;
- }
- }
+ // when virtual space enabled, we can strip whitespace anywhere
+ boolean isVirtualSpaceEnabled = editor == null || editor.getSettings().isVirtualSpace();
- if (!inChangedLinesOnly || myLineSet.isModified(i)) {
- int start = -1;
- int lineEnd = myLineSet.getLineEnd(i) - myLineSet.getSeparatorLength(i);
- int lineStart = myLineSet.getLineStart(i);
- CharSequence text = myText.getCharArray();
- for (int offset = lineEnd - 1; offset >= lineStart; offset--) {
- char c = text.charAt(offset);
- if (c != ' ' && c != '\t') {
- break;
- }
- start = offset;
- }
- if (start != -1) {
- deleteString(start, lineEnd);
- }
- }
- }
+ VisualPosition visualCaret = editor == null ? null : editor.getCaretModel().getVisualPosition();
+ int caretLine = editor == null ? -1 : editor.getCaretModel().getLogicalPosition().line;
- if (!ShutDownTracker.isShutdownHookRunning()) {
- for (int i = 0; i < editors.length; i++) {
- editors[i].getCaretModel().moveToVisualPosition(visualCarets[i]);
+ boolean isTestMode = ApplicationManager.getApplication().isUnitTestMode();
+ boolean markAsNeedsStrippingLater = false;
+ for (int line = 0; line < myLineSet.getLineCount(); line++) {
+ if (inChangedLinesOnly && !myLineSet.isModified(line)) continue;
+ int start = -1;
+ int lineEnd = myLineSet.getLineEnd(line) - myLineSet.getSeparatorLength(line);
+ int lineStart = myLineSet.getLineStart(line);
+ CharSequence text = myText.getCharArray();
+ for (int offset = lineEnd - 1; offset >= lineStart; offset--) {
+ char c = text.charAt(offset);
+ if (c != ' ' && c != '\t') {
+ break;
+ }
+ start = offset;
+ }
+ if (start == -1) continue;
+ if (!isTestMode && !isVirtualSpaceEnabled && caretLine == line) {
+ // mark this as a document that needs stripping later
+ // otherwise the caret would jump madly
+ markAsNeedsStrippingLater = true;
}
+ else {
+ deleteString(start, lineEnd);
+ }
+ }
+
+ if (!ShutDownTracker.isShutdownHookRunning() && editor != null) {
+ editor.getCaretModel().moveToVisualPosition(visualCaret);
}
+ return !markAsNeedsStrippingLater;
}
public void setReadOnly(boolean isReadOnly) {
return myText.toString();
}
+ @NotNull
@Override
- public String getText(TextRange range) {
+ public String getText(@NotNull TextRange range) {
assertReadAccessToDocumentsAllowed();
return myText.substring(range.getStartOffset(), range.getEndOffset()).toString();
}
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import javax.swing.Timer;
ourCaretBlinkingCommand.start();
}
- public EditorImpl(Document document, boolean viewer, Project project) {
+ EditorImpl(@NotNull Document document, boolean viewer, Project project) {
myProject = project;
myDocument = (DocumentImpl)document;
myScheme = new MyColorSchemeDelegate();
return new LogicalPosition(line, column);
}
+ @Override
+ public boolean isCaretActive() {
+ return myCaretCursor.isActive();
+ }
+
+ @TestOnly
+ public void setCaretActive() {
+ myCaretCursor.setActive();
+ }
+
public int offsetToVisualLine(int offset) {
int line = calcLogicalLineNumber(offset);
return logicalToVisualLine(line);
return myIsShown;
}
}
+ public void setActive() {
+ synchronized (ourCaretBlinkingCommand) {
+ myIsShown = true;
+ }
+ }
private void passivate() {
synchronized (ourCaretBlinkingCommand) {
import com.intellij.util.EventDispatcher;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.MessageBusConnection;
+import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
public static final Key<Reference<Document>> DOCUMENT_KEY = Key.create("DOCUMENT_KEY");
private static final Key<VirtualFile> FILE_KEY = Key.create("FILE_KEY");
- private final Set<Document> myUnsavedDocuments = new HashSet<Document>();
+ private final Set<Document> myUnsavedDocuments = new THashSet<Document>();
private final EditReadOnlyListener myReadOnlyListener = new MyEditReadOnlyListener();
- private final EventDispatcher<FileDocumentSynchronizationVetoListener> myVetoDispatcher = EventDispatcher.create(
- FileDocumentSynchronizationVetoListener.class);
+ private final EventDispatcher<FileDocumentSynchronizationVetoListener> myVetoDispatcher = EventDispatcher.create(FileDocumentSynchronizationVetoListener.class);
private final VirtualFileManager myVirtualFileManager;
private final MessageBus myBus;
private static final Object lock = new Object();
+ private final TrailingSpacesStripper myTrailingSpacesStripper;
public FileDocumentManagerImpl(VirtualFileManager virtualFileManager) {
myVirtualFileManager = virtualFileManager;
myVirtualFileManager.addVirtualFileListener(this);
myBus = ApplicationManager.getApplication().getMessageBus();
- myBus.connect().subscribe(AppTopics.FILE_DOCUMENT_SYNC, new TrailingSpacesStripper());
+ myTrailingSpacesStripper = new TrailingSpacesStripper(myBus);
}
@NotNull
throw new RuntimeException("This method is only for test mode!");
}
ApplicationManager.getApplication().assertWriteAccessAllowed();
- if (myUnsavedDocuments.size() > 0) {
+ if (!myUnsavedDocuments.isEmpty()) {
myUnsavedDocuments.clear();
fireUnsavedDocumensDropped();
}
+ myTrailingSpacesStripper.dropAll();
}
public void saveAllDocuments() {
if (myUnsavedDocuments.isEmpty()) return;
- HashSet<Document> failedToSave = new HashSet<Document>();
+ Set<Document> failedToSave = new THashSet<Document>();
while (true) {
final Document[] unsavedDocuments = getUnsavedDocuments();
);
}
- private void _saveDocument(final Document document) {
+ private void _saveDocument(@NotNull final Document document) {
boolean committed = false;
try {
VirtualFile file = getFile(document);
}
};
- //if (!ApplicationManager.getApplication().isUnitTestMode()){
- // LaterInvocator.invokeLater(askReloadRunnable);
- //}
- //else{
askReloadRunnable.run();
- //}
}
else {
reloadFromDisk(document);
);
}
}, UIBundle.message("file.cache.conflict.action"), null);
- //ApplicationManager.getApplication().runWriteAction(
- // new ExternalChangeAction() {
- // public void run() {
- // boolean wasWritable = document.isWritable();
- // DocumentEx documentEx = (DocumentEx)document;
- // documentEx.setReadOnly(false);
- // documentEx.replaceText(LoadTextUtil.loadText(file), file.getModificationStamp());
- // documentEx.setReadOnly(!wasWritable);
- // }
- // }
- //);
myUnsavedDocuments.remove(document);
}
}
});
- //int option = Messages.showYesNoDialog(message, "File Cache Conflict", Messages.getQuestionIcon());
builder.setTitle(UIBundle.message("file.cache.conflict.dialog.title"));
builder.setButtonsAlignment(SwingConstants.CENTER);
builder.setHelpId("reference.dialogs.fileCacheConflict");
return builder.show() == 0;
- //return option == 0;
}
protected void reportErrorOnSave(final IOException e) {
*/
package com.intellij.openapi.fileEditor.impl;
+import com.intellij.AppTopics;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
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.FileDocumentManagerAdapter;
+import com.intellij.util.messages.MessageBus;
import com.intellij.util.text.CharArrayUtil;
+import gnu.trove.THashSet;
+import org.jetbrains.annotations.TestOnly;
-public final class TrailingSpacesStripper extends FileDocumentManagerAdapter {
- public void beforeDocumentSaving(final Document document) {
+import java.util.Set;
+
+public final class TrailingSpacesStripper {
+ private final Set<DocumentEx> myDocumentsToStripLater = new THashSet<DocumentEx>();
+
+ public TrailingSpacesStripper(MessageBus bus) {
+ bus.connect().subscribe(AppTopics.FILE_DOCUMENT_SYNC, new FileDocumentManagerAdapter() {
+ @Override
+ public void beforeAllDocumentsSaving() {
+ Set<DocumentEx> documentsToStrip = new THashSet<DocumentEx>(myDocumentsToStripLater);
+ myDocumentsToStripLater.clear();
+ for (DocumentEx documentEx : documentsToStrip) {
+ strip(documentEx);
+ }
+ }
+
+ @Override
+ public void beforeDocumentSaving(Document document) {
+ strip(document);
+ }
+ });
+ }
+
+ private void strip(final Document document) {
if (!document.isWritable()) return;
final EditorSettingsExternalizable settings = EditorSettingsExternalizable.getInstance();
final boolean ensureEOL = settings.isEnsureNewLineAtEOF();
if (!doStrip && !ensureEOL) return;
- CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
- if (doStrip) {
- final boolean inChangedLinesOnly = !settings.getStripTrailingSpaces().equals(EditorSettingsExternalizable.STRIP_TRAILING_SPACES_WHOLE);
- ((DocumentEx)document).stripTrailingSpaces(inChangedLinesOnly);
- }
-
- if (ensureEOL) {
- final int lines = document.getLineCount();
- if (lines > 0) {
- int start = document.getLineStartOffset(lines - 1);
- int end = document.getLineEndOffset(lines - 1);
- if (start != end) {
- CharSequence content = document.getCharsSequence();
- if (CharArrayUtil.containsOnlyWhiteSpaces(content.subSequence(start, end))) {
- document.deleteString(start, end);
+ CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
+ public void run() {
+ if (doStrip) {
+ final boolean inChangedLinesOnly =
+ !settings.getStripTrailingSpaces().equals(EditorSettingsExternalizable.STRIP_TRAILING_SPACES_WHOLE);
+ DocumentEx ex = (DocumentEx)document;
+ boolean success = ex.stripTrailingSpaces(inChangedLinesOnly);
+ if (!success) {
+ myDocumentsToStripLater.add(ex);
}
- else {
- document.insertString(end, "\n");
+ }
+
+ if (ensureEOL) {
+ final int lines = document.getLineCount();
+ if (lines > 0) {
+ int start = document.getLineStartOffset(lines - 1);
+ int end = document.getLineEndOffset(lines - 1);
+ if (start != end) {
+ CharSequence content = document.getCharsSequence();
+ if (CharArrayUtil.containsOnlyWhiteSpaces(content.subSequence(start, end))) {
+ document.deleteString(start, end);
+ }
+ else {
+ document.insertString(end, "\n");
+ }
+ }
}
}
}
- }
+ });
}
});
}
+
+ @TestOnly
+ public void dropAll() {
+ myDocumentsToStripLater.clear();
+ }
}
myUserData.put(key, value);
}
- public void stripTrailingSpaces(boolean inChangedLinesOnly) {
+ public boolean stripTrailingSpaces(boolean inChangedLinesOnly) {
+ return true;
}
public void setStripTrailingSpacesEnabled(boolean isEnabled) {
import com.intellij.openapi.editor.ex.DocumentEx;
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.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
}
}
- private static Editor createEditor(VirtualFile file) {
- return FileEditorManager.getInstance(getProject()).openTextEditor(new OpenFileDescriptor(getProject(), file, 0), false);
+ protected static Editor createEditor(VirtualFile file) {
+ Editor editor = FileEditorManager.getInstance(getProject()).openTextEditor(new OpenFileDescriptor(getProject(), file, 0), false);
+ ((EditorImpl)editor).setCaretActive();
+ return editor;
}
private static void setupFileEditorAndDocument(final String fileName, String fileText) throws IOException {