| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- /*---------------------------------------------------------------------------------------------
- * 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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
- };
- import { IntervalTimer, timeout } from '../../../base/common/async.js';
- import { Disposable, dispose, toDisposable, DisposableStore } from '../../../base/common/lifecycle.js';
- import { SimpleWorkerClient, logOnceWebWorkerWarning } from '../../../base/common/worker/simpleWorker.js';
- import { DefaultWorkerFactory } from '../../../base/browser/defaultWorkerFactory.js';
- import { Range } from '../../common/core/range.js';
- import { ILanguageConfigurationService } from '../../common/languages/languageConfigurationRegistry.js';
- import { EditorSimpleWorker } from '../../common/services/editorSimpleWorker.js';
- import { IModelService } from '../../common/services/model.js';
- import { ITextResourceConfigurationService } from '../../common/services/textResourceConfiguration.js';
- import { regExpFlags } from '../../../base/common/strings.js';
- import { isNonEmptyArray } from '../../../base/common/arrays.js';
- import { ILogService } from '../../../platform/log/common/log.js';
- import { StopWatch } from '../../../base/common/stopwatch.js';
- import { canceled } from '../../../base/common/errors.js';
- import { ILanguageFeaturesService } from '../../common/services/languageFeatures.js';
- /**
- * Stop syncing a model to the worker if it was not needed for 1 min.
- */
- const STOP_SYNC_MODEL_DELTA_TIME_MS = 60 * 1000;
- /**
- * Stop the worker if it was not needed for 5 min.
- */
- const STOP_WORKER_DELTA_TIME_MS = 5 * 60 * 1000;
- function canSyncModel(modelService, resource) {
- const model = modelService.getModel(resource);
- if (!model) {
- return false;
- }
- if (model.isTooLargeForSyncing()) {
- return false;
- }
- return true;
- }
- let EditorWorkerService = class EditorWorkerService extends Disposable {
- constructor(modelService, configurationService, logService, languageConfigurationService, languageFeaturesService) {
- super();
- this._modelService = modelService;
- this._workerManager = this._register(new WorkerManager(this._modelService, languageConfigurationService));
- this._logService = logService;
- // register default link-provider and default completions-provider
- this._register(languageFeaturesService.linkProvider.register({ language: '*', hasAccessToAllModels: true }, {
- provideLinks: (model, token) => {
- if (!canSyncModel(this._modelService, model.uri)) {
- return Promise.resolve({ links: [] }); // File too large
- }
- return this._workerManager.withWorker().then(client => client.computeLinks(model.uri)).then(links => {
- return links && { links };
- });
- }
- }));
- this._register(languageFeaturesService.completionProvider.register('*', new WordBasedCompletionItemProvider(this._workerManager, configurationService, this._modelService, languageConfigurationService)));
- }
- dispose() {
- super.dispose();
- }
- canComputeUnicodeHighlights(uri) {
- return canSyncModel(this._modelService, uri);
- }
- computedUnicodeHighlights(uri, options, range) {
- return this._workerManager.withWorker().then(client => client.computedUnicodeHighlights(uri, options, range));
- }
- computeDiff(original, modified, ignoreTrimWhitespace, maxComputationTime) {
- return this._workerManager.withWorker().then(client => client.computeDiff(original, modified, ignoreTrimWhitespace, maxComputationTime));
- }
- computeMoreMinimalEdits(resource, edits) {
- if (isNonEmptyArray(edits)) {
- if (!canSyncModel(this._modelService, resource)) {
- return Promise.resolve(edits); // File too large
- }
- const sw = StopWatch.create(true);
- const result = this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits));
- result.finally(() => this._logService.trace('FORMAT#computeMoreMinimalEdits', resource.toString(true), sw.elapsed()));
- return Promise.race([result, timeout(1000).then(() => edits)]);
- }
- else {
- return Promise.resolve(undefined);
- }
- }
- canNavigateValueSet(resource) {
- return (canSyncModel(this._modelService, resource));
- }
- navigateValueSet(resource, range, up) {
- return this._workerManager.withWorker().then(client => client.navigateValueSet(resource, range, up));
- }
- canComputeWordRanges(resource) {
- return canSyncModel(this._modelService, resource);
- }
- computeWordRanges(resource, range) {
- return this._workerManager.withWorker().then(client => client.computeWordRanges(resource, range));
- }
- };
- EditorWorkerService = __decorate([
- __param(0, IModelService),
- __param(1, ITextResourceConfigurationService),
- __param(2, ILogService),
- __param(3, ILanguageConfigurationService),
- __param(4, ILanguageFeaturesService)
- ], EditorWorkerService);
- export { EditorWorkerService };
- class WordBasedCompletionItemProvider {
- constructor(workerManager, configurationService, modelService, languageConfigurationService) {
- this.languageConfigurationService = languageConfigurationService;
- this._debugDisplayName = 'wordbasedCompletions';
- this._workerManager = workerManager;
- this._configurationService = configurationService;
- this._modelService = modelService;
- }
- provideCompletionItems(model, position) {
- return __awaiter(this, void 0, void 0, function* () {
- const config = this._configurationService.getValue(model.uri, position, 'editor');
- if (!config.wordBasedSuggestions) {
- return undefined;
- }
- const models = [];
- if (config.wordBasedSuggestionsMode === 'currentDocument') {
- // only current file and only if not too large
- if (canSyncModel(this._modelService, model.uri)) {
- models.push(model.uri);
- }
- }
- else {
- // either all files or files of same language
- for (const candidate of this._modelService.getModels()) {
- if (!canSyncModel(this._modelService, candidate.uri)) {
- continue;
- }
- if (candidate === model) {
- models.unshift(candidate.uri);
- }
- else if (config.wordBasedSuggestionsMode === 'allDocuments' || candidate.getLanguageId() === model.getLanguageId()) {
- models.push(candidate.uri);
- }
- }
- }
- if (models.length === 0) {
- return undefined; // File too large, no other files
- }
- const wordDefRegExp = this.languageConfigurationService.getLanguageConfiguration(model.getLanguageId()).getWordDefinition();
- const word = model.getWordAtPosition(position);
- const replace = !word ? Range.fromPositions(position) : new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);
- const insert = replace.setEndPosition(position.lineNumber, position.column);
- const client = yield this._workerManager.withWorker();
- const data = yield client.textualSuggest(models, word === null || word === void 0 ? void 0 : word.word, wordDefRegExp);
- if (!data) {
- return undefined;
- }
- return {
- duration: data.duration,
- suggestions: data.words.map((word) => {
- return {
- kind: 18 /* languages.CompletionItemKind.Text */,
- label: word,
- insertText: word,
- range: { insert, replace }
- };
- }),
- };
- });
- }
- }
- class WorkerManager extends Disposable {
- constructor(modelService, languageConfigurationService) {
- super();
- this.languageConfigurationService = languageConfigurationService;
- this._modelService = modelService;
- this._editorWorkerClient = null;
- this._lastWorkerUsedTime = (new Date()).getTime();
- const stopWorkerInterval = this._register(new IntervalTimer());
- stopWorkerInterval.cancelAndSet(() => this._checkStopIdleWorker(), Math.round(STOP_WORKER_DELTA_TIME_MS / 2));
- this._register(this._modelService.onModelRemoved(_ => this._checkStopEmptyWorker()));
- }
- dispose() {
- if (this._editorWorkerClient) {
- this._editorWorkerClient.dispose();
- this._editorWorkerClient = null;
- }
- super.dispose();
- }
- /**
- * Check if the model service has no more models and stop the worker if that is the case.
- */
- _checkStopEmptyWorker() {
- if (!this._editorWorkerClient) {
- return;
- }
- const models = this._modelService.getModels();
- if (models.length === 0) {
- // There are no more models => nothing possible for me to do
- this._editorWorkerClient.dispose();
- this._editorWorkerClient = null;
- }
- }
- /**
- * Check if the worker has been idle for a while and then stop it.
- */
- _checkStopIdleWorker() {
- if (!this._editorWorkerClient) {
- return;
- }
- const timeSinceLastWorkerUsedTime = (new Date()).getTime() - this._lastWorkerUsedTime;
- if (timeSinceLastWorkerUsedTime > STOP_WORKER_DELTA_TIME_MS) {
- this._editorWorkerClient.dispose();
- this._editorWorkerClient = null;
- }
- }
- withWorker() {
- this._lastWorkerUsedTime = (new Date()).getTime();
- if (!this._editorWorkerClient) {
- this._editorWorkerClient = new EditorWorkerClient(this._modelService, false, 'editorWorkerService', this.languageConfigurationService);
- }
- return Promise.resolve(this._editorWorkerClient);
- }
- }
- class EditorModelManager extends Disposable {
- constructor(proxy, modelService, keepIdleModels) {
- super();
- this._syncedModels = Object.create(null);
- this._syncedModelsLastUsedTime = Object.create(null);
- this._proxy = proxy;
- this._modelService = modelService;
- if (!keepIdleModels) {
- const timer = new IntervalTimer();
- timer.cancelAndSet(() => this._checkStopModelSync(), Math.round(STOP_SYNC_MODEL_DELTA_TIME_MS / 2));
- this._register(timer);
- }
- }
- dispose() {
- for (const modelUrl in this._syncedModels) {
- dispose(this._syncedModels[modelUrl]);
- }
- this._syncedModels = Object.create(null);
- this._syncedModelsLastUsedTime = Object.create(null);
- super.dispose();
- }
- ensureSyncedResources(resources, forceLargeModels) {
- for (const resource of resources) {
- const resourceStr = resource.toString();
- if (!this._syncedModels[resourceStr]) {
- this._beginModelSync(resource, forceLargeModels);
- }
- if (this._syncedModels[resourceStr]) {
- this._syncedModelsLastUsedTime[resourceStr] = (new Date()).getTime();
- }
- }
- }
- _checkStopModelSync() {
- const currentTime = (new Date()).getTime();
- const toRemove = [];
- for (const modelUrl in this._syncedModelsLastUsedTime) {
- const elapsedTime = currentTime - this._syncedModelsLastUsedTime[modelUrl];
- if (elapsedTime > STOP_SYNC_MODEL_DELTA_TIME_MS) {
- toRemove.push(modelUrl);
- }
- }
- for (const e of toRemove) {
- this._stopModelSync(e);
- }
- }
- _beginModelSync(resource, forceLargeModels) {
- const model = this._modelService.getModel(resource);
- if (!model) {
- return;
- }
- if (!forceLargeModels && model.isTooLargeForSyncing()) {
- return;
- }
- const modelUrl = resource.toString();
- this._proxy.acceptNewModel({
- url: model.uri.toString(),
- lines: model.getLinesContent(),
- EOL: model.getEOL(),
- versionId: model.getVersionId()
- });
- const toDispose = new DisposableStore();
- toDispose.add(model.onDidChangeContent((e) => {
- this._proxy.acceptModelChanged(modelUrl.toString(), e);
- }));
- toDispose.add(model.onWillDispose(() => {
- this._stopModelSync(modelUrl);
- }));
- toDispose.add(toDisposable(() => {
- this._proxy.acceptRemovedModel(modelUrl);
- }));
- this._syncedModels[modelUrl] = toDispose;
- }
- _stopModelSync(modelUrl) {
- const toDispose = this._syncedModels[modelUrl];
- delete this._syncedModels[modelUrl];
- delete this._syncedModelsLastUsedTime[modelUrl];
- dispose(toDispose);
- }
- }
- class SynchronousWorkerClient {
- constructor(instance) {
- this._instance = instance;
- this._proxyObj = Promise.resolve(this._instance);
- }
- dispose() {
- this._instance.dispose();
- }
- getProxyObject() {
- return this._proxyObj;
- }
- }
- export class EditorWorkerHost {
- constructor(workerClient) {
- this._workerClient = workerClient;
- }
- // foreign host request
- fhr(method, args) {
- return this._workerClient.fhr(method, args);
- }
- }
- export class EditorWorkerClient extends Disposable {
- constructor(modelService, keepIdleModels, label, languageConfigurationService) {
- super();
- this.languageConfigurationService = languageConfigurationService;
- this._disposed = false;
- this._modelService = modelService;
- this._keepIdleModels = keepIdleModels;
- this._workerFactory = new DefaultWorkerFactory(label);
- this._worker = null;
- this._modelManager = null;
- }
- // foreign host request
- fhr(method, args) {
- throw new Error(`Not implemented!`);
- }
- _getOrCreateWorker() {
- if (!this._worker) {
- try {
- this._worker = this._register(new SimpleWorkerClient(this._workerFactory, 'vs/editor/common/services/editorSimpleWorker', new EditorWorkerHost(this)));
- }
- catch (err) {
- logOnceWebWorkerWarning(err);
- this._worker = new SynchronousWorkerClient(new EditorSimpleWorker(new EditorWorkerHost(this), null));
- }
- }
- return this._worker;
- }
- _getProxy() {
- return this._getOrCreateWorker().getProxyObject().then(undefined, (err) => {
- logOnceWebWorkerWarning(err);
- this._worker = new SynchronousWorkerClient(new EditorSimpleWorker(new EditorWorkerHost(this), null));
- return this._getOrCreateWorker().getProxyObject();
- });
- }
- _getOrCreateModelManager(proxy) {
- if (!this._modelManager) {
- this._modelManager = this._register(new EditorModelManager(proxy, this._modelService, this._keepIdleModels));
- }
- return this._modelManager;
- }
- _withSyncedResources(resources, forceLargeModels = false) {
- return __awaiter(this, void 0, void 0, function* () {
- if (this._disposed) {
- return Promise.reject(canceled());
- }
- return this._getProxy().then((proxy) => {
- this._getOrCreateModelManager(proxy).ensureSyncedResources(resources, forceLargeModels);
- return proxy;
- });
- });
- }
- computedUnicodeHighlights(uri, options, range) {
- return this._withSyncedResources([uri]).then(proxy => {
- return proxy.computeUnicodeHighlights(uri.toString(), options, range);
- });
- }
- computeDiff(original, modified, ignoreTrimWhitespace, maxComputationTime) {
- return this._withSyncedResources([original, modified], /* forceLargeModels */ true).then(proxy => {
- return proxy.computeDiff(original.toString(), modified.toString(), ignoreTrimWhitespace, maxComputationTime);
- });
- }
- computeMoreMinimalEdits(resource, edits) {
- return this._withSyncedResources([resource]).then(proxy => {
- return proxy.computeMoreMinimalEdits(resource.toString(), edits);
- });
- }
- computeLinks(resource) {
- return this._withSyncedResources([resource]).then(proxy => {
- return proxy.computeLinks(resource.toString());
- });
- }
- textualSuggest(resources, leadingWord, wordDefRegExp) {
- return __awaiter(this, void 0, void 0, function* () {
- const proxy = yield this._withSyncedResources(resources);
- const wordDef = wordDefRegExp.source;
- const wordDefFlags = regExpFlags(wordDefRegExp);
- return proxy.textualSuggest(resources.map(r => r.toString()), leadingWord, wordDef, wordDefFlags);
- });
- }
- computeWordRanges(resource, range) {
- return this._withSyncedResources([resource]).then(proxy => {
- const model = this._modelService.getModel(resource);
- if (!model) {
- return Promise.resolve(null);
- }
- const wordDefRegExp = this.languageConfigurationService.getLanguageConfiguration(model.getLanguageId()).getWordDefinition();
- const wordDef = wordDefRegExp.source;
- const wordDefFlags = regExpFlags(wordDefRegExp);
- return proxy.computeWordRanges(resource.toString(), range, wordDef, wordDefFlags);
- });
- }
- navigateValueSet(resource, range, up) {
- return this._withSyncedResources([resource]).then(proxy => {
- const model = this._modelService.getModel(resource);
- if (!model) {
- return null;
- }
- const wordDefRegExp = this.languageConfigurationService.getLanguageConfiguration(model.getLanguageId()).getWordDefinition();
- const wordDef = wordDefRegExp.source;
- const wordDefFlags = regExpFlags(wordDefRegExp);
- return proxy.navigateValueSet(resource.toString(), range, up, wordDef, wordDefFlags);
- });
- }
- dispose() {
- super.dispose();
- this._disposed = true;
- }
- }
|