IDEA-121182 Plain text autodetection isn't rerun on file content change

This commit is contained in:
Alexey Kudravtsev
2014-02-25 15:06:44 +04:00
parent bbd2363366
commit 87ef851e5f
3 changed files with 85 additions and 58 deletions
@@ -22,6 +22,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter;
import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeEvent;
import com.intellij.openapi.fileTypes.FileTypeListener;
@@ -33,7 +34,7 @@ import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.impl.BulkVirtualFileListenerAdapter;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiDocumentManagerImpl;
import com.intellij.psi.impl.PsiDocumentManagerBase;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.PsiTreeChangeEventImpl;
import com.intellij.psi.impl.smartPointers.SmartPointerManagerImpl;
@@ -87,7 +88,7 @@ public class PsiVFSListener extends VirtualFileAdapter {
}
@Override
public void fileCreated(VirtualFileEvent event) {
public void fileCreated(@NotNull VirtualFileEvent event) {
final VirtualFile vFile = event.getFile();
ApplicationManager.getApplication().runWriteAction(
@@ -124,7 +125,7 @@ public class PsiVFSListener extends VirtualFileAdapter {
}
@Override
public void beforeFileDeletion(VirtualFileEvent event) {
public void beforeFileDeletion(@NotNull VirtualFileEvent event) {
final VirtualFile vFile = event.getFile();
VirtualFile parent = vFile.getParent();
@@ -159,7 +160,7 @@ public class PsiVFSListener extends VirtualFileAdapter {
}
@Override
public void fileDeleted(final VirtualFileEvent event) {
public void fileDeleted(@NotNull final VirtualFileEvent event) {
final VirtualFile vFile = event.getFile();
VirtualFile parent = event.getParent();
@@ -202,7 +203,7 @@ public class PsiVFSListener extends VirtualFileAdapter {
}
@Override
public void beforePropertyChange(final VirtualFilePropertyEvent event) {
public void beforePropertyChange(@NotNull final VirtualFilePropertyEvent event) {
final VirtualFile vFile = event.getFile();
final String propertyName = event.getPropertyName();
@@ -301,7 +302,7 @@ public class PsiVFSListener extends VirtualFileAdapter {
}
@Override
public void propertyChanged(final VirtualFilePropertyEvent event) {
public void propertyChanged(@NotNull final VirtualFilePropertyEvent event) {
final String propertyName = event.getPropertyName();
final VirtualFile vFile = event.getFile();
@@ -318,29 +319,7 @@ public class PsiVFSListener extends VirtualFileAdapter {
final PsiDirectory parentDir = getCachedDirectory(parent);
if (FileContentUtilCore.FORCE_RELOAD_REQUESTOR.equals(event.getRequestor())) {
FileViewProvider viewProvider = myFileManager.createFileViewProvider(vFile, true);
myFileManager.setViewProvider(vFile, viewProvider);
PsiFile newPsiFile = myManager.findFile(vFile);
if (newPsiFile == null) {
// psi file here can be null for any custom file with null parent
// that is currently open in a file editor, e.g. db table editor
//LOG.error("null psi file for "+vFile+"; provider: "+viewProvider);
return;
}
if (!viewProvider.isPhysical()) {
Document document = viewProvider.getDocument();
if (document != null) {
PsiDocumentManagerImpl.cachePsi(document, newPsiFile);
}
}
if (parentDir != null) {
PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager);
treeEvent.setParent(parentDir);
treeEvent.setOldChild(oldPsiFile);
treeEvent.setNewChild(newPsiFile);
myManager.childReplaced(treeEvent);
}
forceReload(vFile, oldPsiFile, parentDir);
return;
}
@@ -450,8 +429,34 @@ public class PsiVFSListener extends VirtualFileAdapter {
);
}
private void forceReload(@NotNull VirtualFile vFile, PsiFile oldPsiFile, PsiDirectory parentDir) {
FileViewProvider viewProvider = myFileManager.createFileViewProvider(vFile, true);
myFileManager.setViewProvider(vFile, viewProvider);
PsiFile newPsiFile = myManager.findFile(vFile);
if (newPsiFile == null) {
// psi file here can be null for any custom file with null parent
// that is currently open in a file editor, e.g. db table editor
//LOG.error("null psi file for "+vFile+"; provider: "+viewProvider);
return;
}
if (!viewProvider.isPhysical()) {
Document document = viewProvider.getDocument();
if (document != null) {
PsiDocumentManagerBase.cachePsi(document, newPsiFile);
}
}
if (parentDir != null) {
PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager);
treeEvent.setParent(parentDir);
treeEvent.setOldChild(oldPsiFile);
treeEvent.setNewChild(newPsiFile);
myManager.childReplaced(treeEvent);
}
}
@Override
public void beforeFileMovement(VirtualFileMoveEvent event) {
public void beforeFileMovement(@NotNull VirtualFileMoveEvent event) {
final VirtualFile vFile = event.getFile();
final PsiDirectory oldParentDir = myFileManager.findDirectory(event.getOldParent());
@@ -504,7 +509,7 @@ public class PsiVFSListener extends VirtualFileAdapter {
}
@Override
public void fileMoved(VirtualFileMoveEvent event) {
public void fileMoved(@NotNull VirtualFileMoveEvent event) {
final VirtualFile vFile = event.getFile();
final PsiDirectory oldParentDir = myFileManager.findDirectory(event.getOldParent());
@@ -647,13 +652,16 @@ public class PsiVFSListener extends VirtualFileAdapter {
private class MyFileDocumentManagerAdapter extends FileDocumentManagerAdapter {
@Override
public void fileWithNoDocumentChanged(@NotNull VirtualFile file) {
public void fileWithNoDocumentChanged(@NotNull final VirtualFile file) {
final PsiFile psiFile = myFileManager.getCachedPsiFileInner(file);
if (psiFile != null) {
ApplicationManager.getApplication().runWriteAction(
new ExternalChangeAction() {
@Override
public void run() {
if (FileDocumentManagerImpl.recomputeFileTypeIfNecessary(file)) {
forceReload(file, psiFile, null);
}
myFileManager.reloadFromDisk(psiFile, true); // important to ignore document which might appear already!
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 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.
@@ -40,10 +40,7 @@ import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileEditor.*;
import com.intellij.openapi.fileEditor.impl.text.TextEditorImpl;
import com.intellij.openapi.fileTypes.BinaryFileTypeDecompilers;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.UnknownFileType;
import com.intellij.openapi.fileTypes.*;
import com.intellij.openapi.project.*;
import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.openapi.ui.DialogBuilder;
@@ -93,6 +90,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
private static final Key<String> LINE_SEPARATOR_KEY = Key.create("LINE_SEPARATOR_KEY");
public static final Key<Reference<Document>> DOCUMENT_KEY = Key.create("DOCUMENT_KEY");
private static final Key<VirtualFile> FILE_KEY = Key.create("FILE_KEY");
private static final Key<Boolean> MUST_RECOMPUTE_FILE_TYPE = Key.create("Must recompute file type");
private final Set<Document> myUnsavedDocuments = new ConcurrentHashSet<Document>();
@@ -513,7 +511,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
}
@Override
public void reloadFiles(final VirtualFile... files) {
public void reloadFiles(@NotNull final VirtualFile... files) {
for (VirtualFile file : files) {
if (file.exists()) {
final Document doc = getCachedDocument(file);
@@ -547,7 +545,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
}
@Override
public void propertyChanged(VirtualFilePropertyEvent event) {
public void propertyChanged(@NotNull VirtualFilePropertyEvent event) {
final VirtualFile file = event.getFile();
if (VirtualFile.PROP_WRITABLE.equals(event.getPropertyName())) {
final Document document = getCachedDocument(file);
@@ -576,18 +574,18 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
}
}
private static boolean isBinaryWithDecompiler(VirtualFile file) {
private static boolean isBinaryWithDecompiler(@NotNull VirtualFile file) {
final FileType ft = file.getFileType();
return ft.isBinary() && BinaryFileTypeDecompilers.INSTANCE.forFileType(ft) != null;
}
private static boolean isBinaryWithoutDecompiler(VirtualFile file) {
private static boolean isBinaryWithoutDecompiler(@NotNull VirtualFile file) {
final FileType fileType = file.getFileType();
return fileType.isBinary() && BinaryFileTypeDecompilers.INSTANCE.forFileType(fileType) == null;
}
@Override
public void contentsChanged(VirtualFileEvent event) {
public void contentsChanged(@NotNull VirtualFileEvent event) {
if (event.isFromSave()) return;
final VirtualFile file = event.getFile();
final Document document = getCachedDocument(file);
@@ -716,11 +714,11 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
}
@Override
public void fileCreated(VirtualFileEvent event) {
public void fileCreated(@NotNull VirtualFileEvent event) {
}
@Override
public void fileDeleted(VirtualFileEvent event) {
public void fileDeleted(@NotNull VirtualFileEvent event) {
Document doc = getCachedDocument(event.getFile());
if (doc != null) {
myTrailingSpacesStripper.documentDeleted(doc);
@@ -728,24 +726,37 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
}
@Override
public void fileMoved(VirtualFileMoveEvent event) {
public void fileMoved(@NotNull VirtualFileMoveEvent event) {
}
@Override
public void fileCopied(VirtualFileCopyEvent event) {
public void fileCopied(@NotNull VirtualFileCopyEvent event) {
fileCreated(event);
}
@Override
public void beforePropertyChange(VirtualFilePropertyEvent event) {
public void beforePropertyChange(@NotNull VirtualFilePropertyEvent event) {
}
@Override
public void beforeContentsChange(VirtualFileEvent event) {
public void beforeContentsChange(@NotNull VirtualFileEvent event) {
VirtualFile virtualFile = event.getFile();
if (virtualFile.getFileType() == UnknownFileType.INSTANCE && virtualFile.getLength() == 0) {
virtualFile.putUserData(MUST_RECOMPUTE_FILE_TYPE, Boolean.TRUE);
}
}
public static boolean recomputeFileTypeIfNecessary(@NotNull VirtualFile virtualFile) {
if (virtualFile.getUserData(MUST_RECOMPUTE_FILE_TYPE) != null) {
FileTypeRegistry.getInstance().detectFileTypeFromContent(virtualFile);
virtualFile.putUserData(MUST_RECOMPUTE_FILE_TYPE, null);
return true;
}
return false;
}
@Override
public void beforeFileDeletion(VirtualFileEvent event) {
public void beforeFileDeletion(@NotNull VirtualFileEvent event) {
/*
if (!event.isFromRefresh()) {
VirtualFile file = event.getFile();
@@ -768,7 +779,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
}
@Override
public void beforeFileMovement(VirtualFileMoveEvent event) {
public void beforeFileMovement(@NotNull VirtualFileMoveEvent event) {
}
@Override
@@ -818,14 +829,15 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
}
@NotNull
protected FileDocumentManagerListener[] getListeners() {
private static FileDocumentManagerListener[] getListeners() {
return FileDocumentManagerListener.EP_NAME.getExtensions();
}
private void handleErrorsOnSave(@NotNull Map<Document, IOException> failures) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
for (IOException exception : failures.values()) {
throw new RuntimeException(exception);
IOException ioException = failures.isEmpty() ? null : failures.values().iterator().next();
if (ioException != null) {
throw new RuntimeException(ioException);
}
return;
}
@@ -325,7 +325,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME
}
//noinspection ForLoopReplaceableByForEach
for (int i = 0, size = mySpecialFileTypes.size(); i < size; i++) {
for (int i = 0; i < mySpecialFileTypes.size(); i++) {
FileTypeIdentifiableByVirtualFile type = mySpecialFileTypes.get(i);
if (type.isMyFileType(file)) {
return type;
@@ -335,28 +335,35 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME
fileType = getFileTypeByFileName(file.getName());
if (fileType != UnknownFileType.INSTANCE) return fileType;
fileType = file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY);
fileType = cachedDetectedFromContent(file);
if (fileType != null) return fileType;
return UnknownFileType.INSTANCE;
}
private static FileType cachedDetectedFromContent(@NotNull VirtualFile file) {
return file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY);
}
@NotNull
@Override
public FileType detectFileTypeFromContent(@NotNull VirtualFile file) {
if (file.isDirectory() || !file.isValid() || file.is(VFileProperty.SPECIAL)) {
return UnknownFileType.INSTANCE;
}
FileType fileType = file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY);
FileType fileType = cachedDetectedFromContent(file);
if (fileType == null) {
fileType = detectFromContent(file);
file.putUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY, fileType);
// for empty file there is still hope its type will change
if (file.getLength() != 0) {
file.putUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY, fileType);
}
}
return fileType;
}
public static boolean isFileTypeDetectedFromContent(@NotNull VirtualFile file) {
return file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY) != null;
return cachedDetectedFromContent(file) != null;
}
@Override