monaco-editor
Version:
A browser based code editor
771 lines (770 loc) • 35.2 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var WordHighlighter_1, WordHighlighterContribution_1;
import * as nls from '../../../../nls.js';
import * as arrays from '../../../../base/common/arrays.js';
import { alert } from '../../../../base/browser/ui/aria/aria.js';
import { createCancelablePromise, first, timeout } from '../../../../base/common/async.js';
import { CancellationToken } from '../../../../base/common/cancellation.js';
import { onUnexpectedError, onUnexpectedExternalError } from '../../../../base/common/errors.js';
import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js';
import { isDiffEditor } from '../../../browser/editorBrowser.js';
import { EditorAction, registerEditorAction, registerEditorContribution, registerModelAndPositionCommand } from '../../../browser/editorExtensions.js';
import { ICodeEditorService } from '../../../browser/services/codeEditorService.js';
import { Range } from '../../../common/core/range.js';
import { EditorContextKeys } from '../../../common/editorContextKeys.js';
import { DocumentHighlightKind } from '../../../common/languages.js';
import { shouldSynchronizeModel } from '../../../common/model.js';
import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js';
import { getHighlightDecorationOptions } from './highlightDecorations.js';
import { IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
import { Schemas } from '../../../../base/common/network.js';
import { ResourceMap } from '../../../../base/common/map.js';
import { score } from '../../../common/languageSelector.js';
// import { TextualMultiDocumentHighlightFeature } from 'vs/editor/contrib/wordHighlighter/browser/textualHighlightProvider';
// import { registerEditorFeature } from 'vs/editor/common/editorFeatures';
const ctxHasWordHighlights = new RawContextKey('hasWordHighlights', false);
export function getOccurrencesAtPosition(registry, model, position, token) {
const orderedByScore = registry.ordered(model);
// in order of score ask the occurrences provider
// until someone response with a good result
// (good = none empty array)
return first(orderedByScore.map(provider => () => {
return Promise.resolve(provider.provideDocumentHighlights(model, position, token))
.then(undefined, onUnexpectedExternalError);
}), arrays.isNonEmptyArray).then(result => {
if (result) {
const map = new ResourceMap();
map.set(model.uri, result);
return map;
}
return new ResourceMap();
});
}
export function getOccurrencesAcrossMultipleModels(registry, model, position, wordSeparators, token, otherModels) {
const orderedByScore = registry.ordered(model);
// in order of score ask the occurrences provider
// until someone response with a good result
// (good = none empty array)
return first(orderedByScore.map(provider => () => {
const filteredModels = otherModels.filter(otherModel => {
return shouldSynchronizeModel(otherModel);
}).filter(otherModel => {
return score(provider.selector, otherModel.uri, otherModel.getLanguageId(), true, undefined, undefined) > 0;
});
return Promise.resolve(provider.provideMultiDocumentHighlights(model, position, filteredModels, token))
.then(undefined, onUnexpectedExternalError);
}), (t) => t instanceof ResourceMap && t.size > 0);
}
class OccurenceAtPositionRequest {
constructor(_model, _selection, _wordSeparators) {
this._model = _model;
this._selection = _selection;
this._wordSeparators = _wordSeparators;
this._wordRange = this._getCurrentWordRange(_model, _selection);
this._result = null;
}
get result() {
if (!this._result) {
this._result = createCancelablePromise(token => this._compute(this._model, this._selection, this._wordSeparators, token));
}
return this._result;
}
_getCurrentWordRange(model, selection) {
const word = model.getWordAtPosition(selection.getPosition());
if (word) {
return new Range(selection.startLineNumber, word.startColumn, selection.startLineNumber, word.endColumn);
}
return null;
}
isValid(model, selection, decorations) {
const lineNumber = selection.startLineNumber;
const startColumn = selection.startColumn;
const endColumn = selection.endColumn;
const currentWordRange = this._getCurrentWordRange(model, selection);
let requestIsValid = Boolean(this._wordRange && this._wordRange.equalsRange(currentWordRange));
// Even if we are on a different word, if that word is in the decorations ranges, the request is still valid
// (Same symbol)
for (let i = 0, len = decorations.length; !requestIsValid && i < len; i++) {
const range = decorations.getRange(i);
if (range && range.startLineNumber === lineNumber) {
if (range.startColumn <= startColumn && range.endColumn >= endColumn) {
requestIsValid = true;
}
}
}
return requestIsValid;
}
cancel() {
this.result.cancel();
}
}
class SemanticOccurenceAtPositionRequest extends OccurenceAtPositionRequest {
constructor(model, selection, wordSeparators, providers) {
super(model, selection, wordSeparators);
this._providers = providers;
}
_compute(model, selection, wordSeparators, token) {
return getOccurrencesAtPosition(this._providers, model, selection.getPosition(), token).then(value => {
if (!value) {
return new ResourceMap();
}
return value;
});
}
}
class MultiModelOccurenceRequest extends OccurenceAtPositionRequest {
constructor(model, selection, wordSeparators, providers, otherModels) {
super(model, selection, wordSeparators);
this._providers = providers;
this._otherModels = otherModels;
}
_compute(model, selection, wordSeparators, token) {
return getOccurrencesAcrossMultipleModels(this._providers, model, selection.getPosition(), wordSeparators, token, this._otherModels).then(value => {
if (!value) {
return new ResourceMap();
}
return value;
});
}
}
class TextualOccurenceRequest extends OccurenceAtPositionRequest {
constructor(model, selection, word, wordSeparators, otherModels) {
super(model, selection, wordSeparators);
this._otherModels = otherModels;
this._selectionIsEmpty = selection.isEmpty();
this._word = word;
}
_compute(model, selection, wordSeparators, token) {
return timeout(250, token).then(() => {
const result = new ResourceMap();
let wordResult;
if (this._word) {
wordResult = this._word;
}
else {
wordResult = model.getWordAtPosition(selection.getPosition());
}
if (!wordResult) {
return new ResourceMap();
}
const allModels = [model, ...this._otherModels];
for (const otherModel of allModels) {
if (otherModel.isDisposed()) {
continue;
}
const matches = otherModel.findMatches(wordResult.word, true, false, true, wordSeparators, false);
const highlights = matches.map(m => ({
range: m.range,
kind: DocumentHighlightKind.Text
}));
if (highlights) {
result.set(otherModel.uri, highlights);
}
}
return result;
});
}
isValid(model, selection, decorations) {
const currentSelectionIsEmpty = selection.isEmpty();
if (this._selectionIsEmpty !== currentSelectionIsEmpty) {
return false;
}
return super.isValid(model, selection, decorations);
}
}
function computeOccurencesAtPosition(registry, model, selection, word, wordSeparators) {
if (registry.has(model)) {
return new SemanticOccurenceAtPositionRequest(model, selection, wordSeparators, registry);
}
return new TextualOccurenceRequest(model, selection, word, wordSeparators, []);
}
function computeOccurencesMultiModel(registry, model, selection, word, wordSeparators, otherModels) {
if (registry.has(model)) {
return new MultiModelOccurenceRequest(model, selection, wordSeparators, registry, otherModels);
}
return new TextualOccurenceRequest(model, selection, word, wordSeparators, otherModels);
}
registerModelAndPositionCommand('_executeDocumentHighlights', async (accessor, model, position) => {
const languageFeaturesService = accessor.get(ILanguageFeaturesService);
const map = await getOccurrencesAtPosition(languageFeaturesService.documentHighlightProvider, model, position, CancellationToken.None);
return map === null || map === void 0 ? void 0 : map.get(model.uri);
});
let WordHighlighter = WordHighlighter_1 = class WordHighlighter {
constructor(editor, providers, multiProviders, contextKeyService, codeEditorService) {
this.toUnhook = new DisposableStore();
this.workerRequestTokenId = 0;
this.workerRequestCompleted = false;
this.workerRequestValue = new ResourceMap();
this.lastCursorPositionChangeTime = 0;
this.renderDecorationsTimer = -1;
this.editor = editor;
this.providers = providers;
this.multiDocumentProviders = multiProviders;
this.codeEditorService = codeEditorService;
this._hasWordHighlights = ctxHasWordHighlights.bindTo(contextKeyService);
this._ignorePositionChangeEvent = false;
this.occurrencesHighlight = this.editor.getOption(80 /* EditorOption.occurrencesHighlight */);
this.model = this.editor.getModel();
this.toUnhook.add(editor.onDidChangeCursorPosition((e) => {
if (this._ignorePositionChangeEvent) {
// We are changing the position => ignore this event
return;
}
if (this.occurrencesHighlight === 'off') {
// Early exit if nothing needs to be done!
// Leave some form of early exit check here if you wish to continue being a cursor position change listener ;)
return;
}
this._onPositionChanged(e);
}));
this.toUnhook.add(editor.onDidChangeModelContent((e) => {
this._stopAll();
}));
this.toUnhook.add(editor.onDidChangeModel((e) => {
if (!e.newModelUrl && e.oldModelUrl) {
this._stopSingular();
}
else {
if (WordHighlighter_1.query) {
this._run();
}
}
}));
this.toUnhook.add(editor.onDidChangeConfiguration((e) => {
const newValue = this.editor.getOption(80 /* EditorOption.occurrencesHighlight */);
if (this.occurrencesHighlight !== newValue) {
this.occurrencesHighlight = newValue;
this._stopAll();
}
}));
this.decorations = this.editor.createDecorationsCollection();
this.workerRequestTokenId = 0;
this.workerRequest = null;
this.workerRequestCompleted = false;
this.lastCursorPositionChangeTime = 0;
this.renderDecorationsTimer = -1;
// if there is a query already, highlight off that query
if (WordHighlighter_1.query) {
this._run();
}
}
hasDecorations() {
return (this.decorations.length > 0);
}
restore() {
if (this.occurrencesHighlight === 'off') {
return;
}
this._run();
}
_getSortedHighlights() {
return (this.decorations.getRanges()
.sort(Range.compareRangesUsingStarts));
}
moveNext() {
const highlights = this._getSortedHighlights();
const index = highlights.findIndex((range) => range.containsPosition(this.editor.getPosition()));
const newIndex = ((index + 1) % highlights.length);
const dest = highlights[newIndex];
try {
this._ignorePositionChangeEvent = true;
this.editor.setPosition(dest.getStartPosition());
this.editor.revealRangeInCenterIfOutsideViewport(dest);
const word = this._getWord();
if (word) {
const lineContent = this.editor.getModel().getLineContent(dest.startLineNumber);
alert(`${lineContent}, ${newIndex + 1} of ${highlights.length} for '${word.word}'`);
}
}
finally {
this._ignorePositionChangeEvent = false;
}
}
moveBack() {
const highlights = this._getSortedHighlights();
const index = highlights.findIndex((range) => range.containsPosition(this.editor.getPosition()));
const newIndex = ((index - 1 + highlights.length) % highlights.length);
const dest = highlights[newIndex];
try {
this._ignorePositionChangeEvent = true;
this.editor.setPosition(dest.getStartPosition());
this.editor.revealRangeInCenterIfOutsideViewport(dest);
const word = this._getWord();
if (word) {
const lineContent = this.editor.getModel().getLineContent(dest.startLineNumber);
alert(`${lineContent}, ${newIndex + 1} of ${highlights.length} for '${word.word}'`);
}
}
finally {
this._ignorePositionChangeEvent = false;
}
}
_removeSingleDecorations() {
// return if no model
if (!this.editor.hasModel()) {
return;
}
const currentDecorationIDs = WordHighlighter_1.storedDecorations.get(this.editor.getModel().uri);
if (!currentDecorationIDs) {
return;
}
this.editor.removeDecorations(currentDecorationIDs);
WordHighlighter_1.storedDecorations.delete(this.editor.getModel().uri);
if (this.decorations.length > 0) {
this.decorations.clear();
this._hasWordHighlights.set(false);
}
}
_removeAllDecorations() {
const currentEditors = this.codeEditorService.listCodeEditors();
// iterate over editors and store models in currentModels
for (const editor of currentEditors) {
if (!editor.hasModel()) {
continue;
}
const currentDecorationIDs = WordHighlighter_1.storedDecorations.get(editor.getModel().uri);
if (!currentDecorationIDs) {
continue;
}
editor.removeDecorations(currentDecorationIDs);
WordHighlighter_1.storedDecorations.delete(editor.getModel().uri);
const editorHighlighterContrib = WordHighlighterContribution.get(editor);
if (!(editorHighlighterContrib === null || editorHighlighterContrib === void 0 ? void 0 : editorHighlighterContrib.wordHighlighter)) {
continue;
}
if (editorHighlighterContrib.wordHighlighter.decorations.length > 0) {
editorHighlighterContrib.wordHighlighter.decorations.clear();
editorHighlighterContrib.wordHighlighter._hasWordHighlights.set(false);
}
}
}
_stopSingular() {
var _a, _b, _c, _d;
// Remove any existing decorations + a possible query, and re - run to update decorations
this._removeSingleDecorations();
if (this.editor.hasWidgetFocus()) {
if (((_a = this.editor.getModel()) === null || _a === void 0 ? void 0 : _a.uri.scheme) !== Schemas.vscodeNotebookCell && ((_c = (_b = WordHighlighter_1.query) === null || _b === void 0 ? void 0 : _b.modelInfo) === null || _c === void 0 ? void 0 : _c.model.uri.scheme) !== Schemas.vscodeNotebookCell) { // clear query if focused non-nb editor
WordHighlighter_1.query = null;
this._run();
}
else { // remove modelInfo to account for nb cell being disposed
if ((_d = WordHighlighter_1.query) === null || _d === void 0 ? void 0 : _d.modelInfo) {
WordHighlighter_1.query.modelInfo = null;
}
}
}
// Cancel any renderDecorationsTimer
if (this.renderDecorationsTimer !== -1) {
clearTimeout(this.renderDecorationsTimer);
this.renderDecorationsTimer = -1;
}
// Cancel any worker request
if (this.workerRequest !== null) {
this.workerRequest.cancel();
this.workerRequest = null;
}
// Invalidate any worker request callback
if (!this.workerRequestCompleted) {
this.workerRequestTokenId++;
this.workerRequestCompleted = true;
}
}
_stopAll() {
// Remove any existing decorations
this._removeAllDecorations();
// Cancel any renderDecorationsTimer
if (this.renderDecorationsTimer !== -1) {
clearTimeout(this.renderDecorationsTimer);
this.renderDecorationsTimer = -1;
}
// Cancel any worker request
if (this.workerRequest !== null) {
this.workerRequest.cancel();
this.workerRequest = null;
}
// Invalidate any worker request callback
if (!this.workerRequestCompleted) {
this.workerRequestTokenId++;
this.workerRequestCompleted = true;
}
}
_onPositionChanged(e) {
var _a;
// disabled
if (this.occurrencesHighlight === 'off') {
this._stopAll();
return;
}
// ignore typing & other
// need to check if the model is a notebook cell, should not stop if nb
if (e.reason !== 3 /* CursorChangeReason.Explicit */ && ((_a = this.editor.getModel()) === null || _a === void 0 ? void 0 : _a.uri.scheme) !== Schemas.vscodeNotebookCell) {
this._stopAll();
return;
}
this._run();
}
_getWord() {
const editorSelection = this.editor.getSelection();
const lineNumber = editorSelection.startLineNumber;
const startColumn = editorSelection.startColumn;
if (this.model.isDisposed()) {
return null;
}
return this.model.getWordAtPosition({
lineNumber: lineNumber,
column: startColumn
});
}
getOtherModelsToHighlight(model) {
if (!model) {
return [];
}
// notebook case
const isNotebookEditor = model.uri.scheme === Schemas.vscodeNotebookCell;
if (isNotebookEditor) {
const currentModels = [];
const currentEditors = this.codeEditorService.listCodeEditors();
for (const editor of currentEditors) {
const tempModel = editor.getModel();
if (tempModel && tempModel !== model && tempModel.uri.scheme === Schemas.vscodeNotebookCell) {
currentModels.push(tempModel);
}
}
return currentModels;
}
// inline case
// ? current works when highlighting outside of an inline diff, highlighting in.
// ? broken when highlighting within a diff editor. highlighting the main editor does not work
// ? editor group service could be useful here
const currentModels = [];
const currentEditors = this.codeEditorService.listCodeEditors();
for (const editor of currentEditors) {
if (!isDiffEditor(editor)) {
continue;
}
const diffModel = editor.getModel();
if (!diffModel) {
continue;
}
if (model === diffModel.modified) { // embedded inline chat diff would pass this, allowing highlights
//? currentModels.push(diffModel.original);
currentModels.push(diffModel.modified);
}
}
if (currentModels.length) { // no matching editors have been found
return currentModels;
}
// multi-doc OFF
if (this.occurrencesHighlight === 'singleFile') {
return [];
}
// multi-doc ON
for (const editor of currentEditors) {
const tempModel = editor.getModel();
const isValidModel = tempModel && tempModel !== model;
if (isValidModel) {
currentModels.push(tempModel);
}
}
return currentModels;
}
_run() {
var _a, _b;
let workerRequestIsValid;
if (!this.editor.hasWidgetFocus()) { // no focus (new nb cell, etc)
if (WordHighlighter_1.query === null) {
// no previous query, nothing to highlight
return;
}
}
else {
const editorSelection = this.editor.getSelection();
// ignore multiline selection
if (!editorSelection || editorSelection.startLineNumber !== editorSelection.endLineNumber) {
this._stopAll();
return;
}
const startColumn = editorSelection.startColumn;
const endColumn = editorSelection.endColumn;
const word = this._getWord();
// The selection must be inside a word or surround one word at most
if (!word || word.startColumn > startColumn || word.endColumn < endColumn) {
// no previous query, nothing to highlight
WordHighlighter_1.query = null;
this._stopAll();
return;
}
// All the effort below is trying to achieve this:
// - when cursor is moved to a word, trigger immediately a findOccurrences request
// - 250ms later after the last cursor move event, render the occurrences
// - no flickering!
workerRequestIsValid = (this.workerRequest && this.workerRequest.isValid(this.model, editorSelection, this.decorations));
WordHighlighter_1.query = {
modelInfo: {
model: this.model,
selection: editorSelection,
},
word: word
};
}
// There are 4 cases:
// a) old workerRequest is valid & completed, renderDecorationsTimer fired
// b) old workerRequest is valid & completed, renderDecorationsTimer not fired
// c) old workerRequest is valid, but not completed
// d) old workerRequest is not valid
// For a) no action is needed
// For c), member 'lastCursorPositionChangeTime' will be used when installing the timer so no action is needed
this.lastCursorPositionChangeTime = (new Date()).getTime();
if (workerRequestIsValid) {
if (this.workerRequestCompleted && this.renderDecorationsTimer !== -1) {
// case b)
// Delay the firing of renderDecorationsTimer by an extra 250 ms
clearTimeout(this.renderDecorationsTimer);
this.renderDecorationsTimer = -1;
this._beginRenderDecorations();
}
}
else {
// case d)
// Stop all previous actions and start fresh
this._stopAll();
const myRequestId = ++this.workerRequestTokenId;
this.workerRequestCompleted = false;
const otherModelsToHighlight = this.getOtherModelsToHighlight(this.editor.getModel());
// 2 cases where we want to send the word
// a) there is no stored query model, but there is a word. This signals the editor that drove the highlight is disposed (cell out of viewport, etc)
// b) the queried model is not the current model. This signals that the editor that drove the highlight is still in the viewport, but we are highlighting a different cell
// otherwise, we send null in place of the word, and the model and selection are used to compute the word
const sendWord = (!WordHighlighter_1.query.modelInfo && WordHighlighter_1.query.word) ||
(((_a = WordHighlighter_1.query.modelInfo) === null || _a === void 0 ? void 0 : _a.model.uri) !== this.model.uri)
? true : false;
if (!WordHighlighter_1.query.modelInfo || (WordHighlighter_1.query.modelInfo.model.uri !== this.model.uri)) { // use this.model
this.workerRequest = this.computeWithModel(this.model, this.editor.getSelection(), sendWord ? WordHighlighter_1.query.word : null, otherModelsToHighlight);
}
else { // use stored query model + selection
this.workerRequest = this.computeWithModel(WordHighlighter_1.query.modelInfo.model, WordHighlighter_1.query.modelInfo.selection, WordHighlighter_1.query.word, otherModelsToHighlight);
}
(_b = this.workerRequest) === null || _b === void 0 ? void 0 : _b.result.then(data => {
if (myRequestId === this.workerRequestTokenId) {
this.workerRequestCompleted = true;
this.workerRequestValue = data || [];
this._beginRenderDecorations();
}
}, onUnexpectedError);
}
}
computeWithModel(model, selection, word, otherModels) {
if (!otherModels.length) {
return computeOccurencesAtPosition(this.providers, model, selection, word, this.editor.getOption(129 /* EditorOption.wordSeparators */));
}
else {
return computeOccurencesMultiModel(this.multiDocumentProviders, model, selection, word, this.editor.getOption(129 /* EditorOption.wordSeparators */), otherModels);
}
}
_beginRenderDecorations() {
const currentTime = (new Date()).getTime();
const minimumRenderTime = this.lastCursorPositionChangeTime + 250;
if (currentTime >= minimumRenderTime) {
// Synchronous
this.renderDecorationsTimer = -1;
this.renderDecorations();
}
else {
// Asynchronous
this.renderDecorationsTimer = setTimeout(() => {
this.renderDecorations();
}, (minimumRenderTime - currentTime));
}
}
renderDecorations() {
var _a, _b, _c;
this.renderDecorationsTimer = -1;
// create new loop, iterate over current editors using this.codeEditorService.listCodeEditors(),
// if the URI of that codeEditor is in the map, then add the decorations to the decorations array
// then set the decorations for the editor
const currentEditors = this.codeEditorService.listCodeEditors();
for (const editor of currentEditors) {
const editorHighlighterContrib = WordHighlighterContribution.get(editor);
if (!editorHighlighterContrib) {
continue;
}
const newDecorations = [];
const uri = (_a = editor.getModel()) === null || _a === void 0 ? void 0 : _a.uri;
if (uri && this.workerRequestValue.has(uri)) {
const oldDecorationIDs = WordHighlighter_1.storedDecorations.get(uri);
const newDocumentHighlights = this.workerRequestValue.get(uri);
if (newDocumentHighlights) {
for (const highlight of newDocumentHighlights) {
newDecorations.push({
range: highlight.range,
options: getHighlightDecorationOptions(highlight.kind)
});
}
}
let newDecorationIDs = [];
editor.changeDecorations((changeAccessor) => {
newDecorationIDs = changeAccessor.deltaDecorations(oldDecorationIDs !== null && oldDecorationIDs !== void 0 ? oldDecorationIDs : [], newDecorations);
});
WordHighlighter_1.storedDecorations = WordHighlighter_1.storedDecorations.set(uri, newDecorationIDs);
if (newDecorations.length > 0) {
(_b = editorHighlighterContrib.wordHighlighter) === null || _b === void 0 ? void 0 : _b.decorations.set(newDecorations);
(_c = editorHighlighterContrib.wordHighlighter) === null || _c === void 0 ? void 0 : _c._hasWordHighlights.set(true);
}
}
}
}
dispose() {
this._stopSingular();
this.toUnhook.dispose();
}
};
WordHighlighter.storedDecorations = new ResourceMap();
WordHighlighter.query = null;
WordHighlighter = WordHighlighter_1 = __decorate([
__param(4, ICodeEditorService)
], WordHighlighter);
let WordHighlighterContribution = WordHighlighterContribution_1 = class WordHighlighterContribution extends Disposable {
static get(editor) {
return editor.getContribution(WordHighlighterContribution_1.ID);
}
constructor(editor, contextKeyService, languageFeaturesService, codeEditorService) {
super();
this._wordHighlighter = null;
const createWordHighlighterIfPossible = () => {
if (editor.hasModel() && !editor.getModel().isTooLargeForTokenization()) {
this._wordHighlighter = new WordHighlighter(editor, languageFeaturesService.documentHighlightProvider, languageFeaturesService.multiDocumentHighlightProvider, contextKeyService, codeEditorService);
}
};
this._register(editor.onDidChangeModel((e) => {
if (this._wordHighlighter) {
this._wordHighlighter.dispose();
this._wordHighlighter = null;
}
createWordHighlighterIfPossible();
}));
createWordHighlighterIfPossible();
}
get wordHighlighter() {
return this._wordHighlighter;
}
saveViewState() {
if (this._wordHighlighter && this._wordHighlighter.hasDecorations()) {
return true;
}
return false;
}
moveNext() {
var _a;
(_a = this._wordHighlighter) === null || _a === void 0 ? void 0 : _a.moveNext();
}
moveBack() {
var _a;
(_a = this._wordHighlighter) === null || _a === void 0 ? void 0 : _a.moveBack();
}
restoreViewState(state) {
if (this._wordHighlighter && state) {
this._wordHighlighter.restore();
}
}
dispose() {
if (this._wordHighlighter) {
this._wordHighlighter.dispose();
this._wordHighlighter = null;
}
super.dispose();
}
};
WordHighlighterContribution.ID = 'editor.contrib.wordHighlighter';
WordHighlighterContribution = WordHighlighterContribution_1 = __decorate([
__param(1, IContextKeyService),
__param(2, ILanguageFeaturesService),
__param(3, ICodeEditorService)
], WordHighlighterContribution);
export { WordHighlighterContribution };
class WordHighlightNavigationAction extends EditorAction {
constructor(next, opts) {
super(opts);
this._isNext = next;
}
run(accessor, editor) {
const controller = WordHighlighterContribution.get(editor);
if (!controller) {
return;
}
if (this._isNext) {
controller.moveNext();
}
else {
controller.moveBack();
}
}
}
class NextWordHighlightAction extends WordHighlightNavigationAction {
constructor() {
super(true, {
id: 'editor.action.wordHighlight.next',
label: nls.localize('wordHighlight.next.label', "Go to Next Symbol Highlight"),
alias: 'Go to Next Symbol Highlight',
precondition: ctxHasWordHighlights,
kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus,
primary: 65 /* KeyCode.F7 */,
weight: 100 /* KeybindingWeight.EditorContrib */
}
});
}
}
class PrevWordHighlightAction extends WordHighlightNavigationAction {
constructor() {
super(false, {
id: 'editor.action.wordHighlight.prev',
label: nls.localize('wordHighlight.previous.label', "Go to Previous Symbol Highlight"),
alias: 'Go to Previous Symbol Highlight',
precondition: ctxHasWordHighlights,
kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus,
primary: 1024 /* KeyMod.Shift */ | 65 /* KeyCode.F7 */,
weight: 100 /* KeybindingWeight.EditorContrib */
}
});
}
}
class TriggerWordHighlightAction extends EditorAction {
constructor() {
super({
id: 'editor.action.wordHighlight.trigger',
label: nls.localize('wordHighlight.trigger.label', "Trigger Symbol Highlight"),
alias: 'Trigger Symbol Highlight',
precondition: ctxHasWordHighlights.toNegated(),
kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus,
primary: 0,
weight: 100 /* KeybindingWeight.EditorContrib */
}
});
}
run(accessor, editor, args) {
const controller = WordHighlighterContribution.get(editor);
if (!controller) {
return;
}
controller.restoreViewState(true);
}
}
registerEditorContribution(WordHighlighterContribution.ID, WordHighlighterContribution, 0 /* EditorContributionInstantiation.Eager */); // eager because it uses `saveViewState`/`restoreViewState`
registerEditorAction(NextWordHighlightAction);
registerEditorAction(PrevWordHighlightAction);
registerEditorAction(TriggerWordHighlightAction);
// registerEditorFeature(TextualMultiDocumentHighlightFeature);