mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-175757 Support File Type mapping based on shebang
Add ability to detect file type based on hasbang (#! string) inside the file contents (via FileAssocTable.findAssociatedFileTypeByHashBang()). Store/persist hashbang patterns in FileTypeManagerImpl. Enable users to configure hashbang associations via Settings|File types UI. Allow plugins to configure hashbangs via <fileType hashBangs=""/> in plugin.xml Replace some no more needed HashBangFileTypeDetectors for standard langs with xml configs GitOrigin-RevId: 14335912b90f2d4f665d2a71eddeebf5cfc91f30
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3127717d23
commit
ae21cc79ff
@@ -1259,7 +1259,7 @@
|
||||
<completion.plainTextSymbol language="JAVA" implementationClass="com.intellij.codeInsight.completion.JvmPlainTextSymbolCompletionContributor"/>
|
||||
<lookup.actionProvider implementation="com.intellij.codeInsight.completion.ExcludeFromCompletionLookupActionProvider" id="excludeFromCompletion" order="last"/>
|
||||
<lookup.actionProvider implementation="com.intellij.codeInsight.completion.ImportStaticLookupActionProvider" id="importStatic"/>
|
||||
<fileType extensions="java" name="JAVA" language="JAVA" fieldName="INSTANCE" implementationClass="com.intellij.ide.highlighter.JavaFileType"/>
|
||||
<fileType extensions="java" hashBangs="java" name="JAVA" language="JAVA" fieldName="INSTANCE" implementationClass="com.intellij.ide.highlighter.JavaFileType"/>
|
||||
<fileType extensions="class" name="CLASS" fieldName="INSTANCE" implementationClass="com.intellij.ide.highlighter.JavaClassFileType"/>
|
||||
<fileType extensions="snippet" name="JSHELL" language="JShellLanguage" fieldName="INSTANCE" implementationClass="com.intellij.ide.highlighter.JShellFileType"/>
|
||||
<customPropertyScopeProvider implementation="com.intellij.psi.impl.search.SimpleAccessorScopeProvider"/>
|
||||
@@ -1990,7 +1990,6 @@
|
||||
</intentionAction>
|
||||
<externalAnnotationsArtifactsResolver implementation="com.intellij.jarRepository.ExternalAnnotationsRepositoryResolver"/>
|
||||
<errorQuickFixProvider implementation="com.intellij.codeInsight.daemon.impl.analysis.JavaErrorQuickFixProvider"/>
|
||||
<fileTypeDetector implementation="com.intellij.openapi.fileTypes.impl.JavaFileTypeDetector"/>
|
||||
|
||||
<searchEverywhereResultsEqualityProvider implementation="com.intellij.ide.JavaClassAndFileEqualityProvider"/>
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.fileTypes.impl;
|
||||
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
|
||||
public class JavaFileTypeDetector extends HashBangFileTypeDetector {
|
||||
public JavaFileTypeDetector() {
|
||||
super(JavaFileType.INSTANCE, "java");
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.intellij.openapi.fileTypes.ExactFileNameMatcher;
|
||||
import com.intellij.openapi.fileTypes.ExtensionFileNameMatcher;
|
||||
import com.intellij.openapi.fileTypes.FileNameMatcher;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.util.ArrayUtilRt;
|
||||
import com.intellij.util.text.CharSequenceHashingStrategy;
|
||||
@@ -14,16 +15,19 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class FileTypeAssocTable<T> {
|
||||
private final Map<CharSequence, T> myExtensionMappings;
|
||||
private final Map<CharSequence, T> myExactFileNameMappings;
|
||||
private final Map<CharSequence, T> myExactFileNameAnyCaseMappings;
|
||||
private final List<Pair<FileNameMatcher, T>> myMatchingMappings;
|
||||
private final Map<String, T> myHashBangMap;
|
||||
|
||||
private FileTypeAssocTable(@NotNull Map<? extends CharSequence, ? extends T> extensionMappings,
|
||||
@NotNull Map<? extends CharSequence, ? extends T> exactFileNameMappings,
|
||||
@NotNull Map<? extends CharSequence, T> exactFileNameAnyCaseMappings,
|
||||
@NotNull Map<? extends CharSequence, ? extends T> exactFileNameAnyCaseMappings,
|
||||
@NotNull Map<String, ? extends T> hashBangMap,
|
||||
@NotNull List<? extends Pair<FileNameMatcher, T>> matchingMappings) {
|
||||
myExtensionMappings = new THashMap<>(Math.max(10, extensionMappings.size()), 0.5f, CharSequenceHashingStrategy.CASE_INSENSITIVE);
|
||||
myExtensionMappings.putAll(extensionMappings);
|
||||
@@ -31,11 +35,13 @@ public class FileTypeAssocTable<T> {
|
||||
myExactFileNameMappings.putAll(exactFileNameMappings);
|
||||
myExactFileNameAnyCaseMappings = new THashMap<>(Math.max(10, exactFileNameAnyCaseMappings.size()), 0.5f, CharSequenceHashingStrategy.CASE_INSENSITIVE);
|
||||
myExactFileNameAnyCaseMappings.putAll(exactFileNameAnyCaseMappings);
|
||||
myHashBangMap = new THashMap<>(Math.max(10, hashBangMap.size()), 0.5f);
|
||||
myHashBangMap.putAll(hashBangMap);
|
||||
myMatchingMappings = new ArrayList<>(matchingMappings);
|
||||
}
|
||||
|
||||
public FileTypeAssocTable() {
|
||||
this(Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyList());
|
||||
this(Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyList());
|
||||
}
|
||||
|
||||
boolean isAssociatedWith(@NotNull T type, @NotNull FileNameMatcher matcher) {
|
||||
@@ -65,14 +71,21 @@ public class FileTypeAssocTable<T> {
|
||||
}
|
||||
}
|
||||
|
||||
boolean removeAssociation(@NotNull FileNameMatcher matcher, @NotNull T type) {
|
||||
void addHashBangPattern(@NotNull String hashBang, @NotNull T type) {
|
||||
myHashBangMap.put(hashBang, type);
|
||||
}
|
||||
void removeHashBangPattern(@NotNull String hashBang, @NotNull T type) {
|
||||
myHashBangMap.remove(hashBang, type);
|
||||
}
|
||||
|
||||
void removeAssociation(@NotNull FileNameMatcher matcher, @NotNull T type) {
|
||||
if (matcher instanceof ExtensionFileNameMatcher) {
|
||||
String extension = ((ExtensionFileNameMatcher)matcher).getExtension();
|
||||
if (myExtensionMappings.get(extension) == type) {
|
||||
myExtensionMappings.remove(extension);
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (matcher instanceof ExactFileNameMatcher) {
|
||||
@@ -80,27 +93,26 @@ public class FileTypeAssocTable<T> {
|
||||
String fileName = exactFileNameMatcher.getFileName();
|
||||
|
||||
final Map<CharSequence, T> mapToUse = exactFileNameMatcher.isIgnoreCase() ? myExactFileNameAnyCaseMappings : myExactFileNameMappings;
|
||||
if(mapToUse.get(fileName) == type) {
|
||||
if (mapToUse.get(fileName) == type) {
|
||||
mapToUse.remove(fileName);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
return myMatchingMappings.removeIf(assoc -> matcher.equals(assoc.getFirst()));
|
||||
myMatchingMappings.removeIf(assoc -> matcher.equals(assoc.getFirst()));
|
||||
}
|
||||
|
||||
boolean removeAllAssociations(@NotNull T type) {
|
||||
boolean changed = removeAssociationsFromMap(myExtensionMappings, type, false);
|
||||
void removeAllAssociations(@NotNull T type) {
|
||||
removeAssociationsFromMap(myExtensionMappings, type);
|
||||
|
||||
changed = removeAssociationsFromMap(myExactFileNameAnyCaseMappings, type, changed);
|
||||
changed = removeAssociationsFromMap(myExactFileNameMappings, type, changed);
|
||||
removeAssociationsFromMap(myExactFileNameAnyCaseMappings, type);
|
||||
removeAssociationsFromMap(myExactFileNameMappings, type);
|
||||
|
||||
return myMatchingMappings.removeIf(assoc -> assoc.getSecond() == type);
|
||||
myMatchingMappings.removeIf(assoc -> assoc.getSecond() == type);
|
||||
myHashBangMap.entrySet().removeIf(e -> e.getValue().equals(type));
|
||||
}
|
||||
|
||||
private boolean removeAssociationsFromMap(@NotNull Map<CharSequence, T> extensionMappings, @NotNull T type, boolean changed) {
|
||||
return extensionMappings.entrySet().removeIf(entry -> entry.getValue() == type) || changed;
|
||||
private void removeAssociationsFromMap(@NotNull Map<CharSequence, T> extensionMappings, @NotNull T type) {
|
||||
extensionMappings.entrySet().removeIf(entry -> entry.getValue() == type);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -117,13 +129,22 @@ public class FileTypeAssocTable<T> {
|
||||
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0; i < myMatchingMappings.size(); i++) {
|
||||
final Pair<FileNameMatcher, T> mapping = myMatchingMappings.get(i);
|
||||
Pair<FileNameMatcher, T> mapping = myMatchingMappings.get(i);
|
||||
if (mapping.getFirst().acceptsCharSequence(fileName)) return mapping.getSecond();
|
||||
}
|
||||
|
||||
return findByExtension(FileUtilRt.getExtension(fileName));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
T findAssociatedFileTypeByHashBang(@NotNull CharSequence content) {
|
||||
for (Map.Entry<String, T> entry : myHashBangMap.entrySet()) {
|
||||
String hashBang = entry.getKey();
|
||||
if (FileUtil.isHashBangLine(content, hashBang)) return entry.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
T findAssociatedFileType(@NotNull FileNameMatcher matcher) {
|
||||
if (matcher instanceof ExtensionFileNameMatcher) {
|
||||
@@ -148,20 +169,19 @@ public class FileTypeAssocTable<T> {
|
||||
return myExtensionMappings.get(extension);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
String @NotNull [] getAssociatedExtensions(@NotNull T type) {
|
||||
List<String> exts = new ArrayList<>();
|
||||
List<String> extensions = new ArrayList<>();
|
||||
for (Map.Entry<CharSequence, T> entry : myExtensionMappings.entrySet()) {
|
||||
if (entry.getValue() == type) {
|
||||
exts.add(entry.getKey().toString());
|
||||
extensions.add(entry.getKey().toString());
|
||||
}
|
||||
}
|
||||
return ArrayUtilRt.toStringArray(exts);
|
||||
return ArrayUtilRt.toStringArray(extensions);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FileTypeAssocTable<T> copy() {
|
||||
return new FileTypeAssocTable<>(myExtensionMappings, myExactFileNameMappings, myExactFileNameAnyCaseMappings, myMatchingMappings);
|
||||
return new FileTypeAssocTable<>(myExtensionMappings, myExactFileNameMappings, myExactFileNameAnyCaseMappings, myHashBangMap, myMatchingMappings);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -192,9 +212,18 @@ public class FileTypeAssocTable<T> {
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getHashBangPatterns(@NotNull T type) {
|
||||
return myHashBangMap.entrySet().stream()
|
||||
.filter(e -> e.getValue().equals(type))
|
||||
.map(e->e.getKey())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
boolean hasAssociationsFor(@NotNull T fileType) {
|
||||
if (myExtensionMappings.containsValue(fileType) ||
|
||||
myExactFileNameMappings.containsValue(fileType) ||
|
||||
myHashBangMap.containsValue(fileType) ||
|
||||
myExactFileNameAnyCaseMappings.containsValue(fileType)) {
|
||||
return true;
|
||||
}
|
||||
@@ -228,10 +257,11 @@ public class FileTypeAssocTable<T> {
|
||||
return false;
|
||||
}
|
||||
|
||||
FileTypeAssocTable<?> that = (FileTypeAssocTable)o;
|
||||
FileTypeAssocTable<?> that = (FileTypeAssocTable<?>)o;
|
||||
return myExtensionMappings.equals(that.myExtensionMappings) &&
|
||||
myMatchingMappings.equals(that.myMatchingMappings) &&
|
||||
myExactFileNameMappings.equals(that.myExactFileNameMappings) &&
|
||||
myHashBangMap.equals(that.myHashBangMap) &&
|
||||
myExactFileNameAnyCaseMappings.equals(that.myExactFileNameAnyCaseMappings);
|
||||
}
|
||||
|
||||
@@ -239,8 +269,14 @@ public class FileTypeAssocTable<T> {
|
||||
public int hashCode() {
|
||||
int result = myExtensionMappings.hashCode();
|
||||
result = 31 * result + myMatchingMappings.hashCode();
|
||||
result = 31 * result + myHashBangMap.hashCode();
|
||||
result = 31 * result + myExactFileNameMappings.hashCode();
|
||||
result = 31 * result + myExactFileNameAnyCaseMappings.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Map<String, T> getAllHashBangPatterns() {
|
||||
return Collections.unmodifiableMap(new THashMap<>(myHashBangMap));
|
||||
}
|
||||
}
|
||||
|
||||
+242
-158
@@ -8,14 +8,10 @@ import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.fileTypes.*;
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.options.SearchableConfigurable;
|
||||
import com.intellij.openapi.options.SettingsEditor;
|
||||
import com.intellij.openapi.ui.DialogBuilder;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
@@ -44,6 +40,7 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
|
||||
private RecognizedFileTypes myRecognizedFileType;
|
||||
private PatternsPanel myPatterns;
|
||||
private HashBangPanel myHashBangs;
|
||||
private FileTypePanel myFileTypePanel;
|
||||
private Set<FileType> myTempFileTypes;
|
||||
private final FileTypeManagerImpl myManager;
|
||||
@@ -62,14 +59,15 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
|
||||
@Override
|
||||
public JComponent createComponent() {
|
||||
myFileTypePanel = new FileTypePanel().init();
|
||||
myRecognizedFileType = myFileTypePanel.myRecognizedFileType;
|
||||
myPatterns = myFileTypePanel.myPatterns;
|
||||
myRecognizedFileType.attachActions(this);
|
||||
myRecognizedFileType.myFileTypesList.addListSelectionListener(e -> updateExtensionList());
|
||||
myPatterns.attachActions(this);
|
||||
myFileTypePanel = new FileTypePanel();
|
||||
myFileTypePanel.myIgnorePanel.setBorder(
|
||||
IdeBorderFactory.createTitledBorder(IdeBundle.message("editbox.ignore.files.and.folders"), false, TITLE_INSETS).setShowLine(false));
|
||||
myRecognizedFileType = new RecognizedFileTypes(myFileTypePanel.myRecognizedFileTypesPanel);
|
||||
myPatterns = new PatternsPanel(myFileTypePanel.myPatternsPanel);
|
||||
myHashBangs = new HashBangPanel(myFileTypePanel.myHashBangPanel);
|
||||
myRecognizedFileType.myFileTypesList.addListSelectionListener(__ -> updateExtensionList());
|
||||
myFileTypePanel.myIgnoreFilesField.setColumns(30);
|
||||
return myFileTypePanel.getComponent();
|
||||
return myFileTypePanel.myWholePanel;
|
||||
}
|
||||
|
||||
private void updateFileTypeList() {
|
||||
@@ -125,10 +123,15 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
|
||||
@Override
|
||||
public void disposeUIResources() {
|
||||
if (myFileTypePanel != null) myFileTypePanel.dispose();
|
||||
if (myFileTypePanel != null) {
|
||||
myRecognizedFileType.setFileTypes(FileType.EMPTY_ARRAY);
|
||||
myPatterns.clearList();
|
||||
myHashBangs.clearList();
|
||||
}
|
||||
myFileTypePanel = null;
|
||||
myRecognizedFileType = null;
|
||||
myPatterns = null;
|
||||
myHashBangs = null;
|
||||
}
|
||||
|
||||
private static class ExtensionRenderer extends DefaultListCellRenderer {
|
||||
@@ -155,12 +158,8 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
extensions.add(assoc.getPresentableString());
|
||||
}
|
||||
|
||||
myPatterns.clearList();
|
||||
Collections.sort(extensions);
|
||||
for (String extension : extensions) {
|
||||
myPatterns.addPattern(extension);
|
||||
}
|
||||
myPatterns.ensureSelectionExists();
|
||||
myPatterns.refill(extensions);
|
||||
myHashBangs.refill(myTempPatternsTable.getHashBangPatterns(type));
|
||||
}
|
||||
|
||||
private void editFileType() {
|
||||
@@ -224,7 +223,7 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
|
||||
Language oldLanguage = item == null ? null : myTempTemplateDataLanguages.findAssociatedFileType(item);
|
||||
FileTypePatternDialog dialog = new FileTypePatternDialog(item, type, oldLanguage);
|
||||
DialogBuilder builder = new DialogBuilder(myPatterns);
|
||||
DialogBuilder builder = new DialogBuilder(myPatterns.myList);
|
||||
builder.setPreferredFocusComponent(dialog.getPatternField());
|
||||
builder.setCenterPanel(dialog.getMainPanel());
|
||||
builder.setTitle(title);
|
||||
@@ -237,16 +236,16 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
FileType registeredFileType = findExistingFileType(matcher);
|
||||
if (registeredFileType != null && registeredFileType != type) {
|
||||
if (registeredFileType.isReadOnly()) {
|
||||
Messages.showMessageDialog(myPatterns.myPatternsList,
|
||||
Messages.showMessageDialog(myPatterns.myList,
|
||||
FileTypesBundle.message("filetype.edit.add.pattern.exists.error", registeredFileType.getDescription()),
|
||||
title, Messages.getErrorIcon());
|
||||
return;
|
||||
}
|
||||
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());
|
||||
int ret = Messages.showOkCancelDialog(myPatterns.myList, 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());
|
||||
if (ret == Messages.OK) {
|
||||
myTempPatternsTable.removeAssociation(matcher, registeredFileType);
|
||||
if (oldLanguage != null) {
|
||||
@@ -272,11 +271,8 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
}
|
||||
|
||||
updateExtensionList();
|
||||
int index = myPatterns.getListModel().indexOf(matcher.getPresentableString());
|
||||
if (index >= 0) {
|
||||
ScrollingUtil.selectItem(myPatterns.myPatternsList, index);
|
||||
}
|
||||
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myPatterns.myPatternsList, true));
|
||||
myPatterns.select(pattern);
|
||||
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myPatterns.myList, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,10 +282,10 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
|
||||
@Nullable
|
||||
private FileType findExistingFileType(@NotNull FileNameMatcher matcher) {
|
||||
FileType fileTypeByExtension = myTempPatternsTable.findAssociatedFileType(matcher);
|
||||
FileType type = myTempPatternsTable.findAssociatedFileType(matcher);
|
||||
|
||||
if (fileTypeByExtension != null && fileTypeByExtension != FileTypes.UNKNOWN) {
|
||||
return fileTypeByExtension;
|
||||
if (type != null && type != FileTypes.UNKNOWN) {
|
||||
return type;
|
||||
}
|
||||
FileType registeredFileType = FileTypeManager.getInstance().getFileTypeByExtension(matcher.getPresentableString());
|
||||
if (registeredFileType != FileTypes.UNKNOWN && registeredFileType.isReadOnly()) {
|
||||
@@ -306,7 +302,16 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
FileNameMatcher matcher = FileTypeManager.parseFromString(extension);
|
||||
|
||||
myTempPatternsTable.removeAssociation(matcher, type);
|
||||
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myPatterns.myPatternsList, true));
|
||||
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myPatterns.myList, true));
|
||||
}
|
||||
private void removeHashBang() {
|
||||
FileType type = myRecognizedFileType.getSelectedFileType();
|
||||
if (type == null) return;
|
||||
String extension = myHashBangs.removeSelected();
|
||||
if (extension == null) return;
|
||||
|
||||
myTempPatternsTable.removeHashBangPattern(extension, type);
|
||||
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myHashBangs.myList, true));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -315,13 +320,10 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
return "preferences.fileTypes";
|
||||
}
|
||||
|
||||
public static class RecognizedFileTypes extends JPanel {
|
||||
class RecognizedFileTypes {
|
||||
private final JList<FileType> myFileTypesList = new JBList<>(new DefaultListModel<>());
|
||||
private final MySpeedSearch mySpeedSearch;
|
||||
private FileTypeConfigurable myController;
|
||||
|
||||
public RecognizedFileTypes() {
|
||||
super(new BorderLayout());
|
||||
RecognizedFileTypes(@NotNull JPanel panel) {
|
||||
panel.setLayout(new BorderLayout());
|
||||
|
||||
myFileTypesList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
myFileTypesList.setCellRenderer(new FileTypeRenderer(() -> {
|
||||
@@ -335,15 +337,15 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
new DoubleClickListener() {
|
||||
@Override
|
||||
protected boolean onDoubleClick(@NotNull MouseEvent e) {
|
||||
myController.editFileType();
|
||||
editFileType();
|
||||
return true;
|
||||
}
|
||||
}.installOn(myFileTypesList);
|
||||
|
||||
ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myFileTypesList)
|
||||
.setAddAction(button -> myController.addFileType())
|
||||
.setRemoveAction(button -> myController.removeFileType())
|
||||
.setEditAction(button -> myController.editFileType())
|
||||
.setAddAction(__ -> addFileType())
|
||||
.setRemoveAction(__ -> removeFileType())
|
||||
.setEditAction(__ -> editFileType())
|
||||
.setEditActionUpdater(e -> {
|
||||
FileType fileType = getSelectedFileType();
|
||||
return canBeModified(fileType);
|
||||
@@ -351,15 +353,14 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
.setRemoveActionUpdater(e -> canBeModified(getSelectedFileType()))
|
||||
.disableUpDownActions();
|
||||
|
||||
add(toolbarDecorator.createPanel(), BorderLayout.CENTER);
|
||||
setBorder(IdeBorderFactory.createTitledBorder(FileTypesBundle.message("filetype.recognized.group"), false, TITLE_INSETS).setShowLine(false));
|
||||
panel.add(toolbarDecorator.createPanel(), BorderLayout.CENTER);
|
||||
panel.setBorder(IdeBorderFactory.createTitledBorder(FileTypesBundle.message("filetype.recognized.group"), false, TITLE_INSETS).setShowLine(false));
|
||||
|
||||
mySpeedSearch = new MySpeedSearch(myFileTypesList);
|
||||
new MySpeedSearch(myFileTypesList);
|
||||
}
|
||||
|
||||
private static class MySpeedSearch extends SpeedSearchBase<JList<FileType>> {
|
||||
private class MySpeedSearch extends SpeedSearchBase<JList<FileType>> {
|
||||
private final List<Condition<Pair<Object, String>>> myOrderedConverters;
|
||||
private FileTypeConfigurable myController;
|
||||
private Object myCurrentType;
|
||||
private String myExtension;
|
||||
|
||||
@@ -408,43 +409,34 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
protected void selectElement(Object element, String selectedText) {
|
||||
if (element != null) {
|
||||
ScrollingUtil.selectItem(myComponent, (FileType)element);
|
||||
if (myCurrentType != null && myCurrentType.equals(element) && myController != null) {
|
||||
myController.myPatterns.select(myExtension);
|
||||
if (element.equals(myCurrentType)) {
|
||||
myPatterns.select(myExtension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSearchFieldUpdated(String s) {
|
||||
if (myController == null || myController.myTempPatternsTable == null) return;
|
||||
if (myTempPatternsTable == null) return;
|
||||
int index = s.lastIndexOf('.');
|
||||
if (index < 0) {
|
||||
s = "." + s;
|
||||
}
|
||||
myCurrentType = myController.myTempPatternsTable.findAssociatedFileType(s);
|
||||
myCurrentType = myTempPatternsTable.findAssociatedFileType(s);
|
||||
if (myCurrentType != null) {
|
||||
myExtension = s;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
myExtension = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void attachActions(@NotNull FileTypeConfigurable controller) {
|
||||
myController = controller;
|
||||
mySpeedSearch.myController = controller;
|
||||
}
|
||||
|
||||
FileType getSelectedFileType() {
|
||||
return myFileTypesList.getSelectedValue();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JComponent getComponent() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setFileTypes(FileType @NotNull [] types) {
|
||||
void setFileTypes(FileType @NotNull [] types) {
|
||||
DefaultListModel<FileType> listModel = (DefaultListModel<FileType>)myFileTypesList.getModel();
|
||||
listModel.clear();
|
||||
for (FileType type : types) {
|
||||
@@ -455,60 +447,47 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
ScrollingUtil.ensureSelectionExists(myFileTypesList);
|
||||
}
|
||||
|
||||
void selectFileType(FileType fileType) {
|
||||
void selectFileType(@NotNull FileType fileType) {
|
||||
myFileTypesList.setSelectedValue(fileType, true);
|
||||
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myFileTypesList, true));
|
||||
}
|
||||
}
|
||||
|
||||
static class PatternsPanel extends JPanel {
|
||||
private final JBList<String> myPatternsList = new JBList<>(new DefaultListModel<>());
|
||||
private FileTypeConfigurable myController;
|
||||
class PatternsPanel {
|
||||
private final JBList<String> myList = new JBList<>(new DefaultListModel<>());
|
||||
|
||||
PatternsPanel() {
|
||||
super(new BorderLayout());
|
||||
myPatternsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
myPatternsList.setCellRenderer(new ExtensionRenderer());
|
||||
myPatternsList.getEmptyText().setText(FileTypesBundle.message("filetype.settings.no.patterns"));
|
||||
PatternsPanel(@NotNull JPanel panel) {
|
||||
panel.setLayout(new BorderLayout());
|
||||
myList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
myList.setCellRenderer(new ExtensionRenderer());
|
||||
myList.getEmptyText().setText(FileTypesBundle.message("filetype.settings.no.patterns"));
|
||||
|
||||
ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myPatternsList)
|
||||
.setAddAction(__ -> myController.addPattern())
|
||||
.setEditAction(__ -> myController.editPattern())
|
||||
.setRemoveAction(__ -> myController.removePattern())
|
||||
ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myList)
|
||||
.setAddAction(__ -> addPattern())
|
||||
.setEditAction(__ -> editPattern())
|
||||
.setRemoveAction(__ -> removePattern())
|
||||
.disableUpDownActions();
|
||||
add(decorator.createPanel(), BorderLayout.CENTER);
|
||||
panel.add(decorator.createPanel(), BorderLayout.CENTER);
|
||||
|
||||
setBorder(IdeBorderFactory.createTitledBorder(FileTypesBundle.message("filetype.registered.patterns.group"), false, TITLE_INSETS).setShowLine(false));
|
||||
}
|
||||
|
||||
void attachActions(@NotNull FileTypeConfigurable controller) {
|
||||
myController = controller;
|
||||
panel.setBorder(IdeBorderFactory.createTitledBorder(FileTypesBundle.message("filetype.registered.patterns.group"), false, TITLE_INSETS).setShowLine(false));
|
||||
}
|
||||
|
||||
void clearList() {
|
||||
getListModel().clear();
|
||||
myPatternsList.clearSelection();
|
||||
myList.clearSelection();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private DefaultListModel<String> getListModel() {
|
||||
return (DefaultListModel<String>)myPatternsList.getModel();
|
||||
}
|
||||
|
||||
void addPattern(@NotNull String pattern) {
|
||||
getListModel().addElement(pattern);
|
||||
}
|
||||
|
||||
void ensureSelectionExists() {
|
||||
ScrollingUtil.ensureSelectionExists(myPatternsList);
|
||||
return (DefaultListModel<String>)myList.getModel();
|
||||
}
|
||||
|
||||
void select(@NotNull String pattern) {
|
||||
for (int i = 0; i < myPatternsList.getItemsCount(); i++) {
|
||||
String at = myPatternsList.getModel().getElementAt(i);
|
||||
for (int i = 0; i < myList.getItemsCount(); i++) {
|
||||
String at = myList.getModel().getElementAt(i);
|
||||
FileNameMatcher matcher = FileTypeManager.parseFromString(at);
|
||||
if (matcher.acceptsCharSequence(pattern)) {
|
||||
ScrollingUtil.selectItem(myPatternsList, i);
|
||||
ScrollingUtil.selectItem(myList, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -517,79 +496,184 @@ public class FileTypeConfigurable implements SearchableConfigurable, Configurabl
|
||||
String removeSelected() {
|
||||
String selectedValue = getSelectedItem();
|
||||
if (selectedValue == null) return null;
|
||||
ListUtil.removeSelectedItems(myPatternsList);
|
||||
ListUtil.removeSelectedItems(myList);
|
||||
return selectedValue;
|
||||
}
|
||||
|
||||
String getSelectedItem() {
|
||||
return myPatternsList.getSelectedValue();
|
||||
}
|
||||
}
|
||||
|
||||
private static class FileTypePanel {
|
||||
private JPanel myWholePanel;
|
||||
private RecognizedFileTypes myRecognizedFileType;
|
||||
private PatternsPanel myPatterns;
|
||||
private JTextField myIgnoreFilesField;
|
||||
private JPanel myIgnorePanel;
|
||||
|
||||
JComponent getComponent() {
|
||||
return myWholePanel;
|
||||
return myList.getSelectedValue();
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
myRecognizedFileType.setFileTypes(FileType.EMPTY_ARRAY);
|
||||
myPatterns.clearList();
|
||||
}
|
||||
|
||||
private FileTypePanel init() {
|
||||
myIgnorePanel.setBorder(
|
||||
IdeBorderFactory.createTitledBorder(IdeBundle.message("editbox.ignore.files.and.folders"), false, TITLE_INSETS).setShowLine(false));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private static class TypeEditor<T extends UserFileType<T>> extends DialogWrapper {
|
||||
private final T myFileType;
|
||||
private final SettingsEditor<T> myEditor;
|
||||
|
||||
TypeEditor(Component parent, T fileType, String title) {
|
||||
super(parent, false);
|
||||
myFileType = fileType;
|
||||
myEditor = fileType.getEditor();
|
||||
setTitle(title);
|
||||
init();
|
||||
Disposer.register(myDisposable, myEditor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
myEditor.resetFrom(myFileType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
return myEditor.getComponent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
try {
|
||||
myEditor.applyTo(myFileType);
|
||||
private void refill(@NotNull List<String> extensions) {
|
||||
clearList();
|
||||
Collections.sort(extensions);
|
||||
for (String extension : extensions) {
|
||||
getListModel().addElement(extension);
|
||||
}
|
||||
catch (ConfigurationException e) {
|
||||
Messages.showErrorDialog(getContentPane(), e.getMessage(), e.getTitle());
|
||||
ScrollingUtil.ensureSelectionExists(myList);
|
||||
}
|
||||
}
|
||||
|
||||
class HashBangPanel {
|
||||
private final JBList<String> myList = new JBList<>(new DefaultListModel<>());
|
||||
|
||||
HashBangPanel(@NotNull JPanel panel) {
|
||||
panel.setLayout(new BorderLayout());
|
||||
myList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
myList.setCellRenderer(new ExtensionRenderer(){
|
||||
@Override
|
||||
public @NotNull Component getListCellRendererComponent(@NotNull JList list,
|
||||
Object value,
|
||||
int index,
|
||||
boolean isSelected,
|
||||
boolean cellHasFocus) {
|
||||
Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
setText(" #!*"+value+"*");
|
||||
return component;
|
||||
}
|
||||
});
|
||||
myList.getEmptyText().setText(FileTypesBundle.message("filetype.settings.no.patterns"));
|
||||
|
||||
ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myList)
|
||||
.setAddAction(__ -> editHashBang(null))
|
||||
.setAddActionName("Add HashBang Pattern")
|
||||
.setEditAction(__ -> editHashBang())
|
||||
.setRemoveAction(__ -> removeHashBang())
|
||||
.disableUpDownActions();
|
||||
|
||||
panel.add(decorator.createPanel(), BorderLayout.CENTER);
|
||||
|
||||
panel.setBorder(IdeBorderFactory.createTitledBorder(FileTypesBundle.message("filetype.hashbang.group"), false, TITLE_INSETS).setShowLine(false));
|
||||
}
|
||||
|
||||
void clearList() {
|
||||
getListModel().clear();
|
||||
myList.clearSelection();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private DefaultListModel<String> getListModel() {
|
||||
return (DefaultListModel<String>)myList.getModel();
|
||||
}
|
||||
|
||||
void select(@NotNull String pattern) {
|
||||
ScrollingUtil.selectItem(myList, pattern);
|
||||
}
|
||||
|
||||
String removeSelected() {
|
||||
String selectedValue = getSelectedItem();
|
||||
if (selectedValue == null) return null;
|
||||
ListUtil.removeSelectedItems(myList);
|
||||
return selectedValue;
|
||||
}
|
||||
|
||||
String getSelectedItem() {
|
||||
return myList.getSelectedValue();
|
||||
}
|
||||
|
||||
private void refill(@NotNull List<String> values) {
|
||||
clearList();
|
||||
Collections.sort(values);
|
||||
for (String extension : values) {
|
||||
getListModel().addElement(extension);
|
||||
}
|
||||
ScrollingUtil.ensureSelectionExists(myList);
|
||||
}
|
||||
}
|
||||
|
||||
private void editHashBang() {
|
||||
String item = myHashBangs.getSelectedItem();
|
||||
if (item == null) return;
|
||||
|
||||
editHashBang(item);
|
||||
}
|
||||
private void editHashBang(@Nullable("null means new") String oldHashBang) {
|
||||
FileType type = myRecognizedFileType.getSelectedFileType();
|
||||
if (type == null) return;
|
||||
|
||||
String title = FileTypesBundle.message("filetype.edit.hashbang.title");
|
||||
|
||||
Language oldLanguage = oldHashBang == null ? null : myTempTemplateDataLanguages.findAssociatedFileType(oldHashBang);
|
||||
String hashbang = Messages.showInputDialog(myHashBangs.myList, FileTypesBundle.message("filetype.edit.hashbang.prompt"), title, null, oldHashBang, null);
|
||||
if (StringUtil.isEmpty(hashbang)) {
|
||||
return; //canceled or empty
|
||||
}
|
||||
HashBangConflict conflict = checkHashBangConflict(hashbang);
|
||||
if (conflict != null) {
|
||||
FileType existingFileType = conflict.fileType;
|
||||
if (existingFileType == type) return; // ignore duplicate
|
||||
if (!conflict.writeable) {
|
||||
String message = conflict.exact ? FileTypesBundle.message("filetype.edit.hashbang.exists.exact.error", existingFileType.getDescription())
|
||||
: FileTypesBundle.message("filetype.edit.hashbang.exists.similar.error", existingFileType.getDescription(), conflict.existingHashBang);
|
||||
Messages.showMessageDialog(myHashBangs.myList, message, title, Messages.getErrorIcon());
|
||||
return;
|
||||
}
|
||||
super.doOKAction();
|
||||
String message = conflict.exact ? FileTypesBundle.message("filetype.edit.hashbang.exists.exact.message", existingFileType.getDescription())
|
||||
: FileTypesBundle.message("filetype.edit.hashbang.exists.similar.message", existingFileType.getDescription(), conflict.existingHashBang);
|
||||
int ret = Messages.showOkCancelDialog(myHashBangs.myList, message,
|
||||
FileTypesBundle.message("filetype.edit.hashbang.exists.title"),
|
||||
FileTypesBundle.message("filetype.edit.hashbang.reassign.button"),
|
||||
CommonBundle.getCancelButtonText(), Messages.getQuestionIcon());
|
||||
if (ret != Messages.OK) {
|
||||
return;
|
||||
}
|
||||
myTempPatternsTable.removeHashBangPattern(hashbang, existingFileType);
|
||||
if (oldLanguage != null) {
|
||||
myTempTemplateDataLanguages.removeHashBangPattern(hashbang, oldLanguage);
|
||||
}
|
||||
myTempPatternsTable.removeHashBangPattern(conflict.existingHashBang, conflict.fileType);
|
||||
}
|
||||
if (oldHashBang != null) {
|
||||
myTempPatternsTable.removeHashBangPattern(oldHashBang, type);
|
||||
if (oldLanguage != null) {
|
||||
myTempTemplateDataLanguages.removeHashBangPattern(oldHashBang, oldLanguage);
|
||||
}
|
||||
}
|
||||
myTempPatternsTable.addHashBangPattern(hashbang, type);
|
||||
|
||||
@Override
|
||||
protected String getHelpId() {
|
||||
//noinspection SpellCheckingInspection
|
||||
return "reference.dialogs.newfiletype";
|
||||
updateExtensionList();
|
||||
myHashBangs.select(hashbang);
|
||||
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myPatterns.myList, true));
|
||||
}
|
||||
|
||||
// describes conflict between two hashbang patterns when user tried to create new/edit existing hashbang
|
||||
private static class HashBangConflict {
|
||||
FileType fileType; // conflicting file type
|
||||
boolean exact; // true: conflict with the file type with the exactly the same hashbang/false: similar hashbang (more selective or less selective)
|
||||
boolean writeable; //file type can be changed
|
||||
String existingHashBang; // the hashbang of the conflicting file type
|
||||
}
|
||||
private static boolean isStandardFileType(@NotNull FileType fileType) {
|
||||
return FileTypeManager.getInstance().getStdFileType(fileType.getName()) == fileType;
|
||||
}
|
||||
|
||||
// check if there is a conflict between new hasbang and exising ones
|
||||
private HashBangConflict checkHashBangConflict(@NotNull String hashbang) {
|
||||
HashBangConflict conflict = new HashBangConflict();
|
||||
for (Map.Entry<String, FileType> entry : myTempPatternsTable.getAllHashBangPatterns().entrySet()) {
|
||||
String existingHashBang = entry.getKey();
|
||||
if (hashbang.contains(existingHashBang) || existingHashBang.contains(hashbang)) {
|
||||
conflict.fileType = entry.getValue();
|
||||
conflict.exact = existingHashBang.equals(hashbang);
|
||||
conflict.writeable = !conflict.fileType.isReadOnly() && !isStandardFileType(conflict.fileType);
|
||||
conflict.existingHashBang = existingHashBang;
|
||||
return conflict;
|
||||
}
|
||||
}
|
||||
List<FileTypeRegistry.FileTypeDetector> detectors = FileTypeRegistry.FileTypeDetector.EP_NAME.getExtensionList();
|
||||
for (FileTypeRegistry.FileTypeDetector detector : detectors) {
|
||||
if (detector instanceof HashBangFileTypeDetector) {
|
||||
String existingHashBang = ((HashBangFileTypeDetector)detector).getMarker();
|
||||
if (hashbang.contains(existingHashBang) || existingHashBang.contains(hashbang)) {
|
||||
conflict.fileType = ((HashBangFileTypeDetector)detector).getFileType();
|
||||
conflict.exact = existingHashBang.equals(hashbang);
|
||||
conflict.writeable = false;
|
||||
conflict.existingHashBang = existingHashBang;
|
||||
return conflict;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.openapi.fileTypes.impl.FileTypeConfigurable.FileTypePanel">
|
||||
<grid id="975b3" binding="myWholePanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.openapi.fileTypes.impl.FileTypePanel">
|
||||
<grid id="975b3" binding="myWholePanel" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="40" y="17" width="426" height="416"/>
|
||||
@@ -8,22 +8,28 @@
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="1ff7f" class="com.intellij.openapi.fileTypes.impl.FileTypeConfigurable$PatternsPanel" binding="myPatterns">
|
||||
<grid id="b8997" binding="myPatternsPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="10cf2" class="com.intellij.openapi.fileTypes.impl.FileTypeConfigurable$RecognizedFileTypes" binding="myRecognizedFileType">
|
||||
<border type="none"/>
|
||||
<children/>
|
||||
</grid>
|
||||
<grid id="1671e" binding="myRecognizedFileTypesPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="8" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<border type="none"/>
|
||||
<children/>
|
||||
</grid>
|
||||
<grid id="846ad" binding="myIgnorePanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<clientProperties>
|
||||
@@ -45,6 +51,15 @@
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<grid id="79b1b" binding="myHashBangPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children/>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.fileTypes.impl;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
class FileTypePanel {
|
||||
JPanel myWholePanel;
|
||||
JPanel myRecognizedFileTypesPanel;
|
||||
JPanel myPatternsPanel;
|
||||
JTextField myIgnoreFilesField;
|
||||
JPanel myIgnorePanel;
|
||||
JPanel myHashBangPanel;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.fileTypes.impl;
|
||||
|
||||
import com.intellij.openapi.fileTypes.UserFileType;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.options.SettingsEditor;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
class TypeEditor<T extends UserFileType<T>> extends DialogWrapper {
|
||||
private final T myFileType;
|
||||
private final SettingsEditor<T> myEditor;
|
||||
|
||||
TypeEditor(@NotNull Component parent, @NotNull T fileType, @NotNull String title) {
|
||||
super(parent, false);
|
||||
myFileType = fileType;
|
||||
myEditor = fileType.getEditor();
|
||||
setTitle(title);
|
||||
init();
|
||||
Disposer.register(myDisposable, myEditor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
myEditor.resetFrom(myFileType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
return myEditor.getComponent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
try {
|
||||
myEditor.applyTo(myFileType);
|
||||
}
|
||||
catch (ConfigurationException e) {
|
||||
Messages.showErrorDialog(getContentPane(), e.getMessage(), e.getTitle());
|
||||
return;
|
||||
}
|
||||
super.doOKAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHelpId() {
|
||||
//noinspection SpellCheckingInspection
|
||||
return "reference.dialogs.newfiletype";
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ filetype.chooser.title=Register New File Type Association
|
||||
filetype.chooser.prompt=The file ''{0}'' is not associated with any file type. Please define the association:
|
||||
filetype.chooser.change.prompt=The file ''{0}'' is associated with {1} file type. Please define a new association:
|
||||
filetype.chooser.association=Open matching files in {0}:
|
||||
filetype.registered.patterns.group=Registered Patterns:
|
||||
filetype.registered.patterns.group=File Name Patterns:
|
||||
filetype.settings.title=File Types
|
||||
filetype.edit.existing.title=Edit File Type
|
||||
filetype.edit.new.title=New File Type
|
||||
@@ -17,5 +17,14 @@ filetype.settings.component=File types
|
||||
filetype.settings.no.patterns=No registered file patterns
|
||||
filetype.recognized.group=Recognized File Types:
|
||||
filetype.chooser.file.pattern=File &pattern:
|
||||
filetype.hashbang.group=HashBang Patterns:
|
||||
filetype.edit.hashbang.title=Edit HashBang Pattern
|
||||
filetype.edit.hashbang.exists.exact.error=This hashbang is reserved for ''{0}'' filetype and cannot be reassigned
|
||||
filetype.edit.hashbang.exists.similar.error=The similar hashbang (''{1}'') is reserved for ''{0}'' filetype and cannot be reassigned
|
||||
filetype.edit.hashbang.exists.exact.message=This hashbang is already registered by ''{0}'' filetype
|
||||
filetype.edit.hashbang.exists.similar.message=The similar hashbang (''{1}'') is already registered by ''{0}'' filetype
|
||||
filetype.edit.hashbang.reassign.button=&Reassign hashbang
|
||||
filetype.edit.hashbang.exists.title=Add HashBang
|
||||
filetype.edit.hashbang.prompt=HashBang substring (E.g. 'sh' to be associated with hashbang '#!/bin/sh'):
|
||||
notification.file.extension.0.was.reassigned.to.1.revert=File extension {0} was reassigned to {1} <a href=''revert''>Revert</a>
|
||||
notification.title.file.type.recognized=File type recognized
|
||||
|
||||
@@ -82,13 +82,20 @@ public final class FileTypeBean implements PluginAware {
|
||||
@Attribute("language")
|
||||
public String language;
|
||||
|
||||
/**
|
||||
* Semicolon-separated list of hash bang patterns to be associated with the file type
|
||||
*/
|
||||
@Attribute("hashBangs")
|
||||
@NonNls
|
||||
public String hashBangs;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public void addMatchers(List<? extends FileNameMatcher> matchers) {
|
||||
public void addMatchers(@NotNull List<? extends FileNameMatcher> matchers) {
|
||||
myMatchers.addAll(matchers);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public List<FileNameMatcher> getMatchers() {
|
||||
public @NotNull List<FileNameMatcher> getMatchers() {
|
||||
return new ArrayList<>(myMatchers);
|
||||
}
|
||||
|
||||
|
||||
+74
-28
@@ -14,7 +14,10 @@ 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.*;
|
||||
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.fileEditor.impl.LoadTextUtil;
|
||||
import com.intellij.openapi.fileTypes.*;
|
||||
import com.intellij.openapi.fileTypes.ex.ExternalizableFileType;
|
||||
@@ -364,7 +367,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
});
|
||||
|
||||
for (StandardFileType pair : myStandardFileTypes.values()) {
|
||||
registerFileTypeWithoutNotification(pair.fileType, pair.matchers, true);
|
||||
registerFileTypeWithoutNotification(pair.fileType, pair.matchers, Collections.emptyList(), true);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -438,7 +441,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
}
|
||||
}
|
||||
|
||||
private static void initializeMatchers(FileTypeBean bean) {
|
||||
private static void initializeMatchers(@NotNull FileTypeBean bean) {
|
||||
bean.addMatchers(ContainerUtil.concat(
|
||||
parse(bean.extensions),
|
||||
parse(bean.fileNames, token -> new ExactFileNameMatcher(token)),
|
||||
@@ -463,14 +466,14 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
return type.fileType;
|
||||
}
|
||||
|
||||
private FileType instantiateFileTypeBean(@NotNull FileTypeBean fileTypeBean) {
|
||||
private FileType instantiateFileTypeBean(@NotNull FileTypeBean bean) {
|
||||
FileType fileType;
|
||||
PluginId pluginId = fileTypeBean.getPluginDescriptor().getPluginId();
|
||||
PluginId pluginId = bean.getPluginDescriptor().getPluginId();
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<FileType> beanClass = (Class<FileType>)Class.forName(fileTypeBean.implementationClass, true, fileTypeBean.getPluginDescriptor().getPluginClassLoader());
|
||||
if (fileTypeBean.fieldName != null) {
|
||||
Field field = beanClass.getDeclaredField(fileTypeBean.fieldName);
|
||||
Class<FileType> beanClass = (Class<FileType>)Class.forName(bean.implementationClass, true, bean.getPluginDescriptor().getPluginClassLoader());
|
||||
if (bean.fieldName != null) {
|
||||
Field field = beanClass.getDeclaredField(bean.fieldName);
|
||||
field.setAccessible(true);
|
||||
fileType = (FileType)field.get(null);
|
||||
}
|
||||
@@ -484,23 +487,24 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!fileType.getName().equals(fileTypeBean.name)) {
|
||||
LOG.error(new PluginException("Incorrect name specified in <fileType>, should be " + fileType.getName() + ", actual " + fileTypeBean.name, pluginId));
|
||||
if (!fileType.getName().equals(bean.name)) {
|
||||
LOG.error(new PluginException("Incorrect name specified in <fileType>, should be " + fileType.getName() + ", actual " + bean.name, pluginId));
|
||||
}
|
||||
if (fileType instanceof LanguageFileType) {
|
||||
final LanguageFileType languageFileType = (LanguageFileType)fileType;
|
||||
String expectedLanguage = languageFileType.isSecondary() ? null : languageFileType.getLanguage().getID();
|
||||
if (!Comparing.equal(fileTypeBean.language, expectedLanguage)) {
|
||||
LOG.error(new PluginException("Incorrect language specified in <fileType> for " + fileType.getName() + ", should be " + expectedLanguage + ", actual " + fileTypeBean.language, pluginId));
|
||||
if (!Comparing.equal(bean.language, expectedLanguage)) {
|
||||
LOG.error(new PluginException("Incorrect language specified in <fileType> for " + fileType.getName() + ", should be " + expectedLanguage + ", actual " + bean.language, pluginId));
|
||||
}
|
||||
}
|
||||
|
||||
final StandardFileType standardFileType = new StandardFileType(fileType, fileTypeBean.getMatchers());
|
||||
myStandardFileTypes.put(fileTypeBean.name, standardFileType);
|
||||
registerFileTypeWithoutNotification(standardFileType.fileType, standardFileType.matchers, true);
|
||||
final StandardFileType standardFileType = new StandardFileType(fileType, bean.getMatchers());
|
||||
myStandardFileTypes.put(bean.name, standardFileType);
|
||||
List<String> hashBangs = bean.hashBangs == null ? Collections.emptyList() : StringUtil.split(bean.hashBangs, ";");
|
||||
registerFileTypeWithoutNotification(fileType, standardFileType.matchers, hashBangs, true);
|
||||
|
||||
myPendingAssociations.removeAllAssociations(fileTypeBean);
|
||||
myPendingFileTypes.remove(fileTypeBean.name);
|
||||
myPendingAssociations.removeAllAssociations(bean);
|
||||
myPendingFileTypes.remove(bean.name);
|
||||
|
||||
return fileType;
|
||||
}
|
||||
@@ -1083,6 +1087,9 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
}
|
||||
}
|
||||
|
||||
if (detected == null && text != null) {
|
||||
detected = myPatternsTable.findAssociatedFileTypeByHashBang(text);
|
||||
}
|
||||
if (detected == null) {
|
||||
detected = text == null ? UnknownFileType.INSTANCE : PlainTextFileType.INSTANCE;
|
||||
if (toLog()) {
|
||||
@@ -1155,7 +1162,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
DeprecatedMethodException.report("Use fileType extension instead.");
|
||||
ApplicationManager.getApplication().runWriteAction(() -> {
|
||||
fireBeforeFileTypesChanged();
|
||||
registerFileTypeWithoutNotification(type, defaultAssociations, true);
|
||||
registerFileTypeWithoutNotification(type, defaultAssociations, Collections.emptyList(), true);
|
||||
fireFileTypesChanged(type, null);
|
||||
});
|
||||
}
|
||||
@@ -1386,7 +1393,8 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
|
||||
private void readGlobalMappings(@NotNull Element e, boolean isAddToInit) {
|
||||
for (Pair<FileNameMatcher, String> association : AbstractFileType.readAssociations(e)) {
|
||||
FileType type = getFileTypeByName(association.getSecond());
|
||||
String fileTypeName = association.getSecond();
|
||||
FileType type = getFileTypeByName(fileTypeName);
|
||||
FileNameMatcher matcher = association.getFirst();
|
||||
final FileTypeBean pendingFileTypeBean = myPendingAssociations.findAssociatedFileType(matcher);
|
||||
if (pendingFileTypeBean != null) {
|
||||
@@ -1406,7 +1414,16 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
}
|
||||
}
|
||||
else {
|
||||
myUnresolvedMappings.put(matcher, association.getSecond());
|
||||
myUnresolvedMappings.put(matcher, fileTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, FileType> entry : readHashBangs(e).entrySet()) {
|
||||
String hashBang = entry.getKey();
|
||||
FileType fileType = entry.getValue();
|
||||
myPatternsTable.addHashBangPattern(hashBang, fileType);
|
||||
if (isAddToInit) {
|
||||
myInitialAssociations.addHashBangPattern(hashBang, fileType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1419,6 +1436,19 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
}
|
||||
}
|
||||
|
||||
private @NotNull Map<String, FileType> readHashBangs(@NotNull Element e) {
|
||||
List<Element> children = e.getChildren("hashBang");
|
||||
Map<String, FileType> result = new THashMap<>(children.size());
|
||||
for (Element hashBangTag : children) {
|
||||
String typeName = hashBangTag.getAttributeValue("type");
|
||||
String hashBangPattern = hashBangTag.getAttributeValue("value");
|
||||
FileType fileType = typeName == null ? null : getFileTypeByName(typeName);
|
||||
if (hashBangPattern == null || fileType == null) continue;
|
||||
result.put(hashBangPattern, fileType);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addIgnore(@NonNls @NotNull String ignoreMask) {
|
||||
myIgnoredPatterns.addIgnoreMask(ignoreMask);
|
||||
}
|
||||
@@ -1483,11 +1513,13 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
myRemovedMappingTracker.save(map);
|
||||
|
||||
if (!myUnresolvedMappings.isEmpty()) {
|
||||
FileNameMatcher[] unresolvedMappingKeys = myUnresolvedMappings.keySet().toArray(new FileNameMatcher[0]);
|
||||
Arrays.sort(unresolvedMappingKeys, Comparator.comparing(FileNameMatcher::getPresentableString));
|
||||
List<Map.Entry<FileNameMatcher, String>> entries = new ArrayList<>(myUnresolvedMappings.entrySet());
|
||||
entries.sort(Comparator.comparing(e->e.getKey().getPresentableString()));
|
||||
|
||||
for (FileNameMatcher fileNameMatcher : unresolvedMappingKeys) {
|
||||
Element content = AbstractFileType.writeMapping(myUnresolvedMappings.get(fileNameMatcher), fileNameMatcher, true);
|
||||
for (Map.Entry<FileNameMatcher, String> entry : entries) {
|
||||
FileNameMatcher fileNameMatcher = entry.getKey();
|
||||
String typeName = entry.getValue();
|
||||
Element content = AbstractFileType.writeMapping(typeName, fileNameMatcher, true);
|
||||
if (content != null) {
|
||||
map.addContent(content);
|
||||
}
|
||||
@@ -1517,7 +1549,17 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> readOnlyHashBangs = myInitialAssociations.getHashBangPatterns(type);
|
||||
List<String> hashBangPatterns = myPatternsTable.getHashBangPatterns(type);
|
||||
hashBangPatterns.sort(Comparator.naturalOrder());
|
||||
for (String hashBangPattern : hashBangPatterns) {
|
||||
if (!readOnlyHashBangs.contains(hashBangPattern)) {
|
||||
Element hashBangTag = new Element("hashBang");
|
||||
hashBangTag.setAttribute("value", hashBangPattern);
|
||||
hashBangTag.setAttribute("type", type.getName());
|
||||
map.addContent(hashBangTag);
|
||||
}
|
||||
}
|
||||
myRemovedMappingTracker.saveRemovedMappingsForFileType(map, type.getName(), defaultAssociations, specifyTypeName);
|
||||
}
|
||||
|
||||
@@ -1545,7 +1587,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
}
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(semicolonDelimited, FileTypeConsumer.EXTENSION_DELIMITER, false);
|
||||
ArrayList<FileNameMatcher> list = new ArrayList<>(semicolonDelimited.length() / "py;".length());
|
||||
List<FileNameMatcher> list = new ArrayList<>(semicolonDelimited.length() / "py;".length());
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
list.add(matcherFactory.fun(tokenizer.nextToken().trim()));
|
||||
}
|
||||
@@ -1555,7 +1597,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
/**
|
||||
* Registers a standard file type. Doesn't notifyListeners any change events.
|
||||
*/
|
||||
private void registerFileTypeWithoutNotification(@NotNull FileType fileType, @NotNull List<? extends FileNameMatcher> matchers, boolean addScheme) {
|
||||
private void registerFileTypeWithoutNotification(@NotNull FileType fileType, @NotNull List<? extends FileNameMatcher> matchers, @NotNull List<String> hasBangPatterns, boolean addScheme) {
|
||||
if (addScheme) {
|
||||
mySchemeManager.addScheme(fileType);
|
||||
}
|
||||
@@ -1563,6 +1605,10 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
myPatternsTable.addAssociation(matcher, fileType);
|
||||
myInitialAssociations.addAssociation(matcher, fileType);
|
||||
}
|
||||
for (String hashBang : hasBangPatterns) {
|
||||
myPatternsTable.addHashBangPattern(hashBang, fileType);
|
||||
myInitialAssociations.addHashBangPattern(hashBang, fileType);
|
||||
}
|
||||
|
||||
if (fileType instanceof FileTypeIdentifiableByVirtualFile) {
|
||||
mySpecialFileTypes = ArrayUtil.append(mySpecialFileTypes, (FileTypeIdentifiableByVirtualFile)fileType, FileTypeIdentifiableByVirtualFile.ARRAY_FACTORY);
|
||||
@@ -1611,7 +1657,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
|
||||
}
|
||||
|
||||
setFileTypeAttributes((UserFileType)type, fileTypeName, fileTypeDescr, iconPath);
|
||||
registerFileTypeWithoutNotification(type, parse(extensionsStr), isDefault);
|
||||
registerFileTypeWithoutNotification(type, parse(extensionsStr), Collections.emptyList(), isDefault);
|
||||
|
||||
if (isDefault) {
|
||||
myDefaultTypes.add(type);
|
||||
|
||||
+13
@@ -989,4 +989,17 @@ public class FileTypesTest extends HeavyPlatformTestCase {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void testHashBangPatternsCanBeConfiguredDynamically() throws IOException {
|
||||
VirtualFile file0 = createTempFile("xxxx", null, "#!/usr/bin/gogogo\na=b", CharsetToolkit.UTF8_CHARSET);
|
||||
assertEquals(StdFileTypes.PLAIN_TEXT, file0.getFileType());
|
||||
myFileTypeManager.getExtensionMap().addHashBangPattern("gogogo", StdFileTypes.PROPERTIES);
|
||||
try {
|
||||
VirtualFile file = createTempFile("xxxx", null, "#!/usr/bin/gogogo\na=b", CharsetToolkit.UTF8_CHARSET);
|
||||
assertEquals(StdFileTypes.PROPERTIES, file.getFileType());
|
||||
}
|
||||
finally {
|
||||
myFileTypeManager.getExtensionMap().removeHashBangPattern("gogogo", StdFileTypes.PROPERTIES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 org.jetbrains.plugins.groovy;
|
||||
|
||||
import com.intellij.openapi.fileTypes.impl.HashBangFileTypeDetector;
|
||||
|
||||
public class GroovyHashBangFileTypeDetector extends HashBangFileTypeDetector {
|
||||
public GroovyHashBangFileTypeDetector() {
|
||||
super(GroovyFileType.GROOVY_FILE_TYPE, "groovy");
|
||||
}
|
||||
}
|
||||
@@ -304,7 +304,7 @@
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<fileType name="Groovy" language="Groovy" extensions="groovy;gy"
|
||||
<fileType name="Groovy" language="Groovy" extensions="groovy;gy" hashBangs="groovy"
|
||||
implementationClass="org.jetbrains.plugins.groovy.GroovyFileType" fieldName="GROOVY_FILE_TYPE"/>
|
||||
<fileType name="gdsl" extensions="gdsl"
|
||||
implementationClass="org.jetbrains.plugins.groovy.GdslFileType" fieldName="INSTANCE"/>
|
||||
@@ -329,8 +329,6 @@
|
||||
|
||||
<navbar implementation="org.jetbrains.plugins.groovy.navbar.GrNavBarModelExtension"/>
|
||||
|
||||
<fileTypeDetector implementation="org.jetbrains.plugins.groovy.GroovyHashBangFileTypeDetector"/>
|
||||
|
||||
<declarationRangeHandler key="org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod"
|
||||
implementationClass="org.jetbrains.plugins.groovy.codeInsight.hint.GrMethodDeclarationRangeHandler"/>
|
||||
<declarationRangeHandler key="org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition"
|
||||
|
||||
@@ -15,7 +15,7 @@ Adds support for working with shell script files
|
||||
</li></ul>]]></description>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<applicationService serviceInterface="com.intellij.sh.ShSupport" serviceImplementation="com.intellij.sh.ShSupport$Impl"/>
|
||||
<fileType language="Shell Script" extensions="sh;bash;zsh" fieldName="INSTANCE" name="Shell Script" implementationClass="com.intellij.sh.ShFileType"/>
|
||||
<fileType language="Shell Script" extensions="sh;bash;zsh" hashBangs="sh" fieldName="INSTANCE" name="Shell Script" implementationClass="com.intellij.sh.ShFileType"/>
|
||||
<lang.syntaxHighlighter language="Shell Script" implementationClass="com.intellij.sh.highlighter.ShSyntaxHighlighter"/>
|
||||
<lang.parserDefinition language="Shell Script" implementationClass="com.intellij.sh.parser.ShParserDefinition"/>
|
||||
<lang.commenter language="Shell Script" implementationClass="com.intellij.sh.ShCommenter"/>
|
||||
@@ -67,7 +67,6 @@ Adds support for working with shell script files
|
||||
|
||||
<spellchecker.support language="Shell Script" implementationClass="com.intellij.sh.spellchecker.ShSpellcheckingStrategy"/>
|
||||
|
||||
<fileTypeDetector implementation="com.intellij.sh.ShFileTypeDetector" order="first"/>
|
||||
<highlightErrorFilter implementation="com.intellij.sh.ShErrorFilter"/>
|
||||
<daemon.highlightInfoFilter implementation="com.intellij.sh.ShErrorFilter"/>
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.sh;
|
||||
|
||||
import com.intellij.openapi.fileTypes.impl.HashBangFileTypeDetector;
|
||||
|
||||
public class ShFileTypeDetector extends HashBangFileTypeDetector {
|
||||
public ShFileTypeDetector() {
|
||||
super(ShFileType.INSTANCE, "sh");
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@
|
||||
<fileType name="Python"
|
||||
language="Python"
|
||||
extensions="py;pyw;"
|
||||
hashBangs="python"
|
||||
implementationClass="com.jetbrains.python.PythonFileType"
|
||||
fieldName="INSTANCE"/>
|
||||
<projectService serviceInterface="com.jetbrains.python.psi.types.TypeEvalContextCache"
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
fieldName="INSTANCE"/>
|
||||
<fileType name="Qt UI file" extensions="ui" implementationClass="com.jetbrains.pyqt.QtUIFileType" fieldName="INSTANCE"/>
|
||||
<fileType name="XML" language="XML" extensions="qrc"/>
|
||||
<fileTypeDetector implementation="com.jetbrains.python.PyFileTypeDetector"/>
|
||||
<editorHighlighterProvider filetype="Python" implementationClass="com.jetbrains.python.PyEditorHighlighterProvider"/>
|
||||
<lang.syntaxHighlighterFactory language="Python" implementationClass="com.jetbrains.python.highlighting.PySyntaxHighlighterFactory"/>
|
||||
<lang.braceMatcher language="Python" implementationClass="com.jetbrains.python.PyBraceMatcher"/>
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.jetbrains.python;
|
||||
|
||||
import com.intellij.openapi.fileTypes.impl.HashBangFileTypeDetector;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class PyFileTypeDetector extends HashBangFileTypeDetector {
|
||||
public PyFileTypeDetector() {
|
||||
super(PythonFileType.INSTANCE, "python");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user