2b914042516d3eadfb5bf435fd2478d8ae3e0c56a95163f5bb736d9fa724adfd5b27a50243c3235112e083b2e7542b1683722022e25e2fda20942073f10f40 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  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. import { alert } from '../../../../base/browser/ui/aria/aria.js';
  15. import * as arrays from '../../../../base/common/arrays.js';
  16. import { createCancelablePromise, first, timeout } from '../../../../base/common/async.js';
  17. import { CancellationToken } from '../../../../base/common/cancellation.js';
  18. import { onUnexpectedError, onUnexpectedExternalError } from '../../../../base/common/errors.js';
  19. import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js';
  20. import { EditorAction, registerEditorAction, registerEditorContribution, registerModelAndPositionCommand } from '../../../browser/editorExtensions.js';
  21. import { Range } from '../../../common/core/range.js';
  22. import { EditorContextKeys } from '../../../common/editorContextKeys.js';
  23. import { MinimapPosition, OverviewRulerLane } from '../../../common/model.js';
  24. import { ModelDecorationOptions } from '../../../common/model/textModel.js';
  25. import { DocumentHighlightKind } from '../../../common/languages.js';
  26. import * as nls from '../../../../nls.js';
  27. import { IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
  28. import { activeContrastBorder, editorSelectionHighlight, editorSelectionHighlightBorder, minimapSelectionOccurrenceHighlight, overviewRulerSelectionHighlightForeground, registerColor } from '../../../../platform/theme/common/colorRegistry.js';
  29. import { registerThemingParticipant, themeColorFromId } from '../../../../platform/theme/common/themeService.js';
  30. import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js';
  31. import { isHighContrast } from '../../../../platform/theme/common/theme.js';
  32. const editorWordHighlight = registerColor('editor.wordHighlightBackground', { dark: '#575757B8', light: '#57575740', hcDark: null, hcLight: null }, nls.localize('wordHighlight', 'Background color of a symbol during read-access, like reading a variable. The color must not be opaque so as not to hide underlying decorations.'), true);
  33. const editorWordHighlightStrong = registerColor('editor.wordHighlightStrongBackground', { dark: '#004972B8', light: '#0e639c40', hcDark: null, hcLight: null }, nls.localize('wordHighlightStrong', 'Background color of a symbol during write-access, like writing to a variable. The color must not be opaque so as not to hide underlying decorations.'), true);
  34. const editorWordHighlightBorder = registerColor('editor.wordHighlightBorder', { light: null, dark: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder }, nls.localize('wordHighlightBorder', 'Border color of a symbol during read-access, like reading a variable.'));
  35. const editorWordHighlightStrongBorder = registerColor('editor.wordHighlightStrongBorder', { light: null, dark: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder }, nls.localize('wordHighlightStrongBorder', 'Border color of a symbol during write-access, like writing to a variable.'));
  36. const overviewRulerWordHighlightForeground = registerColor('editorOverviewRuler.wordHighlightForeground', { dark: '#A0A0A0CC', light: '#A0A0A0CC', hcDark: '#A0A0A0CC', hcLight: '#A0A0A0CC' }, nls.localize('overviewRulerWordHighlightForeground', 'Overview ruler marker color for symbol highlights. The color must not be opaque so as not to hide underlying decorations.'), true);
  37. const overviewRulerWordHighlightStrongForeground = registerColor('editorOverviewRuler.wordHighlightStrongForeground', { dark: '#C0A0C0CC', light: '#C0A0C0CC', hcDark: '#C0A0C0CC', hcLight: '#C0A0C0CC' }, nls.localize('overviewRulerWordHighlightStrongForeground', 'Overview ruler marker color for write-access symbol highlights. The color must not be opaque so as not to hide underlying decorations.'), true);
  38. const ctxHasWordHighlights = new RawContextKey('hasWordHighlights', false);
  39. export function getOccurrencesAtPosition(registry, model, position, token) {
  40. const orderedByScore = registry.ordered(model);
  41. // in order of score ask the occurrences provider
  42. // until someone response with a good result
  43. // (good = none empty array)
  44. return first(orderedByScore.map(provider => () => {
  45. return Promise.resolve(provider.provideDocumentHighlights(model, position, token))
  46. .then(undefined, onUnexpectedExternalError);
  47. }), arrays.isNonEmptyArray);
  48. }
  49. class OccurenceAtPositionRequest {
  50. constructor(_model, _selection, _wordSeparators) {
  51. this._model = _model;
  52. this._selection = _selection;
  53. this._wordSeparators = _wordSeparators;
  54. this._wordRange = this._getCurrentWordRange(_model, _selection);
  55. this._result = null;
  56. }
  57. get result() {
  58. if (!this._result) {
  59. this._result = createCancelablePromise(token => this._compute(this._model, this._selection, this._wordSeparators, token));
  60. }
  61. return this._result;
  62. }
  63. _getCurrentWordRange(model, selection) {
  64. const word = model.getWordAtPosition(selection.getPosition());
  65. if (word) {
  66. return new Range(selection.startLineNumber, word.startColumn, selection.startLineNumber, word.endColumn);
  67. }
  68. return null;
  69. }
  70. isValid(model, selection, decorations) {
  71. const lineNumber = selection.startLineNumber;
  72. const startColumn = selection.startColumn;
  73. const endColumn = selection.endColumn;
  74. const currentWordRange = this._getCurrentWordRange(model, selection);
  75. let requestIsValid = Boolean(this._wordRange && this._wordRange.equalsRange(currentWordRange));
  76. // Even if we are on a different word, if that word is in the decorations ranges, the request is still valid
  77. // (Same symbol)
  78. for (let i = 0, len = decorations.length; !requestIsValid && i < len; i++) {
  79. const range = decorations.getRange(i);
  80. if (range && range.startLineNumber === lineNumber) {
  81. if (range.startColumn <= startColumn && range.endColumn >= endColumn) {
  82. requestIsValid = true;
  83. }
  84. }
  85. }
  86. return requestIsValid;
  87. }
  88. cancel() {
  89. this.result.cancel();
  90. }
  91. }
  92. class SemanticOccurenceAtPositionRequest extends OccurenceAtPositionRequest {
  93. constructor(model, selection, wordSeparators, providers) {
  94. super(model, selection, wordSeparators);
  95. this._providers = providers;
  96. }
  97. _compute(model, selection, wordSeparators, token) {
  98. return getOccurrencesAtPosition(this._providers, model, selection.getPosition(), token).then(value => value || []);
  99. }
  100. }
  101. class TextualOccurenceAtPositionRequest extends OccurenceAtPositionRequest {
  102. constructor(model, selection, wordSeparators) {
  103. super(model, selection, wordSeparators);
  104. this._selectionIsEmpty = selection.isEmpty();
  105. }
  106. _compute(model, selection, wordSeparators, token) {
  107. return timeout(250, token).then(() => {
  108. if (!selection.isEmpty()) {
  109. return [];
  110. }
  111. const word = model.getWordAtPosition(selection.getPosition());
  112. if (!word || word.word.length > 1000) {
  113. return [];
  114. }
  115. const matches = model.findMatches(word.word, true, false, true, wordSeparators, false);
  116. return matches.map(m => {
  117. return {
  118. range: m.range,
  119. kind: DocumentHighlightKind.Text
  120. };
  121. });
  122. });
  123. }
  124. isValid(model, selection, decorations) {
  125. const currentSelectionIsEmpty = selection.isEmpty();
  126. if (this._selectionIsEmpty !== currentSelectionIsEmpty) {
  127. return false;
  128. }
  129. return super.isValid(model, selection, decorations);
  130. }
  131. }
  132. function computeOccurencesAtPosition(registry, model, selection, wordSeparators) {
  133. if (registry.has(model)) {
  134. return new SemanticOccurenceAtPositionRequest(model, selection, wordSeparators, registry);
  135. }
  136. return new TextualOccurenceAtPositionRequest(model, selection, wordSeparators);
  137. }
  138. registerModelAndPositionCommand('_executeDocumentHighlights', (accessor, model, position) => {
  139. const languageFeaturesService = accessor.get(ILanguageFeaturesService);
  140. return getOccurrencesAtPosition(languageFeaturesService.documentHighlightProvider, model, position, CancellationToken.None);
  141. });
  142. class WordHighlighter {
  143. constructor(editor, providers, contextKeyService) {
  144. this.toUnhook = new DisposableStore();
  145. this.workerRequestTokenId = 0;
  146. this.workerRequestCompleted = false;
  147. this.workerRequestValue = [];
  148. this.lastCursorPositionChangeTime = 0;
  149. this.renderDecorationsTimer = -1;
  150. this.editor = editor;
  151. this.providers = providers;
  152. this._hasWordHighlights = ctxHasWordHighlights.bindTo(contextKeyService);
  153. this._ignorePositionChangeEvent = false;
  154. this.occurrencesHighlight = this.editor.getOption(74 /* EditorOption.occurrencesHighlight */);
  155. this.model = this.editor.getModel();
  156. this.toUnhook.add(editor.onDidChangeCursorPosition((e) => {
  157. if (this._ignorePositionChangeEvent) {
  158. // We are changing the position => ignore this event
  159. return;
  160. }
  161. if (!this.occurrencesHighlight) {
  162. // Early exit if nothing needs to be done!
  163. // Leave some form of early exit check here if you wish to continue being a cursor position change listener ;)
  164. return;
  165. }
  166. this._onPositionChanged(e);
  167. }));
  168. this.toUnhook.add(editor.onDidChangeModelContent((e) => {
  169. this._stopAll();
  170. }));
  171. this.toUnhook.add(editor.onDidChangeConfiguration((e) => {
  172. const newValue = this.editor.getOption(74 /* EditorOption.occurrencesHighlight */);
  173. if (this.occurrencesHighlight !== newValue) {
  174. this.occurrencesHighlight = newValue;
  175. this._stopAll();
  176. }
  177. }));
  178. this.decorations = this.editor.createDecorationsCollection();
  179. this.workerRequestTokenId = 0;
  180. this.workerRequest = null;
  181. this.workerRequestCompleted = false;
  182. this.lastCursorPositionChangeTime = 0;
  183. this.renderDecorationsTimer = -1;
  184. }
  185. hasDecorations() {
  186. return (this.decorations.length > 0);
  187. }
  188. restore() {
  189. if (!this.occurrencesHighlight) {
  190. return;
  191. }
  192. this._run();
  193. }
  194. _getSortedHighlights() {
  195. return (this.decorations.getRanges()
  196. .sort(Range.compareRangesUsingStarts));
  197. }
  198. moveNext() {
  199. const highlights = this._getSortedHighlights();
  200. const index = highlights.findIndex((range) => range.containsPosition(this.editor.getPosition()));
  201. const newIndex = ((index + 1) % highlights.length);
  202. const dest = highlights[newIndex];
  203. try {
  204. this._ignorePositionChangeEvent = true;
  205. this.editor.setPosition(dest.getStartPosition());
  206. this.editor.revealRangeInCenterIfOutsideViewport(dest);
  207. const word = this._getWord();
  208. if (word) {
  209. const lineContent = this.editor.getModel().getLineContent(dest.startLineNumber);
  210. alert(`${lineContent}, ${newIndex + 1} of ${highlights.length} for '${word.word}'`);
  211. }
  212. }
  213. finally {
  214. this._ignorePositionChangeEvent = false;
  215. }
  216. }
  217. moveBack() {
  218. const highlights = this._getSortedHighlights();
  219. const index = highlights.findIndex((range) => range.containsPosition(this.editor.getPosition()));
  220. const newIndex = ((index - 1 + highlights.length) % highlights.length);
  221. const dest = highlights[newIndex];
  222. try {
  223. this._ignorePositionChangeEvent = true;
  224. this.editor.setPosition(dest.getStartPosition());
  225. this.editor.revealRangeInCenterIfOutsideViewport(dest);
  226. const word = this._getWord();
  227. if (word) {
  228. const lineContent = this.editor.getModel().getLineContent(dest.startLineNumber);
  229. alert(`${lineContent}, ${newIndex + 1} of ${highlights.length} for '${word.word}'`);
  230. }
  231. }
  232. finally {
  233. this._ignorePositionChangeEvent = false;
  234. }
  235. }
  236. _removeDecorations() {
  237. if (this.decorations.length > 0) {
  238. // remove decorations
  239. this.decorations.clear();
  240. this._hasWordHighlights.set(false);
  241. }
  242. }
  243. _stopAll() {
  244. // Remove any existing decorations
  245. this._removeDecorations();
  246. // Cancel any renderDecorationsTimer
  247. if (this.renderDecorationsTimer !== -1) {
  248. clearTimeout(this.renderDecorationsTimer);
  249. this.renderDecorationsTimer = -1;
  250. }
  251. // Cancel any worker request
  252. if (this.workerRequest !== null) {
  253. this.workerRequest.cancel();
  254. this.workerRequest = null;
  255. }
  256. // Invalidate any worker request callback
  257. if (!this.workerRequestCompleted) {
  258. this.workerRequestTokenId++;
  259. this.workerRequestCompleted = true;
  260. }
  261. }
  262. _onPositionChanged(e) {
  263. // disabled
  264. if (!this.occurrencesHighlight) {
  265. this._stopAll();
  266. return;
  267. }
  268. // ignore typing & other
  269. if (e.reason !== 3 /* CursorChangeReason.Explicit */) {
  270. this._stopAll();
  271. return;
  272. }
  273. this._run();
  274. }
  275. _getWord() {
  276. const editorSelection = this.editor.getSelection();
  277. const lineNumber = editorSelection.startLineNumber;
  278. const startColumn = editorSelection.startColumn;
  279. return this.model.getWordAtPosition({
  280. lineNumber: lineNumber,
  281. column: startColumn
  282. });
  283. }
  284. _run() {
  285. const editorSelection = this.editor.getSelection();
  286. // ignore multiline selection
  287. if (editorSelection.startLineNumber !== editorSelection.endLineNumber) {
  288. this._stopAll();
  289. return;
  290. }
  291. const startColumn = editorSelection.startColumn;
  292. const endColumn = editorSelection.endColumn;
  293. const word = this._getWord();
  294. // The selection must be inside a word or surround one word at most
  295. if (!word || word.startColumn > startColumn || word.endColumn < endColumn) {
  296. this._stopAll();
  297. return;
  298. }
  299. // All the effort below is trying to achieve this:
  300. // - when cursor is moved to a word, trigger immediately a findOccurrences request
  301. // - 250ms later after the last cursor move event, render the occurrences
  302. // - no flickering!
  303. const workerRequestIsValid = (this.workerRequest && this.workerRequest.isValid(this.model, editorSelection, this.decorations));
  304. // There are 4 cases:
  305. // a) old workerRequest is valid & completed, renderDecorationsTimer fired
  306. // b) old workerRequest is valid & completed, renderDecorationsTimer not fired
  307. // c) old workerRequest is valid, but not completed
  308. // d) old workerRequest is not valid
  309. // For a) no action is needed
  310. // For c), member 'lastCursorPositionChangeTime' will be used when installing the timer so no action is needed
  311. this.lastCursorPositionChangeTime = (new Date()).getTime();
  312. if (workerRequestIsValid) {
  313. if (this.workerRequestCompleted && this.renderDecorationsTimer !== -1) {
  314. // case b)
  315. // Delay the firing of renderDecorationsTimer by an extra 250 ms
  316. clearTimeout(this.renderDecorationsTimer);
  317. this.renderDecorationsTimer = -1;
  318. this._beginRenderDecorations();
  319. }
  320. }
  321. else {
  322. // case d)
  323. // Stop all previous actions and start fresh
  324. this._stopAll();
  325. const myRequestId = ++this.workerRequestTokenId;
  326. this.workerRequestCompleted = false;
  327. this.workerRequest = computeOccurencesAtPosition(this.providers, this.model, this.editor.getSelection(), this.editor.getOption(119 /* EditorOption.wordSeparators */));
  328. this.workerRequest.result.then(data => {
  329. if (myRequestId === this.workerRequestTokenId) {
  330. this.workerRequestCompleted = true;
  331. this.workerRequestValue = data || [];
  332. this._beginRenderDecorations();
  333. }
  334. }, onUnexpectedError);
  335. }
  336. }
  337. _beginRenderDecorations() {
  338. const currentTime = (new Date()).getTime();
  339. const minimumRenderTime = this.lastCursorPositionChangeTime + 250;
  340. if (currentTime >= minimumRenderTime) {
  341. // Synchronous
  342. this.renderDecorationsTimer = -1;
  343. this.renderDecorations();
  344. }
  345. else {
  346. // Asynchronous
  347. this.renderDecorationsTimer = setTimeout(() => {
  348. this.renderDecorations();
  349. }, (minimumRenderTime - currentTime));
  350. }
  351. }
  352. renderDecorations() {
  353. this.renderDecorationsTimer = -1;
  354. const decorations = [];
  355. for (const info of this.workerRequestValue) {
  356. if (info.range) {
  357. decorations.push({
  358. range: info.range,
  359. options: WordHighlighter._getDecorationOptions(info.kind)
  360. });
  361. }
  362. }
  363. this.decorations.set(decorations);
  364. this._hasWordHighlights.set(this.hasDecorations());
  365. }
  366. static _getDecorationOptions(kind) {
  367. if (kind === DocumentHighlightKind.Write) {
  368. return this._WRITE_OPTIONS;
  369. }
  370. else if (kind === DocumentHighlightKind.Text) {
  371. return this._TEXT_OPTIONS;
  372. }
  373. else {
  374. return this._REGULAR_OPTIONS;
  375. }
  376. }
  377. dispose() {
  378. this._stopAll();
  379. this.toUnhook.dispose();
  380. }
  381. }
  382. WordHighlighter._WRITE_OPTIONS = ModelDecorationOptions.register({
  383. description: 'word-highlight-strong',
  384. stickiness: 1 /* TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges */,
  385. className: 'wordHighlightStrong',
  386. overviewRuler: {
  387. color: themeColorFromId(overviewRulerWordHighlightStrongForeground),
  388. position: OverviewRulerLane.Center
  389. },
  390. minimap: {
  391. color: themeColorFromId(minimapSelectionOccurrenceHighlight),
  392. position: MinimapPosition.Inline
  393. },
  394. });
  395. WordHighlighter._TEXT_OPTIONS = ModelDecorationOptions.register({
  396. description: 'selection-highlight',
  397. stickiness: 1 /* TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges */,
  398. className: 'selectionHighlight',
  399. overviewRuler: {
  400. color: themeColorFromId(overviewRulerSelectionHighlightForeground),
  401. position: OverviewRulerLane.Center
  402. },
  403. minimap: {
  404. color: themeColorFromId(minimapSelectionOccurrenceHighlight),
  405. position: MinimapPosition.Inline
  406. },
  407. });
  408. WordHighlighter._REGULAR_OPTIONS = ModelDecorationOptions.register({
  409. description: 'word-highlight',
  410. stickiness: 1 /* TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges */,
  411. className: 'wordHighlight',
  412. overviewRuler: {
  413. color: themeColorFromId(overviewRulerWordHighlightForeground),
  414. position: OverviewRulerLane.Center
  415. },
  416. minimap: {
  417. color: themeColorFromId(minimapSelectionOccurrenceHighlight),
  418. position: MinimapPosition.Inline
  419. },
  420. });
  421. let WordHighlighterContribution = class WordHighlighterContribution extends Disposable {
  422. constructor(editor, contextKeyService, languageFeaturesService) {
  423. super();
  424. this.wordHighlighter = null;
  425. const createWordHighlighterIfPossible = () => {
  426. if (editor.hasModel()) {
  427. this.wordHighlighter = new WordHighlighter(editor, languageFeaturesService.documentHighlightProvider, contextKeyService);
  428. }
  429. };
  430. this._register(editor.onDidChangeModel((e) => {
  431. if (this.wordHighlighter) {
  432. this.wordHighlighter.dispose();
  433. this.wordHighlighter = null;
  434. }
  435. createWordHighlighterIfPossible();
  436. }));
  437. createWordHighlighterIfPossible();
  438. }
  439. static get(editor) {
  440. return editor.getContribution(WordHighlighterContribution.ID);
  441. }
  442. saveViewState() {
  443. if (this.wordHighlighter && this.wordHighlighter.hasDecorations()) {
  444. return true;
  445. }
  446. return false;
  447. }
  448. moveNext() {
  449. if (this.wordHighlighter) {
  450. this.wordHighlighter.moveNext();
  451. }
  452. }
  453. moveBack() {
  454. if (this.wordHighlighter) {
  455. this.wordHighlighter.moveBack();
  456. }
  457. }
  458. restoreViewState(state) {
  459. if (this.wordHighlighter && state) {
  460. this.wordHighlighter.restore();
  461. }
  462. }
  463. dispose() {
  464. if (this.wordHighlighter) {
  465. this.wordHighlighter.dispose();
  466. this.wordHighlighter = null;
  467. }
  468. super.dispose();
  469. }
  470. };
  471. WordHighlighterContribution.ID = 'editor.contrib.wordHighlighter';
  472. WordHighlighterContribution = __decorate([
  473. __param(1, IContextKeyService),
  474. __param(2, ILanguageFeaturesService)
  475. ], WordHighlighterContribution);
  476. class WordHighlightNavigationAction extends EditorAction {
  477. constructor(next, opts) {
  478. super(opts);
  479. this._isNext = next;
  480. }
  481. run(accessor, editor) {
  482. const controller = WordHighlighterContribution.get(editor);
  483. if (!controller) {
  484. return;
  485. }
  486. if (this._isNext) {
  487. controller.moveNext();
  488. }
  489. else {
  490. controller.moveBack();
  491. }
  492. }
  493. }
  494. class NextWordHighlightAction extends WordHighlightNavigationAction {
  495. constructor() {
  496. super(true, {
  497. id: 'editor.action.wordHighlight.next',
  498. label: nls.localize('wordHighlight.next.label', "Go to Next Symbol Highlight"),
  499. alias: 'Go to Next Symbol Highlight',
  500. precondition: ctxHasWordHighlights,
  501. kbOpts: {
  502. kbExpr: EditorContextKeys.editorTextFocus,
  503. primary: 65 /* KeyCode.F7 */,
  504. weight: 100 /* KeybindingWeight.EditorContrib */
  505. }
  506. });
  507. }
  508. }
  509. class PrevWordHighlightAction extends WordHighlightNavigationAction {
  510. constructor() {
  511. super(false, {
  512. id: 'editor.action.wordHighlight.prev',
  513. label: nls.localize('wordHighlight.previous.label', "Go to Previous Symbol Highlight"),
  514. alias: 'Go to Previous Symbol Highlight',
  515. precondition: ctxHasWordHighlights,
  516. kbOpts: {
  517. kbExpr: EditorContextKeys.editorTextFocus,
  518. primary: 1024 /* KeyMod.Shift */ | 65 /* KeyCode.F7 */,
  519. weight: 100 /* KeybindingWeight.EditorContrib */
  520. }
  521. });
  522. }
  523. }
  524. class TriggerWordHighlightAction extends EditorAction {
  525. constructor() {
  526. super({
  527. id: 'editor.action.wordHighlight.trigger',
  528. label: nls.localize('wordHighlight.trigger.label', "Trigger Symbol Highlight"),
  529. alias: 'Trigger Symbol Highlight',
  530. precondition: ctxHasWordHighlights.toNegated(),
  531. kbOpts: {
  532. kbExpr: EditorContextKeys.editorTextFocus,
  533. primary: 0,
  534. weight: 100 /* KeybindingWeight.EditorContrib */
  535. }
  536. });
  537. }
  538. run(accessor, editor, args) {
  539. const controller = WordHighlighterContribution.get(editor);
  540. if (!controller) {
  541. return;
  542. }
  543. controller.restoreViewState(true);
  544. }
  545. }
  546. registerEditorContribution(WordHighlighterContribution.ID, WordHighlighterContribution);
  547. registerEditorAction(NextWordHighlightAction);
  548. registerEditorAction(PrevWordHighlightAction);
  549. registerEditorAction(TriggerWordHighlightAction);
  550. registerThemingParticipant((theme, collector) => {
  551. const selectionHighlight = theme.getColor(editorSelectionHighlight);
  552. if (selectionHighlight) {
  553. collector.addRule(`.monaco-editor .focused .selectionHighlight { background-color: ${selectionHighlight}; }`);
  554. collector.addRule(`.monaco-editor .selectionHighlight { background-color: ${selectionHighlight.transparent(0.5)}; }`);
  555. }
  556. const wordHighlight = theme.getColor(editorWordHighlight);
  557. if (wordHighlight) {
  558. collector.addRule(`.monaco-editor .wordHighlight { background-color: ${wordHighlight}; }`);
  559. }
  560. const wordHighlightStrong = theme.getColor(editorWordHighlightStrong);
  561. if (wordHighlightStrong) {
  562. collector.addRule(`.monaco-editor .wordHighlightStrong { background-color: ${wordHighlightStrong}; }`);
  563. }
  564. const selectionHighlightBorder = theme.getColor(editorSelectionHighlightBorder);
  565. if (selectionHighlightBorder) {
  566. collector.addRule(`.monaco-editor .selectionHighlight { border: 1px ${isHighContrast(theme.type) ? 'dotted' : 'solid'} ${selectionHighlightBorder}; box-sizing: border-box; }`);
  567. }
  568. const wordHighlightBorder = theme.getColor(editorWordHighlightBorder);
  569. if (wordHighlightBorder) {
  570. collector.addRule(`.monaco-editor .wordHighlight { border: 1px ${isHighContrast(theme.type) ? 'dashed' : 'solid'} ${wordHighlightBorder}; box-sizing: border-box; }`);
  571. }
  572. const wordHighlightStrongBorder = theme.getColor(editorWordHighlightStrongBorder);
  573. if (wordHighlightStrongBorder) {
  574. collector.addRule(`.monaco-editor .wordHighlightStrong { border: 1px ${isHighContrast(theme.type) ? 'dashed' : 'solid'} ${wordHighlightStrongBorder}; box-sizing: border-box; }`);
  575. }
  576. });