diff --git a/platform/core-api/src/com/intellij/lang/LanguageExtension.java b/platform/core-api/src/com/intellij/lang/LanguageExtension.java index 30e0a39b5c99..d065d24e62f6 100644 --- a/platform/core-api/src/com/intellij/lang/LanguageExtension.java +++ b/platform/core-api/src/com/intellij/lang/LanguageExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -21,12 +21,12 @@ package com.intellij.lang; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.KeyedExtensionCollector; -import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -55,20 +55,33 @@ public class LanguageExtension extends KeyedExtensionCollector { T cached = l.getUserData(IN_LANGUAGE_CACHE); if (cached != null) return cached; - List extensions = forKey(l); - T result; - if (extensions.isEmpty()) { - Language base = l.getBaseLanguage(); - result = base == null ? myDefaultImplementation : forLanguage(base); - } - else { - result = extensions.get(0); - } + T result = findForLanguage(l); if (result == null) return null; result = l.putUserDataIfAbsent(IN_LANGUAGE_CACHE, result); return result; } + protected T findForLanguage(@NotNull Language l) { + List extensions = forKey(l); + if (!extensions.isEmpty()) { + return extensions.get(0); + } + + Language base = l.getBaseLanguage(); + if (base != null) { + return forLanguage(base); + } + + for (MetaLanguage metaLanguage: MetaLanguage.all()) { + if (metaLanguage.matchesLanguage(l)) { + T result = forLanguage(metaLanguage); + if (result != null) break; + } + } + + return myDefaultImplementation; + } + /** * @see #allForLanguageOrAny(Language) */ @@ -86,9 +99,17 @@ public class LanguageExtension extends KeyedExtensionCollector { @NotNull public List allForLanguageOrAny(@NotNull Language l) { - List providers = allForLanguage(l); - if (l == Language.ANY) return providers; - return ContainerUtil.concat(providers, allForLanguage(Language.ANY)); + List providers = new ArrayList(allForLanguage(l)); + if (l != Language.ANY) { + providers.addAll(allForLanguage(Language.ANY)); + } + + if (!(l instanceof MetaLanguage)) { + for (MetaLanguage metaLanguage : MetaLanguage.all()) { + providers.addAll(allForLanguage(metaLanguage)); + } + } + return providers; } protected T getDefaultImplementation() { @@ -108,6 +129,9 @@ public class LanguageExtension extends KeyedExtensionCollector { key = key.getBaseLanguage(); } allowed.add("any"); + for (MetaLanguage metaLanguage : MetaLanguage.all()) { + allowed.add(metaLanguage.getID()); + } return allowed; } diff --git a/platform/core-api/src/com/intellij/lang/MetaLanguage.java b/platform/core-api/src/com/intellij/lang/MetaLanguage.java new file mode 100644 index 000000000000..ceb824ba4a5b --- /dev/null +++ b/platform/core-api/src/com/intellij/lang/MetaLanguage.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2017 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.intellij.lang; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.extensions.Extensions; +import org.jetbrains.annotations.NotNull; + +/** + * Allows to register a language extension for a group of languages defined by a certain criterion. + * To use this, specify the ID of a meta-language in the "language" attribute of an extension in plugin.xml. + * + * @author yole + */ +public abstract class MetaLanguage extends Language { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.metaLanguage"); + + protected MetaLanguage(@NotNull String ID) { + super(ID); + } + + public static MetaLanguage[] all() { + return Extensions.getExtensions(EP_NAME); + } + + /** + * Checks if the given language matches the criterion of this meta-language. + */ + public abstract boolean matchesLanguage(Language language); +} diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 450d26052853..9c6fb4b0c70c 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -901,6 +901,7 @@ interface="com.intellij.execution.testframework.sm.runner.history.ImportTestOutputExtension"/> +