626280f6c00c5492a8907b353e370e9b7665f47dd1f7e5a9df0206bfd07952e5ff1c721ec311bc1a9fe896f619d741749e4d3565a5ef41def4ac5be4570240 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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. var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  6. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  7. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  8. else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  9. return c > 3 && r && Object.defineProperty(target, key, r), r;
  10. };
  11. var __param = (this && this.__param) || function (paramIndex, decorator) {
  12. return function (target, key) { decorator(target, key, paramIndex); }
  13. };
  14. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  15. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  16. return new (P || (P = Promise))(function (resolve, reject) {
  17. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  18. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  19. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  20. step((generator = generator.apply(thisArg, _arguments || [])).next());
  21. });
  22. };
  23. import { createCancelablePromise, TimeoutTimer } from '../../../../base/common/async.js';
  24. import { RGBA } from '../../../../base/common/color.js';
  25. import { onUnexpectedError } from '../../../../base/common/errors.js';
  26. import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js';
  27. import { StopWatch } from '../../../../base/common/stopwatch.js';
  28. import { noBreakWhitespace } from '../../../../base/common/strings.js';
  29. import { DynamicCssRules } from '../../../browser/editorDom.js';
  30. import { registerEditorContribution } from '../../../browser/editorExtensions.js';
  31. import { Range } from '../../../common/core/range.js';
  32. import { ModelDecorationOptions } from '../../../common/model/textModel.js';
  33. import { ILanguageFeatureDebounceService } from '../../../common/services/languageFeatureDebounce.js';
  34. import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js';
  35. import { getColors } from './color.js';
  36. import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
  37. export const ColorDecorationInjectedTextMarker = Object.create({});
  38. const MAX_DECORATORS = 500;
  39. let ColorDetector = class ColorDetector extends Disposable {
  40. constructor(_editor, _configurationService, _languageFeaturesService, languageFeatureDebounceService) {
  41. super();
  42. this._editor = _editor;
  43. this._configurationService = _configurationService;
  44. this._languageFeaturesService = _languageFeaturesService;
  45. this._localToDispose = this._register(new DisposableStore());
  46. this._decorationsIds = [];
  47. this._colorDatas = new Map();
  48. this._colorDecoratorIds = this._editor.createDecorationsCollection();
  49. this._ruleFactory = new DynamicCssRules(this._editor);
  50. this._colorDecorationClassRefs = this._register(new DisposableStore());
  51. this._debounceInformation = languageFeatureDebounceService.for(_languageFeaturesService.colorProvider, 'Document Colors', { min: ColorDetector.RECOMPUTE_TIME });
  52. this._register(_editor.onDidChangeModel(() => {
  53. this._isEnabled = this.isEnabled();
  54. this.onModelChanged();
  55. }));
  56. this._register(_editor.onDidChangeModelLanguage(() => this.onModelChanged()));
  57. this._register(_languageFeaturesService.colorProvider.onDidChange(() => this.onModelChanged()));
  58. this._register(_editor.onDidChangeConfiguration(() => {
  59. const prevIsEnabled = this._isEnabled;
  60. this._isEnabled = this.isEnabled();
  61. if (prevIsEnabled !== this._isEnabled) {
  62. if (this._isEnabled) {
  63. this.onModelChanged();
  64. }
  65. else {
  66. this.removeAllDecorations();
  67. }
  68. }
  69. }));
  70. this._timeoutTimer = null;
  71. this._computePromise = null;
  72. this._isEnabled = this.isEnabled();
  73. this.onModelChanged();
  74. }
  75. isEnabled() {
  76. const model = this._editor.getModel();
  77. if (!model) {
  78. return false;
  79. }
  80. const languageId = model.getLanguageId();
  81. // handle deprecated settings. [languageId].colorDecorators.enable
  82. const deprecatedConfig = this._configurationService.getValue(languageId);
  83. if (deprecatedConfig && typeof deprecatedConfig === 'object') {
  84. const colorDecorators = deprecatedConfig['colorDecorators']; // deprecatedConfig.valueOf('.colorDecorators.enable');
  85. if (colorDecorators && colorDecorators['enable'] !== undefined && !colorDecorators['enable']) {
  86. return colorDecorators['enable'];
  87. }
  88. }
  89. return this._editor.getOption(17 /* EditorOption.colorDecorators */);
  90. }
  91. static get(editor) {
  92. return editor.getContribution(this.ID);
  93. }
  94. dispose() {
  95. this.stop();
  96. this.removeAllDecorations();
  97. super.dispose();
  98. }
  99. onModelChanged() {
  100. this.stop();
  101. if (!this._isEnabled) {
  102. return;
  103. }
  104. const model = this._editor.getModel();
  105. if (!model || !this._languageFeaturesService.colorProvider.has(model)) {
  106. return;
  107. }
  108. this._localToDispose.add(this._editor.onDidChangeModelContent(() => {
  109. if (!this._timeoutTimer) {
  110. this._timeoutTimer = new TimeoutTimer();
  111. this._timeoutTimer.cancelAndSet(() => {
  112. this._timeoutTimer = null;
  113. this.beginCompute();
  114. }, this._debounceInformation.get(model));
  115. }
  116. }));
  117. this.beginCompute();
  118. }
  119. beginCompute() {
  120. this._computePromise = createCancelablePromise((token) => __awaiter(this, void 0, void 0, function* () {
  121. const model = this._editor.getModel();
  122. if (!model) {
  123. return Promise.resolve([]);
  124. }
  125. const sw = new StopWatch(false);
  126. const colors = yield getColors(this._languageFeaturesService.colorProvider, model, token);
  127. this._debounceInformation.update(model, sw.elapsed());
  128. return colors;
  129. }));
  130. this._computePromise.then((colorInfos) => {
  131. this.updateDecorations(colorInfos);
  132. this.updateColorDecorators(colorInfos);
  133. this._computePromise = null;
  134. }, onUnexpectedError);
  135. }
  136. stop() {
  137. if (this._timeoutTimer) {
  138. this._timeoutTimer.cancel();
  139. this._timeoutTimer = null;
  140. }
  141. if (this._computePromise) {
  142. this._computePromise.cancel();
  143. this._computePromise = null;
  144. }
  145. this._localToDispose.clear();
  146. }
  147. updateDecorations(colorDatas) {
  148. const decorations = colorDatas.map(c => ({
  149. range: {
  150. startLineNumber: c.colorInfo.range.startLineNumber,
  151. startColumn: c.colorInfo.range.startColumn,
  152. endLineNumber: c.colorInfo.range.endLineNumber,
  153. endColumn: c.colorInfo.range.endColumn
  154. },
  155. options: ModelDecorationOptions.EMPTY
  156. }));
  157. this._editor.changeDecorations((changeAccessor) => {
  158. this._decorationsIds = changeAccessor.deltaDecorations(this._decorationsIds, decorations);
  159. this._colorDatas = new Map();
  160. this._decorationsIds.forEach((id, i) => this._colorDatas.set(id, colorDatas[i]));
  161. });
  162. }
  163. updateColorDecorators(colorData) {
  164. this._colorDecorationClassRefs.clear();
  165. const decorations = [];
  166. for (let i = 0; i < colorData.length && decorations.length < MAX_DECORATORS; i++) {
  167. const { red, green, blue, alpha } = colorData[i].colorInfo.color;
  168. const rgba = new RGBA(Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255), alpha);
  169. const color = `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`;
  170. const ref = this._colorDecorationClassRefs.add(this._ruleFactory.createClassNameRef({
  171. backgroundColor: color
  172. }));
  173. decorations.push({
  174. range: {
  175. startLineNumber: colorData[i].colorInfo.range.startLineNumber,
  176. startColumn: colorData[i].colorInfo.range.startColumn,
  177. endLineNumber: colorData[i].colorInfo.range.endLineNumber,
  178. endColumn: colorData[i].colorInfo.range.endColumn
  179. },
  180. options: {
  181. description: 'colorDetector',
  182. before: {
  183. content: noBreakWhitespace,
  184. inlineClassName: `${ref.className} colorpicker-color-decoration`,
  185. inlineClassNameAffectsLetterSpacing: true,
  186. attachedData: ColorDecorationInjectedTextMarker
  187. }
  188. }
  189. });
  190. }
  191. this._colorDecoratorIds.set(decorations);
  192. }
  193. removeAllDecorations() {
  194. this._editor.removeDecorations(this._decorationsIds);
  195. this._decorationsIds = [];
  196. this._colorDecoratorIds.clear();
  197. this._colorDecorationClassRefs.clear();
  198. }
  199. getColorData(position) {
  200. const model = this._editor.getModel();
  201. if (!model) {
  202. return null;
  203. }
  204. const decorations = model
  205. .getDecorationsInRange(Range.fromPositions(position, position))
  206. .filter(d => this._colorDatas.has(d.id));
  207. if (decorations.length === 0) {
  208. return null;
  209. }
  210. return this._colorDatas.get(decorations[0].id);
  211. }
  212. isColorDecoration(decoration) {
  213. return this._colorDecoratorIds.has(decoration);
  214. }
  215. };
  216. ColorDetector.ID = 'editor.contrib.colorDetector';
  217. ColorDetector.RECOMPUTE_TIME = 1000; // ms
  218. ColorDetector = __decorate([
  219. __param(1, IConfigurationService),
  220. __param(2, ILanguageFeaturesService),
  221. __param(3, ILanguageFeatureDebounceService)
  222. ], ColorDetector);
  223. export { ColorDetector };
  224. registerEditorContribution(ColorDetector.ID, ColorDetector);