Merge branch 'main' into fix-path-prefix-in-shell-integrations

This commit is contained in:
Anton Matosov
2024-07-23 15:57:31 -07:00
committed by GitHub
40 changed files with 757 additions and 128 deletions
+2 -1
View File
@@ -755,7 +755,8 @@
"vs/base/~",
"vs/base/parts/*/~",
"vs/platform/*/~",
"vs/editor/~"
"vs/editor/~",
"@vscode/tree-sitter-wasm" // node module allowed even in /common/
]
},
{
+1
View File
@@ -38,6 +38,7 @@ 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/**
@@ -180,6 +180,11 @@
"items": {
"type": "string"
}
},
"disableAutomaticConfiguration": {
"type": "boolean",
"description": "Disables the setup that is automatically run in a codespace if no `postCreateCommand` is specified.",
"default": false
}
}
}
@@ -11,8 +11,7 @@ import { registerBaseCommands } from './commands/index';
import { TypeScriptServiceConfiguration } from './configuration/configuration';
import { BrowserServiceConfigurationProvider } from './configuration/configuration.browser';
import { ExperimentationTelemetryReporter, IExperimentationTelemetryReporter } from './experimentTelemetryReporter';
import { AutoInstallerFs } from './filesystems/autoInstallerFs';
import { MemFs } from './filesystems/memFs';
import { registerAtaSupport } from './filesystems/ata';
import { createLazyClientHost, lazilyActivateClient } from './lazyClientHost';
import { Logger } from './logging/logger';
import RemoteRepositories from './remoteRepositories.browser';
@@ -25,7 +24,7 @@ import { ITypeScriptVersionProvider, TypeScriptVersion, TypeScriptVersionSource
import { ActiveJsTsEditorTracker } from './ui/activeJsTsEditorTracker';
import { Disposable } from './utils/dispose';
import { getPackageInfo } from './utils/packageInfo';
import { isWebAndHasSharedArrayBuffers, supportsReadableByteStreams } from './utils/platform';
import { isWebAndHasSharedArrayBuffers } from './utils/platform';
class StaticVersionProvider implements ITypeScriptVersionProvider {
@@ -102,16 +101,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<Api> {
await startPreloadWorkspaceContentsIfNeeded(context, logger);
}));
if (supportsReadableByteStreams()) {
context.subscriptions.push(vscode.workspace.registerFileSystemProvider('vscode-global-typings', new MemFs(), {
isCaseSensitive: true,
isReadonly: false
}));
context.subscriptions.push(vscode.workspace.registerFileSystemProvider('vscode-node-modules', new AutoInstallerFs(), {
isCaseSensitive: true,
isReadonly: false
}));
}
context.subscriptions.push(registerAtaSupport());
return getExtensionApi(onCompletionAccepted.event, pluginManager);
}
@@ -0,0 +1,30 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { conditionalRegistration, requireGlobalConfiguration } from '../languageFeatures/util/dependentRegistration';
import { supportsReadableByteStreams } from '../utils/platform';
import { AutoInstallerFs } from './autoInstallerFs';
import { MemFs } from './memFs';
export function registerAtaSupport(): vscode.Disposable {
if (!supportsReadableByteStreams()) {
return vscode.Disposable.from();
}
return conditionalRegistration([
requireGlobalConfiguration('typescript', 'tsserver.web.typeAcquisition.enabled'),
], () => {
return vscode.Disposable.from(
vscode.workspace.registerFileSystemProvider('vscode-global-typings', new MemFs(), {
isCaseSensitive: true,
isReadonly: false
}),
vscode.workspace.registerFileSystemProvider('vscode-node-modules', new AutoInstallerFs(), {
isCaseSensitive: true,
isReadonly: false
}));
});
}
@@ -40,7 +40,7 @@ export class WorkerServerProcessFactory implements TsServerProcessFactory {
version: TypeScriptVersion,
args: readonly string[],
kind: TsServerProcessKind,
_configuration: TypeScriptServiceConfiguration,
configuration: TypeScriptServiceConfiguration,
_versionManager: TypeScriptVersionManager,
_nodeVersionManager: NodeVersionManager,
tsServerLog: TsServerLog | undefined,
@@ -50,10 +50,10 @@ export class WorkerServerProcessFactory implements TsServerProcessFactory {
...args,
// Explicitly give TS Server its path so it can load local resources
'--executingFilePath', tsServerPath,
// Enable/disable web type acquisition
(configuration.webTypeAcquisitionEnabled && supportsReadableByteStreams() ? '--experimentalTypeAcquisition' : '--disableAutomaticTypingAcquisition'),
];
if (_configuration.webTypeAcquisitionEnabled && supportsReadableByteStreams()) {
launchArgs.push('--experimentalTypeAcquisition');
}
return new WorkerServerProcess(kind, tsServerPath, this._extensionUri, launchArgs, tsServerLog, this._logger);
}
}
+1
View File
@@ -78,6 +78,7 @@
"@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",
+1
View File
@@ -11,6 +11,7 @@
"@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",
+1
View File
@@ -6,6 +6,7 @@
"@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",
+5
View File
@@ -43,6 +43,11 @@
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"
+5
View File
@@ -98,6 +98,11 @@
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"
+1
View File
@@ -197,6 +197,7 @@ 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`,
+10
View File
@@ -190,6 +190,16 @@ export function validateConstraint(arg: unknown, constraint: TypeConstraint | un
}
}
/**
* Helper type assertion that safely upcasts a type to a supertype.
*
* This can be used to make sure the argument correctly conforms to the subtype while still being able to pass it
* to contexts that expects the supertype.
*/
export function upcast<Base, Sub extends Base>(x: Sub): Base {
return x;
}
type AddFirstParameterToFunction<T, TargetFunctionsReturnType, FirstParameter> = T extends (...args: any[]) => TargetFunctionsReturnType ?
// Function: add param to function
(firstArg: FirstParameter, ...args: Parameters<T>) => ReturnType<T> :
@@ -0,0 +1,347 @@
/*---------------------------------------------------------------------------------------------
* 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<void> = 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<Parser.Tree | undefined> {
let telemetryTag: string;
if (this.tree) {
telemetryTag = 'incrementalParse';
} else {
telemetryTag = 'fullParse';
}
return this._parseAndYield(model, telemetryTag);
}
private async _parseAndYield(model: ITextModel, telemetryTag: string): Promise<Parser.Tree | undefined> {
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<void>(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<string, Parser.Language> = new Map();
constructor(private readonly _treeSitterImporter: TreeSitterImporter,
private readonly _fileService: IFileService
) {
super();
}
public async getLanguage(languageId: string): Promise<Parser.Language | undefined> {
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<Parser.Language | undefined> {
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<typeof import('@vscode/tree-sitter-wasm')>('@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<boolean>;
private _textModelTreeSitters: DisposableMap<ITextModel, TextModelTreeSitter> = this._register(new DisposableMap());
private _registeredLanguages: DisposableMap<string, IDisposable> = 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<boolean> {
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<string[]>(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');
}
}
}
+21 -9
View File
@@ -82,6 +82,14 @@ export class EncodedTokenizationResult {
}
}
/**
* An intermediate interface for scaffolding the new tree sitter tokenization support. Not final.
* @internal
*/
export interface ITreeSitterTokenizationSupport {
name: string;
}
/**
* @internal
*/
@@ -2106,14 +2114,14 @@ export interface ITokenizationSupportChangedEvent {
/**
* @internal
*/
export interface ILazyTokenizationSupport {
get tokenizationSupport(): Promise<ITokenizationSupport | null>;
export interface ILazyTokenizationSupport<TSupport> {
get tokenizationSupport(): Promise<TSupport | null>;
}
/**
* @internal
*/
export class LazyTokenizationSupport implements IDisposable, ILazyTokenizationSupport {
export class LazyTokenizationSupport implements IDisposable, ILazyTokenizationSupport<ITokenizationSupport> {
private _tokenizationSupport: Promise<ITokenizationSupport & IDisposable | null> | null = null;
constructor(private readonly createSupport: () => Promise<ITokenizationSupport & IDisposable | null>) {
@@ -2140,7 +2148,7 @@ export class LazyTokenizationSupport implements IDisposable, ILazyTokenizationSu
/**
* @internal
*/
export interface ITokenizationRegistry {
export interface ITokenizationRegistry<TSupport> {
/**
* An event triggered when:
@@ -2158,24 +2166,24 @@ export interface ITokenizationRegistry {
/**
* Register a tokenization support.
*/
register(languageId: string, support: ITokenizationSupport): IDisposable;
register(languageId: string, support: TSupport): IDisposable;
/**
* Register a tokenization support factory.
*/
registerFactory(languageId: string, factory: ILazyTokenizationSupport): IDisposable;
registerFactory(languageId: string, factory: ILazyTokenizationSupport<TSupport>): IDisposable;
/**
* Get or create the tokenization support for a language.
* Returns `null` if not found.
*/
getOrCreate(languageId: string): Promise<ITokenizationSupport | null>;
getOrCreate(languageId: string): Promise<TSupport | null>;
/**
* Get the tokenization support for a language.
* Returns `null` if not found.
*/
get(languageId: string): ITokenizationSupport | null;
get(languageId: string): TSupport | null;
/**
* Returns false if a factory is still pending.
@@ -2195,8 +2203,12 @@ export interface ITokenizationRegistry {
/**
* @internal
*/
export const TokenizationRegistry: ITokenizationRegistry = new TokenizationRegistryImpl();
export const TokenizationRegistry: ITokenizationRegistry<ITokenizationSupport> = new TokenizationRegistryImpl();
/**
* @internal
*/
export const TreeSitterTokenizationRegistry: ITokenizationRegistry<ITreeSitterTokenizationSupport> = new TokenizationRegistryImpl();
/**
* @internal
+4 -4
View File
@@ -43,6 +43,7 @@ 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';
@@ -299,6 +300,7 @@ 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();
@@ -327,13 +329,11 @@ 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 = new TokenizationTextModelPart(
this._languageService,
this._languageConfigurationService,
this._tokenizationTextModelPart = this.instantiationService.createInstance(TokenizationTextModelPart,
this,
this._bracketPairs,
languageId,
this._attachedViews,
this._attachedViews
);
const bufferLineCount = this._buffer.getLineCount();
@@ -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();
@@ -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, ILanguageService } from 'vs/editor/common/languages/language';
import { ILanguageSelection } 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 { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
function MODEL_ID(resource: URI): string {
return resource.toString();
@@ -107,8 +107,7 @@ export class ModelService extends Disposable implements IModelService {
@IConfigurationService private readonly _configurationService: IConfigurationService,
@ITextResourcePropertiesService private readonly _resourcePropertiesService: ITextResourcePropertiesService,
@IUndoRedoService private readonly _undoRedoService: IUndoRedoService,
@ILanguageService private readonly _languageService: ILanguageService,
@ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService,
@IInstantiationService private readonly _instantiationService: IInstantiationService
) {
super();
this._modelCreationOptionsByLanguageAndResource = Object.create(null);
@@ -314,14 +313,11 @@ 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 = new TextModel(
const model: TextModel = this._instantiationService.createInstance(TextModel,
value,
languageIdOrSelection,
options,
resource,
this._undoRedoService,
this._languageService,
this._languageConfigurationService,
resource
);
if (resource && this._disposedModels.has(MODEL_ID(resource))) {
const disposedModelData = this._removeDisposedModel(resource)!;
@@ -0,0 +1,16 @@
/*---------------------------------------------------------------------------------------------
* 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<ITreeSitterParserService>('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;
}
+3
View File
@@ -55,6 +55,9 @@ 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.
+11 -11
View File
@@ -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, ITokenizationSupport, ITokenizationSupportChangedEvent, ILazyTokenizationSupport } from 'vs/editor/common/languages';
import { ITokenizationRegistry, ITokenizationSupportChangedEvent, ILazyTokenizationSupport } from 'vs/editor/common/languages';
import { ColorId } from 'vs/editor/common/encodedTokenAttributes';
export class TokenizationRegistry implements ITokenizationRegistry {
export class TokenizationRegistry<TSupport> implements ITokenizationRegistry<TSupport> {
private readonly _tokenizationSupports = new Map<string, ITokenizationSupport>();
private readonly _factories = new Map<string, TokenizationSupportFactoryData>();
private readonly _tokenizationSupports = new Map<string, TSupport>();
private readonly _factories = new Map<string, TokenizationSupportFactoryData<TSupport>>();
private readonly _onDidChange = new Emitter<ITokenizationSupportChangedEvent>();
public readonly onDidChange: Event<ITokenizationSupportChangedEvent> = this._onDidChange.event;
@@ -30,7 +30,7 @@ export class TokenizationRegistry implements ITokenizationRegistry {
});
}
public register(languageId: string, support: ITokenizationSupport): IDisposable {
public register(languageId: string, support: TSupport): IDisposable {
this._tokenizationSupports.set(languageId, support);
this.handleChange([languageId]);
return toDisposable(() => {
@@ -42,11 +42,11 @@ export class TokenizationRegistry implements ITokenizationRegistry {
});
}
public get(languageId: string): ITokenizationSupport | null {
public get(languageId: string): TSupport | null {
return this._tokenizationSupports.get(languageId) || null;
}
public registerFactory(languageId: string, factory: ILazyTokenizationSupport): IDisposable {
public registerFactory(languageId: string, factory: ILazyTokenizationSupport<TSupport>): 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<ITokenizationSupport | null> {
public async getOrCreate(languageId: string): Promise<TSupport | null> {
// check first if the support is already set
const tokenizationSupport = this.get(languageId);
if (tokenizationSupport) {
@@ -112,7 +112,7 @@ export class TokenizationRegistry implements ITokenizationRegistry {
}
}
class TokenizationSupportFactoryData extends Disposable {
class TokenizationSupportFactoryData<TSupport> extends Disposable {
private _isDisposed: boolean = false;
private _resolvePromise: Promise<void> | null = null;
@@ -123,9 +123,9 @@ class TokenizationSupportFactoryData extends Disposable {
}
constructor(
private readonly _registry: TokenizationRegistry,
private readonly _registry: TokenizationRegistry<TSupport>,
private readonly _languageId: string,
private readonly _factory: ILazyTokenizationSupport,
private readonly _factory: ILazyTokenizationSupport<TSupport>,
) {
super();
}
@@ -23,9 +23,7 @@ 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';
@@ -35,7 +33,6 @@ 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 {
@@ -224,10 +221,7 @@ 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);
@@ -315,7 +309,7 @@ export class ReferenceWidget extends peekView.PeekViewWidget {
};
this._preview = this._instantiationService.createInstance(EmbeddedCodeEditorWidget, this._previewContainer, options, {}, this.editor);
dom.hide(this._previewContainer);
this._previewNotAvailableMessage = new TextModel(nls.localize('missingPreviewMessage', "no preview available"), PLAINTEXT_LANGUAGE_ID, TextModel.DEFAULT_CREATION_OPTIONS, null, this._undoRedoService, this._languageService, this._languageConfigurationService);
this._previewNotAvailableMessage = this._instantiationService.createInstance(TextModel, nls.localize('missingPreviewMessage', "no preview available"), PLAINTEXT_LANGUAGE_ID, TextModel.DEFAULT_CREATION_OPTIONS, null);
// tree
this._treeContainer = dom.append(containerElement, dom.$('div.ref-tree.inline'));
@@ -14,6 +14,7 @@ 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';
@@ -29,6 +30,7 @@ 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';
@@ -50,12 +52,14 @@ 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()),
languageService,
new TestLanguageConfigurationService(),
instantiationService
));
const envService = new class extends mock<IEnvironmentService>() {
override isBuilt: boolean = true;
@@ -0,0 +1,27 @@
/*---------------------------------------------------------------------------------------------
* 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<void> {
return Promise.resolve();
}
public getTree(_model: ITextModel): Parser.Tree | undefined {
return undefined;
}
}
@@ -0,0 +1,144 @@
/*---------------------------------------------------------------------------------------------
* 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<void> { }
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<typeof Parser> {
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<ITelemetryService>() {
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<Parser.Language | undefined> {
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');
});
});
+3
View File
@@ -2919,6 +2919,9 @@ 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.
@@ -18,6 +18,7 @@ import { removeDangerousEnvVariables } from 'vs/base/common/processes';
import { deepClone } from 'vs/base/common/objects';
import { isWindows } from 'vs/base/common/platform';
import { isUNCAccessRestrictionsDisabled, getUNCHostAllowlist } from 'vs/base/node/unc';
import { upcast } from 'vs/base/common/types';
export interface IUtilityProcessConfiguration {
@@ -249,7 +250,10 @@ export class UtilityProcess extends Disposable {
this.log('creating new...', Severity.Info);
// Fork utility process
this.process = utilityProcess.fork(modulePath, args, {
this.process = utilityProcess.fork(modulePath, args, upcast<ForkOptions, ForkOptions & {
forceAllocationsToV8Sandbox?: boolean;
respondToAuthRequestsFromMainProcess?: boolean;
}>({
serviceName,
env,
execArgv,
@@ -257,10 +261,7 @@ export class UtilityProcess extends Disposable {
forceAllocationsToV8Sandbox,
respondToAuthRequestsFromMainProcess,
stdio
} as ForkOptions & {
forceAllocationsToV8Sandbox?: Boolean;
respondToAuthRequestsFromMainProcess?: boolean;
});
}));
// Register to events
this.registerListeners(this.process, this.configuration, serviceName);
@@ -7,7 +7,7 @@ import { AsyncIterableObject } from 'vs/base/common/async';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import * as errors from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { combinedDisposable, IDisposable } from 'vs/base/common/lifecycle';
import { combinedDisposable } from 'vs/base/common/lifecycle';
import { Schemas, matchesScheme } from 'vs/base/common/network';
import Severity from 'vs/base/common/severity';
import { URI } from 'vs/base/common/uri';
@@ -1206,17 +1206,17 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
},
registerFileSearchProviderNew: (scheme: string, provider: vscode.FileSearchProviderNew) => {
checkProposedApiEnabled(extension, 'fileSearchProviderNew');
return <IDisposable>{ dispose: () => { } };
return { dispose: () => { } };
},
registerTextSearchProviderNew: (scheme: string, provider: vscode.TextSearchProviderNew) => {
checkProposedApiEnabled(extension, 'textSearchProviderNew');
return <IDisposable>{ dispose: () => { } };
return { dispose: () => { } };
},
registerAITextSearchProviderNew: (scheme: string, provider: vscode.AITextSearchProviderNew) => {
// there are some dependencies on textSearchProvider, so we need to check for both
checkProposedApiEnabled(extension, 'aiTextSearchProviderNew');
checkProposedApiEnabled(extension, 'textSearchProviderNew');
return <IDisposable>{ dispose: () => { } };
return { dispose: () => { } };
},
registerRemoteAuthorityResolver: (authorityPrefix: string, resolver: vscode.RemoteAuthorityResolver) => {
checkProposedApiEnabled(extension, 'resolvers');
@@ -787,7 +787,7 @@ export namespace SymbolTag {
export namespace WorkspaceSymbol {
export function from(info: vscode.SymbolInformation): search.IWorkspaceSymbol {
return <search.IWorkspaceSymbol>{
return {
name: info.name,
kind: SymbolKind.from(info.kind),
tags: info.tags && info.tags.map(SymbolTag.from),
@@ -966,7 +966,7 @@ export namespace Hover {
export namespace EvaluatableExpression {
export function from(expression: vscode.EvaluatableExpression): languages.EvaluatableExpression {
return <languages.EvaluatableExpression>{
return {
range: Range.from(expression.range),
expression: expression.expression
};
@@ -980,24 +980,24 @@ export namespace EvaluatableExpression {
export namespace InlineValue {
export function from(inlineValue: vscode.InlineValue): languages.InlineValue {
if (inlineValue instanceof types.InlineValueText) {
return <languages.InlineValueText>{
return {
type: 'text',
range: Range.from(inlineValue.range),
text: inlineValue.text
};
} satisfies languages.InlineValueText;
} else if (inlineValue instanceof types.InlineValueVariableLookup) {
return <languages.InlineValueVariableLookup>{
return {
type: 'variable',
range: Range.from(inlineValue.range),
variableName: inlineValue.variableName,
caseSensitiveLookup: inlineValue.caseSensitiveLookup
};
} satisfies languages.InlineValueVariableLookup;
} else if (inlineValue instanceof types.InlineValueEvaluatableExpression) {
return <languages.InlineValueExpression>{
return {
type: 'expression',
range: Range.from(inlineValue.range),
expression: inlineValue.expression
};
} satisfies languages.InlineValueExpression;
} else {
throw new Error(`Unknown 'InlineValue' type`);
}
@@ -1006,28 +1006,28 @@ export namespace InlineValue {
export function to(inlineValue: languages.InlineValue): vscode.InlineValue {
switch (inlineValue.type) {
case 'text':
return <vscode.InlineValueText>{
return {
range: Range.to(inlineValue.range),
text: inlineValue.text
};
} satisfies vscode.InlineValueText;
case 'variable':
return <vscode.InlineValueVariableLookup>{
return {
range: Range.to(inlineValue.range),
variableName: inlineValue.variableName,
caseSensitiveLookup: inlineValue.caseSensitiveLookup
};
} satisfies vscode.InlineValueVariableLookup;
case 'expression':
return <vscode.InlineValueEvaluatableExpression>{
return {
range: Range.to(inlineValue.range),
expression: inlineValue.expression
};
} satisfies vscode.InlineValueEvaluatableExpression;
}
}
}
export namespace InlineValueContext {
export function from(inlineValueContext: vscode.InlineValueContext): extHostProtocol.IInlineValueContextDto {
return <extHostProtocol.IInlineValueContextDto>{
return {
frameId: inlineValueContext.frameId,
stoppedLocation: Range.from(inlineValueContext.stoppedLocation)
};
@@ -27,11 +27,15 @@ 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', () => {
@@ -61,12 +65,15 @@ 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,
disposables.add(new LanguageService()),
new TestLanguageConfigurationService(),
instantiationService
);
codeEditorService = new TestCodeEditorService(themeService);
textFileService = new class extends mock<ITextFileService>() {
@@ -16,12 +16,10 @@ 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';
@@ -57,6 +55,10 @@ 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', () => {
@@ -80,19 +82,11 @@ 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));
@@ -178,8 +172,18 @@ 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));
});
@@ -25,13 +25,11 @@ 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
@@ -202,9 +200,7 @@ export class BulkEditDataSource implements IAsyncDataSource<BulkFileOperations,
constructor(
@ITextModelService private readonly _textModelService: ITextModelService,
@IUndoRedoService private readonly _undoRedoService: IUndoRedoService,
@ILanguageService private readonly _languageService: ILanguageService,
@ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
) { }
hasChildren(element: BulkFileOperations | BulkEditElement): boolean {
@@ -241,7 +237,7 @@ export class BulkEditDataSource implements IAsyncDataSource<BulkFileOperations,
textModel = ref.object.textEditorModel;
textModelDisposable = ref;
} catch {
textModel = new TextModel('', PLAINTEXT_LANGUAGE_ID, TextModel.DEFAULT_CREATION_OPTIONS, null, this._undoRedoService, this._languageService, this._languageConfigurationService);
textModel = this._instantiationService.createInstance(TextModel, '', PLAINTEXT_LANGUAGE_ID, TextModel.DEFAULT_CREATION_OPTIONS, null);
textModelDisposable = textModel;
}
@@ -7,15 +7,18 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { Codicon } from 'vs/base/common/codicons';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { Schemas } from 'vs/base/common/network';
import { IRange } from 'vs/editor/common/core/range';
import { compare } from 'vs/base/common/strings';
import { ThemeIcon } from 'vs/base/common/themables';
import { URI } from 'vs/base/common/uri';
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { IRange } from 'vs/editor/common/core/range';
import { EditorType } from 'vs/editor/common/editorCommon';
import { Command } from 'vs/editor/common/languages';
import { AbstractGotoSymbolQuickAccessProvider, IGotoSymbolQuickPickItem } from 'vs/editor/contrib/quickAccess/browser/gotoSymbolQuickAccess';
import { localize, localize2 } from 'vs/nls';
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { AnythingQuickAccessProviderRunOptions } from 'vs/platform/quickinput/common/quickAccess';
import { IQuickInputService, IQuickPickItem, QuickPickItem } from 'vs/platform/quickinput/common/quickInput';
@@ -27,13 +30,10 @@ import { CONTEXT_CHAT_LOCATION, CONTEXT_IN_CHAT_INPUT, CONTEXT_IN_QUICK_CHAT } f
import { IChatRequestVariableEntry } from 'vs/workbench/contrib/chat/common/chatModel';
import { ChatRequestAgentPart } from 'vs/workbench/contrib/chat/common/chatParserTypes';
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
import { ILanguageModelToolsService } from 'vs/workbench/contrib/chat/common/languageModelToolsService';
import { AnythingQuickAccessProvider } from 'vs/workbench/contrib/search/browser/anythingQuickAccess';
import { ISymbolQuickPickItem, SymbolsQuickAccessProvider } from 'vs/workbench/contrib/search/browser/symbolsQuickAccess';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { EditorType } from 'vs/editor/common/editorCommon';
import { compare } from 'vs/base/common/strings';
import { ILanguageModelToolsService } from 'vs/workbench/contrib/chat/common/languageModelToolsService';
export function registerChatContextActions() {
registerAction2(AttachContextAction);
@@ -107,7 +107,7 @@ class AttachFileAction extends Action2 {
const textEditorService = accessor.get(IEditorService);
const activeUri = textEditorService.activeEditor?.resource;
if (textEditorService.activeTextEditorControl?.getEditorType() === EditorType.ICodeEditor && activeUri && [Schemas.file, Schemas.vscodeRemote].includes(activeUri.scheme)) {
if (textEditorService.activeTextEditorControl?.getEditorType() === EditorType.ICodeEditor && activeUri && [Schemas.file, Schemas.vscodeRemote, Schemas.untitled].includes(activeUri.scheme)) {
variablesService.attachContext('file', activeUri, ChatAgentLocation.Panel);
}
}
@@ -132,7 +132,7 @@ class AttachSelectionAction extends Action2 {
const activeEditor = textEditorService.activeTextEditorControl;
const activeUri = textEditorService.activeEditor?.resource;
if (textEditorService.activeTextEditorControl?.getEditorType() === EditorType.ICodeEditor && activeUri && [Schemas.file, Schemas.vscodeRemote].includes(activeUri.scheme)) {
if (textEditorService.activeTextEditorControl?.getEditorType() === EditorType.ICodeEditor && activeUri && [Schemas.file, Schemas.vscodeRemote, Schemas.untitled].includes(activeUri.scheme)) {
const selection = activeEditor?.getSelection();
if (selection) {
variablesService.attachContext('file', { uri: activeUri, range: selection }, ChatAgentLocation.Panel);
@@ -164,8 +164,7 @@ export class ChatVariablesService implements IChatVariablesService {
return;
}
await showChatView(this.viewsService);
const widget = this.chatWidgetService.lastFocusedWidget;
const widget = await showChatView(this.viewsService);
if (!widget || !widget.viewModel) {
return;
}
@@ -4,26 +4,24 @@
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';
import { IModelService } from 'vs/editor/common/services/model';
import { ModelService } from 'vs/editor/common/services/modelService';
import { ILanguageService } from 'vs/editor/common/languages/language';
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfiguration';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { IPathService } from 'vs/workbench/services/path/common/pathService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
export class WorkbenchModelService extends ModelService {
constructor(
@IConfigurationService configurationService: IConfigurationService,
@ITextResourcePropertiesService resourcePropertiesService: ITextResourcePropertiesService,
@IUndoRedoService undoRedoService: IUndoRedoService,
@ILanguageConfigurationService languageConfigurationService: ILanguageConfigurationService,
@ILanguageService languageService: ILanguageService,
@IPathService private readonly _pathService: IPathService,
@IInstantiationService instantiationService: IInstantiationService,
) {
super(configurationService, resourcePropertiesService, undoRedoService, languageService, languageConfigurationService);
super(configurationService, resourcePropertiesService, undoRedoService, instantiationService);
}
protected override _schemaShouldMaintainUndoRedoElements(resource: URI) {
@@ -0,0 +1,25 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { registerSingleton, InstantiationType } from 'vs/platform/instantiation/common/extensions';
import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from 'vs/workbench/common/contributions';
import { TreeSitterTextModelService } from 'vs/editor/browser/services/treeSitter/treeSitterParserService';
import { ITreeSitterParserService } from 'vs/editor/common/services/treeSitterParserService';
/**
* Makes sure the ITreeSitterTokenizationService is instantiated
*/
class TreeSitterTokenizationInstantiator implements IWorkbenchContribution {
static readonly ID = 'workbench.contrib.treeSitterTokenizationInstantiator';
constructor(
@ITreeSitterParserService _treeSitterTokenizationService: ITreeSitterParserService
) { }
}
registerSingleton(ITreeSitterParserService, TreeSitterTextModelService, InstantiationType.Eager);
registerWorkbenchContribution2(TreeSitterTokenizationInstantiator.ID, TreeSitterTokenizationInstantiator, WorkbenchPhase.BlockRestore);
@@ -123,7 +123,7 @@ import { IEnterWorkspaceResult, IRecent, IRecentlyOpened, IWorkspaceFolderCreati
import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust';
import { IExtensionTerminalProfile, IShellLaunchConfig, ITerminalBackend, ITerminalLogService, ITerminalProfile, TerminalIcon, TerminalLocation, TerminalShellType } from 'vs/platform/terminal/common/terminal';
import { ICreateTerminalOptions, IDeserializedTerminalEditorInput, ITerminalConfigurationService, ITerminalEditorService, ITerminalGroup, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, TerminalEditorLocation } from 'vs/workbench/contrib/terminal/browser/terminal';
import { assertIsDefined } from 'vs/base/common/types';
import { assertIsDefined, upcast } from 'vs/base/common/types';
import { IRegisterContributedProfileArgs, IShellLaunchConfigResolveOptions, ITerminalProfileProvider, ITerminalProfileResolverService, ITerminalProfileService } from 'vs/workbench/contrib/terminal/common/terminal';
import { EditorResolverService } from 'vs/workbench/services/editor/browser/editorResolverService';
import { FILE_EDITOR_INPUT_ID } from 'vs/workbench/contrib/files/common/files';
@@ -211,12 +211,7 @@ export class TestTextFileEditor extends TextFileEditor {
}
setSelection(selection: Selection | undefined, reason: EditorPaneSelectionChangeReason): void {
if (selection) {
const options: ITextEditorOptions = { selection };
this._options = options;
} else {
this._options = undefined;
}
this._options = selection ? upcast<IEditorOptions, ITextEditorOptions>({ selection }) : undefined;
this._onDidChangeSelection.fire({ reason });
}
@@ -115,6 +115,7 @@ import 'vs/editor/common/services/languageFeaturesService';
import 'vs/editor/common/services/semanticTokensStylingService';
import 'vs/editor/common/services/treeViewsDndService';
import 'vs/workbench/services/textMate/browser/textMateTokenizationFeature.contribution';
import 'vs/workbench/services/treeSitter/browser/treeSitterTokenizationFeature.contribution';
import 'vs/workbench/services/userActivity/common/userActivityService';
import 'vs/workbench/services/userActivity/browser/userActivityBrowser';
import 'vs/workbench/services/editor/browser/editorPaneService';
+1
View File
@@ -59,6 +59,7 @@
'sinon-test': new URL('../../../node_modules/sinon-test/dist/sinon-test.js', baseUrl).href,
'@xterm/xterm': new URL('../../../node_modules/@xterm/xterm/lib/xterm.js', baseUrl).href,
'@vscode/iconv-lite-umd': new URL('../../../node_modules/@vscode/iconv-lite-umd/lib/iconv-lite-umd.js', baseUrl).href,
'@vscode/tree-sitter-wasm': new URL('../../../node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter.js', baseUrl).href,
jschardet: new URL('../../../node_modules/jschardet/dist/jschardet.min.js', baseUrl).href
}
});
+5
View File
@@ -1666,6 +1666,11 @@
tar-fs "^3.0.6"
vscode-uri "^3.0.8"
"@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/v8-heap-parser@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@vscode/v8-heap-parser/-/v8-heap-parser-0.1.0.tgz#f3fe61ce954cc3dd78ed42e09f865450685e351f"