123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import { onUnexpectedError } from '../../../base/common/errors.js';
- import { Emitter } from '../../../base/common/event.js';
- import { Disposable } from '../../../base/common/lifecycle.js';
- import * as mime from '../../../base/common/mime.js';
- import * as strings from '../../../base/common/strings.js';
- import { ModesRegistry, PLAINTEXT_MODE_ID } from '../modes/modesRegistry.js';
- import { NULL_MODE_ID } from '../modes/nullMode.js';
- import { Extensions } from '../../../platform/configuration/common/configurationRegistry.js';
- import { Registry } from '../../../platform/registry/common/platform.js';
- const hasOwnProperty = Object.prototype.hasOwnProperty;
- export class LanguageIdCodec {
- constructor() {
- this._languageIdToLanguage = [];
- this._languageToLanguageId = new Map();
- this._register(NULL_MODE_ID, 0 /* Null */);
- this._register(PLAINTEXT_MODE_ID, 1 /* PlainText */);
- this._nextLanguageId = 2;
- }
- _register(language, languageId) {
- this._languageIdToLanguage[languageId] = language;
- this._languageToLanguageId.set(language, languageId);
- }
- register(language) {
- if (this._languageToLanguageId.has(language)) {
- return;
- }
- const languageId = this._nextLanguageId++;
- this._register(language, languageId);
- }
- encodeLanguageId(languageId) {
- return this._languageToLanguageId.get(languageId) || 0 /* Null */;
- }
- decodeLanguageId(languageId) {
- return this._languageIdToLanguage[languageId] || NULL_MODE_ID;
- }
- }
- export class LanguagesRegistry extends Disposable {
- constructor(useModesRegistry = true, warnOnOverwrite = false) {
- super();
- this._onDidChange = this._register(new Emitter());
- this.onDidChange = this._onDidChange.event;
- LanguagesRegistry.instanceCount++;
- this._warnOnOverwrite = warnOnOverwrite;
- this.languageIdCodec = new LanguageIdCodec();
- this._languages = {};
- this._mimeTypesMap = {};
- this._nameMap = {};
- this._lowercaseNameMap = {};
- if (useModesRegistry) {
- this._initializeFromRegistry();
- this._register(ModesRegistry.onDidChangeLanguages((m) => {
- // console.log(`onDidChangeLanguages - inst count: ${LanguagesRegistry.instanceCount}`);
- this._initializeFromRegistry();
- }));
- }
- }
- dispose() {
- LanguagesRegistry.instanceCount--;
- super.dispose();
- }
- _initializeFromRegistry() {
- this._languages = {};
- this._mimeTypesMap = {};
- this._nameMap = {};
- this._lowercaseNameMap = {};
- mime.clearTextMimes();
- const desc = ModesRegistry.getLanguages();
- this._registerLanguages(desc);
- }
- _registerLanguages(desc) {
- for (const d of desc) {
- this._registerLanguage(d);
- }
- // Rebuild fast path maps
- this._mimeTypesMap = {};
- this._nameMap = {};
- this._lowercaseNameMap = {};
- Object.keys(this._languages).forEach((langId) => {
- let language = this._languages[langId];
- if (language.name) {
- this._nameMap[language.name] = language.identifier;
- }
- language.aliases.forEach((alias) => {
- this._lowercaseNameMap[alias.toLowerCase()] = language.identifier;
- });
- language.mimetypes.forEach((mimetype) => {
- this._mimeTypesMap[mimetype] = language.identifier;
- });
- });
- Registry.as(Extensions.Configuration).registerOverrideIdentifiers(ModesRegistry.getLanguages().map(language => language.id));
- this._onDidChange.fire();
- }
- _registerLanguage(lang) {
- const langId = lang.id;
- let resolvedLanguage;
- if (hasOwnProperty.call(this._languages, langId)) {
- resolvedLanguage = this._languages[langId];
- }
- else {
- this.languageIdCodec.register(langId);
- resolvedLanguage = {
- identifier: langId,
- name: null,
- mimetypes: [],
- aliases: [],
- extensions: [],
- filenames: [],
- configurationFiles: []
- };
- this._languages[langId] = resolvedLanguage;
- }
- this._mergeLanguage(resolvedLanguage, lang);
- }
- _mergeLanguage(resolvedLanguage, lang) {
- const langId = lang.id;
- let primaryMime = null;
- if (Array.isArray(lang.mimetypes) && lang.mimetypes.length > 0) {
- resolvedLanguage.mimetypes.push(...lang.mimetypes);
- primaryMime = lang.mimetypes[0];
- }
- if (!primaryMime) {
- primaryMime = `text/x-${langId}`;
- resolvedLanguage.mimetypes.push(primaryMime);
- }
- if (Array.isArray(lang.extensions)) {
- if (lang.configuration) {
- // insert first as this appears to be the 'primary' language definition
- resolvedLanguage.extensions = lang.extensions.concat(resolvedLanguage.extensions);
- }
- else {
- resolvedLanguage.extensions = resolvedLanguage.extensions.concat(lang.extensions);
- }
- for (let extension of lang.extensions) {
- mime.registerTextMime({ id: langId, mime: primaryMime, extension: extension }, this._warnOnOverwrite);
- }
- }
- if (Array.isArray(lang.filenames)) {
- for (let filename of lang.filenames) {
- mime.registerTextMime({ id: langId, mime: primaryMime, filename: filename }, this._warnOnOverwrite);
- resolvedLanguage.filenames.push(filename);
- }
- }
- if (Array.isArray(lang.filenamePatterns)) {
- for (let filenamePattern of lang.filenamePatterns) {
- mime.registerTextMime({ id: langId, mime: primaryMime, filepattern: filenamePattern }, this._warnOnOverwrite);
- }
- }
- if (typeof lang.firstLine === 'string' && lang.firstLine.length > 0) {
- let firstLineRegexStr = lang.firstLine;
- if (firstLineRegexStr.charAt(0) !== '^') {
- firstLineRegexStr = '^' + firstLineRegexStr;
- }
- try {
- let firstLineRegex = new RegExp(firstLineRegexStr);
- if (!strings.regExpLeadsToEndlessLoop(firstLineRegex)) {
- mime.registerTextMime({ id: langId, mime: primaryMime, firstline: firstLineRegex }, this._warnOnOverwrite);
- }
- }
- catch (err) {
- // Most likely, the regex was bad
- onUnexpectedError(err);
- }
- }
- resolvedLanguage.aliases.push(langId);
- let langAliases = null;
- if (typeof lang.aliases !== 'undefined' && Array.isArray(lang.aliases)) {
- if (lang.aliases.length === 0) {
- // signal that this language should not get a name
- langAliases = [null];
- }
- else {
- langAliases = lang.aliases;
- }
- }
- if (langAliases !== null) {
- for (const langAlias of langAliases) {
- if (!langAlias || langAlias.length === 0) {
- continue;
- }
- resolvedLanguage.aliases.push(langAlias);
- }
- }
- let containsAliases = (langAliases !== null && langAliases.length > 0);
- if (containsAliases && langAliases[0] === null) {
- // signal that this language should not get a name
- }
- else {
- let bestName = (containsAliases ? langAliases[0] : null) || langId;
- if (containsAliases || !resolvedLanguage.name) {
- resolvedLanguage.name = bestName;
- }
- }
- if (lang.configuration) {
- resolvedLanguage.configurationFiles.push(lang.configuration);
- }
- }
- isRegisteredMode(mimetypeOrModeId) {
- // Is this a known mime type ?
- if (hasOwnProperty.call(this._mimeTypesMap, mimetypeOrModeId)) {
- return true;
- }
- // Is this a known mode id ?
- return hasOwnProperty.call(this._languages, mimetypeOrModeId);
- }
- getModeIdForLanguageNameLowercase(languageNameLower) {
- if (!hasOwnProperty.call(this._lowercaseNameMap, languageNameLower)) {
- return null;
- }
- return this._lowercaseNameMap[languageNameLower];
- }
- extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds) {
- if (!commaSeparatedMimetypesOrCommaSeparatedIds) {
- return [];
- }
- return (commaSeparatedMimetypesOrCommaSeparatedIds.
- split(',').
- map((mimeTypeOrId) => mimeTypeOrId.trim()).
- map((mimeTypeOrId) => {
- if (hasOwnProperty.call(this._mimeTypesMap, mimeTypeOrId)) {
- return this._mimeTypesMap[mimeTypeOrId];
- }
- return mimeTypeOrId;
- }).
- filter((languageId) => {
- return hasOwnProperty.call(this._languages, languageId);
- }));
- }
- validateLanguageId(languageId) {
- if (!languageId || languageId === NULL_MODE_ID) {
- return NULL_MODE_ID;
- }
- if (!hasOwnProperty.call(this._languages, languageId)) {
- return null;
- }
- return languageId;
- }
- getModeIdsFromFilepathOrFirstLine(resource, firstLine) {
- if (!resource && !firstLine) {
- return [];
- }
- let mimeTypes = mime.guessMimeTypes(resource, firstLine);
- return this.extractModeIds(mimeTypes.join(','));
- }
- }
- LanguagesRegistry.instanceCount = 0;
|