a better fix for IDEA-61160: don't save documents when there's an open lookup anywhere

This commit is contained in:
peter
2013-01-24 18:01:42 +01:00
parent daf7e50271
commit 6746fb0877
8 changed files with 62 additions and 61 deletions
@@ -26,8 +26,6 @@ import java.util.List;
public interface DocumentEx extends Document {
void setStripTrailingSpacesEnabled(boolean isEnabled);
boolean isStripTrailingSpacesEnabled();
@NotNull LineIterator createLineIterator();
void setModificationStamp(long modificationStamp);
@@ -71,8 +69,6 @@ public interface DocumentEx extends Document {
boolean processRangeMarkers(@NotNull Processor<RangeMarker> processor);
boolean processRangeMarkersOverlappingWith(int start, int end, @NotNull Processor<RangeMarker> processor);
void markLineModified(int line);
}
@@ -117,11 +117,6 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
isStripTrailingSpacesEnabled = isEnabled;
}
@Override
public boolean isStripTrailingSpacesEnabled() {
return isStripTrailingSpacesEnabled;
}
@TestOnly
public boolean stripTrailingSpaces() {
return stripTrailingSpaces(null, false, false, -1, -1);
@@ -540,15 +535,10 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
boolean wasModified = caretLine >= 0 && caretLine < myLineSet.getLineCount() && myLineSet.isModified(caretLine);
clearLineModificationFlags();
if (wasModified) {
markLineModified(caretLine);
myLineSet.setModified(caretLine);
}
}
@Override
public void markLineModified(int line) {
myLineSet.setModified(line);
}
@NotNull
private DocumentEvent beforeChangedUpdate(int offset, CharSequence oldString, CharSequence newString, boolean wholeTextReplaced) {
myChangeInProgress = true;
@@ -0,0 +1,44 @@
/*
* Copyright 2000-2013 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.codeInsight.lookup.impl;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentSynchronizationVetoer;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
/**
* @author peter
*/
public class LookupDocumentSavingVetoer implements FileDocumentSynchronizationVetoer {
@Override
public boolean maySaveDocument(@NotNull Document document) {
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
if (LookupManager.getInstance(project).getActiveLookup() != null) {
return false;
}
}
return true;
}
@Override
public boolean mayReloadFileContent(VirtualFile file, @NotNull Document document) {
return true;
}
}
@@ -43,7 +43,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.event.*;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
@@ -224,26 +223,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
new ChangeLookupSorting().installOn(mySortingLabel);
updateSorting();
myModalityState = ModalityState.stateForComponent(getComponent());
disableTrailingSpaceStripping();
}
private void disableTrailingSpaceStripping() {
final DocumentEx document = (DocumentEx)myEditor.getDocument();
final boolean oldStrip = document.isStripTrailingSpacesEnabled();
document.setStripTrailingSpacesEnabled(false);
Disposer.register(this, new Disposable() {
@Override
public void dispose() {
document.setStripTrailingSpacesEnabled(oldStrip);
if (!myEditor.isDisposed()) {
int caretLine = myEditor.getCaretModel().getLogicalPosition().line;
if (caretLine < document.getLineCount()) {
document.markLineModified(caretLine);
}
}
}
});
}
private CollectionListModel<LookupElement> getListModel() {
@@ -552,11 +552,6 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
myDelegate.setStripTrailingSpacesEnabled(isEnabled);
}
@Override
public boolean isStripTrailingSpacesEnabled() {
return myDelegate.isStripTrailingSpacesEnabled();
}
@Override
public int getLineSeparatorLength(final int line) {
return myDelegate.getLineSeparatorLength(injectedToHostLine(line));
@@ -951,8 +946,4 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
public boolean processRangeMarkersOverlappingWith(int start, int end, @NotNull Processor<RangeMarker> processor) {
return myDelegate.processRangeMarkersOverlappingWith(start, end, processor);
}
@Override
public void markLineModified(int line) {
}
}
@@ -298,11 +298,13 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
if (myUnsavedDocuments.isEmpty()) return;
final Map<Document, IOException> failedToSave = new HashMap<Document, IOException>();
final Set<Document> vetoed = new HashSet<Document>();
while (true) {
int count = 0;
for (Document document : myUnsavedDocuments) {
if (failedToSave.containsKey(document)) continue;
if (vetoed.contains(document)) continue;
try {
doSaveDocument(document);
}
@@ -310,6 +312,9 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
//noinspection ThrowableResultOfMethodCallIgnored
failedToSave.put(document, e);
}
catch (SaveVetoException e) {
vetoed.add(document);
}
count++;
}
@@ -332,6 +337,8 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
catch (IOException e) {
handleErrorsOnSave(Collections.singletonMap(document, e));
}
catch (SaveVetoException ignored) {
}
}
@Override
@@ -351,7 +358,9 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
}
}
private void doSaveDocument(@NotNull final Document document) throws IOException {
private static class SaveVetoException extends Exception {}
private void doSaveDocument(@NotNull final Document document) throws IOException, SaveVetoException {
VirtualFile file = getFile(document);
if (file == null || file instanceof LightVirtualFile || file.isValid() && !isFileModified(file)) {
@@ -364,6 +373,12 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
if (!myUnsavedDocuments.contains(document)) return;
}
for (FileDocumentSynchronizationVetoer vetoer : Extensions.getExtensions(FileDocumentSynchronizationVetoer.EP_NAME)) {
if (!vetoer.maySaveDocument(document)) {
throw new SaveVetoException();
}
}
final AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(getClass());
try {
doSaveDocumentInWriteAction(document, file);
@@ -392,12 +407,6 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
return;
}
for (FileDocumentSynchronizationVetoer vetoer : Extensions.getExtensions(FileDocumentSynchronizationVetoer.EP_NAME)) {
if (!vetoer.maySaveDocument(document)) {
return;
}
}
myMultiCaster.beforeDocumentSaving(document);
LOG.assertTrue(file.isValid());
@@ -804,4 +804,5 @@
<postStartupActivity implementation="com.intellij.codeInsight.highlighting.BraceHighlighter"/>
<usageContextPanelProvider implementation="com.intellij.usages.impl.UsagePreviewPanel$Provider"/>
<usageContextPanelProvider implementation="com.intellij.usageView.impl.UsageContextCallHierarchyPanel$Provider"/>
<fileDocumentSynchronizationVetoer implementation="com.intellij.codeInsight.lookup.impl.LookupDocumentSavingVetoer"/>
</extensions>
@@ -194,11 +194,6 @@ public class MockDocument implements DocumentEx {
public void setStripTrailingSpacesEnabled(boolean isEnabled) {
}
@Override
public boolean isStripTrailingSpacesEnabled() {
return false;
}
@Override
public int getLineSeparatorLength(int line) {
return 0;
@@ -316,8 +311,4 @@ public class MockDocument implements DocumentEx {
public boolean processRangeMarkersOverlappingWith(int start, int end, @NotNull Processor<RangeMarker> processor) {
return false;
}
@Override
public void markLineModified(int line) {
}
}