diff --git a/.eslintrc.json b/.eslintrc.json index d7f317c85b9..c39a66311e4 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -755,8 +755,7 @@ "vs/base/~", "vs/base/parts/*/~", "vs/platform/*/~", - "vs/editor/~", - "@vscode/tree-sitter-wasm" // node module allowed even in /common/ + "vs/editor/~" ] }, { diff --git a/build/.webignore b/build/.webignore index 860ab59616b..15935edce8a 100644 --- a/build/.webignore +++ b/build/.webignore @@ -38,7 +38,6 @@ vscode-textmate/webpack.config.js # This makes sure the model is included in the package !@vscode/vscode-languagedetection/model/** -!@vscode/tree-sitter-wasm/wasm/** # Ensure only the required telemetry pieces are loaded in web to reduce bundle size @microsoft/1ds-core-js/** diff --git a/package.json b/package.json index 4c00a91cce8..cc8cbfb8fb7 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,6 @@ "@vscode/spdlog": "^0.15.0", "@vscode/sqlite3": "5.1.6-vscode", "@vscode/sudo-prompt": "9.3.1", - "@vscode/tree-sitter-wasm": "^0.0.1", "@vscode/vscode-languagedetection": "1.0.21", "@vscode/windows-mutex": "^0.5.0", "@vscode/windows-process-tree": "^0.6.0", diff --git a/remote/package.json b/remote/package.json index 460258a2bf2..48b849c5928 100644 --- a/remote/package.json +++ b/remote/package.json @@ -11,7 +11,6 @@ "@vscode/proxy-agent": "^0.22.0", "@vscode/ripgrep": "^1.15.9", "@vscode/spdlog": "^0.15.0", - "@vscode/tree-sitter-wasm": "^0.0.1", "@vscode/vscode-languagedetection": "1.0.21", "@vscode/windows-process-tree": "^0.6.0", "@vscode/windows-registry": "^1.1.0", diff --git a/remote/web/package.json b/remote/web/package.json index 06c3256114e..7d7ca2fa12a 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -6,7 +6,6 @@ "@microsoft/1ds-core-js": "^3.2.13", "@microsoft/1ds-post-js": "^3.2.13", "@vscode/iconv-lite-umd": "0.7.0", - "@vscode/tree-sitter-wasm": "^0.0.1", "@vscode/vscode-languagedetection": "1.0.21", "@xterm/addon-clipboard": "0.2.0-beta.34", "@xterm/addon-image": "0.9.0-beta.51", diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 3800e9c0196..d0dae067240 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -43,11 +43,6 @@ resolved "https://registry.yarnpkg.com/@vscode/iconv-lite-umd/-/iconv-lite-umd-0.7.0.tgz#d2f1e0664ee6036408f9743fee264ea0699b0e48" integrity sha512-bRRFxLfg5dtAyl5XyiVWz/ZBPahpOpPrNYnnHpOpUZvam4tKH35wdhP4Kj6PbM0+KdliOsPzbGWpkxcdpNB/sg== -"@vscode/tree-sitter-wasm@^0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.0.1.tgz#ffb2e295a416698f4c77cbffeca3b28567d6754b" - integrity sha512-m0GKnQ3BxWnVd+20KLGwr1+Qvt/RiiaJmKAqHNU35pNydDtduUzyBm7ETz/T0vOVKoeIAaiYsJOA1aKWs7Y1tA== - "@vscode/vscode-languagedetection@1.0.21": version "1.0.21" resolved "https://registry.yarnpkg.com/@vscode/vscode-languagedetection/-/vscode-languagedetection-1.0.21.tgz#89b48f293f6aa3341bb888c1118d16ff13b032d3" diff --git a/remote/yarn.lock b/remote/yarn.lock index 7cff8526869..38f916a284e 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -98,11 +98,6 @@ mkdirp "^1.0.4" node-addon-api "7.1.0" -"@vscode/tree-sitter-wasm@^0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.0.1.tgz#ffb2e295a416698f4c77cbffeca3b28567d6754b" - integrity sha512-m0GKnQ3BxWnVd+20KLGwr1+Qvt/RiiaJmKAqHNU35pNydDtduUzyBm7ETz/T0vOVKoeIAaiYsJOA1aKWs7Y1tA== - "@vscode/vscode-languagedetection@1.0.21": version "1.0.21" resolved "https://registry.yarnpkg.com/@vscode/vscode-languagedetection/-/vscode-languagedetection-1.0.21.tgz#89b48f293f6aa3341bb888c1118d16ff13b032d3" diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index ccc437c304f..59ddc3fdfbf 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -197,7 +197,6 @@ const isESM = false; // using a fallback such as node.js require which does not exist in sandbox const baseNodeModulesPath = isDev ? '../node_modules' : '../node_modules.asar'; loaderConfig.paths = { - '@vscode/tree-sitter-wasm': `${baseNodeModulesPath}/@vscode/tree-sitter-wasm/wasm/tree-sitter.js`, 'vscode-textmate': `${baseNodeModulesPath}/vscode-textmate/release/main.js`, 'vscode-oniguruma': `${baseNodeModulesPath}/vscode-oniguruma/release/main.js`, 'vsda': `${baseNodeModulesPath}/vsda/index.js`, diff --git a/src/vs/editor/browser/services/treeSitter/treeSitterParserService.ts b/src/vs/editor/browser/services/treeSitter/treeSitterParserService.ts deleted file mode 100644 index 7b1b17c6133..00000000000 --- a/src/vs/editor/browser/services/treeSitter/treeSitterParserService.ts +++ /dev/null @@ -1,347 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { TreeSitterTokenizationRegistry } from 'vs/editor/common/languages'; -import type { Parser } from '@vscode/tree-sitter-wasm'; -import { AppResourcePath, FileAccess, nodeModulesPath } from 'vs/base/common/network'; -import { ITreeSitterParserService } from 'vs/editor/common/services/treeSitterParserService'; -import { IModelService } from 'vs/editor/common/services/model'; -import { Disposable, DisposableMap, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; -import { ITextModel } from 'vs/editor/common/model'; -import { IFileService } from 'vs/platform/files/common/files'; -import { IModelContentChangedEvent } from 'vs/editor/common/textModelEvents'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { ILogService } from 'vs/platform/log/common/log'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { setTimeout0 } from 'vs/base/common/platform'; -import { importAMDNodeModule } from 'vs/amdX'; -import { Event } from 'vs/base/common/event'; -import { cancelOnDispose } from 'vs/base/common/cancellation'; - -const EDITOR_EXPERIMENTAL_PREFER_TREESITTER = 'editor.experimental.preferTreeSitter'; -const moduleLocationTreeSitter: AppResourcePath = `${nodeModulesPath}/@vscode/tree-sitter-wasm/wasm`; -const moduleLocationTreeSitterWasm: AppResourcePath = `${moduleLocationTreeSitter}/tree-sitter.wasm`; - -export class TextModelTreeSitter extends Disposable { - private _treeSitterTree: TreeSitterTree | undefined; - - // Not currently used since we just get telemetry, but later this will be needed. - get tree() { return this._treeSitterTree; } - - constructor(readonly model: ITextModel, - private readonly _treeSitterParser: TreeSitterLanguages, - private readonly _treeSitterImporter: TreeSitterImporter, - private readonly _logService: ILogService, - private readonly _telemetryService: ITelemetryService - ) { - super(); - this._register(Event.runAndSubscribe(this.model.onDidChangeLanguage, (e => this._onDidChangeLanguage(e ? e.newLanguage : this.model.getLanguageId())))); - } - - private readonly _languageSessionDisposables = this._register(new DisposableStore()); - /** - * Be very careful when making changes to this method as it is easy to introduce race conditions. - */ - private async _onDidChangeLanguage(languageId: string) { - this._languageSessionDisposables.clear(); - this._treeSitterTree = undefined; - - const token = cancelOnDispose(this._languageSessionDisposables); - const language = await this._treeSitterParser.getLanguage(languageId); - if (!language || token.isCancellationRequested) { - return; - } - - const Parser = await this._treeSitterImporter.getParserClass(); - if (token.isCancellationRequested) { - return; - } - - const treeSitterTree = this._languageSessionDisposables.add(new TreeSitterTree(new Parser(), language, this._logService, this._telemetryService)); - this._languageSessionDisposables.add(this.model.onDidChangeContent(e => this._onDidChangeContent(treeSitterTree, e))); - await this._onDidChangeContent(treeSitterTree); - if (token.isCancellationRequested) { - return; - } - - this._treeSitterTree = treeSitterTree; - } - - private async _onDidChangeContent(treeSitterTree: TreeSitterTree, e?: IModelContentChangedEvent) { - return treeSitterTree.onDidChangeContent(this.model, e); - } -} - -export class TreeSitterTree implements IDisposable { - private _tree: Parser.Tree | undefined; - private _isDisposed: boolean = false; - constructor(public readonly parser: Parser, - public /** exposed for tests **/ readonly language: Parser.Language, - private readonly _logService: ILogService, - private readonly _telemetryService: ITelemetryService) { - this.parser.setTimeoutMicros(50 * 1000); // 50 ms - this.parser.setLanguage(language); - } - dispose(): void { - this._isDisposed = true; - this._tree?.delete(); - this.parser?.delete(); - } - get tree() { return this._tree; } - set tree(newTree: Parser.Tree | undefined) { - this._tree?.delete(); - this._tree = newTree; - } - get isDisposed() { return this._isDisposed; } - - private _onDidChangeContentQueue: Promise = Promise.resolve(); - public async onDidChangeContent(model: ITextModel, e?: IModelContentChangedEvent) { - this._onDidChangeContentQueue = this._onDidChangeContentQueue.then(() => { - if (this.isDisposed) { - // No need to continue the queue if we are disposed - return; - } - return this._onDidChangeContent(model, e); - }).catch((e) => { - this._logService.error('Error parsing tree-sitter tree', e); - }); - return this._onDidChangeContentQueue; - } - - private async _onDidChangeContent(model: ITextModel, e?: IModelContentChangedEvent) { - if (e) { - for (const change of e.changes) { - const newEndOffset = change.rangeOffset + change.text.length; - const newEndPosition = model.getPositionAt(newEndOffset); - - this.tree?.edit({ - startIndex: change.rangeOffset, - oldEndIndex: change.rangeOffset + change.rangeLength, - newEndIndex: change.rangeOffset + change.text.length, - startPosition: { row: change.range.startLineNumber - 1, column: change.range.startColumn - 1 }, - oldEndPosition: { row: change.range.endLineNumber - 1, column: change.range.endColumn - 1 }, - newEndPosition: { row: newEndPosition.lineNumber - 1, column: newEndPosition.column - 1 } - }); - } - } - - this.tree = await this.parse(model); - } - - private parse(model: ITextModel): Promise { - let telemetryTag: string; - if (this.tree) { - telemetryTag = 'incrementalParse'; - } else { - telemetryTag = 'fullParse'; - } - return this._parseAndYield(model, telemetryTag); - } - - private async _parseAndYield(model: ITextModel, telemetryTag: string): Promise { - const language = model.getLanguageId(); - let tree: Parser.Tree | undefined; - let time: number = 0; - let passes: number = 0; - do { - const timer = performance.now(); - try { - tree = this.parser.parse((index: number, position?: Parser.Point) => this._parseCallback(model, index), this.tree); - } catch (e) { - // parsing can fail when the timeout is reached, will resume upon next loop - } finally { - time += performance.now() - timer; - passes++; - } - - // Even if the model changes and edits are applied, the tree parsing will continue correctly after the await. - await new Promise(resolve => setTimeout0(resolve)); - - if (model.isDisposed() || this.isDisposed) { - return; - } - } while (!tree); - this.sendParseTimeTelemetry(telemetryTag, language, time, passes); - return tree; - } - - private _parseCallback(textModel: ITextModel, index: number): string | null { - return textModel.getTextBuffer().getNearestChunk(index); - } - - private sendParseTimeTelemetry(eventName: string, languageId: string, time: number, passes: number): void { - this._logService.debug(`Tree parsing (${eventName}) took ${time} ms and ${passes} passes.`); - type ParseTimeClassification = { - owner: 'alros'; - comment: 'Used to understand how long it takes to parse a tree-sitter tree'; - languageId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The programming language ID.' }; - time: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The ms it took to parse' }; - passes: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The number of passes it took to parse' }; - }; - this._telemetryService.publicLog2<{ languageId: string; time: number; passes: number }, ParseTimeClassification>(`treeSitter.${eventName}`, { languageId, time, passes }); - } -} - -export class TreeSitterLanguages extends Disposable { - private _languages: Map = new Map(); - - constructor(private readonly _treeSitterImporter: TreeSitterImporter, - private readonly _fileService: IFileService - ) { - super(); - } - - public async getLanguage(languageId: string): Promise { - let language = this._languages.get(languageId); - if (!language) { - language = await this._fetchLanguage(languageId); - if (!language) { - return undefined; - } - this._languages.set(languageId, language); - } - return language; - } - - private async _fetchLanguage(languageId: string): Promise { - const grammarName = TreeSitterTokenizationRegistry.get(languageId); - const languageLocation = this._getLanguageLocation(languageId); - if (!grammarName || !languageLocation) { - return undefined; - } - const wasmPath: AppResourcePath = `${languageLocation}/${grammarName.name}.wasm`; - const languageFile = await (this._fileService.readFile(FileAccess.asFileUri(wasmPath))); - const Parser = await this._treeSitterImporter.getParserClass(); - return Parser.Language.load(languageFile.value.buffer); - } - - private _getLanguageLocation(languageId: string): AppResourcePath | undefined { - const grammarName = TreeSitterTokenizationRegistry.get(languageId); - if (!grammarName) { - return undefined; - } - return moduleLocationTreeSitter; - } -} - -export class TreeSitterImporter { - private _treeSitterImport: typeof import('@vscode/tree-sitter-wasm') | undefined; - private async _getTreeSitterImport() { - if (!this._treeSitterImport) { - this._treeSitterImport = await importAMDNodeModule('@vscode/tree-sitter-wasm', 'wasm/tree-sitter.js'); - } - return this._treeSitterImport; - } - - private _parserClass: typeof Parser | undefined; - public async getParserClass() { - if (!this._parserClass) { - this._parserClass = (await this._getTreeSitterImport()).Parser; - } - return this._parserClass; - } -} - -export class TreeSitterTextModelService extends Disposable implements ITreeSitterParserService { - readonly _serviceBrand: undefined; - private _init!: Promise; - private _textModelTreeSitters: DisposableMap = this._register(new DisposableMap()); - private _registeredLanguages: DisposableMap = this._register(new DisposableMap()); - private readonly _treeSitterImporter: TreeSitterImporter = new TreeSitterImporter(); - private readonly _treeSitterParser: TreeSitterLanguages; - - constructor(@IModelService private readonly _modelService: IModelService, - @IFileService fileService: IFileService, - @ITelemetryService private readonly _telemetryService: ITelemetryService, - @ILogService private readonly _logService: ILogService, - @IConfigurationService private readonly _configurationService: IConfigurationService, - ) { - super(); - this._treeSitterParser = this._register(new TreeSitterLanguages(this._treeSitterImporter, fileService)); - this._register(this._configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration(EDITOR_EXPERIMENTAL_PREFER_TREESITTER)) { - this._supportedLanguagesChanged(); - } - })); - this._supportedLanguagesChanged(); - } - - private async _doInitParser() { - const Parser = await this._treeSitterImporter.getParserClass(); - await Parser.init({ - locateFile(_file: string, _folder: string) { - return FileAccess.asBrowserUri(moduleLocationTreeSitterWasm).toString(true); - } - }); - return true; - } - - private _hasInit: boolean = false; - private async _initParser(hasLanguages: boolean): Promise { - if (this._hasInit) { - return this._init; - } - - if (hasLanguages) { - this._hasInit = true; - this._init = this._doInitParser(); - - // New init, we need to deal with all the existing text models and set up listeners - this._init.then(() => this._registerModelServiceListeners()); - } else { - this._init = Promise.resolve(false); - } - return this._init; - } - - private async _supportedLanguagesChanged() { - const setting = this._getSetting(); - - let hasLanguages = true; - if (setting.length === 0) { - hasLanguages = false; - } - - if (await this._initParser(hasLanguages)) { - // Eventually, this should actually use an extension point to add tree sitter grammars, but for now they are hard coded in core - if (setting.includes('typescript')) { - this._addGrammar('typescript', 'tree-sitter-typescript'); - } else { - this._removeGrammar('typescript'); - } - } - } - - private _getSetting(): string[] { - return this._configurationService.getValue(EDITOR_EXPERIMENTAL_PREFER_TREESITTER) || []; - } - - private async _registerModelServiceListeners() { - this._register(this._modelService.onModelAdded(model => { - this._createTextModelTreeSitter(model); - })); - this._register(this._modelService.onModelRemoved(model => { - this._textModelTreeSitters.deleteAndDispose(model); - })); - this._modelService.getModels().forEach(model => this._createTextModelTreeSitter(model)); - } - - private _createTextModelTreeSitter(model: ITextModel) { - const textModelTreeSitter = new TextModelTreeSitter(model, this._treeSitterParser, this._treeSitterImporter, this._logService, this._telemetryService); - this._textModelTreeSitters.set(model, textModelTreeSitter); - } - - private _addGrammar(languageId: string, grammarName: string) { - if (!TreeSitterTokenizationRegistry.get(languageId)) { - this._registeredLanguages.set(languageId, TreeSitterTokenizationRegistry.register(languageId, { name: grammarName })); - } - } - - private _removeGrammar(languageId: string) { - if (this._registeredLanguages.has(languageId)) { - this._registeredLanguages.deleteAndDispose('typescript'); - } - } -} diff --git a/src/vs/editor/common/languages.ts b/src/vs/editor/common/languages.ts index ad1c39e3fa5..72fd97338ec 100644 --- a/src/vs/editor/common/languages.ts +++ b/src/vs/editor/common/languages.ts @@ -82,14 +82,6 @@ export class EncodedTokenizationResult { } } -/** - * An intermediate interface for scaffolding the new tree sitter tokenization support. Not final. - * @internal - */ -export interface ITreeSitterTokenizationSupport { - name: string; -} - /** * @internal */ @@ -2114,14 +2106,14 @@ export interface ITokenizationSupportChangedEvent { /** * @internal */ -export interface ILazyTokenizationSupport { - get tokenizationSupport(): Promise; +export interface ILazyTokenizationSupport { + get tokenizationSupport(): Promise; } /** * @internal */ -export class LazyTokenizationSupport implements IDisposable, ILazyTokenizationSupport { +export class LazyTokenizationSupport implements IDisposable, ILazyTokenizationSupport { private _tokenizationSupport: Promise | null = null; constructor(private readonly createSupport: () => Promise) { @@ -2148,7 +2140,7 @@ export class LazyTokenizationSupport implements IDisposable, ILazyTokenizationSu /** * @internal */ -export interface ITokenizationRegistry { +export interface ITokenizationRegistry { /** * An event triggered when: @@ -2166,24 +2158,24 @@ export interface ITokenizationRegistry { /** * Register a tokenization support. */ - register(languageId: string, support: TSupport): IDisposable; + register(languageId: string, support: ITokenizationSupport): IDisposable; /** * Register a tokenization support factory. */ - registerFactory(languageId: string, factory: ILazyTokenizationSupport): IDisposable; + registerFactory(languageId: string, factory: ILazyTokenizationSupport): IDisposable; /** * Get or create the tokenization support for a language. * Returns `null` if not found. */ - getOrCreate(languageId: string): Promise; + getOrCreate(languageId: string): Promise; /** * Get the tokenization support for a language. * Returns `null` if not found. */ - get(languageId: string): TSupport | null; + get(languageId: string): ITokenizationSupport | null; /** * Returns false if a factory is still pending. @@ -2203,12 +2195,8 @@ export interface ITokenizationRegistry { /** * @internal */ -export const TokenizationRegistry: ITokenizationRegistry = new TokenizationRegistryImpl(); +export const TokenizationRegistry: ITokenizationRegistry = new TokenizationRegistryImpl(); -/** - * @internal - */ -export const TreeSitterTokenizationRegistry: ITokenizationRegistry = new TokenizationRegistryImpl(); /** * @internal diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index 04f76ee800b..97b5a483fc3 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -43,7 +43,6 @@ import { IBracketPairsTextModelPart } from 'vs/editor/common/textModelBracketPai import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelOptionsChangedEvent, InternalModelContentChangeEvent, LineInjectedText, ModelInjectedTextChangedEvent, ModelRawChange, ModelRawContentChangedEvent, ModelRawEOLChanged, ModelRawFlush, ModelRawLineChanged, ModelRawLinesDeleted, ModelRawLinesInserted } from 'vs/editor/common/textModelEvents'; import { IGuidesTextModelPart } from 'vs/editor/common/textModelGuides'; import { ITokenizationTextModelPart } from 'vs/editor/common/tokenizationTextModelPart'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IColorTheme } from 'vs/platform/theme/common/themeService'; import { IUndoRedoService, ResourceEditStackSnapshot, UndoRedoGroup } from 'vs/platform/undoRedo/common/undoRedo'; @@ -300,7 +299,6 @@ export class TextModel extends Disposable implements model.ITextModel, IDecorati @IUndoRedoService private readonly _undoRedoService: IUndoRedoService, @ILanguageService private readonly _languageService: ILanguageService, @ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService, - @IInstantiationService private readonly instantiationService: IInstantiationService ) { super(); @@ -329,11 +327,13 @@ export class TextModel extends Disposable implements model.ITextModel, IDecorati this._bracketPairs = this._register(new BracketPairsTextModelPart(this, this._languageConfigurationService)); this._guidesTextModelPart = this._register(new GuidesTextModelPart(this, this._languageConfigurationService)); this._decorationProvider = this._register(new ColorizedBracketPairsDecorationProvider(this)); - this._tokenizationTextModelPart = this.instantiationService.createInstance(TokenizationTextModelPart, + this._tokenizationTextModelPart = new TokenizationTextModelPart( + this._languageService, + this._languageConfigurationService, this, this._bracketPairs, languageId, - this._attachedViews + this._attachedViews, ); const bufferLineCount = this._buffer.getLineCount(); diff --git a/src/vs/editor/common/model/tokenizationTextModelPart.ts b/src/vs/editor/common/model/tokenizationTextModelPart.ts index 30972f1a33b..40c6c921afc 100644 --- a/src/vs/editor/common/model/tokenizationTextModelPart.ts +++ b/src/vs/editor/common/model/tokenizationTextModelPart.ts @@ -47,12 +47,12 @@ export class TokenizationTextModelPart extends TextModelPart implements ITokeniz private readonly grammarTokens = this._register(new GrammarTokens(this._languageService.languageIdCodec, this._textModel, () => this._languageId, this._attachedViews)); constructor( + private readonly _languageService: ILanguageService, + private readonly _languageConfigurationService: ILanguageConfigurationService, private readonly _textModel: TextModel, private readonly _bracketPairsTextModelPart: BracketPairsTextModelPart, private _languageId: string, private readonly _attachedViews: AttachedViews, - @ILanguageService private readonly _languageService: ILanguageService, - @ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService, ) { super(); diff --git a/src/vs/editor/common/services/modelService.ts b/src/vs/editor/common/services/modelService.ts index 00019d6f961..2bbda14a026 100644 --- a/src/vs/editor/common/services/modelService.ts +++ b/src/vs/editor/common/services/modelService.ts @@ -14,7 +14,7 @@ import { TextModel, createTextBuffer } from 'vs/editor/common/model/textModel'; import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/core/textModelDefaults'; import { IModelLanguageChangedEvent } from 'vs/editor/common/textModelEvents'; import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry'; -import { ILanguageSelection } from 'vs/editor/common/languages/language'; +import { ILanguageSelection, ILanguageService } from 'vs/editor/common/languages/language'; import { IModelService } from 'vs/editor/common/services/model'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfiguration'; import { IConfigurationChangeEvent, IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -23,7 +23,7 @@ import { StringSHA1 } from 'vs/base/common/hash'; import { isEditStackElement } from 'vs/editor/common/model/editStack'; import { Schemas } from 'vs/base/common/network'; import { equals } from 'vs/base/common/objects'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; function MODEL_ID(resource: URI): string { return resource.toString(); @@ -107,7 +107,8 @@ export class ModelService extends Disposable implements IModelService { @IConfigurationService private readonly _configurationService: IConfigurationService, @ITextResourcePropertiesService private readonly _resourcePropertiesService: ITextResourcePropertiesService, @IUndoRedoService private readonly _undoRedoService: IUndoRedoService, - @IInstantiationService private readonly _instantiationService: IInstantiationService + @ILanguageService private readonly _languageService: ILanguageService, + @ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService, ) { super(); this._modelCreationOptionsByLanguageAndResource = Object.create(null); @@ -313,11 +314,14 @@ export class ModelService extends Disposable implements IModelService { private _createModelData(value: string | ITextBufferFactory, languageIdOrSelection: string | ILanguageSelection, resource: URI | undefined, isForSimpleWidget: boolean): ModelData { // create & save the model const options = this.getCreationOptions(languageIdOrSelection, resource, isForSimpleWidget); - const model: TextModel = this._instantiationService.createInstance(TextModel, + const model: TextModel = new TextModel( value, languageIdOrSelection, options, - resource + resource, + this._undoRedoService, + this._languageService, + this._languageConfigurationService, ); if (resource && this._disposedModels.has(MODEL_ID(resource))) { const disposedModelData = this._removeDisposedModel(resource)!; diff --git a/src/vs/editor/common/services/treeSitterParserService.ts b/src/vs/editor/common/services/treeSitterParserService.ts deleted file mode 100644 index e3e911efc49..00000000000 --- a/src/vs/editor/common/services/treeSitterParserService.ts +++ /dev/null @@ -1,16 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 'vs/platform/instantiation/common/instantiation'; - -export const ITreeSitterParserService = createDecorator('treeSitterParserService'); - -/** - * Currently this service just logs telemetry about how long it takes to parse files. - * Actual API will come later as we add features like syntax highlighting. - */ -export interface ITreeSitterParserService { - readonly _serviceBrand: undefined; -} diff --git a/src/vs/editor/common/textModelEvents.ts b/src/vs/editor/common/textModelEvents.ts index 7d63afec8e8..58c720ac87c 100644 --- a/src/vs/editor/common/textModelEvents.ts +++ b/src/vs/editor/common/textModelEvents.ts @@ -55,9 +55,6 @@ export interface IModelContentChange { * An event describing a change in the text of a model. */ export interface IModelContentChangedEvent { - /** - * The changes are ordered from the end of the document to the beginning, so they should be safe to apply in sequence. - */ readonly changes: IModelContentChange[]; /** * The (new) end-of-line character. diff --git a/src/vs/editor/common/tokenizationRegistry.ts b/src/vs/editor/common/tokenizationRegistry.ts index 15ad1b85159..d9fb1bba82f 100644 --- a/src/vs/editor/common/tokenizationRegistry.ts +++ b/src/vs/editor/common/tokenizationRegistry.ts @@ -6,13 +6,13 @@ import { Color } from 'vs/base/common/color'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { ITokenizationRegistry, ITokenizationSupportChangedEvent, ILazyTokenizationSupport } from 'vs/editor/common/languages'; +import { ITokenizationRegistry, ITokenizationSupport, ITokenizationSupportChangedEvent, ILazyTokenizationSupport } from 'vs/editor/common/languages'; import { ColorId } from 'vs/editor/common/encodedTokenAttributes'; -export class TokenizationRegistry implements ITokenizationRegistry { +export class TokenizationRegistry implements ITokenizationRegistry { - private readonly _tokenizationSupports = new Map(); - private readonly _factories = new Map>(); + private readonly _tokenizationSupports = new Map(); + private readonly _factories = new Map(); private readonly _onDidChange = new Emitter(); public readonly onDidChange: Event = this._onDidChange.event; @@ -30,7 +30,7 @@ export class TokenizationRegistry implements ITokenizationRegistry { @@ -42,11 +42,11 @@ export class TokenizationRegistry implements ITokenizationRegistry): IDisposable { + public registerFactory(languageId: string, factory: ILazyTokenizationSupport): IDisposable { this._factories.get(languageId)?.dispose(); const myData = new TokenizationSupportFactoryData(this, languageId, factory); this._factories.set(languageId, myData); @@ -60,7 +60,7 @@ export class TokenizationRegistry implements ITokenizationRegistry { + public async getOrCreate(languageId: string): Promise { // check first if the support is already set const tokenizationSupport = this.get(languageId); if (tokenizationSupport) { @@ -112,7 +112,7 @@ export class TokenizationRegistry implements ITokenizationRegistry extends Disposable { +class TokenizationSupportFactoryData extends Disposable { private _isDisposed: boolean = false; private _resolvePromise: Promise | null = null; @@ -123,9 +123,9 @@ class TokenizationSupportFactoryData extends Disposable { } constructor( - private readonly _registry: TokenizationRegistry, + private readonly _registry: TokenizationRegistry, private readonly _languageId: string, - private readonly _factory: ILazyTokenizationSupport, + private readonly _factory: ILazyTokenizationSupport, ) { super(); } diff --git a/src/vs/editor/contrib/gotoSymbol/browser/peek/referencesWidget.ts b/src/vs/editor/contrib/gotoSymbol/browser/peek/referencesWidget.ts index 6503b7df220..0941671756d 100644 --- a/src/vs/editor/contrib/gotoSymbol/browser/peek/referencesWidget.ts +++ b/src/vs/editor/contrib/gotoSymbol/browser/peek/referencesWidget.ts @@ -23,7 +23,9 @@ import { ScrollType } from 'vs/editor/common/editorCommon'; import { IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/model'; import { ModelDecorationOptions, TextModel } from 'vs/editor/common/model/textModel'; import { Location } from 'vs/editor/common/languages'; +import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry'; +import { ILanguageService } from 'vs/editor/common/languages/language'; import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; import { AccessibilityProvider, DataSource, Delegate, FileReferencesRenderer, IdentityProvider, OneReferenceRenderer, StringRepresentationProvider, TreeElement } from 'vs/editor/contrib/gotoSymbol/browser/peek/referencesTree'; import * as peekView from 'vs/editor/contrib/peekView/browser/peekView'; @@ -33,6 +35,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ILabelService } from 'vs/platform/label/common/label'; import { IWorkbenchAsyncDataTreeOptions, WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService'; import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; +import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { FileReferences, OneReference, ReferencesModel } from '../referencesModel'; class DecorationsManager implements IDisposable { @@ -221,7 +224,10 @@ export class ReferenceWidget extends peekView.PeekViewWidget { @IInstantiationService private readonly _instantiationService: IInstantiationService, @peekView.IPeekViewService private readonly _peekViewService: peekView.IPeekViewService, @ILabelService private readonly _uriLabel: ILabelService, + @IUndoRedoService private readonly _undoRedoService: IUndoRedoService, @IKeybindingService private readonly _keybindingService: IKeybindingService, + @ILanguageService private readonly _languageService: ILanguageService, + @ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService, ) { super(editor, { showFrame: false, showArrow: true, isResizeable: true, isAccessible: true, supportOnTitleClick: true }, _instantiationService); @@ -309,7 +315,7 @@ export class ReferenceWidget extends peekView.PeekViewWidget { }; this._preview = this._instantiationService.createInstance(EmbeddedCodeEditorWidget, this._previewContainer, options, {}, this.editor); dom.hide(this._previewContainer); - this._previewNotAvailableMessage = this._instantiationService.createInstance(TextModel, nls.localize('missingPreviewMessage', "no preview available"), PLAINTEXT_LANGUAGE_ID, TextModel.DEFAULT_CREATION_OPTIONS, null); + this._previewNotAvailableMessage = new TextModel(nls.localize('missingPreviewMessage', "no preview available"), PLAINTEXT_LANGUAGE_ID, TextModel.DEFAULT_CREATION_OPTIONS, null, this._undoRedoService, this._languageService, this._languageConfigurationService); // tree this._treeContainer = dom.append(containerElement, dom.$('div.ref-tree.inline')); diff --git a/src/vs/editor/contrib/semanticTokens/test/browser/documentSemanticTokens.test.ts b/src/vs/editor/contrib/semanticTokens/test/browser/documentSemanticTokens.test.ts index 9eb8d2f0006..86d3bf5d62d 100644 --- a/src/vs/editor/contrib/semanticTokens/test/browser/documentSemanticTokens.test.ts +++ b/src/vs/editor/contrib/semanticTokens/test/browser/documentSemanticTokens.test.ts @@ -14,7 +14,6 @@ import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/uti import { Range } from 'vs/editor/common/core/range'; import { DocumentSemanticTokensProvider, SemanticTokens, SemanticTokensEdits, SemanticTokensLegend } from 'vs/editor/common/languages'; import { ILanguageService } from 'vs/editor/common/languages/language'; -import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; import { ITextModel } from 'vs/editor/common/model'; import { LanguageFeatureDebounceService } from 'vs/editor/common/services/languageFeatureDebounce'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; @@ -30,7 +29,6 @@ import { TestTextResourcePropertiesService } from 'vs/editor/test/common/service import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { NullLogService } from 'vs/platform/log/common/log'; import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; import { ColorScheme } from 'vs/platform/theme/common/theme'; @@ -52,14 +50,12 @@ suite('ModelSemanticColoring', () => { languageFeaturesService = new LanguageFeaturesService(); languageService = disposables.add(new LanguageService(false)); const semanticTokensStylingService = disposables.add(new SemanticTokensStylingService(themeService, logService, languageService)); - const instantiationService = new TestInstantiationService(); - instantiationService.set(ILanguageService, languageService); - instantiationService.set(ILanguageConfigurationService, new TestLanguageConfigurationService()); modelService = disposables.add(new ModelService( configService, new TestTextResourcePropertiesService(configService), new UndoRedoService(new TestDialogService(), new TestNotificationService()), - instantiationService + languageService, + new TestLanguageConfigurationService(), )); const envService = new class extends mock() { override isBuilt: boolean = true; diff --git a/src/vs/editor/test/browser/services/testTreeSitterService.ts b/src/vs/editor/test/browser/services/testTreeSitterService.ts deleted file mode 100644 index f449962d6cd..00000000000 --- a/src/vs/editor/test/browser/services/testTreeSitterService.ts +++ /dev/null @@ -1,27 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { AppResourcePath } from 'vs/base/common/network'; -import type { Parser } from '@vscode/tree-sitter-wasm'; -import { ITextModel } from 'vs/editor/common/model'; -import { ITreeSitterParserService } from 'vs/editor/common/services/treeSitterParserService'; - -export class TestTreeSitterParserService implements ITreeSitterParserService { - getLanguage(model: ITextModel): Parser.Language | undefined { - throw new Error('Method not implemented.'); - } - getLanguageLocation(languageId: string): AppResourcePath { - throw new Error('Method not implemented.'); - } - readonly _serviceBrand: undefined; - - public initTreeSitter(): Promise { - return Promise.resolve(); - } - - public getTree(_model: ITextModel): Parser.Tree | undefined { - return undefined; - } -} diff --git a/src/vs/editor/test/browser/services/treeSitterParserService.test.ts b/src/vs/editor/test/browser/services/treeSitterParserService.test.ts deleted file mode 100644 index be1b58185ad..00000000000 --- a/src/vs/editor/test/browser/services/treeSitterParserService.test.ts +++ /dev/null @@ -1,144 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import assert from 'assert'; -import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; -import { TextModelTreeSitter, TreeSitterImporter, TreeSitterLanguages } from 'vs/editor/browser/services/treeSitter/treeSitterParserService'; -import type { Parser } from '@vscode/tree-sitter-wasm'; -import { createTextModel } from 'vs/editor/test/common/testTextModel'; -import { timeout } from 'vs/base/common/async'; -import { ConsoleMainLogger, ILogService } from 'vs/platform/log/common/log'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { LogService } from 'vs/platform/log/common/logService'; -import { mock } from 'vs/base/test/common/mock'; - -class MockParser implements Parser { - static async init(): Promise { } - delete(): void { } - parse(input: string | Parser.Input, oldTree?: Parser.Tree, options?: Parser.Options): Parser.Tree { - return new MockTree(); - } - getIncludedRanges(): Parser.Range[] { - return []; - } - getTimeoutMicros(): number { return 0; } - setTimeoutMicros(timeout: number): void { } - reset(): void { } - getLanguage(): Parser.Language { return {} as any; } - setLanguage(): void { } - getLogger(): Parser.Logger { - throw new Error('Method not implemented.'); - } - setLogger(logFunc?: Parser.Logger | false | null): void { - throw new Error('Method not implemented.'); - } -} - -class MockTreeSitterImporter extends TreeSitterImporter { - public override async getParserClass(): Promise { - return MockParser as any; - } -} - -class MockTree implements Parser.Tree { - editorLanguage: string = ''; - editorContents: string = ''; - rootNode: Parser.SyntaxNode = {} as any; - rootNodeWithOffset(offsetBytes: number, offsetExtent: Parser.Point): Parser.SyntaxNode { - throw new Error('Method not implemented.'); - } - copy(): Parser.Tree { - throw new Error('Method not implemented.'); - } - delete(): void { } - edit(edit: Parser.Edit): Parser.Tree { - return this; - } - walk(): Parser.TreeCursor { - throw new Error('Method not implemented.'); - } - getChangedRanges(other: Parser.Tree): Parser.Range[] { - throw new Error('Method not implemented.'); - } - getIncludedRanges(): Parser.Range[] { - throw new Error('Method not implemented.'); - } - getEditedRange(other: Parser.Tree): Parser.Range { - throw new Error('Method not implemented.'); - } - getLanguage(): Parser.Language { - throw new Error('Method not implemented.'); - } -} - -class MockLanguage implements Parser.Language { - version: number = 0; - fieldCount: number = 0; - stateCount: number = 0; - nodeTypeCount: number = 0; - fieldNameForId(fieldId: number): string | null { - throw new Error('Method not implemented.'); - } - fieldIdForName(fieldName: string): number | null { - throw new Error('Method not implemented.'); - } - idForNodeType(type: string, named: boolean): number { - throw new Error('Method not implemented.'); - } - nodeTypeForId(typeId: number): string | null { - throw new Error('Method not implemented.'); - } - nodeTypeIsNamed(typeId: number): boolean { - throw new Error('Method not implemented.'); - } - nodeTypeIsVisible(typeId: number): boolean { - throw new Error('Method not implemented.'); - } - nextState(stateId: number, typeId: number): number { - throw new Error('Method not implemented.'); - } - query(source: string): Parser.Query { - throw new Error('Method not implemented.'); - } - lookaheadIterator(stateId: number): Parser.LookaheadIterable | null { - throw new Error('Method not implemented.'); - } - languageId: string = ''; -} - -suite('TreeSitterParserService', function () { - const treeSitterImporter: TreeSitterImporter = new MockTreeSitterImporter(); - let logService: ILogService; - let telemetryService: ITelemetryService; - setup(function () { - logService = new LogService(new ConsoleMainLogger()); - telemetryService = new class extends mock() { - override async publicLog2() { - // - } - }; - }); - - const store = ensureNoDisposablesAreLeakedInTestSuite(); - - test('TextModelTreeSitter race condition: first language is slow to load', async function () { - class MockTreeSitterParser extends TreeSitterLanguages { - public override async getLanguage(languageId: string): Promise { - if (languageId === 'javascript') { - await timeout(200); - } - const language = new MockLanguage(); - language.languageId = languageId; - return language; - } - } - - const treeSitterParser: TreeSitterLanguages = store.add(new MockTreeSitterParser(treeSitterImporter, {} as any)); - const textModel = store.add(createTextModel('console.log("Hello, world!");', 'javascript')); - const textModelTreeSitter = store.add(new TextModelTreeSitter(textModel, treeSitterParser, treeSitterImporter, logService, telemetryService)); - textModel.setLanguage('typescript'); - await timeout(300); - assert.strictEqual((textModelTreeSitter.tree?.language as MockLanguage).languageId, 'typescript'); - }); -}); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index be2c930e9eb..24cb17d259c 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2919,9 +2919,6 @@ declare namespace monaco.editor { * An event describing a change in the text of a model. */ export interface IModelContentChangedEvent { - /** - * The changes are ordered from the end of the document to the beginning, so they should be safe to apply in sequence. - */ readonly changes: IModelContentChange[]; /** * The (new) end-of-line character. diff --git a/src/vs/workbench/api/test/browser/mainThreadDocumentsAndEditors.test.ts b/src/vs/workbench/api/test/browser/mainThreadDocumentsAndEditors.test.ts index 17a9049d064..f0d0538ce22 100644 --- a/src/vs/workbench/api/test/browser/mainThreadDocumentsAndEditors.test.ts +++ b/src/vs/workbench/api/test/browser/mainThreadDocumentsAndEditors.test.ts @@ -27,15 +27,11 @@ import { TestTextResourcePropertiesService, TestWorkingCopyFileService } from 'v import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; +import { TestLanguageConfigurationService } from 'vs/editor/test/common/modes/testLanguageConfigurationService'; import { TextModel } from 'vs/editor/common/model/textModel'; +import { LanguageService } from 'vs/editor/common/services/languageService'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; -import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; -import { ILanguageService } from 'vs/editor/common/languages/language'; -import { LanguageService } from 'vs/editor/common/services/languageService'; -import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; -import { TestLanguageConfigurationService } from 'vs/editor/test/common/modes/testLanguageConfigurationService'; -import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; suite('MainThreadDocumentsAndEditors', () => { @@ -65,15 +61,12 @@ suite('MainThreadDocumentsAndEditors', () => { const notificationService = new TestNotificationService(); const undoRedoService = new UndoRedoService(dialogService, notificationService); const themeService = new TestThemeService(); - const instantiationService = new TestInstantiationService(); - instantiationService.set(ILanguageService, disposables.add(new LanguageService())); - instantiationService.set(ILanguageConfigurationService, new TestLanguageConfigurationService()); - instantiationService.set(IUndoRedoService, undoRedoService); modelService = new ModelService( configService, new TestTextResourcePropertiesService(configService), undoRedoService, - instantiationService + disposables.add(new LanguageService()), + new TestLanguageConfigurationService(), ); codeEditorService = new TestCodeEditorService(themeService); textFileService = new class extends mock() { diff --git a/src/vs/workbench/api/test/browser/mainThreadEditors.test.ts b/src/vs/workbench/api/test/browser/mainThreadEditors.test.ts index d83a5ebcf42..1ca165c1b5f 100644 --- a/src/vs/workbench/api/test/browser/mainThreadEditors.test.ts +++ b/src/vs/workbench/api/test/browser/mainThreadEditors.test.ts @@ -16,10 +16,12 @@ import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { ITextSnapshot } from 'vs/editor/common/model'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; +import { LanguageService } from 'vs/editor/common/services/languageService'; import { IModelService } from 'vs/editor/common/services/model'; import { ModelService } from 'vs/editor/common/services/modelService'; import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; import { TestCodeEditorService } from 'vs/editor/test/browser/editorTestServices'; +import { TestLanguageConfigurationService } from 'vs/editor/test/common/modes/testLanguageConfigurationService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; @@ -55,10 +57,6 @@ import { ICopyOperation, ICreateFileOperation, ICreateOperation, IDeleteOperatio import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { TestEditorGroupsService, TestEditorService, TestEnvironmentService, TestFileService, TestLifecycleService, TestWorkingCopyService } from 'vs/workbench/test/browser/workbenchTestServices'; import { TestContextService, TestTextResourcePropertiesService } from 'vs/workbench/test/common/workbenchTestServices'; -import { ILanguageService } from 'vs/editor/common/languages/language'; -import { LanguageService } from 'vs/editor/common/services/languageService'; -import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; -import { TestLanguageConfigurationService } from 'vs/editor/test/common/modes/testLanguageConfigurationService'; suite('MainThreadEditors', () => { @@ -82,11 +80,19 @@ suite('MainThreadEditors', () => { createdResources.clear(); deletedResources.clear(); + const configService = new TestConfigurationService(); const dialogService = new TestDialogService(); const notificationService = new TestNotificationService(); const undoRedoService = new UndoRedoService(dialogService, notificationService); const themeService = new TestThemeService(); + modelService = new ModelService( + configService, + new TestTextResourcePropertiesService(configService), + undoRedoService, + disposables.add(new LanguageService()), + new TestLanguageConfigurationService(), + ); const services = new ServiceCollection(); services.set(IBulkEditService, new SyncDescriptor(BulkEditService)); @@ -172,18 +178,8 @@ suite('MainThreadEditors', () => { } }); - services.set(ILanguageService, disposables.add(new LanguageService())); - services.set(ILanguageConfigurationService, new TestLanguageConfigurationService()); - const instaService = new InstantiationService(services); - modelService = new ModelService( - configService, - new TestTextResourcePropertiesService(configService), - undoRedoService, - instaService - ); - bulkEdits = instaService.createInstance(MainThreadBulkEdits, SingleProxyRPCProtocol(null)); }); diff --git a/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts index 45a97a0c67a..e45a95008c3 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts @@ -25,11 +25,13 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ThemeIcon } from 'vs/base/common/themables'; import { compare } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; +import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { ResourceFileEdit } from 'vs/editor/browser/services/bulkEditService'; +import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; +import { ILanguageService } from 'vs/editor/common/languages/language'; import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry'; import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser'; import { AriaRole } from 'vs/base/browser/ui/aria/aria'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; // --- VIEW MODEL @@ -200,7 +202,9 @@ export class BulkEditDataSource implements IAsyncDataSource