From 87ef851e5f24203e32b744df412ccb41199df2b8 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 25 Feb 2014 14:41:56 +0400 Subject: [PATCH] IDEA-121182 Plain text autodetection isn't rerun on file content change --- .../psi/impl/file/impl/PsiVFSListener.java | 72 ++++++++++--------- .../impl/FileDocumentManagerImpl.java | 54 ++++++++------ .../fileTypes/impl/FileTypeManagerImpl.java | 17 +++-- 3 files changed, 85 insertions(+), 58 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java index 1d9ef8c6525b..bf306856c2c3 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java @@ -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! } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java index 5c26205ea268..14af91d690f1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java @@ -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 LINE_SEPARATOR_KEY = Key.create("LINE_SEPARATOR_KEY"); public static final Key> DOCUMENT_KEY = Key.create("DOCUMENT_KEY"); private static final Key FILE_KEY = Key.create("FILE_KEY"); + private static final Key MUST_RECOMPUTE_FILE_TYPE = Key.create("Must recompute file type"); private final Set myUnsavedDocuments = new ConcurrentHashSet(); @@ -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 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; } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java index 3e21d9c3e38a..037029de3768 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java @@ -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