diff --git a/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeConfigurable.java b/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeConfigurable.java index e2661daec356..bfc59e1f884a 100644 --- a/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeConfigurable.java +++ b/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeConfigurable.java @@ -207,33 +207,33 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl } private void editPattern() { - final String item = myPatterns.getSelectedItem(); + String item = myPatterns.getSelectedItem(); if (item == null) return; editPattern(item); } - private void editPattern(@Nullable final String item) { - final FileType type = myRecognizedFileType.getSelectedFileType(); + private void editPattern(@Nullable String item) { + FileType type = myRecognizedFileType.getSelectedFileType(); if (type == null) return; - final String title = + String title = item == null ? FileTypesBundle.message("filetype.edit.add.pattern.title") : FileTypesBundle.message("filetype.edit.edit.pattern.title"); - final Language oldLanguage = item == null ? null : myTempTemplateDataLanguages.findAssociatedFileType(item); - final FileTypePatternDialog dialog = new FileTypePatternDialog(item, type, oldLanguage); - final DialogBuilder builder = new DialogBuilder(myPatterns); + Language oldLanguage = item == null ? null : myTempTemplateDataLanguages.findAssociatedFileType(item); + FileTypePatternDialog dialog = new FileTypePatternDialog(item, type, oldLanguage); + DialogBuilder builder = new DialogBuilder(myPatterns); builder.setPreferredFocusComponent(dialog.getPatternField()); builder.setCenterPanel(dialog.getMainPanel()); builder.setTitle(title); builder.showModal(true); if (builder.getDialogWrapper().isOK()) { - final String pattern = dialog.getPatternField().getText(); + String pattern = dialog.getPatternField().getText(); if (StringUtil.isEmpty(pattern)) return; - final FileNameMatcher matcher = FileTypeManager.parseFromString(pattern); + FileNameMatcher matcher = FileTypeManager.parseFromString(pattern); FileType registeredFileType = findExistingFileType(matcher); if (registeredFileType != null && registeredFileType != type) { if (registeredFileType.isReadOnly()) { @@ -242,25 +242,24 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl title, Messages.getErrorIcon()); return; } - else { - if (Messages.OK == Messages.showOkCancelDialog(myPatterns.myPatternsList, FileTypesBundle.message("filetype.edit.add.pattern.exists.message", + int ret = Messages.showOkCancelDialog(myPatterns.myPatternsList, FileTypesBundle.message("filetype.edit.add.pattern.exists.message", registeredFileType.getDescription()), - FileTypesBundle.message("filetype.edit.add.pattern.exists.title"), - FileTypesBundle.message("filetype.edit.add.pattern.reassign.button"), - CommonBundle.getCancelButtonText(), Messages.getQuestionIcon())) { - myTempPatternsTable.removeAssociation(matcher, registeredFileType); - if (oldLanguage != null) { - myTempTemplateDataLanguages.removeAssociation(matcher, oldLanguage); - } - } - else { - return; + FileTypesBundle.message("filetype.edit.add.pattern.exists.title"), + FileTypesBundle.message("filetype.edit.add.pattern.reassign.button"), + CommonBundle.getCancelButtonText(), Messages.getQuestionIcon()); + if (ret == Messages.OK) { + myTempPatternsTable.removeAssociation(matcher, registeredFileType); + if (oldLanguage != null) { + myTempTemplateDataLanguages.removeAssociation(matcher, oldLanguage); } } + else { + return; + } } if (item != null) { - final FileNameMatcher oldMatcher = FileTypeManager.parseFromString(item); + FileNameMatcher oldMatcher = FileTypeManager.parseFromString(item); myTempPatternsTable.removeAssociation(oldMatcher, type); if (oldLanguage != null) { myTempTemplateDataLanguages.removeAssociation(oldMatcher, oldLanguage); @@ -268,10 +267,12 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl } myTempPatternsTable.addAssociation(matcher, type); Language language = dialog.getTemplateDataLanguage(); - if (language != null) myTempTemplateDataLanguages.addAssociation(matcher, language); + if (language != null) { + myTempTemplateDataLanguages.addAssociation(matcher, language); + } updateExtensionList(); - final int index = myPatterns.getListModel().indexOf(matcher.getPresentableString()); + int index = myPatterns.getListModel().indexOf(matcher.getPresentableString()); if (index >= 0) { ScrollingUtil.selectItem(myPatterns.myPatternsList, index); } @@ -344,7 +345,7 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl .setRemoveAction(button -> myController.removeFileType()) .setEditAction(button -> myController.editFileType()) .setEditActionUpdater(e -> { - final FileType fileType = getSelectedFileType(); + FileType fileType = getSelectedFileType(); return canBeModified(fileType); }) .setRemoveActionUpdater(e -> canBeModified(getSelectedFileType())) @@ -460,34 +461,30 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl } } - public static class PatternsPanel extends JPanel { - private final JBList myPatternsList; + static class PatternsPanel extends JPanel { + private final JBList myPatternsList = new JBList<>(new DefaultListModel<>()); private FileTypeConfigurable myController; - public PatternsPanel() { + PatternsPanel() { super(new BorderLayout()); - myPatternsList = new JBList<>(new DefaultListModel<>()); myPatternsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); myPatternsList.setCellRenderer(new ExtensionRenderer()); myPatternsList.getEmptyText().setText(FileTypesBundle.message("filetype.settings.no.patterns")); - add(ToolbarDecorator.createDecorator(myPatternsList) - .setAddAction(button -> myController.addPattern()).setEditAction(button -> myController.editPattern()).setRemoveAction( - button -> myController.removePattern()).disableUpDownActions().createPanel(), BorderLayout.CENTER); + ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myPatternsList) + .setAddAction(__ -> myController.addPattern()) + .setEditAction(__ -> myController.editPattern()) + .setRemoveAction(__ -> myController.removePattern()) + .disableUpDownActions(); + add(decorator.createPanel(), BorderLayout.CENTER); - setBorder(IdeBorderFactory.createTitledBorder(FileTypesBundle.message("filetype.registered.patterns.group"), false, TITLE_INSETS) - .setShowLine(false)); + setBorder(IdeBorderFactory.createTitledBorder(FileTypesBundle.message("filetype.registered.patterns.group"), false, TITLE_INSETS).setShowLine(false)); } void attachActions(@NotNull FileTypeConfigurable controller) { myController = controller; } - @NotNull - public JComponent getComponent() { - return this; - } - void clearList() { getListModel().clear(); myPatternsList.clearSelection(); @@ -498,18 +495,18 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl return (DefaultListModel)myPatternsList.getModel(); } - public void addPattern(@NotNull String pattern) { + void addPattern(@NotNull String pattern) { getListModel().addElement(pattern); } - public void ensureSelectionExists() { + void ensureSelectionExists() { ScrollingUtil.ensureSelectionExists(myPatternsList); } - public void select(@NotNull String pattern) { + void select(@NotNull String pattern) { for (int i = 0; i < myPatternsList.getItemsCount(); i++) { - final String at = myPatternsList.getModel().getElementAt(i); - final FileNameMatcher matcher = FileTypeManager.parseFromString(at); + String at = myPatternsList.getModel().getElementAt(i); + FileNameMatcher matcher = FileTypeManager.parseFromString(at); if (matcher.acceptsCharSequence(pattern)) { ScrollingUtil.selectItem(myPatternsList, i); return; @@ -517,18 +514,14 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl } } - public String removeSelected() { + String removeSelected() { String selectedValue = getSelectedItem(); if (selectedValue == null) return null; ListUtil.removeSelectedItems(myPatternsList); return selectedValue; } - public String getDefaultExtension() { - return getListModel().getElementAt(0); - } - - public String getSelectedItem() { + String getSelectedItem() { return myPatternsList.getSelectedValue(); } } @@ -540,11 +533,11 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl private JTextField myIgnoreFilesField; private JPanel myIgnorePanel; - public JComponent getComponent() { + JComponent getComponent() { return myWholePanel; } - public void dispose() { + void dispose() { myRecognizedFileType.setFileTypes(FileType.EMPTY_ARRAY); myPatterns.clearList(); } @@ -560,7 +553,7 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl private final T myFileType; private final SettingsEditor myEditor; - TypeEditor(Component parent, T fileType, final String title) { + TypeEditor(Component parent, T fileType, String title) { super(parent, false); myFileType = fileType; myEditor = fileType.getEditor(); @@ -593,8 +586,8 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl } @Override - @SuppressWarnings("SpellCheckingInspection") protected String getHelpId() { + //noinspection SpellCheckingInspection return "reference.dialogs.newfiletype"; } } 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 23663574da48..a9b7f25cd485 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 @@ -14,10 +14,7 @@ import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.extensions.ExtensionPointListener; -import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.extensions.PluginDescriptor; -import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.extensions.*; import com.intellij.openapi.fileEditor.impl.LoadTextUtil; import com.intellij.openapi.fileTypes.*; import com.intellij.openapi.fileTypes.ex.ExternalizableFileType; @@ -77,7 +74,6 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -import java.util.stream.StreamSupport; @State(name = "FileTypeManager", storages = @Storage("filetypes.xml"), additionalExportFile = FileTypeManagerImpl.FILE_SPEC ) public class FileTypeManagerImpl extends FileTypeManagerEx implements PersistentStateComponent, Disposable { @@ -149,6 +145,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent private final AtomicInteger counterAutoDetect = new AtomicInteger(); private final AtomicLong elapsedAutoDetect = new AtomicLong(); + private int cachedDetectFileBufferSize = -1; private final Object PENDING_INIT_LOCK = new Object(); @@ -285,6 +282,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent } } }, this); + FileTypeDetector.EP_NAME.addExtensionPointListener(() -> cachedDetectFileBufferSize = -1, this); } private void unregisterMatchers(@NotNull StandardFileType stdFileType, @NotNull FileTypeBean extension) { @@ -457,14 +455,12 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent @NotNull private FileType mergeOrInstantiateFileTypeBean(@NotNull FileTypeBean fileTypeBean) { - final StandardFileType type = myStandardFileTypes.get(fileTypeBean.name); - if (type != null) { - type.matchers.addAll(fileTypeBean.getMatchers()); - return type.fileType; - } - else { + StandardFileType type = myStandardFileTypes.get(fileTypeBean.name); + if (type == null) { return instantiateFileTypeBean(fileTypeBean); } + type.matchers.addAll(fileTypeBean.getMatchers()); + return type.fileType; } private FileType instantiateFileTypeBean(@NotNull FileTypeBean fileTypeBean) { @@ -699,7 +695,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent @NotNull public FileType getFileTypeByFileName(@NotNull CharSequence fileName) { synchronized (PENDING_INIT_LOCK) { - final FileTypeBean pendingFileType = myPendingAssociations.findAssociatedFileType(fileName); + FileTypeBean pendingFileType = myPendingAssociations.findAssociatedFileType(fileName); if (pendingFileType != null) { return ObjectUtils.notNull(instantiateFileTypeBean(pendingFileType), UnknownFileType.INSTANCE); } @@ -746,22 +742,14 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent } FileType fileType = getByFile(file); - if (!(file instanceof StubVirtualFile)) { - if (fileType == null) { - return getOrDetectFromContent(file, content); - } - if (mightBeReplacedByDetectedFileType(fileType) && isDetectable(file)) { - FileType detectedFromContent = getOrDetectFromContent(file, content); - // unknown file type means that it was detected as binary, it's better to keep it binary - if (detectedFromContent != PlainTextFileType.INSTANCE) { - return detectedFromContent; - } - } + if (!(file instanceof StubVirtualFile) + && (fileType == null || mightBeReplacedByDetectedFileType(fileType) && isDetectable(file))) { + return getOrDetectFromContent(file, content); } return ObjectUtils.notNull(fileType, UnknownFileType.INSTANCE); } - private static boolean mightBeReplacedByDetectedFileType(FileType fileType) { + private static boolean mightBeReplacedByDetectedFileType(@NotNull FileType fileType) { return fileType instanceof PlainTextLikeFileType && fileType.isReadOnly(); } @@ -992,7 +980,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent @NotNull private FileType detectFromContentAndCache(@NotNull final VirtualFile file, byte @Nullable [] content) throws IOException { long start = System.currentTimeMillis(); - FileType fileType = detectFromContent(file, content, FileTypeDetector.EP_NAME.getExtensionList()); + FileType fileType = detectFromContent(file, content); cacheAutoDetectedFileType(file, fileType); counterAutoDetect.incrementAndGet(); @@ -1003,7 +991,8 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent } @NotNull - private FileType detectFromContent(@NotNull VirtualFile file, byte @Nullable [] content, @NotNull Iterable detectors) throws IOException { + private FileType detectFromContent(@NotNull VirtualFile file, byte @Nullable [] content) throws IOException { + List detectors = FileTypeDetector.EP_NAME.getExtensionList(); FileType fileType; if (content != null) { fileType = detect(file, content, content.length, detectors); @@ -1015,11 +1004,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent } int fileLength = (int)file.getLength(); - - int bufferLength = StreamSupport.stream(detectors.spliterator(), false) - .mapToInt(FileTypeDetector::getDesiredContentPrefixLength) - .max() - .orElse(FileUtilRt.getUserContentLoadLimit()); + int bufferLength = getDetectFileBufferSize(); byte[] buffer = fileLength <= FileUtilRt.THREAD_LOCAL_BUFFER_LENGTH ? FileUtilRt.getThreadLocalBuffer() : new byte[Math.min(fileLength, bufferLength)]; @@ -1047,8 +1032,25 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent return fileType; } + private int getDetectFileBufferSize() { + int bufferLength = cachedDetectFileBufferSize; + if (bufferLength == -1) { + List detectors = FileTypeDetector.EP_NAME.getExtensionList(); + //noinspection ForLoopReplaceableByForEach + for (int i = 0; i < detectors.size(); i++) { + FileTypeDetector detector = detectors.get(i); + bufferLength = Math.max(bufferLength, detector.getDesiredContentPrefixLength()); + } + if (bufferLength <= 0) { + bufferLength = FileUtilRt.getUserContentLoadLimit(); + } + cachedDetectFileBufferSize = bufferLength; + } + return bufferLength; + } + @NotNull - private FileType detect(@NotNull VirtualFile file, byte @NotNull [] bytes, int length, @NotNull Iterable detectors) { + private FileType detect(@NotNull VirtualFile file, byte @NotNull [] bytes, int length, @NotNull List detectors) { if (length <= 0) return UnknownFileType.INSTANCE; // use PlainTextFileType because it doesn't supply its own charset detector @@ -1094,7 +1096,6 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent // for diagnostics @NonNls - @SuppressWarnings("ConstantConditions") private static Object streamInfo(@NotNull InputStream stream) throws IOException { if (stream instanceof BufferedInputStream) { InputStream in = ReflectionUtil.getField(stream.getClass(), stream, InputStream.class, "in"); @@ -1234,7 +1235,6 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent synchronized (PENDING_INIT_LOCK) { instantiatePendingFileTypeByName(type.getName()); - //noinspection deprecation return myPatternsTable.getAssociatedExtensions(type); } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java index 31d7623fa0be..3908c5c65912 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java @@ -55,7 +55,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; -@SuppressWarnings("ConstantConditions") public class FileTypesTest extends HeavyPlatformTestCase { private FileTypeManagerImpl myFileTypeManager; private String myOldIgnoredFilesList; @@ -841,7 +840,7 @@ public class FileTypesTest extends HeavyPlatformTestCase { assertEquals(1, detectorCalls.get()); } - public void testUniqueLanguage() { + public void testEveryLanguageHasOnePrimaryFileType() { Map map = new HashMap<>(); for (FileType type : FileTypeManager.getInstance().getRegisteredFileTypes()) { if (!(type instanceof LanguageFileType)) continue; @@ -885,7 +884,7 @@ public class FileTypesTest extends HeavyPlatformTestCase { FileType replaceableFileType = createFileTypeReplaceableByContentDetection(); ApplicationManager.getApplication().runWriteAction(() -> myFileTypeManager.associatePattern(replaceableFileType, "*." + extension)); - VirtualFile file = createTempFile(extension, null, "", CharsetToolkit.UTF8_CHARSET); + VirtualFile file = createTempFile("x."+extension, null, "", CharsetToolkit.UTF8_CHARSET); assertEquals(replaceableFileType, file.getFileType()); } @@ -953,7 +952,7 @@ public class FileTypesTest extends HeavyPlatformTestCase { @NotNull @Override public String getName() { - return "PlainTextLike files"; + return "PlainTextLike Replaceable"; } @NotNull