modeServiceImpl.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import { Emitter } from '../../../base/common/event.js';
  6. import { Disposable } from '../../../base/common/lifecycle.js';
  7. import { NULL_MODE_ID } from '../modes/nullMode.js';
  8. import { LanguagesRegistry } from './languagesRegistry.js';
  9. import { firstOrDefault } from '../../../base/common/arrays.js';
  10. class LanguageSelection {
  11. constructor(onLanguagesMaybeChanged, selector) {
  12. this._selector = selector;
  13. this.languageId = this._selector();
  14. let listener;
  15. this._onDidChange = new Emitter({
  16. onFirstListenerAdd: () => {
  17. listener = onLanguagesMaybeChanged(() => this._evaluate());
  18. },
  19. onLastListenerRemove: () => {
  20. listener.dispose();
  21. }
  22. });
  23. this.onDidChange = this._onDidChange.event;
  24. }
  25. _evaluate() {
  26. const languageId = this._selector();
  27. if (languageId === this.languageId) {
  28. // no change
  29. return;
  30. }
  31. this.languageId = languageId;
  32. this._onDidChange.fire(this.languageId);
  33. }
  34. }
  35. export class ModeServiceImpl extends Disposable {
  36. constructor(warnOnOverwrite = false) {
  37. super();
  38. this._onDidEncounterLanguage = this._register(new Emitter());
  39. this.onDidEncounterLanguage = this._onDidEncounterLanguage.event;
  40. this._onLanguagesMaybeChanged = this._register(new Emitter({ leakWarningThreshold: 200 /* https://github.com/microsoft/vscode/issues/119968 */ }));
  41. this.onLanguagesMaybeChanged = this._onLanguagesMaybeChanged.event;
  42. ModeServiceImpl.instanceCount++;
  43. this._encounteredLanguages = new Set();
  44. this._registry = this._register(new LanguagesRegistry(true, warnOnOverwrite));
  45. this.languageIdCodec = this._registry.languageIdCodec;
  46. this._register(this._registry.onDidChange(() => this._onLanguagesMaybeChanged.fire()));
  47. }
  48. dispose() {
  49. ModeServiceImpl.instanceCount--;
  50. super.dispose();
  51. }
  52. isRegisteredMode(mimetypeOrModeId) {
  53. return this._registry.isRegisteredMode(mimetypeOrModeId);
  54. }
  55. getModeIdForLanguageName(alias) {
  56. return this._registry.getModeIdForLanguageNameLowercase(alias);
  57. }
  58. getModeIdByFilepathOrFirstLine(resource, firstLine) {
  59. const modeIds = this._registry.getModeIdsFromFilepathOrFirstLine(resource, firstLine);
  60. return firstOrDefault(modeIds, null);
  61. }
  62. getModeId(commaSeparatedMimetypesOrCommaSeparatedIds) {
  63. const modeIds = this._registry.extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds);
  64. return firstOrDefault(modeIds, null);
  65. }
  66. validateLanguageId(languageId) {
  67. return this._registry.validateLanguageId(languageId);
  68. }
  69. // --- instantiation
  70. create(commaSeparatedMimetypesOrCommaSeparatedIds) {
  71. return new LanguageSelection(this.onLanguagesMaybeChanged, () => {
  72. const languageId = this.getModeId(commaSeparatedMimetypesOrCommaSeparatedIds);
  73. return this._createModeAndGetLanguageIdentifier(languageId);
  74. });
  75. }
  76. createByFilepathOrFirstLine(resource, firstLine) {
  77. return new LanguageSelection(this.onLanguagesMaybeChanged, () => {
  78. const languageId = this.getModeIdByFilepathOrFirstLine(resource, firstLine);
  79. return this._createModeAndGetLanguageIdentifier(languageId);
  80. });
  81. }
  82. _createModeAndGetLanguageIdentifier(languageId) {
  83. // Fall back to plain text if no mode was found
  84. const validLanguageId = this.validateLanguageId(languageId || 'plaintext') || NULL_MODE_ID;
  85. this._getOrCreateMode(validLanguageId);
  86. return validLanguageId;
  87. }
  88. triggerMode(commaSeparatedMimetypesOrCommaSeparatedIds) {
  89. const languageId = this.getModeId(commaSeparatedMimetypesOrCommaSeparatedIds);
  90. // Fall back to plain text if no mode was found
  91. this._getOrCreateMode(languageId || 'plaintext');
  92. }
  93. _getOrCreateMode(languageId) {
  94. if (!this._encounteredLanguages.has(languageId)) {
  95. this._encounteredLanguages.add(languageId);
  96. const validLanguageId = this.validateLanguageId(languageId) || NULL_MODE_ID;
  97. this._onDidEncounterLanguage.fire(validLanguageId);
  98. }
  99. }
  100. }
  101. ModeServiceImpl.instanceCount = 0;