unicodeHighlighter.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  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 { RunOnceScheduler } from '../../../base/common/async.js';
  24. import { Codicon } from '../../../base/common/codicons.js';
  25. import { Disposable } from '../../../base/common/lifecycle.js';
  26. import { InvisibleCharacters } from '../../../base/common/strings.js';
  27. import './unicodeHighlighter.css';
  28. import { EditorAction, registerEditorAction, registerEditorContribution } from '../../browser/editorExtensions.js';
  29. import { inUntrustedWorkspace, unicodeHighlightConfigKeys } from '../../common/config/editorOptions.js';
  30. import { MinimapPosition, OverviewRulerLane } from '../../common/model.js';
  31. import { ModelDecorationOptions } from '../../common/model/textModel.js';
  32. import { UnicodeTextModelHighlighter } from '../../common/modes/unicodeTextModelHighlighter.js';
  33. import { IEditorWorkerService } from '../../common/services/editorWorkerService.js';
  34. import { IModeService } from '../../common/services/modeService.js';
  35. import { isModelDecorationVisible } from '../../common/viewModel/viewModelDecorations.js';
  36. import { MarkdownHover, renderMarkdownHovers } from '../hover/markdownHoverParticipant.js';
  37. import { BannerController } from './bannerController.js';
  38. import * as nls from '../../../nls.js';
  39. import { IConfigurationService } from '../../../platform/configuration/common/configuration.js';
  40. import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';
  41. import { IOpenerService } from '../../../platform/opener/common/opener.js';
  42. import { IQuickInputService } from '../../../platform/quickinput/common/quickInput.js';
  43. import { minimapFindMatch, minimapUnicodeHighlight, overviewRulerFindMatchForeground, overviewRulerUnicodeHighlightForeground } from '../../../platform/theme/common/colorRegistry.js';
  44. import { registerIcon } from '../../../platform/theme/common/iconRegistry.js';
  45. import { themeColorFromId } from '../../../platform/theme/common/themeService.js';
  46. import { IWorkspaceTrustManagementService } from '../../../platform/workspace/common/workspaceTrust.js';
  47. export const warningIcon = registerIcon('extensions-warning-message', Codicon.warning, nls.localize('warningIcon', 'Icon shown with a warning message in the extensions editor.'));
  48. let UnicodeHighlighter = class UnicodeHighlighter extends Disposable {
  49. constructor(_editor, _editorWorkerService, _workspaceTrustService, instantiationService) {
  50. super();
  51. this._editor = _editor;
  52. this._editorWorkerService = _editorWorkerService;
  53. this._workspaceTrustService = _workspaceTrustService;
  54. this._highlighter = null;
  55. this._bannerClosed = false;
  56. this._updateState = (state) => {
  57. if (state && state.hasMore) {
  58. if (this._bannerClosed) {
  59. return;
  60. }
  61. // This document contains many non-basic ASCII characters.
  62. const max = Math.max(state.ambiguousCharacterCount, state.nonBasicAsciiCharacterCount, state.invisibleCharacterCount);
  63. let data;
  64. if (state.nonBasicAsciiCharacterCount >= max) {
  65. data = {
  66. message: nls.localize('unicodeHighlighting.thisDocumentHasManyNonBasicAsciiUnicodeCharacters', 'This document contains many non-basic ASCII unicode characters'),
  67. command: new DisableHighlightingOfNonBasicAsciiCharactersAction(),
  68. };
  69. }
  70. else if (state.ambiguousCharacterCount >= max) {
  71. data = {
  72. message: nls.localize('unicodeHighlighting.thisDocumentHasManyAmbiguousUnicodeCharacters', 'This document contains many ambiguous unicode characters'),
  73. command: new DisableHighlightingOfAmbiguousCharactersAction(),
  74. };
  75. }
  76. else if (state.invisibleCharacterCount >= max) {
  77. data = {
  78. message: nls.localize('unicodeHighlighting.thisDocumentHasManyInvisibleUnicodeCharacters', 'This document contains many invisible unicode characters'),
  79. command: new DisableHighlightingOfInvisibleCharactersAction(),
  80. };
  81. }
  82. else {
  83. throw new Error('Unreachable');
  84. }
  85. this._bannerController.show({
  86. id: 'unicodeHighlightBanner',
  87. message: data.message,
  88. icon: warningIcon,
  89. actions: [
  90. {
  91. label: data.command.shortLabel,
  92. href: `command:${data.command.id}`
  93. }
  94. ],
  95. onClose: () => {
  96. this._bannerClosed = true;
  97. },
  98. });
  99. }
  100. else {
  101. this._bannerController.hide();
  102. }
  103. };
  104. this._bannerController = this._register(instantiationService.createInstance(BannerController, _editor));
  105. this._register(this._editor.onDidChangeModel(() => {
  106. this._bannerClosed = false;
  107. this._updateHighlighter();
  108. }));
  109. this._options = _editor.getOption(112 /* unicodeHighlighting */);
  110. this._register(_workspaceTrustService.onDidChangeTrust(e => {
  111. this._updateHighlighter();
  112. }));
  113. this._register(_editor.onDidChangeConfiguration(e => {
  114. if (e.hasChanged(112 /* unicodeHighlighting */)) {
  115. this._options = _editor.getOption(112 /* unicodeHighlighting */);
  116. this._updateHighlighter();
  117. }
  118. }));
  119. this._updateHighlighter();
  120. }
  121. dispose() {
  122. if (this._highlighter) {
  123. this._highlighter.dispose();
  124. this._highlighter = null;
  125. }
  126. super.dispose();
  127. }
  128. _updateHighlighter() {
  129. this._updateState(null);
  130. if (this._highlighter) {
  131. this._highlighter.dispose();
  132. this._highlighter = null;
  133. }
  134. if (!this._editor.hasModel()) {
  135. return;
  136. }
  137. const options = resolveOptions(this._workspaceTrustService.isWorkspaceTrusted(), this._options);
  138. if ([
  139. options.nonBasicASCII,
  140. options.ambiguousCharacters,
  141. options.invisibleCharacters,
  142. ].every((option) => option === false)) {
  143. // Don't do anything if the feature is fully disabled
  144. return;
  145. }
  146. const highlightOptions = {
  147. nonBasicASCII: options.nonBasicASCII,
  148. ambiguousCharacters: options.ambiguousCharacters,
  149. invisibleCharacters: options.invisibleCharacters,
  150. includeComments: options.includeComments,
  151. allowedCodePoints: Object.keys(options.allowedCharacters).map(c => c.codePointAt(0)),
  152. };
  153. if (this._editorWorkerService.canComputeUnicodeHighlights(this._editor.getModel().uri)) {
  154. this._highlighter = new DocumentUnicodeHighlighter(this._editor, highlightOptions, this._updateState, this._editorWorkerService);
  155. }
  156. else {
  157. this._highlighter = new ViewportUnicodeHighlighter(this._editor, highlightOptions, this._updateState);
  158. }
  159. }
  160. getDecorationInfo(decorationId) {
  161. if (this._highlighter) {
  162. return this._highlighter.getDecorationInfo(decorationId);
  163. }
  164. return null;
  165. }
  166. };
  167. UnicodeHighlighter.ID = 'editor.contrib.unicodeHighlighter';
  168. UnicodeHighlighter = __decorate([
  169. __param(1, IEditorWorkerService),
  170. __param(2, IWorkspaceTrustManagementService),
  171. __param(3, IInstantiationService)
  172. ], UnicodeHighlighter);
  173. export { UnicodeHighlighter };
  174. function resolveOptions(trusted, options) {
  175. var _a;
  176. return {
  177. nonBasicASCII: options.nonBasicASCII === inUntrustedWorkspace ? !trusted : options.nonBasicASCII,
  178. ambiguousCharacters: options.ambiguousCharacters,
  179. invisibleCharacters: options.invisibleCharacters,
  180. includeComments: options.includeComments === inUntrustedWorkspace ? !trusted : options.includeComments,
  181. allowedCharacters: (_a = options.allowedCharacters) !== null && _a !== void 0 ? _a : {},
  182. };
  183. }
  184. let DocumentUnicodeHighlighter = class DocumentUnicodeHighlighter extends Disposable {
  185. constructor(_editor, _options, _updateState, _editorWorkerService) {
  186. super();
  187. this._editor = _editor;
  188. this._options = _options;
  189. this._updateState = _updateState;
  190. this._editorWorkerService = _editorWorkerService;
  191. this._model = this._editor.getModel();
  192. this._decorationIds = new Set();
  193. this._updateSoon = this._register(new RunOnceScheduler(() => this._update(), 250));
  194. this._register(this._editor.onDidChangeModelContent(() => {
  195. this._updateSoon.schedule();
  196. }));
  197. this._updateSoon.schedule();
  198. }
  199. dispose() {
  200. this._decorationIds = new Set(this._model.deltaDecorations(Array.from(this._decorationIds), []));
  201. super.dispose();
  202. }
  203. _update() {
  204. if (!this._model.mightContainNonBasicASCII()) {
  205. this._decorationIds = new Set(this._editor.deltaDecorations(Array.from(this._decorationIds), []));
  206. return;
  207. }
  208. const modelVersionId = this._model.getVersionId();
  209. this._editorWorkerService
  210. .computedUnicodeHighlights(this._model.uri, this._options)
  211. .then((info) => {
  212. if (this._model.getVersionId() !== modelVersionId) {
  213. // model changed in the meantime
  214. return;
  215. }
  216. this._updateState(info);
  217. const decorations = [];
  218. if (!info.hasMore) {
  219. // Don't show decoration if there are too many.
  220. // In this case, a banner is shown.
  221. for (const range of info.ranges) {
  222. decorations.push({ range: range, options: this._options.includeComments ? DECORATION : DECORATION_HIDE_IN_COMMENTS });
  223. }
  224. }
  225. this._decorationIds = new Set(this._editor.deltaDecorations(Array.from(this._decorationIds), decorations));
  226. });
  227. }
  228. getDecorationInfo(decorationId) {
  229. if (!this._decorationIds.has(decorationId)) {
  230. return null;
  231. }
  232. const model = this._editor.getModel();
  233. const range = model.getDecorationRange(decorationId);
  234. if (!isModelDecorationVisible(model, {
  235. range: range,
  236. options: this._options.includeComments
  237. ? DECORATION
  238. : DECORATION_HIDE_IN_COMMENTS,
  239. id: decorationId,
  240. ownerId: 0,
  241. })) {
  242. return null;
  243. }
  244. const text = model.getValueInRange(range);
  245. return {
  246. reason: computeReason(text, this._options),
  247. };
  248. }
  249. };
  250. DocumentUnicodeHighlighter = __decorate([
  251. __param(3, IEditorWorkerService)
  252. ], DocumentUnicodeHighlighter);
  253. class ViewportUnicodeHighlighter extends Disposable {
  254. constructor(_editor, _options, _updateState) {
  255. super();
  256. this._editor = _editor;
  257. this._options = _options;
  258. this._updateState = _updateState;
  259. this._model = this._editor.getModel();
  260. this._decorationIds = new Set();
  261. this._updateSoon = this._register(new RunOnceScheduler(() => this._update(), 250));
  262. this._register(this._editor.onDidLayoutChange(() => {
  263. this._updateSoon.schedule();
  264. }));
  265. this._register(this._editor.onDidScrollChange(() => {
  266. this._updateSoon.schedule();
  267. }));
  268. this._register(this._editor.onDidChangeHiddenAreas(() => {
  269. this._updateSoon.schedule();
  270. }));
  271. this._register(this._editor.onDidChangeModelContent(() => {
  272. this._updateSoon.schedule();
  273. }));
  274. this._updateSoon.schedule();
  275. }
  276. dispose() {
  277. this._decorationIds = new Set(this._model.deltaDecorations(Array.from(this._decorationIds), []));
  278. super.dispose();
  279. }
  280. _update() {
  281. if (!this._model.mightContainNonBasicASCII()) {
  282. this._decorationIds = new Set(this._editor.deltaDecorations(Array.from(this._decorationIds), []));
  283. return;
  284. }
  285. const ranges = this._editor.getVisibleRanges();
  286. const decorations = [];
  287. const totalResult = {
  288. ranges: [],
  289. ambiguousCharacterCount: 0,
  290. invisibleCharacterCount: 0,
  291. nonBasicAsciiCharacterCount: 0,
  292. hasMore: false,
  293. };
  294. for (const range of ranges) {
  295. const result = UnicodeTextModelHighlighter.computeUnicodeHighlights(this._model, this._options, range);
  296. for (const r of result.ranges) {
  297. totalResult.ranges.push(r);
  298. }
  299. totalResult.ambiguousCharacterCount += totalResult.ambiguousCharacterCount;
  300. totalResult.invisibleCharacterCount += totalResult.invisibleCharacterCount;
  301. totalResult.nonBasicAsciiCharacterCount += totalResult.nonBasicAsciiCharacterCount;
  302. totalResult.hasMore = totalResult.hasMore || result.hasMore;
  303. }
  304. if (!totalResult.hasMore) {
  305. // Don't show decorations if there are too many.
  306. // A banner will be shown instead.
  307. for (const range of totalResult.ranges) {
  308. decorations.push({ range, options: this._options.includeComments ? DECORATION : DECORATION_HIDE_IN_COMMENTS });
  309. }
  310. }
  311. this._updateState(totalResult);
  312. this._decorationIds = new Set(this._editor.deltaDecorations(Array.from(this._decorationIds), decorations));
  313. }
  314. getDecorationInfo(decorationId) {
  315. if (!this._decorationIds.has(decorationId)) {
  316. return null;
  317. }
  318. const model = this._editor.getModel();
  319. const range = model.getDecorationRange(decorationId);
  320. const text = model.getValueInRange(range);
  321. if (!isModelDecorationVisible(model, {
  322. range: range,
  323. options: this._options.includeComments
  324. ? DECORATION
  325. : DECORATION_HIDE_IN_COMMENTS,
  326. id: decorationId,
  327. ownerId: 0,
  328. })) {
  329. return null;
  330. }
  331. return {
  332. reason: computeReason(text, this._options),
  333. };
  334. }
  335. }
  336. let UnicodeHighlighterHoverParticipant = class UnicodeHighlighterHoverParticipant {
  337. constructor(_editor, _hover, _modeService, _openerService) {
  338. this._editor = _editor;
  339. this._hover = _hover;
  340. this._modeService = _modeService;
  341. this._openerService = _openerService;
  342. }
  343. computeSync(anchor, lineDecorations) {
  344. if (!this._editor.hasModel() || anchor.type !== 1 /* Range */) {
  345. return [];
  346. }
  347. const model = this._editor.getModel();
  348. const unicodeHighlighter = this._editor.getContribution(UnicodeHighlighter.ID);
  349. const result = [];
  350. let index = 300;
  351. for (const d of lineDecorations) {
  352. const highlightInfo = unicodeHighlighter.getDecorationInfo(d.id);
  353. if (!highlightInfo) {
  354. continue;
  355. }
  356. const char = model.getValueInRange(d.range);
  357. // text refers to a single character.
  358. const codePoint = char.codePointAt(0);
  359. function formatCodePoint(codePoint) {
  360. let value = `\`U+${codePoint.toString(16).padStart(4, '0')}\``;
  361. if (!InvisibleCharacters.isInvisibleCharacter(codePoint)) {
  362. // Don't render any control characters or any invisible characters, as they cannot be seen anyways.
  363. value += ` "${`${renderCodePointAsInlineCode(codePoint)}`}"`;
  364. }
  365. return value;
  366. }
  367. const codePointStr = formatCodePoint(codePoint);
  368. let reason;
  369. switch (highlightInfo.reason.kind) {
  370. case 0 /* Ambiguous */:
  371. reason = nls.localize('unicodeHighlight.characterIsAmbiguous', 'The character {0} could be confused with the character {1}, which is more common in source code.', codePointStr, formatCodePoint(highlightInfo.reason.confusableWith.codePointAt(0)));
  372. break;
  373. case 1 /* Invisible */:
  374. reason = nls.localize('unicodeHighlight.characterIsInvisible', 'The character {0} is invisible.', codePointStr);
  375. break;
  376. case 2 /* NonBasicAscii */:
  377. reason = nls.localize('unicodeHighlight.characterIsNonBasicAscii', 'The character {0} is not a basic ASCII character.', codePointStr);
  378. break;
  379. }
  380. const adjustSettingsArgs = {
  381. codePoint: codePoint,
  382. reason: highlightInfo.reason.kind,
  383. };
  384. const adjustSettings = nls.localize('unicodeHighlight.adjustSettings', 'Adjust settings');
  385. const contents = [{
  386. value: `${reason} [${adjustSettings}](command:${ShowExcludeOptions.ID}?${encodeURIComponent(JSON.stringify(adjustSettingsArgs))})`,
  387. isTrusted: true,
  388. }];
  389. result.push(new MarkdownHover(this, d.range, contents, index++));
  390. }
  391. return result;
  392. }
  393. renderHoverParts(hoverParts, fragment, statusBar) {
  394. return renderMarkdownHovers(hoverParts, fragment, this._editor, this._hover, this._modeService, this._openerService);
  395. }
  396. };
  397. UnicodeHighlighterHoverParticipant = __decorate([
  398. __param(2, IModeService),
  399. __param(3, IOpenerService)
  400. ], UnicodeHighlighterHoverParticipant);
  401. export { UnicodeHighlighterHoverParticipant };
  402. function renderCodePointAsInlineCode(codePoint) {
  403. if (codePoint === 96 /* BackTick */) {
  404. return '`` ` ``';
  405. }
  406. return '`' + String.fromCodePoint(codePoint) + '`';
  407. }
  408. function computeReason(char, options) {
  409. return UnicodeTextModelHighlighter.computeUnicodeHighlightReason(char, options);
  410. }
  411. const DECORATION_HIDE_IN_COMMENTS = ModelDecorationOptions.register({
  412. description: 'unicode-highlight',
  413. stickiness: 1 /* NeverGrowsWhenTypingAtEdges */,
  414. className: 'unicode-highlight',
  415. showIfCollapsed: true,
  416. overviewRuler: {
  417. color: themeColorFromId(overviewRulerUnicodeHighlightForeground),
  418. position: OverviewRulerLane.Center
  419. },
  420. minimap: {
  421. color: themeColorFromId(minimapUnicodeHighlight),
  422. position: MinimapPosition.Inline
  423. },
  424. hideInCommentTokens: true
  425. });
  426. const DECORATION = ModelDecorationOptions.register({
  427. description: 'unicode-highlight',
  428. stickiness: 1 /* NeverGrowsWhenTypingAtEdges */,
  429. className: 'unicode-highlight',
  430. showIfCollapsed: true,
  431. overviewRuler: {
  432. color: themeColorFromId(overviewRulerFindMatchForeground),
  433. position: OverviewRulerLane.Center
  434. },
  435. minimap: {
  436. color: themeColorFromId(minimapFindMatch),
  437. position: MinimapPosition.Inline
  438. }
  439. });
  440. export class DisableHighlightingOfAmbiguousCharactersAction extends EditorAction {
  441. constructor() {
  442. super({
  443. id: DisableHighlightingOfAmbiguousCharactersAction.ID,
  444. label: nls.localize('action.unicodeHighlight.disableHighlightingOfAmbiguousCharacters', 'Disable highlighting of ambiguous characters'),
  445. alias: 'Disable highlighting of ambiguous characters',
  446. precondition: undefined
  447. });
  448. this.shortLabel = nls.localize('unicodeHighlight.disableHighlightingOfAmbiguousCharacters.shortLabel', 'Disable Ambiguous Highlight');
  449. }
  450. run(accessor, editor, args) {
  451. return __awaiter(this, void 0, void 0, function* () {
  452. let configurationService = accessor === null || accessor === void 0 ? void 0 : accessor.get(IConfigurationService);
  453. if (configurationService) {
  454. this.runAction(configurationService);
  455. }
  456. });
  457. }
  458. runAction(configurationService) {
  459. return __awaiter(this, void 0, void 0, function* () {
  460. yield configurationService.updateValue(unicodeHighlightConfigKeys.ambiguousCharacters, false, 1 /* USER */);
  461. });
  462. }
  463. }
  464. DisableHighlightingOfAmbiguousCharactersAction.ID = 'editor.action.unicodeHighlight.disableHighlightingOfAmbiguousCharacters';
  465. export class DisableHighlightingOfInvisibleCharactersAction extends EditorAction {
  466. constructor() {
  467. super({
  468. id: DisableHighlightingOfInvisibleCharactersAction.ID,
  469. label: nls.localize('action.unicodeHighlight.disableHighlightingOfInvisibleCharacters', 'Disable highlighting of invisible characters'),
  470. alias: 'Disable highlighting of invisible characters',
  471. precondition: undefined
  472. });
  473. this.shortLabel = nls.localize('unicodeHighlight.disableHighlightingOfInvisibleCharacters.shortLabel', 'Disable Invisible Highlight');
  474. }
  475. run(accessor, editor, args) {
  476. return __awaiter(this, void 0, void 0, function* () {
  477. let configurationService = accessor === null || accessor === void 0 ? void 0 : accessor.get(IConfigurationService);
  478. if (configurationService) {
  479. this.runAction(configurationService);
  480. }
  481. });
  482. }
  483. runAction(configurationService) {
  484. return __awaiter(this, void 0, void 0, function* () {
  485. yield configurationService.updateValue(unicodeHighlightConfigKeys.invisibleCharacters, false, 1 /* USER */);
  486. });
  487. }
  488. }
  489. DisableHighlightingOfInvisibleCharactersAction.ID = 'editor.action.unicodeHighlight.disableHighlightingOfInvisibleCharacters';
  490. export class DisableHighlightingOfNonBasicAsciiCharactersAction extends EditorAction {
  491. constructor() {
  492. super({
  493. id: DisableHighlightingOfNonBasicAsciiCharactersAction.ID,
  494. label: nls.localize('action.unicodeHighlight.disableHighlightingOfNonBasicAsciiCharacters', 'Disable highlighting of non basic ASCII characters'),
  495. alias: 'Disable highlighting of non basic ASCII characters',
  496. precondition: undefined
  497. });
  498. this.shortLabel = nls.localize('unicodeHighlight.disableHighlightingOfNonBasicAsciiCharacters.shortLabel', 'Disable Non ASCII Highlight');
  499. }
  500. run(accessor, editor, args) {
  501. return __awaiter(this, void 0, void 0, function* () {
  502. let configurationService = accessor === null || accessor === void 0 ? void 0 : accessor.get(IConfigurationService);
  503. if (configurationService) {
  504. this.runAction(configurationService);
  505. }
  506. });
  507. }
  508. runAction(configurationService) {
  509. return __awaiter(this, void 0, void 0, function* () {
  510. yield configurationService.updateValue(unicodeHighlightConfigKeys.nonBasicASCII, false, 1 /* USER */);
  511. });
  512. }
  513. }
  514. DisableHighlightingOfNonBasicAsciiCharactersAction.ID = 'editor.action.unicodeHighlight.disableHighlightingOfNonBasicAsciiCharacters';
  515. export class ShowExcludeOptions extends EditorAction {
  516. constructor() {
  517. super({
  518. id: ShowExcludeOptions.ID,
  519. label: nls.localize('action.unicodeHighlight.showExcludeOptions', "Show Exclude Options"),
  520. alias: 'Show Exclude Options',
  521. precondition: undefined
  522. });
  523. }
  524. run(accessor, editor, args) {
  525. return __awaiter(this, void 0, void 0, function* () {
  526. const { codePoint, reason } = args;
  527. const char = String.fromCodePoint(codePoint);
  528. const quickPickService = accessor.get(IQuickInputService);
  529. const configurationService = accessor.get(IConfigurationService);
  530. function getExcludeCharFromBeingHighlightedLabel(codePoint) {
  531. if (InvisibleCharacters.isInvisibleCharacter(codePoint)) {
  532. return nls.localize('unicodeHighlight.excludeInvisibleCharFromBeingHighlighted', 'Exclude {0} (invisible character) from being highlighted', `U+${codePoint.toString(16)}`);
  533. }
  534. return nls.localize('unicodeHighlight.excludeCharFromBeingHighlighted', 'Exclude {0} from being highlighted', `U+${codePoint.toString(16)} "${char}"`);
  535. }
  536. const options = [
  537. {
  538. label: getExcludeCharFromBeingHighlightedLabel(codePoint),
  539. run: () => excludeCharFromBeingHighlighted(configurationService, [codePoint])
  540. },
  541. ];
  542. if (reason === 0 /* Ambiguous */) {
  543. const action = new DisableHighlightingOfAmbiguousCharactersAction();
  544. options.push({ label: action.label, run: () => __awaiter(this, void 0, void 0, function* () { return action.runAction(configurationService); }) });
  545. }
  546. else if (reason === 1 /* Invisible */) {
  547. const action = new DisableHighlightingOfInvisibleCharactersAction();
  548. options.push({ label: action.label, run: () => __awaiter(this, void 0, void 0, function* () { return action.runAction(configurationService); }) });
  549. }
  550. else if (reason === 2 /* NonBasicAscii */) {
  551. const action = new DisableHighlightingOfNonBasicAsciiCharactersAction();
  552. options.push({ label: action.label, run: () => __awaiter(this, void 0, void 0, function* () { return action.runAction(configurationService); }) });
  553. }
  554. else {
  555. expectNever(reason);
  556. }
  557. const result = yield quickPickService.pick(options, { title: nls.localize('unicodeHighlight.configureUnicodeHighlightOptions', 'Configure Unicode Highlight Options') });
  558. if (result) {
  559. yield result.run();
  560. }
  561. });
  562. }
  563. }
  564. ShowExcludeOptions.ID = 'editor.action.unicodeHighlight.showExcludeOptions';
  565. function excludeCharFromBeingHighlighted(configurationService, charCodes) {
  566. return __awaiter(this, void 0, void 0, function* () {
  567. const existingValue = configurationService.getValue(unicodeHighlightConfigKeys.allowedCharacters);
  568. let value;
  569. if ((typeof existingValue === 'object') && existingValue) {
  570. value = existingValue;
  571. }
  572. else {
  573. value = {};
  574. }
  575. for (const charCode of charCodes) {
  576. value[String.fromCodePoint(charCode)] = true;
  577. }
  578. yield configurationService.updateValue(unicodeHighlightConfigKeys.allowedCharacters, value, 1 /* USER */);
  579. });
  580. }
  581. function expectNever(value) {
  582. throw new Error(`Unexpected value: ${value}`);
  583. }
  584. registerEditorAction(DisableHighlightingOfAmbiguousCharactersAction);
  585. registerEditorAction(DisableHighlightingOfInvisibleCharactersAction);
  586. registerEditorAction(DisableHighlightingOfNonBasicAsciiCharactersAction);
  587. registerEditorAction(ShowExcludeOptions);
  588. registerEditorContribution(UnicodeHighlighter.ID, UnicodeHighlighter);