784a8864b55fce7ed96140016101b67365447d4f4cd67cfe85cb53b5ae0f0bc9697602c4dbdd8cbebd920654d2a5fa2b96142d23c600c657b329f365b5d321 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  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 { MarkdownString } from '../../../../base/common/htmlContent.js';
  26. import { Disposable } from '../../../../base/common/lifecycle.js';
  27. import * as platform from '../../../../base/common/platform.js';
  28. import { InvisibleCharacters } from '../../../../base/common/strings.js';
  29. import './unicodeHighlighter.css';
  30. import { EditorAction, registerEditorAction, registerEditorContribution } from '../../../browser/editorExtensions.js';
  31. import { inUntrustedWorkspace, unicodeHighlightConfigKeys } from '../../../common/config/editorOptions.js';
  32. import { ModelDecorationOptions } from '../../../common/model/textModel.js';
  33. import { UnicodeTextModelHighlighter } from '../../../common/services/unicodeTextModelHighlighter.js';
  34. import { IEditorWorkerService } from '../../../common/services/editorWorker.js';
  35. import { ILanguageService } from '../../../common/languages/language.js';
  36. import { isModelDecorationInComment, isModelDecorationInString, isModelDecorationVisible } from '../../../common/viewModel/viewModelDecorations.js';
  37. import { HoverParticipantRegistry } from '../../hover/browser/hoverTypes.js';
  38. import { MarkdownHover, renderMarkdownHovers } from '../../hover/browser/markdownHoverParticipant.js';
  39. import { BannerController } from './bannerController.js';
  40. import * as nls from '../../../../nls.js';
  41. import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
  42. import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
  43. import { IOpenerService } from '../../../../platform/opener/common/opener.js';
  44. import { IQuickInputService } from '../../../../platform/quickinput/common/quickInput.js';
  45. import { registerIcon } from '../../../../platform/theme/common/iconRegistry.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(115 /* EditorOption.unicodeHighlighting */);
  110. this._register(_workspaceTrustService.onDidChangeTrust(e => {
  111. this._updateHighlighter();
  112. }));
  113. this._register(_editor.onDidChangeConfiguration(e => {
  114. if (e.hasChanged(115 /* EditorOption.unicodeHighlighting */)) {
  115. this._options = _editor.getOption(115 /* EditorOption.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. includeStrings: options.includeStrings,
  152. allowedCodePoints: Object.keys(options.allowedCharacters).map(c => c.codePointAt(0)),
  153. allowedLocales: Object.keys(options.allowedLocales).map(locale => {
  154. if (locale === '_os') {
  155. const osLocale = new Intl.NumberFormat().resolvedOptions().locale;
  156. return osLocale;
  157. }
  158. else if (locale === '_vscode') {
  159. return platform.language;
  160. }
  161. return locale;
  162. }),
  163. };
  164. if (this._editorWorkerService.canComputeUnicodeHighlights(this._editor.getModel().uri)) {
  165. this._highlighter = new DocumentUnicodeHighlighter(this._editor, highlightOptions, this._updateState, this._editorWorkerService);
  166. }
  167. else {
  168. this._highlighter = new ViewportUnicodeHighlighter(this._editor, highlightOptions, this._updateState);
  169. }
  170. }
  171. getDecorationInfo(decoration) {
  172. if (this._highlighter) {
  173. return this._highlighter.getDecorationInfo(decoration);
  174. }
  175. return null;
  176. }
  177. };
  178. UnicodeHighlighter.ID = 'editor.contrib.unicodeHighlighter';
  179. UnicodeHighlighter = __decorate([
  180. __param(1, IEditorWorkerService),
  181. __param(2, IWorkspaceTrustManagementService),
  182. __param(3, IInstantiationService)
  183. ], UnicodeHighlighter);
  184. export { UnicodeHighlighter };
  185. function resolveOptions(trusted, options) {
  186. return {
  187. nonBasicASCII: options.nonBasicASCII === inUntrustedWorkspace ? !trusted : options.nonBasicASCII,
  188. ambiguousCharacters: options.ambiguousCharacters,
  189. invisibleCharacters: options.invisibleCharacters,
  190. includeComments: options.includeComments === inUntrustedWorkspace ? !trusted : options.includeComments,
  191. includeStrings: options.includeStrings === inUntrustedWorkspace ? !trusted : options.includeStrings,
  192. allowedCharacters: options.allowedCharacters,
  193. allowedLocales: options.allowedLocales,
  194. };
  195. }
  196. let DocumentUnicodeHighlighter = class DocumentUnicodeHighlighter extends Disposable {
  197. constructor(_editor, _options, _updateState, _editorWorkerService) {
  198. super();
  199. this._editor = _editor;
  200. this._options = _options;
  201. this._updateState = _updateState;
  202. this._editorWorkerService = _editorWorkerService;
  203. this._model = this._editor.getModel();
  204. this._decorations = this._editor.createDecorationsCollection();
  205. this._updateSoon = this._register(new RunOnceScheduler(() => this._update(), 250));
  206. this._register(this._editor.onDidChangeModelContent(() => {
  207. this._updateSoon.schedule();
  208. }));
  209. this._updateSoon.schedule();
  210. }
  211. dispose() {
  212. this._decorations.clear();
  213. super.dispose();
  214. }
  215. _update() {
  216. if (this._model.isDisposed()) {
  217. return;
  218. }
  219. if (!this._model.mightContainNonBasicASCII()) {
  220. this._decorations.clear();
  221. return;
  222. }
  223. const modelVersionId = this._model.getVersionId();
  224. this._editorWorkerService
  225. .computedUnicodeHighlights(this._model.uri, this._options)
  226. .then((info) => {
  227. if (this._model.isDisposed()) {
  228. return;
  229. }
  230. if (this._model.getVersionId() !== modelVersionId) {
  231. // model changed in the meantime
  232. return;
  233. }
  234. this._updateState(info);
  235. const decorations = [];
  236. if (!info.hasMore) {
  237. // Don't show decoration if there are too many.
  238. // In this case, a banner is shown.
  239. for (const range of info.ranges) {
  240. decorations.push({
  241. range: range,
  242. options: Decorations.instance.getDecorationFromOptions(this._options),
  243. });
  244. }
  245. }
  246. this._decorations.set(decorations);
  247. });
  248. }
  249. getDecorationInfo(decoration) {
  250. if (!this._decorations.has(decoration)) {
  251. return null;
  252. }
  253. const model = this._editor.getModel();
  254. if (!isModelDecorationVisible(model, decoration)) {
  255. return null;
  256. }
  257. const text = model.getValueInRange(decoration.range);
  258. return {
  259. reason: computeReason(text, this._options),
  260. inComment: isModelDecorationInComment(model, decoration),
  261. inString: isModelDecorationInString(model, decoration),
  262. };
  263. }
  264. };
  265. DocumentUnicodeHighlighter = __decorate([
  266. __param(3, IEditorWorkerService)
  267. ], DocumentUnicodeHighlighter);
  268. class ViewportUnicodeHighlighter extends Disposable {
  269. constructor(_editor, _options, _updateState) {
  270. super();
  271. this._editor = _editor;
  272. this._options = _options;
  273. this._updateState = _updateState;
  274. this._model = this._editor.getModel();
  275. this._decorations = this._editor.createDecorationsCollection();
  276. this._updateSoon = this._register(new RunOnceScheduler(() => this._update(), 250));
  277. this._register(this._editor.onDidLayoutChange(() => {
  278. this._updateSoon.schedule();
  279. }));
  280. this._register(this._editor.onDidScrollChange(() => {
  281. this._updateSoon.schedule();
  282. }));
  283. this._register(this._editor.onDidChangeHiddenAreas(() => {
  284. this._updateSoon.schedule();
  285. }));
  286. this._register(this._editor.onDidChangeModelContent(() => {
  287. this._updateSoon.schedule();
  288. }));
  289. this._updateSoon.schedule();
  290. }
  291. dispose() {
  292. this._decorations.clear();
  293. super.dispose();
  294. }
  295. _update() {
  296. if (this._model.isDisposed()) {
  297. return;
  298. }
  299. if (!this._model.mightContainNonBasicASCII()) {
  300. this._decorations.clear();
  301. return;
  302. }
  303. const ranges = this._editor.getVisibleRanges();
  304. const decorations = [];
  305. const totalResult = {
  306. ranges: [],
  307. ambiguousCharacterCount: 0,
  308. invisibleCharacterCount: 0,
  309. nonBasicAsciiCharacterCount: 0,
  310. hasMore: false,
  311. };
  312. for (const range of ranges) {
  313. const result = UnicodeTextModelHighlighter.computeUnicodeHighlights(this._model, this._options, range);
  314. for (const r of result.ranges) {
  315. totalResult.ranges.push(r);
  316. }
  317. totalResult.ambiguousCharacterCount += totalResult.ambiguousCharacterCount;
  318. totalResult.invisibleCharacterCount += totalResult.invisibleCharacterCount;
  319. totalResult.nonBasicAsciiCharacterCount += totalResult.nonBasicAsciiCharacterCount;
  320. totalResult.hasMore = totalResult.hasMore || result.hasMore;
  321. }
  322. if (!totalResult.hasMore) {
  323. // Don't show decorations if there are too many.
  324. // A banner will be shown instead.
  325. for (const range of totalResult.ranges) {
  326. decorations.push({ range, options: Decorations.instance.getDecorationFromOptions(this._options) });
  327. }
  328. }
  329. this._updateState(totalResult);
  330. this._decorations.set(decorations);
  331. }
  332. getDecorationInfo(decoration) {
  333. if (!this._decorations.has(decoration)) {
  334. return null;
  335. }
  336. const model = this._editor.getModel();
  337. const text = model.getValueInRange(decoration.range);
  338. if (!isModelDecorationVisible(model, decoration)) {
  339. return null;
  340. }
  341. return {
  342. reason: computeReason(text, this._options),
  343. inComment: isModelDecorationInComment(model, decoration),
  344. inString: isModelDecorationInString(model, decoration),
  345. };
  346. }
  347. }
  348. let UnicodeHighlighterHoverParticipant = class UnicodeHighlighterHoverParticipant {
  349. constructor(_editor, _languageService, _openerService) {
  350. this._editor = _editor;
  351. this._languageService = _languageService;
  352. this._openerService = _openerService;
  353. this.hoverOrdinal = 4;
  354. }
  355. computeSync(anchor, lineDecorations) {
  356. if (!this._editor.hasModel() || anchor.type !== 1 /* HoverAnchorType.Range */) {
  357. return [];
  358. }
  359. const model = this._editor.getModel();
  360. const unicodeHighlighter = this._editor.getContribution(UnicodeHighlighter.ID);
  361. if (!unicodeHighlighter) {
  362. return [];
  363. }
  364. const result = [];
  365. let index = 300;
  366. for (const d of lineDecorations) {
  367. const highlightInfo = unicodeHighlighter.getDecorationInfo(d);
  368. if (!highlightInfo) {
  369. continue;
  370. }
  371. const char = model.getValueInRange(d.range);
  372. // text refers to a single character.
  373. const codePoint = char.codePointAt(0);
  374. const codePointStr = formatCodePointMarkdown(codePoint);
  375. let reason;
  376. switch (highlightInfo.reason.kind) {
  377. case 0 /* UnicodeHighlighterReasonKind.Ambiguous */:
  378. reason = nls.localize('unicodeHighlight.characterIsAmbiguous', 'The character {0} could be confused with the character {1}, which is more common in source code.', codePointStr, formatCodePointMarkdown(highlightInfo.reason.confusableWith.codePointAt(0)));
  379. break;
  380. case 1 /* UnicodeHighlighterReasonKind.Invisible */:
  381. reason = nls.localize('unicodeHighlight.characterIsInvisible', 'The character {0} is invisible.', codePointStr);
  382. break;
  383. case 2 /* UnicodeHighlighterReasonKind.NonBasicAscii */:
  384. reason = nls.localize('unicodeHighlight.characterIsNonBasicAscii', 'The character {0} is not a basic ASCII character.', codePointStr);
  385. break;
  386. }
  387. const adjustSettingsArgs = {
  388. codePoint: codePoint,
  389. reason: highlightInfo.reason,
  390. inComment: highlightInfo.inComment,
  391. inString: highlightInfo.inString,
  392. };
  393. const adjustSettings = nls.localize('unicodeHighlight.adjustSettings', 'Adjust settings');
  394. const uri = `command:${ShowExcludeOptions.ID}?${encodeURIComponent(JSON.stringify(adjustSettingsArgs))}`;
  395. const markdown = new MarkdownString('', true)
  396. .appendMarkdown(reason)
  397. .appendText(' ')
  398. .appendLink(uri, adjustSettings);
  399. result.push(new MarkdownHover(this, d.range, [markdown], index++));
  400. }
  401. return result;
  402. }
  403. renderHoverParts(context, hoverParts) {
  404. return renderMarkdownHovers(context, hoverParts, this._editor, this._languageService, this._openerService);
  405. }
  406. };
  407. UnicodeHighlighterHoverParticipant = __decorate([
  408. __param(1, ILanguageService),
  409. __param(2, IOpenerService)
  410. ], UnicodeHighlighterHoverParticipant);
  411. export { UnicodeHighlighterHoverParticipant };
  412. function codePointToHex(codePoint) {
  413. return `U+${codePoint.toString(16).padStart(4, '0')}`;
  414. }
  415. function formatCodePointMarkdown(codePoint) {
  416. let value = `\`${codePointToHex(codePoint)}\``;
  417. if (!InvisibleCharacters.isInvisibleCharacter(codePoint)) {
  418. // Don't render any control characters or any invisible characters, as they cannot be seen anyways.
  419. value += ` "${`${renderCodePointAsInlineCode(codePoint)}`}"`;
  420. }
  421. return value;
  422. }
  423. function renderCodePointAsInlineCode(codePoint) {
  424. if (codePoint === 96 /* CharCode.BackTick */) {
  425. return '`` ` ``';
  426. }
  427. return '`' + String.fromCodePoint(codePoint) + '`';
  428. }
  429. function computeReason(char, options) {
  430. return UnicodeTextModelHighlighter.computeUnicodeHighlightReason(char, options);
  431. }
  432. class Decorations {
  433. constructor() {
  434. this.map = new Map();
  435. }
  436. getDecorationFromOptions(options) {
  437. return this.getDecoration(!options.includeComments, !options.includeStrings);
  438. }
  439. getDecoration(hideInComments, hideInStrings) {
  440. const key = `${hideInComments}${hideInStrings}`;
  441. let options = this.map.get(key);
  442. if (!options) {
  443. options = ModelDecorationOptions.createDynamic({
  444. description: 'unicode-highlight',
  445. stickiness: 1 /* TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges */,
  446. className: 'unicode-highlight',
  447. showIfCollapsed: true,
  448. overviewRuler: null,
  449. minimap: null,
  450. hideInCommentTokens: hideInComments,
  451. hideInStringTokens: hideInStrings,
  452. });
  453. this.map.set(key, options);
  454. }
  455. return options;
  456. }
  457. }
  458. Decorations.instance = new Decorations();
  459. export class DisableHighlightingInCommentsAction extends EditorAction {
  460. constructor() {
  461. super({
  462. id: DisableHighlightingOfAmbiguousCharactersAction.ID,
  463. label: nls.localize('action.unicodeHighlight.disableHighlightingInComments', 'Disable highlighting of characters in comments'),
  464. alias: 'Disable highlighting of characters in comments',
  465. precondition: undefined
  466. });
  467. this.shortLabel = nls.localize('unicodeHighlight.disableHighlightingInComments.shortLabel', 'Disable Highlight In Comments');
  468. }
  469. run(accessor, editor, args) {
  470. return __awaiter(this, void 0, void 0, function* () {
  471. const configurationService = accessor === null || accessor === void 0 ? void 0 : accessor.get(IConfigurationService);
  472. if (configurationService) {
  473. this.runAction(configurationService);
  474. }
  475. });
  476. }
  477. runAction(configurationService) {
  478. return __awaiter(this, void 0, void 0, function* () {
  479. yield configurationService.updateValue(unicodeHighlightConfigKeys.includeComments, false, 2 /* ConfigurationTarget.USER */);
  480. });
  481. }
  482. }
  483. export class DisableHighlightingInStringsAction extends EditorAction {
  484. constructor() {
  485. super({
  486. id: DisableHighlightingOfAmbiguousCharactersAction.ID,
  487. label: nls.localize('action.unicodeHighlight.disableHighlightingInStrings', 'Disable highlighting of characters in strings'),
  488. alias: 'Disable highlighting of characters in strings',
  489. precondition: undefined
  490. });
  491. this.shortLabel = nls.localize('unicodeHighlight.disableHighlightingInStrings.shortLabel', 'Disable Highlight In Strings');
  492. }
  493. run(accessor, editor, args) {
  494. return __awaiter(this, void 0, void 0, function* () {
  495. const configurationService = accessor === null || accessor === void 0 ? void 0 : accessor.get(IConfigurationService);
  496. if (configurationService) {
  497. this.runAction(configurationService);
  498. }
  499. });
  500. }
  501. runAction(configurationService) {
  502. return __awaiter(this, void 0, void 0, function* () {
  503. yield configurationService.updateValue(unicodeHighlightConfigKeys.includeStrings, false, 2 /* ConfigurationTarget.USER */);
  504. });
  505. }
  506. }
  507. export class DisableHighlightingOfAmbiguousCharactersAction extends EditorAction {
  508. constructor() {
  509. super({
  510. id: DisableHighlightingOfAmbiguousCharactersAction.ID,
  511. label: nls.localize('action.unicodeHighlight.disableHighlightingOfAmbiguousCharacters', 'Disable highlighting of ambiguous characters'),
  512. alias: 'Disable highlighting of ambiguous characters',
  513. precondition: undefined
  514. });
  515. this.shortLabel = nls.localize('unicodeHighlight.disableHighlightingOfAmbiguousCharacters.shortLabel', 'Disable Ambiguous Highlight');
  516. }
  517. run(accessor, editor, args) {
  518. return __awaiter(this, void 0, void 0, function* () {
  519. const configurationService = accessor === null || accessor === void 0 ? void 0 : accessor.get(IConfigurationService);
  520. if (configurationService) {
  521. this.runAction(configurationService);
  522. }
  523. });
  524. }
  525. runAction(configurationService) {
  526. return __awaiter(this, void 0, void 0, function* () {
  527. yield configurationService.updateValue(unicodeHighlightConfigKeys.ambiguousCharacters, false, 2 /* ConfigurationTarget.USER */);
  528. });
  529. }
  530. }
  531. DisableHighlightingOfAmbiguousCharactersAction.ID = 'editor.action.unicodeHighlight.disableHighlightingOfAmbiguousCharacters';
  532. export class DisableHighlightingOfInvisibleCharactersAction extends EditorAction {
  533. constructor() {
  534. super({
  535. id: DisableHighlightingOfInvisibleCharactersAction.ID,
  536. label: nls.localize('action.unicodeHighlight.disableHighlightingOfInvisibleCharacters', 'Disable highlighting of invisible characters'),
  537. alias: 'Disable highlighting of invisible characters',
  538. precondition: undefined
  539. });
  540. this.shortLabel = nls.localize('unicodeHighlight.disableHighlightingOfInvisibleCharacters.shortLabel', 'Disable Invisible Highlight');
  541. }
  542. run(accessor, editor, args) {
  543. return __awaiter(this, void 0, void 0, function* () {
  544. const configurationService = accessor === null || accessor === void 0 ? void 0 : accessor.get(IConfigurationService);
  545. if (configurationService) {
  546. this.runAction(configurationService);
  547. }
  548. });
  549. }
  550. runAction(configurationService) {
  551. return __awaiter(this, void 0, void 0, function* () {
  552. yield configurationService.updateValue(unicodeHighlightConfigKeys.invisibleCharacters, false, 2 /* ConfigurationTarget.USER */);
  553. });
  554. }
  555. }
  556. DisableHighlightingOfInvisibleCharactersAction.ID = 'editor.action.unicodeHighlight.disableHighlightingOfInvisibleCharacters';
  557. export class DisableHighlightingOfNonBasicAsciiCharactersAction extends EditorAction {
  558. constructor() {
  559. super({
  560. id: DisableHighlightingOfNonBasicAsciiCharactersAction.ID,
  561. label: nls.localize('action.unicodeHighlight.disableHighlightingOfNonBasicAsciiCharacters', 'Disable highlighting of non basic ASCII characters'),
  562. alias: 'Disable highlighting of non basic ASCII characters',
  563. precondition: undefined
  564. });
  565. this.shortLabel = nls.localize('unicodeHighlight.disableHighlightingOfNonBasicAsciiCharacters.shortLabel', 'Disable Non ASCII Highlight');
  566. }
  567. run(accessor, editor, args) {
  568. return __awaiter(this, void 0, void 0, function* () {
  569. const configurationService = accessor === null || accessor === void 0 ? void 0 : accessor.get(IConfigurationService);
  570. if (configurationService) {
  571. this.runAction(configurationService);
  572. }
  573. });
  574. }
  575. runAction(configurationService) {
  576. return __awaiter(this, void 0, void 0, function* () {
  577. yield configurationService.updateValue(unicodeHighlightConfigKeys.nonBasicASCII, false, 2 /* ConfigurationTarget.USER */);
  578. });
  579. }
  580. }
  581. DisableHighlightingOfNonBasicAsciiCharactersAction.ID = 'editor.action.unicodeHighlight.disableHighlightingOfNonBasicAsciiCharacters';
  582. export class ShowExcludeOptions extends EditorAction {
  583. constructor() {
  584. super({
  585. id: ShowExcludeOptions.ID,
  586. label: nls.localize('action.unicodeHighlight.showExcludeOptions', "Show Exclude Options"),
  587. alias: 'Show Exclude Options',
  588. precondition: undefined
  589. });
  590. }
  591. run(accessor, editor, args) {
  592. return __awaiter(this, void 0, void 0, function* () {
  593. const { codePoint, reason, inString, inComment } = args;
  594. const char = String.fromCodePoint(codePoint);
  595. const quickPickService = accessor.get(IQuickInputService);
  596. const configurationService = accessor.get(IConfigurationService);
  597. function getExcludeCharFromBeingHighlightedLabel(codePoint) {
  598. if (InvisibleCharacters.isInvisibleCharacter(codePoint)) {
  599. return nls.localize('unicodeHighlight.excludeInvisibleCharFromBeingHighlighted', 'Exclude {0} (invisible character) from being highlighted', codePointToHex(codePoint));
  600. }
  601. return nls.localize('unicodeHighlight.excludeCharFromBeingHighlighted', 'Exclude {0} from being highlighted', `${codePointToHex(codePoint)} "${char}"`);
  602. }
  603. const options = [];
  604. if (reason.kind === 0 /* UnicodeHighlighterReasonKind.Ambiguous */) {
  605. for (const locale of reason.notAmbiguousInLocales) {
  606. options.push({
  607. label: nls.localize("unicodeHighlight.allowCommonCharactersInLanguage", "Allow unicode characters that are more common in the language \"{0}\".", locale),
  608. run: () => __awaiter(this, void 0, void 0, function* () {
  609. excludeLocaleFromBeingHighlighted(configurationService, [locale]);
  610. }),
  611. });
  612. }
  613. }
  614. options.push({
  615. label: getExcludeCharFromBeingHighlightedLabel(codePoint),
  616. run: () => excludeCharFromBeingHighlighted(configurationService, [codePoint])
  617. });
  618. if (inComment) {
  619. const action = new DisableHighlightingInCommentsAction();
  620. options.push({ label: action.label, run: () => __awaiter(this, void 0, void 0, function* () { return action.runAction(configurationService); }) });
  621. }
  622. else if (inString) {
  623. const action = new DisableHighlightingInStringsAction();
  624. options.push({ label: action.label, run: () => __awaiter(this, void 0, void 0, function* () { return action.runAction(configurationService); }) });
  625. }
  626. if (reason.kind === 0 /* UnicodeHighlighterReasonKind.Ambiguous */) {
  627. const action = new DisableHighlightingOfAmbiguousCharactersAction();
  628. options.push({ label: action.label, run: () => __awaiter(this, void 0, void 0, function* () { return action.runAction(configurationService); }) });
  629. }
  630. else if (reason.kind === 1 /* UnicodeHighlighterReasonKind.Invisible */) {
  631. const action = new DisableHighlightingOfInvisibleCharactersAction();
  632. options.push({ label: action.label, run: () => __awaiter(this, void 0, void 0, function* () { return action.runAction(configurationService); }) });
  633. }
  634. else if (reason.kind === 2 /* UnicodeHighlighterReasonKind.NonBasicAscii */) {
  635. const action = new DisableHighlightingOfNonBasicAsciiCharactersAction();
  636. options.push({ label: action.label, run: () => __awaiter(this, void 0, void 0, function* () { return action.runAction(configurationService); }) });
  637. }
  638. else {
  639. expectNever(reason);
  640. }
  641. const result = yield quickPickService.pick(options, { title: nls.localize('unicodeHighlight.configureUnicodeHighlightOptions', 'Configure Unicode Highlight Options') });
  642. if (result) {
  643. yield result.run();
  644. }
  645. });
  646. }
  647. }
  648. ShowExcludeOptions.ID = 'editor.action.unicodeHighlight.showExcludeOptions';
  649. function excludeCharFromBeingHighlighted(configurationService, charCodes) {
  650. return __awaiter(this, void 0, void 0, function* () {
  651. const existingValue = configurationService.getValue(unicodeHighlightConfigKeys.allowedCharacters);
  652. let value;
  653. if ((typeof existingValue === 'object') && existingValue) {
  654. value = existingValue;
  655. }
  656. else {
  657. value = {};
  658. }
  659. for (const charCode of charCodes) {
  660. value[String.fromCodePoint(charCode)] = true;
  661. }
  662. yield configurationService.updateValue(unicodeHighlightConfigKeys.allowedCharacters, value, 2 /* ConfigurationTarget.USER */);
  663. });
  664. }
  665. function excludeLocaleFromBeingHighlighted(configurationService, locales) {
  666. var _a;
  667. return __awaiter(this, void 0, void 0, function* () {
  668. const existingValue = (_a = configurationService.inspect(unicodeHighlightConfigKeys.allowedLocales).user) === null || _a === void 0 ? void 0 : _a.value;
  669. let value;
  670. if ((typeof existingValue === 'object') && existingValue) {
  671. // Copy value, as the existing value is read only
  672. value = Object.assign({}, existingValue);
  673. }
  674. else {
  675. value = {};
  676. }
  677. for (const locale of locales) {
  678. value[locale] = true;
  679. }
  680. yield configurationService.updateValue(unicodeHighlightConfigKeys.allowedLocales, value, 2 /* ConfigurationTarget.USER */);
  681. });
  682. }
  683. function expectNever(value) {
  684. throw new Error(`Unexpected value: ${value}`);
  685. }
  686. registerEditorAction(DisableHighlightingOfAmbiguousCharactersAction);
  687. registerEditorAction(DisableHighlightingOfInvisibleCharactersAction);
  688. registerEditorAction(DisableHighlightingOfNonBasicAsciiCharactersAction);
  689. registerEditorAction(ShowExcludeOptions);
  690. registerEditorContribution(UnicodeHighlighter.ID, UnicodeHighlighter);
  691. HoverParticipantRegistry.register(UnicodeHighlighterHoverParticipant);