feat: 添加vscode编辑器
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
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 { Emitter } from '../../../base/common/event.js';
|
||||
import { Disposable, toDisposable } from '../../../base/common/lifecycle.js';
|
||||
import { LinkedList } from '../../../base/common/linkedList.js';
|
||||
import { IThemeService } from '../../../platform/theme/common/themeService.js';
|
||||
let AbstractCodeEditorService = class AbstractCodeEditorService extends Disposable {
|
||||
constructor(_themeService) {
|
||||
super();
|
||||
this._themeService = _themeService;
|
||||
this._onCodeEditorAdd = this._register(new Emitter());
|
||||
this.onCodeEditorAdd = this._onCodeEditorAdd.event;
|
||||
this._onCodeEditorRemove = this._register(new Emitter());
|
||||
this.onCodeEditorRemove = this._onCodeEditorRemove.event;
|
||||
this._onDiffEditorAdd = this._register(new Emitter());
|
||||
this.onDiffEditorAdd = this._onDiffEditorAdd.event;
|
||||
this._onDiffEditorRemove = this._register(new Emitter());
|
||||
this.onDiffEditorRemove = this._onDiffEditorRemove.event;
|
||||
this._decorationOptionProviders = new Map();
|
||||
this._codeEditorOpenHandlers = new LinkedList();
|
||||
this._modelProperties = new Map();
|
||||
this._codeEditors = Object.create(null);
|
||||
this._diffEditors = Object.create(null);
|
||||
this._globalStyleSheet = null;
|
||||
}
|
||||
addCodeEditor(editor) {
|
||||
this._codeEditors[editor.getId()] = editor;
|
||||
this._onCodeEditorAdd.fire(editor);
|
||||
}
|
||||
removeCodeEditor(editor) {
|
||||
if (delete this._codeEditors[editor.getId()]) {
|
||||
this._onCodeEditorRemove.fire(editor);
|
||||
}
|
||||
}
|
||||
listCodeEditors() {
|
||||
return Object.keys(this._codeEditors).map(id => this._codeEditors[id]);
|
||||
}
|
||||
addDiffEditor(editor) {
|
||||
this._diffEditors[editor.getId()] = editor;
|
||||
this._onDiffEditorAdd.fire(editor);
|
||||
}
|
||||
removeDiffEditor(editor) {
|
||||
if (delete this._diffEditors[editor.getId()]) {
|
||||
this._onDiffEditorRemove.fire(editor);
|
||||
}
|
||||
}
|
||||
listDiffEditors() {
|
||||
return Object.keys(this._diffEditors).map(id => this._diffEditors[id]);
|
||||
}
|
||||
getFocusedCodeEditor() {
|
||||
let editorWithWidgetFocus = null;
|
||||
const editors = this.listCodeEditors();
|
||||
for (const editor of editors) {
|
||||
if (editor.hasTextFocus()) {
|
||||
// bingo!
|
||||
return editor;
|
||||
}
|
||||
if (editor.hasWidgetFocus()) {
|
||||
editorWithWidgetFocus = editor;
|
||||
}
|
||||
}
|
||||
return editorWithWidgetFocus;
|
||||
}
|
||||
removeDecorationType(key) {
|
||||
const provider = this._decorationOptionProviders.get(key);
|
||||
if (provider) {
|
||||
provider.refCount--;
|
||||
if (provider.refCount <= 0) {
|
||||
this._decorationOptionProviders.delete(key);
|
||||
provider.dispose();
|
||||
this.listCodeEditors().forEach((ed) => ed.removeDecorationsByType(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
setModelProperty(resource, key, value) {
|
||||
const key1 = resource.toString();
|
||||
let dest;
|
||||
if (this._modelProperties.has(key1)) {
|
||||
dest = this._modelProperties.get(key1);
|
||||
}
|
||||
else {
|
||||
dest = new Map();
|
||||
this._modelProperties.set(key1, dest);
|
||||
}
|
||||
dest.set(key, value);
|
||||
}
|
||||
getModelProperty(resource, key) {
|
||||
const key1 = resource.toString();
|
||||
if (this._modelProperties.has(key1)) {
|
||||
const innerMap = this._modelProperties.get(key1);
|
||||
return innerMap.get(key);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
openCodeEditor(input, source, sideBySide) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
for (const handler of this._codeEditorOpenHandlers) {
|
||||
const candidate = yield handler(input, source, sideBySide);
|
||||
if (candidate !== null) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
registerCodeEditorOpenHandler(handler) {
|
||||
const rm = this._codeEditorOpenHandlers.unshift(handler);
|
||||
return toDisposable(rm);
|
||||
}
|
||||
};
|
||||
AbstractCodeEditorService = __decorate([
|
||||
__param(0, IThemeService)
|
||||
], AbstractCodeEditorService);
|
||||
export { AbstractCodeEditorService };
|
||||
export class GlobalStyleSheet {
|
||||
constructor(styleSheet) {
|
||||
this._styleSheet = styleSheet;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
|
||||
import { URI } from '../../../base/common/uri.js';
|
||||
import { isObject } from '../../../base/common/types.js';
|
||||
export const IBulkEditService = createDecorator('IWorkspaceEditService');
|
||||
export class ResourceEdit {
|
||||
constructor(metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
static convert(edit) {
|
||||
return edit.edits.map(edit => {
|
||||
if (ResourceTextEdit.is(edit)) {
|
||||
return ResourceTextEdit.lift(edit);
|
||||
}
|
||||
if (ResourceFileEdit.is(edit)) {
|
||||
return ResourceFileEdit.lift(edit);
|
||||
}
|
||||
throw new Error('Unsupported edit');
|
||||
});
|
||||
}
|
||||
}
|
||||
export class ResourceTextEdit extends ResourceEdit {
|
||||
constructor(resource, textEdit, versionId = undefined, metadata) {
|
||||
super(metadata);
|
||||
this.resource = resource;
|
||||
this.textEdit = textEdit;
|
||||
this.versionId = versionId;
|
||||
}
|
||||
static is(candidate) {
|
||||
if (candidate instanceof ResourceTextEdit) {
|
||||
return true;
|
||||
}
|
||||
return isObject(candidate)
|
||||
&& URI.isUri(candidate.resource)
|
||||
&& isObject(candidate.textEdit);
|
||||
}
|
||||
static lift(edit) {
|
||||
if (edit instanceof ResourceTextEdit) {
|
||||
return edit;
|
||||
}
|
||||
else {
|
||||
return new ResourceTextEdit(edit.resource, edit.textEdit, edit.versionId, edit.metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
export class ResourceFileEdit extends ResourceEdit {
|
||||
constructor(oldResource, newResource, options = {}, metadata) {
|
||||
super(metadata);
|
||||
this.oldResource = oldResource;
|
||||
this.newResource = newResource;
|
||||
this.options = options;
|
||||
}
|
||||
static is(candidate) {
|
||||
if (candidate instanceof ResourceFileEdit) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return isObject(candidate)
|
||||
&& (Boolean(candidate.newResource) || Boolean(candidate.oldResource));
|
||||
}
|
||||
}
|
||||
static lift(edit) {
|
||||
if (edit instanceof ResourceFileEdit) {
|
||||
return edit;
|
||||
}
|
||||
else {
|
||||
return new ResourceFileEdit(edit.oldResource, edit.newResource, edit.options, edit.metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
|
||||
export const ICodeEditorService = createDecorator('codeEditorService');
|
||||
@@ -0,0 +1,443 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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); }
|
||||
};
|
||||
import { IMarkerDecorationsService } from '../../common/services/markerDecorations.js';
|
||||
import { registerEditorContribution } from '../editorExtensions.js';
|
||||
let MarkerDecorationsContribution = class MarkerDecorationsContribution {
|
||||
constructor(_editor, _markerDecorationsService) {
|
||||
// Doesn't do anything, just requires `IMarkerDecorationsService` to make sure it gets instantiated
|
||||
}
|
||||
dispose() {
|
||||
}
|
||||
};
|
||||
MarkerDecorationsContribution.ID = 'editor.contrib.markerDecorations';
|
||||
MarkerDecorationsContribution = __decorate([
|
||||
__param(1, IMarkerDecorationsService)
|
||||
], MarkerDecorationsContribution);
|
||||
export { MarkerDecorationsContribution };
|
||||
registerEditorContribution(MarkerDecorationsContribution.ID, MarkerDecorationsContribution);
|
||||
@@ -0,0 +1,243 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 * as dom from '../../../base/browser/dom.js';
|
||||
import { CancellationToken } from '../../../base/common/cancellation.js';
|
||||
import { LinkedList } from '../../../base/common/linkedList.js';
|
||||
import { ResourceMap } from '../../../base/common/map.js';
|
||||
import { parse } from '../../../base/common/marshalling.js';
|
||||
import { Schemas } from '../../../base/common/network.js';
|
||||
import { normalizePath } from '../../../base/common/resources.js';
|
||||
import { URI } from '../../../base/common/uri.js';
|
||||
import { ICodeEditorService } from './codeEditorService.js';
|
||||
import { ICommandService } from '../../../platform/commands/common/commands.js';
|
||||
import { EditorOpenSource } from '../../../platform/editor/common/editor.js';
|
||||
import { extractSelection, matchesScheme, matchesSomeScheme } from '../../../platform/opener/common/opener.js';
|
||||
let CommandOpener = class CommandOpener {
|
||||
constructor(_commandService) {
|
||||
this._commandService = _commandService;
|
||||
}
|
||||
open(target, options) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (!matchesScheme(target, Schemas.command)) {
|
||||
return false;
|
||||
}
|
||||
if (!(options === null || options === void 0 ? void 0 : options.allowCommands)) {
|
||||
// silently ignore commands when command-links are disabled, also
|
||||
// surpress other openers by returning TRUE
|
||||
return true;
|
||||
}
|
||||
// run command or bail out if command isn't known
|
||||
if (typeof target === 'string') {
|
||||
target = URI.parse(target);
|
||||
}
|
||||
// execute as command
|
||||
let args = [];
|
||||
try {
|
||||
args = parse(decodeURIComponent(target.query));
|
||||
}
|
||||
catch (_a) {
|
||||
// ignore and retry
|
||||
try {
|
||||
args = parse(target.query);
|
||||
}
|
||||
catch (_b) {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
if (!Array.isArray(args)) {
|
||||
args = [args];
|
||||
}
|
||||
yield this._commandService.executeCommand(target.path, ...args);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
};
|
||||
CommandOpener = __decorate([
|
||||
__param(0, ICommandService)
|
||||
], CommandOpener);
|
||||
let EditorOpener = class EditorOpener {
|
||||
constructor(_editorService) {
|
||||
this._editorService = _editorService;
|
||||
}
|
||||
open(target, options) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof target === 'string') {
|
||||
target = URI.parse(target);
|
||||
}
|
||||
const { selection, uri } = extractSelection(target);
|
||||
target = uri;
|
||||
if (target.scheme === Schemas.file) {
|
||||
target = normalizePath(target); // workaround for non-normalized paths (https://github.com/microsoft/vscode/issues/12954)
|
||||
}
|
||||
yield this._editorService.openCodeEditor({
|
||||
resource: target,
|
||||
options: Object.assign({ selection, source: (options === null || options === void 0 ? void 0 : options.fromUserGesture) ? EditorOpenSource.USER : EditorOpenSource.API }, options === null || options === void 0 ? void 0 : options.editorOptions)
|
||||
}, this._editorService.getFocusedCodeEditor(), options === null || options === void 0 ? void 0 : options.openToSide);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
};
|
||||
EditorOpener = __decorate([
|
||||
__param(0, ICodeEditorService)
|
||||
], EditorOpener);
|
||||
let OpenerService = class OpenerService {
|
||||
constructor(editorService, commandService) {
|
||||
this._openers = new LinkedList();
|
||||
this._validators = new LinkedList();
|
||||
this._resolvers = new LinkedList();
|
||||
this._resolvedUriTargets = new ResourceMap(uri => uri.with({ path: null, fragment: null, query: null }).toString());
|
||||
this._externalOpeners = new LinkedList();
|
||||
// Default external opener is going through window.open()
|
||||
this._defaultExternalOpener = {
|
||||
openExternal: (href) => __awaiter(this, void 0, void 0, function* () {
|
||||
// ensure to open HTTP/HTTPS links into new windows
|
||||
// to not trigger a navigation. Any other link is
|
||||
// safe to be set as HREF to prevent a blank window
|
||||
// from opening.
|
||||
if (matchesSomeScheme(href, Schemas.http, Schemas.https)) {
|
||||
dom.windowOpenNoOpener(href);
|
||||
}
|
||||
else {
|
||||
window.location.href = href;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
};
|
||||
// Default opener: any external, maito, http(s), command, and catch-all-editors
|
||||
this._openers.push({
|
||||
open: (target, options) => __awaiter(this, void 0, void 0, function* () {
|
||||
if ((options === null || options === void 0 ? void 0 : options.openExternal) || matchesSomeScheme(target, Schemas.mailto, Schemas.http, Schemas.https, Schemas.vsls)) {
|
||||
// open externally
|
||||
yield this._doOpenExternal(target, options);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
});
|
||||
this._openers.push(new CommandOpener(commandService));
|
||||
this._openers.push(new EditorOpener(editorService));
|
||||
}
|
||||
registerOpener(opener) {
|
||||
const remove = this._openers.unshift(opener);
|
||||
return { dispose: remove };
|
||||
}
|
||||
registerValidator(validator) {
|
||||
const remove = this._validators.push(validator);
|
||||
return { dispose: remove };
|
||||
}
|
||||
registerExternalUriResolver(resolver) {
|
||||
const remove = this._resolvers.push(resolver);
|
||||
return { dispose: remove };
|
||||
}
|
||||
setDefaultExternalOpener(externalOpener) {
|
||||
this._defaultExternalOpener = externalOpener;
|
||||
}
|
||||
registerExternalOpener(opener) {
|
||||
const remove = this._externalOpeners.push(opener);
|
||||
return { dispose: remove };
|
||||
}
|
||||
open(target, options) {
|
||||
var _a;
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// check with contributed validators
|
||||
const targetURI = typeof target === 'string' ? URI.parse(target) : target;
|
||||
// validate against the original URI that this URI resolves to, if one exists
|
||||
const validationTarget = (_a = this._resolvedUriTargets.get(targetURI)) !== null && _a !== void 0 ? _a : target;
|
||||
for (const validator of this._validators) {
|
||||
if (!(yield validator.shouldOpen(validationTarget, options))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// check with contributed openers
|
||||
for (const opener of this._openers) {
|
||||
const handled = yield opener.open(target, options);
|
||||
if (handled) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
resolveExternalUri(resource, options) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
for (const resolver of this._resolvers) {
|
||||
try {
|
||||
const result = yield resolver.resolveExternalUri(resource, options);
|
||||
if (result) {
|
||||
if (!this._resolvedUriTargets.has(result.resolved)) {
|
||||
this._resolvedUriTargets.set(result.resolved, resource);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (_a) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
throw new Error('Could not resolve external URI: ' + resource.toString());
|
||||
});
|
||||
}
|
||||
_doOpenExternal(resource, options) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
//todo@jrieken IExternalUriResolver should support `uri: URI | string`
|
||||
const uri = typeof resource === 'string' ? URI.parse(resource) : resource;
|
||||
let externalUri;
|
||||
try {
|
||||
externalUri = (yield this.resolveExternalUri(uri, options)).resolved;
|
||||
}
|
||||
catch (_a) {
|
||||
externalUri = uri;
|
||||
}
|
||||
let href;
|
||||
if (typeof resource === 'string' && uri.toString() === externalUri.toString()) {
|
||||
// open the url-string AS IS
|
||||
href = resource;
|
||||
}
|
||||
else {
|
||||
// open URI using the toString(noEncode)+encodeURI-trick
|
||||
href = encodeURI(externalUri.toString(true));
|
||||
}
|
||||
if (options === null || options === void 0 ? void 0 : options.allowContributedOpeners) {
|
||||
const preferredOpenerId = typeof (options === null || options === void 0 ? void 0 : options.allowContributedOpeners) === 'string' ? options === null || options === void 0 ? void 0 : options.allowContributedOpeners : undefined;
|
||||
for (const opener of this._externalOpeners) {
|
||||
const didOpen = yield opener.openExternal(href, {
|
||||
sourceUri: uri,
|
||||
preferredOpenerId,
|
||||
}, CancellationToken.None);
|
||||
if (didOpen) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._defaultExternalOpener.openExternal(href, { sourceUri: uri }, CancellationToken.None);
|
||||
});
|
||||
}
|
||||
dispose() {
|
||||
this._validators.clear();
|
||||
}
|
||||
};
|
||||
OpenerService = __decorate([
|
||||
__param(0, ICodeEditorService),
|
||||
__param(1, ICommandService)
|
||||
], OpenerService);
|
||||
export { OpenerService };
|
||||
@@ -0,0 +1,65 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { EditorWorkerClient } from './editorWorkerService.js';
|
||||
import * as types from '../../../base/common/types.js';
|
||||
/**
|
||||
* Create a new web worker that has model syncing capabilities built in.
|
||||
* Specify an AMD module to load that will `create` an object that will be proxied.
|
||||
*/
|
||||
export function createWebWorker(modelService, languageConfigurationService, opts) {
|
||||
return new MonacoWebWorkerImpl(modelService, languageConfigurationService, opts);
|
||||
}
|
||||
class MonacoWebWorkerImpl extends EditorWorkerClient {
|
||||
constructor(modelService, languageConfigurationService, opts) {
|
||||
super(modelService, opts.keepIdleModels || false, opts.label, languageConfigurationService);
|
||||
this._foreignModuleId = opts.moduleId;
|
||||
this._foreignModuleCreateData = opts.createData || null;
|
||||
this._foreignModuleHost = opts.host || null;
|
||||
this._foreignProxy = null;
|
||||
}
|
||||
// foreign host request
|
||||
fhr(method, args) {
|
||||
if (!this._foreignModuleHost || typeof this._foreignModuleHost[method] !== 'function') {
|
||||
return Promise.reject(new Error('Missing method ' + method + ' or missing main thread foreign host.'));
|
||||
}
|
||||
try {
|
||||
return Promise.resolve(this._foreignModuleHost[method].apply(this._foreignModuleHost, args));
|
||||
}
|
||||
catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
}
|
||||
_getForeignProxy() {
|
||||
if (!this._foreignProxy) {
|
||||
this._foreignProxy = this._getProxy().then((proxy) => {
|
||||
const foreignHostMethods = this._foreignModuleHost ? types.getAllMethodNames(this._foreignModuleHost) : [];
|
||||
return proxy.loadForeignModule(this._foreignModuleId, this._foreignModuleCreateData, foreignHostMethods).then((foreignMethods) => {
|
||||
this._foreignModuleCreateData = null;
|
||||
const proxyMethodRequest = (method, args) => {
|
||||
return proxy.fmr(method, args);
|
||||
};
|
||||
const createProxyMethod = (method, proxyMethodRequest) => {
|
||||
return function () {
|
||||
const args = Array.prototype.slice.call(arguments, 0);
|
||||
return proxyMethodRequest(method, args);
|
||||
};
|
||||
};
|
||||
const foreignProxy = {};
|
||||
for (const foreignMethod of foreignMethods) {
|
||||
foreignProxy[foreignMethod] = createProxyMethod(foreignMethod, proxyMethodRequest);
|
||||
}
|
||||
return foreignProxy;
|
||||
});
|
||||
});
|
||||
}
|
||||
return this._foreignProxy;
|
||||
}
|
||||
getProxy() {
|
||||
return this._getForeignProxy();
|
||||
}
|
||||
withSyncedResources(resources) {
|
||||
return this._withSyncedResources(resources).then(_ => this.getProxy());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user