Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMickael Istria2017-07-27 08:40:05 +0000
committerMickael Istria2017-08-23 14:02:22 +0000
commit85b23928b9d76e3b2ed9aeca2df0c520a79040ca (patch)
treeed5e79ed9e84ddfdead54b0f65441e1861f12605
parent5f4c9dc850a8cb72d6e1f9173ddb46940d277913 (diff)
downloadeclipse.platform.runtime-85b23928b9d76e3b2ed9aeca2df0c520a79040ca.tar.gz
eclipse.platform.runtime-85b23928b9d76e3b2ed9aeca2df0c520a79040ca.tar.xz
eclipse.platform.runtime-85b23928b9d76e3b2ed9aeca2df0c520a79040ca.zip
Change-Id: I6e890f5b284e48b204a1c4fe860e64d88f25a641 Signed-off-by: Mickael Istria <mistria@redhat.com>
-rw-r--r--bundles/org.eclipse.core.contenttype/.settings/.api_filters10
-rw-r--r--bundles/org.eclipse.core.contenttype/META-INF/MANIFEST.MF2
-rw-r--r--bundles/org.eclipse.core.contenttype/pom.xml2
-rw-r--r--bundles/org.eclipse.core.contenttype/schema/contentTypes.exsd61
-rw-r--r--bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentType.java34
-rw-r--r--bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeBuilder.java14
-rw-r--r--bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeCatalog.java189
-rw-r--r--bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeManager.java2
-rw-r--r--bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeMatcher.java64
-rw-r--r--bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentType.java20
-rw-r--r--bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentTypeSettings.java15
11 files changed, 304 insertions, 109 deletions
diff --git a/bundles/org.eclipse.core.contenttype/.settings/.api_filters b/bundles/org.eclipse.core.contenttype/.settings/.api_filters
index 856259830..97dfc21a7 100644
--- a/bundles/org.eclipse.core.contenttype/.settings/.api_filters
+++ b/bundles/org.eclipse.core.contenttype/.settings/.api_filters
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.core.contenttype" version="2">
- <resource path="src/org/eclipse/core/runtime/content/IContentTypeManager.java" type="org.eclipse.core.runtime.content.IContentTypeManager">
- <filter comment="https://bugs.eclipse.org/bugs/show_bug.cgi?id=57908#c37" id="403853384">
+ <resource path="src/org/eclipse/core/runtime/content/IContentType.java" type="org.eclipse.core.runtime.content.IContentType">
+ <filter comment="The Javadoc comment was replaced by proper API Tools tag" id="403853384">
<message_arguments>
- <message_argument value="org.eclipse.core.runtime.content.IContentTypeManager"/>
+ <message_argument value="org.eclipse.core.runtime.content.IContentType"/>
</message_arguments>
</filter>
</resource>
- <resource path="src/org/eclipse/core/runtime/content/IContentTypeSettings.java" type="org.eclipse.core.runtime.content.IContentTypeSettings">
+ <resource path="src/org/eclipse/core/runtime/content/IContentTypeManager.java" type="org.eclipse.core.runtime.content.IContentTypeManager">
<filter comment="https://bugs.eclipse.org/bugs/show_bug.cgi?id=57908#c37" id="403853384">
<message_arguments>
- <message_argument value="org.eclipse.core.runtime.content.IContentTypeSettings"/>
+ <message_argument value="org.eclipse.core.runtime.content.IContentTypeManager"/>
</message_arguments>
</filter>
</resource>
diff --git a/bundles/org.eclipse.core.contenttype/META-INF/MANIFEST.MF b/bundles/org.eclipse.core.contenttype/META-INF/MANIFEST.MF
index 039b12b2c..c54f4d484 100644
--- a/bundles/org.eclipse.core.contenttype/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.core.contenttype/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.core.contenttype; singleton:=true
-Bundle-Version: 3.6.100.qualifier
+Bundle-Version: 3.7.0.qualifier
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Require-Bundle: org.eclipse.equinox.preferences;bundle-version="[3.2.0,4.0.0)",
diff --git a/bundles/org.eclipse.core.contenttype/pom.xml b/bundles/org.eclipse.core.contenttype/pom.xml
index 1fa77a25b..bb2c76a36 100644
--- a/bundles/org.eclipse.core.contenttype/pom.xml
+++ b/bundles/org.eclipse.core.contenttype/pom.xml
@@ -19,6 +19,6 @@
</parent>
<groupId>org.eclipse.core</groupId>
<artifactId>org.eclipse.core.contenttype</artifactId>
- <version>3.6.100-SNAPSHOT</version>
+ <version>3.7.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
diff --git a/bundles/org.eclipse.core.contenttype/schema/contentTypes.exsd b/bundles/org.eclipse.core.contenttype/schema/contentTypes.exsd
index 85a0b3dc2..59d5c3011 100644
--- a/bundles/org.eclipse.core.contenttype/schema/contentTypes.exsd
+++ b/bundles/org.eclipse.core.contenttype/schema/contentTypes.exsd
@@ -2,9 +2,9 @@
<!-- Schema file written by PDE -->
<schema targetNamespace="org.eclipse.core.contenttype" xmlns="http://www.w3.org/2001/XMLSchema">
<annotation>
- <appinfo>
+ <appInfo>
<meta.schema plugin="org.eclipse.core.contenttype" id="contentTypes" name="Content Types"/>
- </appinfo>
+ </appInfo>
<documentation>
The content types extension point allows plug-ins to contribute to the platform content type catalog. There are two forms of contributions: &lt;cite&gt;content types&lt;/cite&gt; and &lt;cite&gt;file associations&lt;/cite&gt;.
&lt;ul&gt;
@@ -24,9 +24,9 @@ a file association extends an existing content type by associating new file name
<element name="extension">
<annotation>
- <appinfo>
+ <appInfo>
<meta.element />
- </appinfo>
+ </appInfo>
</annotation>
<complexType>
<sequence>
@@ -52,9 +52,9 @@ a file association extends an existing content type by associating new file name
<documentation>
an optional name of the extension instance
</documentation>
- <appinfo>
+ <appInfo>
<meta.attribute translatable="true"/>
- </appinfo>
+ </appInfo>
</annotation>
</attribute>
</complexType>
@@ -85,9 +85,9 @@ a file association extends an existing content type by associating new file name
<documentation>
the human-readable name of this content type
</documentation>
- <appinfo>
+ <appInfo>
<meta.attribute translatable="true"/>
- </appinfo>
+ </appInfo>
</annotation>
</attribute>
<attribute name="file-extensions" type="string">
@@ -104,6 +104,13 @@ a file association extends an existing content type by associating new file name
</documentation>
</annotation>
</attribute>
+ <attribute name="file-patterns" type="string">
+ <annotation>
+ <documentation>
+ a comma-separated list of file name patterns to be associated with this content type. Since 3.7
+ </documentation>
+ </annotation>
+ </attribute>
<attribute name="priority" use="default" value="normal">
<annotation>
<documentation>
@@ -138,9 +145,9 @@ a file association extends an existing content type by associating new file name
<documentation>
the fully qualified name of a class that implements &lt;samp&gt;org.eclipse.core.runtime.content.IContentDescriber&lt;/samp&gt; or &lt;samp&gt;org.eclipse.core.runtime.content.ITextContentDescriber&lt;/samp&gt;, or an empty string, if this content type should not have a describer even if the parent has one
</documentation>
- <appinfo>
+ <appInfo>
<meta.attribute kind="java"/>
- </appinfo>
+ </appInfo>
</annotation>
</attribute>
<attribute name="alias-for" type="string">
@@ -168,9 +175,9 @@ a file association extends an existing content type by associating new file name
<documentation>
the fully qualified name of a class that implements &lt;samp&gt;org.eclipse.core.runtime.content.IContentDescriber&lt;/samp&gt; or &lt;samp&gt;org.eclipse.core.runtime.content.ITextContentDescriber&lt;/samp&gt;, or an empty string, if this content type should not have a describer even if the parent has one
</documentation>
- <appinfo>
+ <appInfo>
<meta.attribute kind="java" basedOn="org.eclipse.core.runtime.content.IContentDescriber"/>
- </appinfo>
+ </appInfo>
</annotation>
</attribute>
<attribute name="plugin" type="string">
@@ -190,6 +197,9 @@ a file association extends an existing content type by associating new file name
<documentation>
the fully qualified identifier for the content type this file association contributes to
</documentation>
+ <appInfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.core.contenttype.contentTypes/content-type/@id"/>
+ </appInfo>
</annotation>
</attribute>
<attribute name="file-names" type="string">
@@ -206,6 +216,13 @@ a file association extends an existing content type by associating new file name
</documentation>
</annotation>
</attribute>
+ <attribute name="file-patterns" type="string">
+ <annotation>
+ <documentation>
+ a comma-separated list of file name patterns to be associated with this content type. Since 3.7
+ </documentation>
+ </annotation>
+ </attribute>
</complexType>
</element>
@@ -253,18 +270,18 @@ a file association extends an existing content type by associating new file name
</element>
<annotation>
- <appinfo>
+ <appInfo>
<meta.section type="since"/>
- </appinfo>
+ </appInfo>
<documentation>
3.2
</documentation>
</annotation>
<annotation>
- <appinfo>
+ <appInfo>
<meta.section type="examples"/>
- </appinfo>
+ </appInfo>
<documentation>
Following is an example of a XML-based content type declaration using &lt;code&gt;org.eclipse.core.runtime.content.XMLRootElementContentDescriber2&lt;/code&gt;,
a built-in describer:
@@ -315,9 +332,9 @@ Here is an example of a content type that defines properties:
</annotation>
<annotation>
- <appinfo>
+ <appInfo>
<meta.section type="apiInfo"/>
- </appinfo>
+ </appInfo>
<documentation>
The value of the class attribute in the describer element must represent an
implementor of
@@ -328,9 +345,9 @@ implementor of
</annotation>
<annotation>
- <appinfo>
+ <appInfo>
<meta.section type="implementation"/>
- </appinfo>
+ </appInfo>
<documentation>
&lt;p&gt;The org.eclipse.core.contenttype plug-in provides the following content types:&lt;ul&gt;
&lt;li&gt;org.eclipse.core.runtime.text&lt;/li&gt;
@@ -348,9 +365,9 @@ Also, the org.eclipse.core.contenttype plug-in provides ready-to-use implementat
</annotation>
<annotation>
- <appinfo>
+ <appInfo>
<meta.section type="copyright"/>
- </appinfo>
+ </appInfo>
<documentation>
Copyright (c) 2004, 2008 IBM Corporation and others.&lt;br&gt;
All rights reserved. This program and the accompanying materials are made
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentType.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentType.java
index 136feaa3c..66c615c97 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentType.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentType.java
@@ -51,6 +51,8 @@ public final class ContentType implements IContentType, IContentTypeInfo {
public final static String PREF_DEFAULT_CHARSET = "charset"; //$NON-NLS-1$
public final static String PREF_FILE_EXTENSIONS = "file-extensions"; //$NON-NLS-1$
public final static String PREF_FILE_NAMES = "file-names"; //$NON-NLS-1$
+ /** @since 3.7 */
+ public final static String PREF_FILE_PATTERNS = "file-patterns"; //$NON-NLS-1$
/** @since 3.6 */
public static final String PREF_USER_DEFINED = "userDefined"; //$NON-NLS-1$
/** @since 3.6 */
@@ -89,20 +91,26 @@ public final class ContentType implements IContentType, IContentTypeInfo {
// -1 means unknown
private byte depth = -1;
- public static ContentType createContentType(ContentTypeCatalog catalog, String uniqueId, String name, byte priority, String[] fileExtensions, String[] fileNames, String baseTypeId, String aliasTargetId, Map<QualifiedName, String> defaultProperties, IConfigurationElement contentTypeElement) {
+ public static ContentType createContentType(ContentTypeCatalog catalog, String uniqueId, String name, byte priority,
+ String[] fileExtensions, String[] fileNames, String[] filePatterns, String baseTypeId, String aliasTargetId,
+ Map<QualifiedName, String> defaultProperties, IConfigurationElement contentTypeElement) {
ContentType contentType = new ContentType(catalog.getManager());
contentType.catalog = catalog;
contentType.defaultDescription = new DefaultDescription(contentType);
contentType.id = uniqueId;
contentType.name = name;
contentType.priority = priority;
- if ((fileExtensions != null && fileExtensions.length > 0) || (fileNames != null && fileNames.length > 0)) {
+ if ((fileExtensions != null && fileExtensions.length > 0) || (fileNames != null && fileNames.length > 0)
+ || (filePatterns != null && filePatterns.length > 0)) {
contentType.builtInAssociations = true;
- contentType.fileSpecs = new ArrayList<>(fileExtensions.length + fileNames.length);
+ contentType.fileSpecs = new ArrayList<>(fileExtensions.length + fileNames.length + filePatterns.length);
for (String fileName : fileNames)
contentType.internalAddFileSpec(fileName, FILE_NAME_SPEC | SPEC_PRE_DEFINED);
for (String fileExtension : fileExtensions)
contentType.internalAddFileSpec(fileExtension, FILE_EXTENSION_SPEC | SPEC_PRE_DEFINED);
+ for (String fileExtension : filePatterns) {
+ contentType.internalAddFileSpec(fileExtension, FILE_PATTERN_SPEC | SPEC_PRE_DEFINED);
+ }
}
contentType.defaultProperties = defaultProperties;
contentType.contentTypeElement = contentTypeElement;
@@ -120,6 +128,8 @@ public final class ContentType implements IContentType, IContentTypeInfo {
return PREF_FILE_EXTENSIONS;
if ((flags & FILE_NAME_SPEC) != 0)
return PREF_FILE_NAMES;
+ if ((flags & FILE_PATTERN_SPEC) != 0)
+ return PREF_FILE_PATTERNS;
throw new IllegalArgumentException("Unknown type: " + flags); //$NON-NLS-1$
}
@@ -139,7 +149,8 @@ public final class ContentType implements IContentType, IContentTypeInfo {
@Override
public void addFileSpec(String fileSpec, int type) throws CoreException {
- Assert.isLegal(type == FILE_EXTENSION_SPEC || type == FILE_NAME_SPEC, "Unknown type: " + type); //$NON-NLS-1$
+ Assert.isLegal(type == FILE_EXTENSION_SPEC || type == FILE_NAME_SPEC || type == FILE_PATTERN_SPEC,
+ "Unknown type: " + type); //$NON-NLS-1$
String[] userSet;
synchronized (this) {
if (!internalAddFileSpec(fileSpec, type | SPEC_USER_DEFINED))
@@ -377,8 +388,10 @@ public final class ContentType implements IContentType, IContentTypeInfo {
/**
* Returns whether this content type has the given file spec.
*
- * @param text the file spec string
- * @param typeMask FILE_NAME_SPEC or FILE_EXTENSION_SPEC
+ * @param text
+ * the file spec string
+ * @param typeMask
+ * FILE_NAME_SPEC or FILE_EXTENSION_SPEC or FILE_REGEXP_SPEC
* @param strict
* @return true if this file spec has already been added, false otherwise
*/
@@ -542,11 +555,18 @@ public final class ContentType implements IContentType, IContentTypeInfo {
String[] fileExtensions = Util.parseItems(userSetFileExtensions);
for (String fileExtension : fileExtensions)
internalAddFileSpec(fileExtension, FILE_EXTENSION_SPEC | SPEC_USER_DEFINED);
+ // user set file name regexp
+ String userSetFileRegexp = contentTypeNode.get(PREF_FILE_PATTERNS, null);
+ String[] fileRegexps = Util.parseItems(userSetFileRegexp);
+ for (String fileRegexp : fileRegexps) {
+ internalAddFileSpec(fileRegexp, FILE_PATTERN_SPEC | SPEC_USER_DEFINED);
+ }
}
@Override
public void removeFileSpec(String fileSpec, int type) throws CoreException {
- Assert.isLegal(type == FILE_EXTENSION_SPEC || type == FILE_NAME_SPEC, "Unknown type: " + type); //$NON-NLS-1$
+ Assert.isLegal(type == FILE_EXTENSION_SPEC || type == FILE_NAME_SPEC || type == FILE_PATTERN_SPEC,
+ "Unknown type: " + type); //$NON-NLS-1$
synchronized (this) {
if (!internalRemoveFileSpec(fileSpec, type | SPEC_USER_DEFINED))
return;
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeBuilder.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeBuilder.java
index 2dfcb9fa9..4d688cb5d 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeBuilder.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeBuilder.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2009 IBM Corporation and others.
+ * Copyright (c) 2004, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Mickael Istria (Red Hat Inc.) - [263316] regexp for file association
*******************************************************************************/
package org.eclipse.core.internal.content;
@@ -77,6 +78,9 @@ public class ContentTypeBuilder {
String[] fileExtensions = Util.parseItems(fileAssociationElement.getAttribute("file-extensions")); //$NON-NLS-1$
for (String fileExtension : fileExtensions)
target.internalAddFileSpec(fileExtension, IContentType.FILE_EXTENSION_SPEC | ContentType.SPEC_PRE_DEFINED);
+ String[] filePatterns = Util.parseItems(fileAssociationElement.getAttribute("file-patterns")); //$NON-NLS-1$
+ for (String filePattern : filePatterns)
+ target.internalAddFileSpec(filePattern, IContentType.FILE_PATTERN_SPEC | ContentType.SPEC_PRE_DEFINED);
}
/**
@@ -91,7 +95,8 @@ public class ContentTypeBuilder {
IEclipsePreferences node = context.getNode(id);
catalog.addContentType(ContentType.createContentType(catalog, id,
node.get(ContentType.PREF_USER_DEFINED__NAME, ContentType.EMPTY_STRING),
- (byte) 0, new String[0], new String[0], node.get(ContentType.PREF_USER_DEFINED__BASE_TYPE_ID, null), null, Collections.emptyMap(),
+ (byte) 0, new String[0], new String[0], new String[0],
+ node.get(ContentType.PREF_USER_DEFINED__BASE_TYPE_ID, null), null, Collections.emptyMap(),
null));
}
for (IConfigurationElement allContentTypeCE : allContentTypeCEs)
@@ -145,6 +150,7 @@ public class ContentTypeBuilder {
byte priority = parsePriority(contentTypeCE.getAttribute("priority")); //$NON-NLS-1$ );
String[] fileNames = Util.parseItems(contentTypeCE.getAttribute("file-names")); //$NON-NLS-1$
String[] fileExtensions = Util.parseItems(contentTypeCE.getAttribute("file-extensions")); //$NON-NLS-1$
+ String[] filePatterns = Util.parseItems(contentTypeCE.getAttribute("file-patterns")); //$NON-NLS-1$
String baseTypeId = getUniqueId(namespace, contentTypeCE.getAttribute("base-type")); //$NON-NLS-1$
String aliasTargetTypeId = getUniqueId(namespace, contentTypeCE.getAttribute("alias-for")); //$NON-NLS-1$
IConfigurationElement[] propertyCEs = null;
@@ -174,8 +180,8 @@ public class ContentTypeBuilder {
defaultProperties = Collections.singletonMap(IContentDescription.CHARSET, defaultCharset);
else if (!defaultProperties.containsKey(IContentDescription.CHARSET))
defaultProperties.put(IContentDescription.CHARSET, defaultCharset);
- return ContentType.createContentType(catalog, uniqueId, name, priority, fileExtensions, fileNames, baseTypeId,
- aliasTargetTypeId, defaultProperties, contentTypeCE);
+ return ContentType.createContentType(catalog, uniqueId, name, priority, fileExtensions, fileNames, filePatterns,
+ baseTypeId, aliasTargetTypeId, defaultProperties, contentTypeCE);
}
// Store this around for performance
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeCatalog.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeCatalog.java
index 5f23e1f31..5a53975b6 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeCatalog.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeCatalog.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2016 IBM Corporation and others.
+ * Copyright (c) 2004, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,11 +7,14 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Mickael Istria (Red Hat Inc.) - [263316] regexp for file association
*******************************************************************************/
package org.eclipse.core.internal.content;
import java.io.*;
import java.util.*;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.content.*;
import org.eclipse.core.runtime.content.IContentTypeManager.ISelectionPolicy;
@@ -28,6 +31,9 @@ public final class ContentTypeCatalog {
private final Map<String, IContentType> contentTypes = new HashMap<>();
private final Map<String, Set<ContentType>> fileExtensions = new HashMap<>();
private final Map<String, Set<ContentType>> fileNames = new HashMap<>();
+ private final Map<String, Pattern> compiledRegexps = new HashMap<>();
+ private final Map<Pattern, String> initialPatternForRegexp = new HashMap<>();
+ private final Map<Pattern, Set<ContentType>> fileRegexps = new HashMap<>();
private int generation;
private ContentTypeManager manager;
@@ -127,13 +133,23 @@ public final class ContentTypeCatalog {
};
private static IContentType[] concat(IContentType[][] types) {
- if (types[0].length == 0)
- return types[1];
- if (types[1].length == 0)
- return types[0];
- IContentType[] result = new IContentType[types[0].length + types[1].length];
- System.arraycopy(types[0], 0, result, 0, types[0].length);
- System.arraycopy(types[1], 0, result, types[0].length, types[1].length);
+ int size = 0;
+ IContentType[] nonEmptyOne = NO_CONTENT_TYPES;
+ for (IContentType[] array : types) {
+ size += array.length;
+ if (array.length > 0) {
+ nonEmptyOne = array;
+ }
+ }
+ if (nonEmptyOne.length == size) { // no other array has content
+ return nonEmptyOne;
+ }
+ IContentType[] result = new IContentType[size];
+ int currentIndex = 0;
+ for (IContentType[] array : types) {
+ System.arraycopy(array, 0, result, currentIndex, array.length);
+ currentIndex += array.length;
+ }
return result;
}
@@ -174,15 +190,40 @@ public final class ContentTypeCatalog {
String[] builtInFileExtensions = contentType.getFileSpecs(IContentType.IGNORE_USER_DEFINED | IContentType.FILE_EXTENSION_SPEC);
for (String builtInFileExtension : builtInFileExtensions)
associate(contentType, builtInFileExtension, IContentType.FILE_EXTENSION_SPEC);
+ String[] builtInFilePatterns = contentType
+ .getFileSpecs(IContentType.IGNORE_USER_DEFINED | IContentType.FILE_PATTERN_SPEC);
+ for (String builtInFilePattern : builtInFilePatterns) {
+ associate(contentType, builtInFilePattern, IContentType.FILE_PATTERN_SPEC);
+ }
+ }
+
+ String toRegexp(String filePattern) {
+ return filePattern.replace(".", "\\.").replace('?', '.').replace("*", ".*"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
synchronized void associate(ContentType contentType, String text, int type) {
- Map<String, Set<ContentType>> fileSpecMap = ((type & IContentType.FILE_NAME_SPEC) != 0) ? fileNames : fileExtensions;
- String mappingKey = FileSpec.getMappingKeyFor(text);
- Set<ContentType> existing = fileSpecMap.get(mappingKey);
- if (existing == null)
- fileSpecMap.put(mappingKey, existing = new HashSet<>());
- existing.add(contentType);
+ Map<String, Set<ContentType>> fileSpecMap = null;
+ if ((type & IContentType.FILE_NAME_SPEC) != 0) {
+ fileSpecMap = fileNames;
+ } else if ((type & IContentType.FILE_EXTENSION_SPEC) != 0) {
+ fileSpecMap = fileExtensions;
+ }
+ if (fileSpecMap != null) {
+ String mappingKey = FileSpec.getMappingKeyFor(text);
+ Set<ContentType> existing = fileSpecMap.get(mappingKey);
+ if (existing == null)
+ fileSpecMap.put(mappingKey, existing = new HashSet<>());
+ existing.add(contentType);
+ } else if ((type & IContentType.FILE_PATTERN_SPEC) != 0) {
+ Pattern compiledPattern = compiledRegexps.get(text);
+ if (compiledPattern == null) {
+ compiledPattern = Pattern.compile(toRegexp(text));
+ compiledRegexps.put(text, compiledPattern);
+ initialPatternForRegexp.put(compiledPattern, text);
+ fileRegexps.put(compiledPattern, new HashSet<>());
+ }
+ fileRegexps.get(compiledPattern).add(contentType);
+ }
}
private int collectMatchingByContents(int valid, IContentType[] subset, List<ContentType> destination, ILazySource contents, Map<String, Object> properties) throws IOException {
@@ -410,15 +451,26 @@ public final class ContentTypeCatalog {
final int appropriateFullName = appropriate.size();
final int validExtension = collectMatchingByContents(validFullName, subset[1], appropriate, buffer, properties) - validFullName;
final int appropriateExtension = appropriate.size() - appropriateFullName;
+ final int validPattern = collectMatchingByContents(validExtension, subset[2], appropriate, buffer, properties)
+ - validExtension;
+ final int appropriatePattern = appropriate.size() - appropriateFullName - appropriateExtension;
IContentType[] result = appropriate.toArray(new IContentType[appropriate.size()]);
if (validFullName > 1)
Arrays.sort(result, 0, validFullName, validPolicy);
if (validExtension > 1)
Arrays.sort(result, validFullName, validFullName + validExtension, validPolicy);
+ if (validPattern > 1) {
+ Arrays.sort(result, validFullName + validExtension, validFullName + validExtension + validPattern,
+ validPolicy);
+ }
if (appropriateFullName - validFullName > 1)
Arrays.sort(result, validFullName + validExtension, appropriateFullName + validExtension, indeterminatePolicy);
if (appropriateExtension - validExtension > 1)
- Arrays.sort(result, appropriateFullName + validExtension, appropriate.size(), indeterminatePolicy);
+ Arrays.sort(result, appropriateFullName + validExtension, appropriate.size() - validPattern,
+ indeterminatePolicy);
+ if (appropriatePattern - validPattern > 1) {
+ Arrays.sort(result, appropriate.size() - validPattern, appropriate.size(), indeterminatePolicy);
+ }
return result;
}
@@ -427,8 +479,9 @@ public final class ContentTypeCatalog {
final Comparator<IContentType> validPolicy;
Comparator<IContentType> indeterminatePolicy;
if (fileName == null) {
- // we only have a single array, by need to provide a two-dimensional, 2-element array
- subset = new IContentType[][] {getAllContentTypes(), NO_CONTENT_TYPES};
+ // we only have a single array, by need to provide a two-dimensional, 3-element
+ // array
+ subset = new IContentType[][] { getAllContentTypes(), NO_CONTENT_TYPES, NO_CONTENT_TYPES };
indeterminatePolicy = policyConstantGeneralIsBetter;
validPolicy = policyConstantSpecificIsBetter;
} else {
@@ -436,13 +489,13 @@ public final class ContentTypeCatalog {
indeterminatePolicy = policyGeneralIsBetter;
validPolicy = policySpecificIsBetter;
}
- int total = subset[0].length + subset[1].length;
+ int total = subset[0].length + subset[1].length + subset[2].length;
if (total == 0)
// don't do further work if subset is empty
return NO_CONTENT_TYPES;
if (!forceValidation && total == 1) {
// do not do validation if not forced and only one was found (caller will validate later)
- IContentType[] found = subset[0].length == 1 ? subset[0] : subset[1];
+ IContentType[] found = subset[0].length == 1 ? subset[0] : (subset[1].length == 1 ? subset[1] : subset[2]);
// bug 100032 - ignore binary content type if contents are text
if (!buffer.isText())
// binary buffer, caller can call the describer with no risk
@@ -466,10 +519,11 @@ public final class ContentTypeCatalog {
*/
synchronized private IContentType[][] internalFindContentTypesFor(ContentTypeMatcher matcher, final String fileName, Comparator<IContentType> sortingPolicy) {
IScopeContext context = matcher.getContext();
- IContentType[][] result = {NO_CONTENT_TYPES, NO_CONTENT_TYPES};
+ IContentType[][] result = { NO_CONTENT_TYPES, NO_CONTENT_TYPES, NO_CONTENT_TYPES };
- final Set<ContentType> allByFileName;
+ Set<ContentType> existing = new HashSet<>();
+ final Set<ContentType> allByFileName;
if (context.equals(manager.getContext()))
allByFileName = getDirectlyAssociated(fileName, IContentTypeSettings.FILE_NAME_SPEC);
else {
@@ -478,7 +532,11 @@ public final class ContentTypeCatalog {
}
Set<ContentType> selectedByName = selectMatchingByName(context, allByFileName, Collections.emptySet(), fileName,
IContentType.FILE_NAME_SPEC);
+ existing.addAll(selectedByName);
result[0] = selectedByName.toArray(new IContentType[selectedByName.size()]);
+ if (result[0].length > 1)
+ Arrays.sort(result[0], sortingPolicy);
+
final String fileExtension = ContentTypeManager.getFileExtension(fileName);
if (fileExtension != null) {
final Set<ContentType> allByFileExtension;
@@ -489,16 +547,44 @@ public final class ContentTypeCatalog {
allByFileExtension.addAll(matcher.getDirectlyAssociated(this, fileExtension, IContentTypeSettings.FILE_EXTENSION_SPEC));
}
Set<ContentType> selectedByExtension = selectMatchingByName(context, allByFileExtension, selectedByName, fileExtension, IContentType.FILE_EXTENSION_SPEC);
+ existing.addAll(selectedByExtension);
if (!selectedByExtension.isEmpty())
result[1] = selectedByExtension.toArray(new IContentType[selectedByExtension.size()]);
}
- if (result[0].length > 1)
- Arrays.sort(result[0], sortingPolicy);
if (result[1].length > 1)
Arrays.sort(result[1], sortingPolicy);
+
+ final Set<ContentType> allByFilePattern;
+ if (context.equals(manager.getContext()))
+ allByFilePattern = getMatchingRegexpAssociated(fileName, IContentTypeSettings.FILE_PATTERN_SPEC);
+ else {
+ allByFilePattern = new HashSet<>(getMatchingRegexpAssociated(fileName,
+ IContentTypeSettings.FILE_PATTERN_SPEC | IContentType.IGNORE_USER_DEFINED));
+ allByFilePattern
+ .addAll(matcher.getMatchingRegexpAssociated(this, fileName,
+ IContentTypeSettings.FILE_PATTERN_SPEC));
+ }
+ existing.addAll(allByFilePattern);
+ if (!allByFilePattern.isEmpty())
+ result[2] = allByFilePattern.toArray(new IContentType[allByFilePattern.size()]);
+
return result;
}
+ private Set<ContentType> getMatchingRegexpAssociated(String fileName, int typeMask) {
+ if ((typeMask & IContentType.FILE_PATTERN_SPEC) == 0) {
+ throw new IllegalArgumentException("This method requires FILE_PATTERN_SPEC."); //$NON-NLS-1$
+ }
+ Set<ContentType> res = new HashSet<>();
+ for (Entry<Pattern, Set<ContentType>> spec : this.fileRegexps.entrySet()) {
+ if (spec.getKey().matcher(fileName).matches()) {
+ res.addAll(filterOnDefinitionSource(initialPatternForRegexp.get(spec.getKey()), typeMask,
+ spec.getValue()));
+ }
+ }
+ return res;
+ }
+
/**
* Returns content types directly associated with the given file spec.
*
@@ -513,29 +599,50 @@ public final class ContentTypeCatalog {
* @return a set of content types
*/
private Set<ContentType> getDirectlyAssociated(String text, int typeMask) {
+ if ((typeMask & IContentType.FILE_PATTERN_SPEC) != 0) {
+ throw new IllegalArgumentException("This method don't allow FILE_REGEXP_SPEC."); //$NON-NLS-1$
+ }
Map<String, Set<ContentType>> associations = (typeMask & IContentTypeSettings.FILE_NAME_SPEC) != 0 ? fileNames : fileExtensions;
- Set<ContentType> result = null;
- if ((typeMask & (IContentType.IGNORE_PRE_DEFINED | IContentType.IGNORE_USER_DEFINED)) == 0)
- // no restrictions, get everything
- result = associations.get(FileSpec.getMappingKeyFor(text));
- else {
- // only those specs satisfying the type mask should be included
- Set<ContentType> initialSet = associations.get(FileSpec.getMappingKeyFor(text));
- if (initialSet != null && !initialSet.isEmpty()) {
- // copy so we can modify
- result = new HashSet<>(initialSet);
- // invert the last two bits so it is easier to compare
- typeMask ^= (IContentType.IGNORE_PRE_DEFINED | IContentType.IGNORE_USER_DEFINED);
- for (Iterator<ContentType> i = result.iterator(); i.hasNext();) {
- ContentType contentType = i.next();
- if (!contentType.hasFileSpec(text, typeMask, true))
- i.remove();
- }
- }
+ Set<ContentType> result = associations.get(FileSpec.getMappingKeyFor(text));
+ if ((typeMask & (IContentType.IGNORE_PRE_DEFINED | IContentType.IGNORE_USER_DEFINED)) != 0) {
+ result = filterOnDefinitionSource(text, typeMask, result);
}
return result == null ? Collections.EMPTY_SET : result;
}
+ /**
+ * Filters a set of content-types on whether they have a mapping that matches
+ * provided criteria.
+ *
+ * @param text
+ * file name, file extension or file regexp (depending on value of
+ * {@code typeMask}.
+ * @param typeMask
+ * the type mask. Spec type, and definition source (pre-defined or
+ * user-defined) will be used
+ * @param contentTypes
+ * content types to filter from (not modified during method
+ * execution)
+ * @return set of filtered content-type
+ */
+ private Set<ContentType> filterOnDefinitionSource(String text, int typeMask, Set<ContentType> contentTypes) {
+ if ((typeMask & (IContentType.IGNORE_PRE_DEFINED | IContentType.IGNORE_USER_DEFINED)) == 0) {
+ return contentTypes;
+ }
+ if (contentTypes != null && !contentTypes.isEmpty()) {
+ // copy so we can modify
+ contentTypes = new HashSet<>(contentTypes);
+ // invert the last two bits so it is easier to compare
+ typeMask ^= (IContentType.IGNORE_PRE_DEFINED | IContentType.IGNORE_USER_DEFINED);
+ for (Iterator<ContentType> i = contentTypes.iterator(); i.hasNext();) {
+ ContentType contentType = i.next();
+ if (!contentType.hasFileSpec(text, typeMask, true))
+ i.remove();
+ }
+ }
+ return contentTypes;
+ }
+
synchronized ContentType internalGetContentType(String contentTypeIdentifier) {
return (ContentType) contentTypes.get(contentTypeIdentifier);
}
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeManager.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeManager.java
index 5b2158abf..ec0a5dd42 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeManager.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeManager.java
@@ -265,7 +265,7 @@ public class ContentTypeManager extends ContentTypeMatcher implements IContentTy
throw new IllegalArgumentException("Content-type '" + id + "' already exists.");//$NON-NLS-1$ //$NON-NLS-2$
}
ContentType contentType = ContentType.createContentType(getCatalog(), id, name, (byte) 0, new String[0],
- new String[0], baseType != null ? baseType.getId() : null, null, null, null);
+ new String[0], new String[0], baseType != null ? baseType.getId() : null, null, null, null);
getCatalog().addContentType(contentType);
// Add preferences for this content type.
String currentUserDefined = getContext().getNode(ContentType.PREF_USER_DEFINED)
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeMatcher.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeMatcher.java
index 89ba95256..6d26b35da 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeMatcher.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/internal/content/ContentTypeMatcher.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * Copyright (c) 2005, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,14 +7,17 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Mickael Istria (Red Hat Inc.) - [263316] regexp for file association
*******************************************************************************/
package org.eclipse.core.internal.content;
import java.io.*;
import java.util.*;
+import java.util.regex.Pattern;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.content.*;
-import org.eclipse.core.runtime.preferences.*;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
import org.osgi.service.prefs.BackingStoreException;
/**
@@ -93,26 +96,52 @@ public class ContentTypeMatcher implements IContentTypeMatcher {
* Enumerates all content types whose settings satisfy the given file spec type mask.
*/
public Collection<ContentType> getDirectlyAssociated(final ContentTypeCatalog catalog, final String fileSpec, final int typeMask) {
+ if ((typeMask & (IContentType.FILE_EXTENSION_SPEC | IContentType.FILE_NAME_SPEC)) == 0) {
+ throw new IllegalArgumentException("This method only apply to name or extension based associations"); //$NON-NLS-1$
+ }
//TODO: make sure we include built-in associations as well
final IEclipsePreferences root = context.getNode(ContentTypeManager.CONTENT_TYPE_PREF_NODE);
final Set<ContentType> result = new HashSet<>(3);
try {
- root.accept(new IPreferenceNodeVisitor() {
- @Override
- public boolean visit(IEclipsePreferences node) {
- if (node == root)
- return true;
- String[] fileSpecs = ContentTypeSettings.getFileSpecs(node, typeMask);
- for (String fileSpecification : fileSpecs)
- if (fileSpecification.equalsIgnoreCase(fileSpec)) {
- ContentType associated = catalog.getContentType(node.name());
- if (associated != null)
- result.add(associated);
- break;
- }
- return false;
- }
+ root.accept(node -> {
+ if (node == root)
+ return true;
+ String[] fileSpecs = ContentTypeSettings.getFileSpecs(node, typeMask);
+ for (String fileSpecification : fileSpecs)
+ if (fileSpecification.equalsIgnoreCase(fileSpec)) {
+ ContentType associated = catalog.getContentType(node.name());
+ if (associated != null)
+ result.add(associated);
+ break;
+ }
+ return false;
+ });
+ } catch (BackingStoreException bse) {
+ ContentType.log(ContentMessages.content_errorLoadingSettings, bse);
+ }
+ return result == null ? Collections.EMPTY_SET : result;
+ }
+ public Collection<? extends ContentType> getMatchingRegexpAssociated(ContentTypeCatalog catalog,
+ String fileName, final int typeMask) {
+ if ((typeMask & IContentType.FILE_PATTERN_SPEC) == 0) {
+ throw new IllegalArgumentException("This method only applies for FILE_REGEXP_SPEC."); //$NON-NLS-1$
+ }
+ final IEclipsePreferences root = context.getNode(ContentTypeManager.CONTENT_TYPE_PREF_NODE);
+ final Set<ContentType> result = new HashSet<>(3);
+ try {
+ root.accept(node -> {
+ if (node == root)
+ return true;
+ String[] fileSpecs = ContentTypeSettings.getFileSpecs(node, typeMask);
+ for (String fileSpecification : fileSpecs)
+ if (Pattern.matches(catalog.toRegexp(fileSpecification), fileName)) {
+ ContentType associated = catalog.getContentType(node.name());
+ if (associated != null)
+ result.add(associated);
+ break;
+ }
+ return false;
});
} catch (BackingStoreException bse) {
ContentType.log(ContentMessages.content_errorLoadingSettings, bse);
@@ -133,4 +162,5 @@ public class ContentTypeMatcher implements IContentTypeMatcher {
((ContentDescription) description).setContentTypeInfo(new ContentTypeSettings((ContentType) description.getContentTypeInfo(), context));
return description;
}
+
}
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentType.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentType.java
index 4fd5d2f9c..953ea0c67 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentType.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentType.java
@@ -18,10 +18,8 @@ import org.eclipse.core.runtime.preferences.IScopeContext;
/**
* Content types represent and provide information on file types, such as
* associated file names/extensions, default charset, etc.
- * <p>
- * This interface is not intended to be implemented by clients.
- * </p>
*
+ * @noimplement This interface is not intended to be implemented by clients.
* @since 3.0
*/
public interface IContentType extends IContentTypeSettings {
@@ -29,20 +27,28 @@ public interface IContentType extends IContentTypeSettings {
* File spec type flag constant, indicating that predefined file
* specifications should not be taken into account.
*/
- public static final int IGNORE_PRE_DEFINED = 0x01;
+ public static final int IGNORE_PRE_DEFINED = 0b1;
/**
* File spec type flag constant, indicating that user-defined file
* specifications should not be taken into account.
*/
- public static final int IGNORE_USER_DEFINED = 0x02;
+ public static final int IGNORE_USER_DEFINED = 0b10;
/**
* File spec type constant, indicating a file name specification.
*/
- public static final int FILE_NAME_SPEC = 0x04;
+ public static final int FILE_NAME_SPEC = 0b100;
/**
* File spec type constant, indicating a file extension specification.
*/
- public static final int FILE_EXTENSION_SPEC = 0x08;
+ public static final int FILE_EXTENSION_SPEC = 0b1000;
+ /**
+ * File spec type constant, indicating a file name pattern specification.
+ * <code>?</code> represents any single character, <code>*<code> represent any
+ * string.
+ *
+ * @since 3.7
+ */
+ public static final int FILE_PATTERN_SPEC = 0b10000;
/**
* Returns a reference to this content type's base type. If this content type
diff --git a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentTypeSettings.java b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentTypeSettings.java
index a89f67d52..8156e7a1a 100644
--- a/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentTypeSettings.java
+++ b/bundles/org.eclipse.core.contenttype/src/org/eclipse/core/runtime/content/IContentTypeSettings.java
@@ -28,11 +28,18 @@ public interface IContentTypeSettings {
/**
* File spec type constant, indicating a file extension specification.
*/
- public static final int FILE_EXTENSION_SPEC = 0x08;
+ public static final int FILE_EXTENSION_SPEC = 0b1000;
/**
* File spec type constant, indicating a file name specification.
*/
- public static final int FILE_NAME_SPEC = 0x04;
+ public static final int FILE_NAME_SPEC = 0b100;
+
+ /**
+ * File spec type constant, indicating a file pattern specification
+ *
+ * @since 3.7
+ */
+ public static final int FILE_PATTERN_SPEC = 0b10000;
/**
* Adds a user-defined file specification to the corresponding content type. Has no
@@ -41,7 +48,8 @@ public interface IContentTypeSettings {
* @param fileSpec the file specification
* @param type the type of the file specification. One of
* <code>FILE_NAME_SPEC</code>,
- * <code>FILE_EXTENSION_SPEC</code>.
+ * <code>FILE_EXTENSION_SPEC</code>,
+ * <code>FILE_PATTERN_SPEC</code>.
* @throws IllegalArgumentException if the type bit mask is
* incorrect
* @throws CoreException if this method fails. Reasons include:
@@ -50,6 +58,7 @@ public interface IContentTypeSettings {
* </ul>
* @see #FILE_NAME_SPEC
* @see #FILE_EXTENSION_SPEC
+ * @see #FILE_PATTERN_SPEC
*/
public void addFileSpec(String fileSpec, int type) throws CoreException;

Back to the top