mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-02 01:25:39 -05:00
Merge from vscode 2f984aad710215f4e4684a035bb02f55d1a9e2cc (#9819)
This commit is contained in:
@@ -12,7 +12,7 @@ import { ExtHostAuthenticationShape, ExtHostContext, IExtHostContext, MainContex
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { MenuRegistry, MenuId, IMenuItem } from 'vs/platform/actions/common/actions';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
|
||||
@@ -53,6 +53,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
private _sessionMenuItems = new Map<string, IDisposable[]>();
|
||||
private _accounts = new Map<string, string[]>(); // Map account name to session ids
|
||||
private _sessions = new Map<string, string>(); // Map account id to name
|
||||
private _signInMenuItem: IMenuItem | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly _proxy: ExtHostAuthenticationShape,
|
||||
@@ -94,7 +95,9 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
quickPick.show();
|
||||
}
|
||||
|
||||
private registerCommandsAndContextMenuItems(): void {
|
||||
private async registerCommandsAndContextMenuItems(): Promise<void> {
|
||||
const sessions = await this._proxy.$getSessions(this.id);
|
||||
|
||||
if (this.dependents.length) {
|
||||
this._register(CommandsRegistry.registerCommand({
|
||||
id: `signIn${this.id}`,
|
||||
@@ -103,19 +106,21 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
},
|
||||
}));
|
||||
|
||||
this._register(MenuRegistry.appendMenuItem(MenuId.AccountsContext, {
|
||||
this._signInMenuItem = {
|
||||
group: '2_providers',
|
||||
command: {
|
||||
id: `signIn${this.id}`,
|
||||
title: nls.localize('addAccount', "Sign in to {0}", this.displayName)
|
||||
title: sessions.length
|
||||
? nls.localize('addAnotherAccount', "Sign in to another {0} account", this.displayName)
|
||||
: nls.localize('addAccount', "Sign in to {0}", this.displayName)
|
||||
},
|
||||
order: 3
|
||||
}));
|
||||
};
|
||||
|
||||
this._register(MenuRegistry.appendMenuItem(MenuId.AccountsContext, this._signInMenuItem));
|
||||
}
|
||||
|
||||
this._proxy.$getSessions(this.id).then(sessions => {
|
||||
sessions.forEach(session => this.registerSession(session));
|
||||
});
|
||||
sessions.forEach(session => this.registerSession(session));
|
||||
}
|
||||
|
||||
private registerSession(session: modes.AuthenticationSession) {
|
||||
@@ -205,11 +210,19 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
this._sessionMenuItems.delete(accountName);
|
||||
}
|
||||
this._accounts.delete(accountName);
|
||||
|
||||
if (this._signInMenuItem) {
|
||||
this._signInMenuItem.command.title = nls.localize('addAccount', "Sign in to {0}", this.displayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
addedSessions.forEach(session => this.registerSession(session));
|
||||
|
||||
if (addedSessions.length && this._signInMenuItem) {
|
||||
this._signInMenuItem.command.title = nls.localize('addAnotherAccount', "Sign in to another {0} account", this.displayName);
|
||||
}
|
||||
}
|
||||
|
||||
login(scopes: string[]): Promise<modes.AuthenticationSession> {
|
||||
|
||||
@@ -21,7 +21,7 @@ import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { decodeSemanticTokensDto } from 'vs/workbench/api/common/shared/semanticTokens';
|
||||
import { decodeSemanticTokensDto } from 'vs/workbench/api/common/shared/semanticTokensDto';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
|
||||
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
export class MainThreadNotebookDocument extends Disposable {
|
||||
private _textModel: NotebookTextModel;
|
||||
@@ -163,8 +164,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
controller?.spliceNotebookCellOutputs(resource, cellHandle, splices, renderers);
|
||||
}
|
||||
|
||||
async executeNotebook(viewType: string, uri: URI): Promise<void> {
|
||||
return this._proxy.$executeNotebook(viewType, uri, undefined);
|
||||
async executeNotebook(viewType: string, uri: URI, token: CancellationToken): Promise<void> {
|
||||
return this._proxy.$executeNotebook(viewType, uri, undefined, token);
|
||||
}
|
||||
|
||||
async $postMessage(handle: number, value: any): Promise<boolean> {
|
||||
@@ -232,8 +233,8 @@ export class MainThreadNotebookController implements IMainNotebookController {
|
||||
mainthreadNotebook?.textModel.$spliceNotebookCellOutputs(cellHandle, splices);
|
||||
}
|
||||
|
||||
async executeNotebook(viewType: string, uri: URI): Promise<void> {
|
||||
this._mainThreadNotebook.executeNotebook(viewType, uri);
|
||||
async executeNotebook(viewType: string, uri: URI, token: CancellationToken): Promise<void> {
|
||||
this._mainThreadNotebook.executeNotebook(viewType, uri, token);
|
||||
}
|
||||
|
||||
onDidReceiveMessage(uri: UriComponents, message: any): void {
|
||||
@@ -266,8 +267,8 @@ export class MainThreadNotebookController implements IMainNotebookController {
|
||||
document?.textModel.updateRenderers(renderers);
|
||||
}
|
||||
|
||||
async executeNotebookCell(uri: URI, handle: number): Promise<void> {
|
||||
return this._proxy.$executeNotebook(this._viewType, uri, handle);
|
||||
async executeNotebookCell(uri: URI, handle: number, token: CancellationToken): Promise<void> {
|
||||
return this._proxy.$executeNotebook(this._viewType, uri, handle, token);
|
||||
}
|
||||
|
||||
async destoryNotebookDocument(notebook: INotebookTextModel): Promise<void> {
|
||||
|
||||
@@ -43,7 +43,7 @@ const configurationEntrySchema: IJSONSchema = {
|
||||
default: 'window',
|
||||
enumDescriptions: [
|
||||
nls.localize('scope.application.description', "Configuration that can be configured only in the user settings."),
|
||||
nls.localize('scope.machine.description', "Configuration that can be configured only in the user settings when the extension is running locally, or only in the remote settings when the extension is running remotely."),
|
||||
nls.localize('scope.machine.description', "Configuration that can be configured only in the user settings or only in the remote settings."),
|
||||
nls.localize('scope.window.description', "Configuration that can be configured in the user, remote or workspace settings."),
|
||||
nls.localize('scope.resource.description', "Configuration that can be configured in the user, remote, workspace or folder settings."),
|
||||
nls.localize('scope.language-overridable.description', "Resource configuration that can be configured in language specific settings."),
|
||||
|
||||
@@ -391,11 +391,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
return extHostLanguageFeatures.registerOnTypeFormattingEditProvider(extension, checkSelector(selector), provider, [firstTriggerCharacter].concat(moreTriggerCharacters));
|
||||
},
|
||||
registerDocumentSemanticTokensProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSemanticTokensProvider, legend: vscode.SemanticTokensLegend): vscode.Disposable {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostLanguageFeatures.registerDocumentSemanticTokensProvider(extension, checkSelector(selector), provider, legend);
|
||||
},
|
||||
registerDocumentRangeSemanticTokensProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentRangeSemanticTokensProvider, legend: vscode.SemanticTokensLegend): vscode.Disposable {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostLanguageFeatures.registerDocumentRangeSemanticTokensProvider(extension, checkSelector(selector), provider, legend);
|
||||
},
|
||||
registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, firstItem?: string | vscode.SignatureHelpProviderMetadata, ...remaining: string[]): vscode.Disposable {
|
||||
@@ -588,7 +586,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
return extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializer);
|
||||
},
|
||||
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomEditorProvider | vscode.CustomTextEditorProvider, options?: { webviewOptions?: vscode.WebviewPanelOptions }) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostWebviews.registerCustomEditorProvider(extension, viewType, provider, options?.webviewOptions);
|
||||
},
|
||||
registerDecorationProvider(provider: vscode.DecorationProvider) {
|
||||
|
||||
@@ -1538,7 +1538,7 @@ export interface ExtHostCommentsShape {
|
||||
|
||||
export interface ExtHostNotebookShape {
|
||||
$resolveNotebook(viewType: string, uri: UriComponents): Promise<number | undefined>;
|
||||
$executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined): Promise<void>;
|
||||
$executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void>;
|
||||
$saveNotebook(viewType: string, uri: UriComponents): Promise<boolean>;
|
||||
$updateActiveEditor(viewType: string, uri: UriComponents): Promise<void>;
|
||||
$destoryNotebookDocument(viewType: string, uri: UriComponents): Promise<boolean>;
|
||||
|
||||
@@ -27,7 +27,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
|
||||
import { IURITransformer } from 'vs/base/common/uriIpc';
|
||||
import { DisposableStore, dispose } from 'vs/base/common/lifecycle';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { encodeSemanticTokensDto } from 'vs/workbench/api/common/shared/semanticTokens';
|
||||
import { encodeSemanticTokensDto } from 'vs/workbench/api/common/shared/semanticTokensDto';
|
||||
import { IdGenerator } from 'vs/base/common/idGenerator';
|
||||
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
|
||||
import { Cache } from './cache';
|
||||
|
||||
@@ -13,8 +13,9 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
|
||||
import { CellKind, CellOutputKind, ExtHostNotebookShape, IMainContext, MainContext, MainThreadNotebookShape, NotebookCellOutputsSplice } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { CellEditType, CellUri, diff, ICellEditOperation, ICellInsertEdit, IErrorOutput, INotebookDisplayOrder, INotebookEditData, IOrderedMimeType, IStreamOutput, ITransformedDisplayOutputDto, mimeTypeSupportedByCore, NotebookCellsChangedEvent, NotebookCellsSplice2, sortMimeTypes, ICellDeleteEdit } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellEditType, CellUri, diff, ICellEditOperation, ICellInsertEdit, IErrorOutput, INotebookDisplayOrder, INotebookEditData, IOrderedMimeType, IStreamOutput, ITransformedDisplayOutputDto, mimeTypeSupportedByCore, NotebookCellsChangedEvent, NotebookCellsSplice2, sortMimeTypes, ICellDeleteEdit, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { Disposable as VSCodeDisposable } from './extHostTypes';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
interface IObservable<T> {
|
||||
proxy: T;
|
||||
@@ -37,12 +38,6 @@ function getObservable<T extends Object>(obj: T): IObservable<T> {
|
||||
};
|
||||
}
|
||||
|
||||
const notebookDocumentMetadataDefaults: vscode.NotebookDocumentMetadata = {
|
||||
editable: true,
|
||||
cellEditable: true,
|
||||
cellRunnable: true
|
||||
};
|
||||
|
||||
export class ExtHostCell extends Disposable implements vscode.NotebookCell {
|
||||
|
||||
private originalSource: string[];
|
||||
@@ -80,7 +75,7 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
|
||||
this.originalSource = this._content.split(/\r|\n|\r\n/g);
|
||||
this._outputs = outputs;
|
||||
|
||||
const observableMetadata = getObservable(_metadata || {} as any);
|
||||
const observableMetadata = getObservable(_metadata || {});
|
||||
this._metadata = observableMetadata.proxy;
|
||||
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
|
||||
this.updateMetadata();
|
||||
@@ -115,8 +110,9 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
|
||||
}
|
||||
|
||||
set metadata(newMetadata: vscode.NotebookCellMetadata) {
|
||||
// Don't apply metadata defaults here, 'undefined' means 'inherit from document metadata'
|
||||
this._metadataChangeListener.dispose();
|
||||
const observableMetadata = getObservable(newMetadata || {} as any); // TODO defaults
|
||||
const observableMetadata = getObservable(newMetadata);
|
||||
this._metadata = observableMetadata.proxy;
|
||||
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
|
||||
this.updateMetadata();
|
||||
@@ -175,15 +171,24 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
|
||||
this._proxy.$updateNotebookLanguages(this.viewType, this.uri, this._languages);
|
||||
}
|
||||
|
||||
private _metadata: vscode.NotebookDocumentMetadata | undefined = notebookDocumentMetadataDefaults;
|
||||
private _metadata: Required<vscode.NotebookDocumentMetadata> = notebookDocumentMetadataDefaults;
|
||||
private _metadataChangeListener: IDisposable;
|
||||
|
||||
get metadata() {
|
||||
return this._metadata;
|
||||
}
|
||||
|
||||
set metadata(newMetadata: vscode.NotebookDocumentMetadata | undefined) {
|
||||
this._metadata = newMetadata || notebookDocumentMetadataDefaults;
|
||||
this._proxy.$updateNotebookMetadata(this.viewType, this.uri, this._metadata);
|
||||
set metadata(newMetadata: Required<vscode.NotebookDocumentMetadata>) {
|
||||
this._metadataChangeListener.dispose();
|
||||
newMetadata = {
|
||||
...notebookDocumentMetadataDefaults,
|
||||
...newMetadata
|
||||
};
|
||||
const observableMetadata = getObservable(newMetadata);
|
||||
this._metadata = observableMetadata.proxy;
|
||||
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
|
||||
this.updateMetadata();
|
||||
}));
|
||||
}
|
||||
|
||||
private _displayOrder: string[] = [];
|
||||
@@ -210,6 +215,16 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
|
||||
public renderingHandler: ExtHostNotebookOutputRenderingHandler
|
||||
) {
|
||||
super();
|
||||
|
||||
const observableMetadata = getObservable(notebookDocumentMetadataDefaults);
|
||||
this._metadata = observableMetadata.proxy;
|
||||
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
|
||||
this.updateMetadata();
|
||||
}));
|
||||
}
|
||||
|
||||
private updateMetadata() {
|
||||
this._proxy.$updateNotebookMetadata(this.viewType, this.uri, this._metadata);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@@ -686,7 +701,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
async $executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined): Promise<void> {
|
||||
async $executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void> {
|
||||
let provider = this._notebookProviders.get(viewType);
|
||||
|
||||
if (!provider) {
|
||||
@@ -700,7 +715,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
}
|
||||
|
||||
let cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
|
||||
return provider.provider.executeCell(document!, cell);
|
||||
return provider.provider.executeCell(document!, cell, token);
|
||||
}
|
||||
|
||||
async $saveNotebook(viewType: string, uri: UriComponents): Promise<boolean> {
|
||||
|
||||
@@ -20,12 +20,10 @@ import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
function es5ClassCompat(target: Function): any {
|
||||
///@ts-ignore
|
||||
///@ts-expect-error
|
||||
function _() { return Reflect.construct(target, arguments, this.constructor); }
|
||||
Object.defineProperty(_, 'name', Object.getOwnPropertyDescriptor(target, 'name')!);
|
||||
///@ts-ignore
|
||||
Object.setPrototypeOf(_, target);
|
||||
///@ts-ignore
|
||||
Object.setPrototypeOf(_.prototype, target.prototype);
|
||||
return _;
|
||||
}
|
||||
@@ -2428,24 +2426,126 @@ export class SemanticTokensLegend {
|
||||
}
|
||||
}
|
||||
|
||||
function isStrArrayOrUndefined(arg: any): arg is string[] | undefined {
|
||||
if (typeof arg === 'undefined') {
|
||||
return true;
|
||||
}
|
||||
if (Array.isArray(arg)) {
|
||||
for (const element of arg) {
|
||||
if (typeof element !== 'string') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export class SemanticTokensBuilder {
|
||||
|
||||
private _prevLine: number;
|
||||
private _prevChar: number;
|
||||
private _dataIsSortedAndDeltaEncoded: boolean;
|
||||
private _data: number[];
|
||||
private _dataLen: number;
|
||||
private _tokenTypeStrToInt: Map<string, number>;
|
||||
private _tokenModifierStrToInt: Map<string, number>;
|
||||
private _hasLegend: boolean;
|
||||
|
||||
constructor() {
|
||||
constructor(legend?: vscode.SemanticTokensLegend) {
|
||||
this._prevLine = 0;
|
||||
this._prevChar = 0;
|
||||
this._dataIsSortedAndDeltaEncoded = true;
|
||||
this._data = [];
|
||||
this._dataLen = 0;
|
||||
this._tokenTypeStrToInt = new Map<string, number>();
|
||||
this._tokenModifierStrToInt = new Map<string, number>();
|
||||
this._hasLegend = false;
|
||||
if (legend) {
|
||||
this._hasLegend = true;
|
||||
for (let i = 0, len = legend.tokenTypes.length; i < len; i++) {
|
||||
this._tokenTypeStrToInt.set(legend.tokenTypes[i], i);
|
||||
}
|
||||
for (let i = 0, len = legend.tokenModifiers.length; i < len; i++) {
|
||||
this._tokenModifierStrToInt.set(legend.tokenModifiers[i], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public push(line: number, char: number, length: number, tokenType: number, tokenModifiers: number): void {
|
||||
public push(line: number, char: number, length: number, tokenType: number, tokenModifiers: number): void;
|
||||
public push(range: Range, tokenType: string, tokenModifiers?: string[]): void;
|
||||
public push(arg0: any, arg1: any, arg2: any, arg3?: any, arg4?: any): void {
|
||||
if (typeof arg0 === 'number' && typeof arg1 === 'number' && typeof arg2 === 'number' && typeof arg3 === 'number' && typeof arg4 === 'number') {
|
||||
// 1st overload
|
||||
return this._pushEncoded(arg0, arg1, arg2, arg3, arg4);
|
||||
}
|
||||
if (Range.isRange(arg0) && typeof arg1 === 'string' && isStrArrayOrUndefined(arg2)) {
|
||||
// 2nd overload
|
||||
return this._push(arg0, arg1, arg2);
|
||||
}
|
||||
throw illegalArgument();
|
||||
}
|
||||
|
||||
private _push(range: vscode.Range, tokenType: string, tokenModifiers?: string[]): void {
|
||||
if (!this._hasLegend) {
|
||||
throw new Error('Legend must be provided in constructor');
|
||||
}
|
||||
if (range.start.line !== range.end.line) {
|
||||
throw new Error('`range` cannot span multiple lines');
|
||||
}
|
||||
if (!this._tokenTypeStrToInt.has(tokenType)) {
|
||||
throw new Error('`tokenType` is not in the provided legend');
|
||||
}
|
||||
const line = range.start.line;
|
||||
const char = range.start.character;
|
||||
const length = range.end.character - range.start.character;
|
||||
const nTokenType = this._tokenTypeStrToInt.get(tokenType)!;
|
||||
let nTokenModifiers = 0;
|
||||
if (tokenModifiers) {
|
||||
for (const tokenModifier of tokenModifiers) {
|
||||
if (!this._tokenModifierStrToInt.has(tokenModifier)) {
|
||||
throw new Error('`tokenModifier` is not in the provided legend');
|
||||
}
|
||||
const nTokenModifier = this._tokenModifierStrToInt.get(tokenModifier)!;
|
||||
nTokenModifiers |= (1 << nTokenModifier) >>> 0;
|
||||
}
|
||||
}
|
||||
this._pushEncoded(line, char, length, nTokenType, nTokenModifiers);
|
||||
}
|
||||
|
||||
private _pushEncoded(line: number, char: number, length: number, tokenType: number, tokenModifiers: number): void {
|
||||
if (this._dataIsSortedAndDeltaEncoded && (line < this._prevLine || (line === this._prevLine && char < this._prevChar))) {
|
||||
// push calls were ordered and are no longer ordered
|
||||
this._dataIsSortedAndDeltaEncoded = false;
|
||||
|
||||
// Remove delta encoding from data
|
||||
const tokenCount = (this._data.length / 5) | 0;
|
||||
let prevLine = 0;
|
||||
let prevChar = 0;
|
||||
for (let i = 0; i < tokenCount; i++) {
|
||||
let line = this._data[5 * i];
|
||||
let char = this._data[5 * i + 1];
|
||||
|
||||
if (line === 0) {
|
||||
// on the same line as previous token
|
||||
line = prevLine;
|
||||
char += prevChar;
|
||||
} else {
|
||||
// on a different line than previous token
|
||||
line += prevLine;
|
||||
}
|
||||
|
||||
this._data[5 * i] = line;
|
||||
this._data[5 * i + 1] = char;
|
||||
|
||||
prevLine = line;
|
||||
prevChar = char;
|
||||
}
|
||||
}
|
||||
|
||||
let pushLine = line;
|
||||
let pushChar = char;
|
||||
if (this._dataLen > 0) {
|
||||
if (this._dataIsSortedAndDeltaEncoded && this._dataLen > 0) {
|
||||
pushLine -= this._prevLine;
|
||||
if (pushLine === 0) {
|
||||
pushChar -= this._prevChar;
|
||||
@@ -2462,8 +2562,55 @@ export class SemanticTokensBuilder {
|
||||
this._prevChar = char;
|
||||
}
|
||||
|
||||
public build(): Uint32Array {
|
||||
return new Uint32Array(this._data);
|
||||
private static _sortAndDeltaEncode(data: number[]): Uint32Array {
|
||||
let pos: number[] = [];
|
||||
const tokenCount = (data.length / 5) | 0;
|
||||
for (let i = 0; i < tokenCount; i++) {
|
||||
pos[i] = i;
|
||||
}
|
||||
pos.sort((a, b) => {
|
||||
const aLine = data[5 * a];
|
||||
const bLine = data[5 * b];
|
||||
if (aLine === bLine) {
|
||||
const aChar = data[5 * a + 1];
|
||||
const bChar = data[5 * b + 1];
|
||||
return aChar - bChar;
|
||||
}
|
||||
return aLine - bLine;
|
||||
});
|
||||
const result = new Uint32Array(data.length);
|
||||
let prevLine = 0;
|
||||
let prevChar = 0;
|
||||
for (let i = 0; i < tokenCount; i++) {
|
||||
const srcOffset = 5 * pos[i];
|
||||
const line = data[srcOffset + 0];
|
||||
const char = data[srcOffset + 1];
|
||||
const length = data[srcOffset + 2];
|
||||
const tokenType = data[srcOffset + 3];
|
||||
const tokenModifiers = data[srcOffset + 4];
|
||||
|
||||
const pushLine = line - prevLine;
|
||||
const pushChar = (pushLine === 0 ? char - prevChar : char);
|
||||
|
||||
const dstOffset = 5 * i;
|
||||
result[dstOffset + 0] = pushLine;
|
||||
result[dstOffset + 1] = pushChar;
|
||||
result[dstOffset + 2] = length;
|
||||
result[dstOffset + 3] = tokenType;
|
||||
result[dstOffset + 4] = tokenModifiers;
|
||||
|
||||
prevLine = line;
|
||||
prevChar = char;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public build(resultId?: string): SemanticTokens {
|
||||
if (!this._dataIsSortedAndDeltaEncoded) {
|
||||
return new SemanticTokens(SemanticTokensBuilder._sortAndDeltaEncode(this._data), resultId);
|
||||
}
|
||||
return new SemanticTokens(new Uint32Array(this._data), resultId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2600,7 +2747,6 @@ export class CustomDocument<EditType = unknown> implements vscode.CustomDocument
|
||||
|
||||
readonly #edits = new Cache<EditType>('edits');
|
||||
|
||||
readonly #viewType: string;
|
||||
readonly #uri: vscode.Uri;
|
||||
|
||||
#editState: EditState = {
|
||||
@@ -2611,15 +2757,12 @@ export class CustomDocument<EditType = unknown> implements vscode.CustomDocument
|
||||
#isDisposed = false;
|
||||
#version = 1;
|
||||
|
||||
constructor(viewType: string, uri: vscode.Uri) {
|
||||
this.#viewType = viewType;
|
||||
constructor(uri: vscode.Uri) {
|
||||
this.#uri = uri;
|
||||
}
|
||||
|
||||
//#region Public API
|
||||
|
||||
public get viewType(): string { return this.#viewType; }
|
||||
|
||||
public get uri(): vscode.Uri { return this.#uri; }
|
||||
|
||||
public get fileName(): string { return this.uri.fsPath; }
|
||||
@@ -2672,11 +2815,11 @@ export class CustomDocument<EditType = unknown> implements vscode.CustomDocument
|
||||
|
||||
/** @internal*/ _addEdit(edit: EditType): number {
|
||||
const id = this.#edits.add([edit]);
|
||||
this.#editState = {
|
||||
allEdits: [...this.#editState.allEdits.slice(0, this.#editState.currentIndex), id],
|
||||
this._updateEditState({
|
||||
allEdits: [...this.#editState.allEdits.slice(0, this.#editState.currentIndex + 1), id],
|
||||
currentIndex: this.#editState.currentIndex + 1,
|
||||
saveIndex: this.#editState.saveIndex,
|
||||
};
|
||||
});
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,16 +269,16 @@ class WebviewDocumentStore {
|
||||
return this._documents.get(this.key(viewType, resource));
|
||||
}
|
||||
|
||||
public add(document: extHostTypes.CustomDocument) {
|
||||
const key = this.key(document.viewType, document.uri);
|
||||
public add(viewType: string, document: extHostTypes.CustomDocument) {
|
||||
const key = this.key(viewType, document.uri);
|
||||
if (this._documents.has(key)) {
|
||||
throw new Error(`Document already exists for viewType:${document.viewType} resource:${document.uri}`);
|
||||
throw new Error(`Document already exists for viewType:${viewType} resource:${document.uri}`);
|
||||
}
|
||||
this._documents.set(key, document);
|
||||
}
|
||||
|
||||
public delete(document: extHostTypes.CustomDocument) {
|
||||
const key = this.key(document.viewType, document.uri);
|
||||
public delete(viewType: string, document: extHostTypes.CustomDocument) {
|
||||
const key = this.key(viewType, document.uri);
|
||||
this._documents.delete(key);
|
||||
}
|
||||
|
||||
@@ -414,7 +414,7 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
disposables.add(provider.editingDelegate.onDidEdit(e => {
|
||||
const document = e.document;
|
||||
const editId = (document as extHostTypes.CustomDocument)._addEdit(e.edit);
|
||||
this._proxy.$onDidEdit(document.uri, document.viewType, editId, e.label);
|
||||
this._proxy.$onDidEdit(document.uri, viewType, editId, e.label);
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -516,7 +516,7 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
|
||||
const revivedResource = URI.revive(resource);
|
||||
const document = await entry.provider.openCustomDocument(revivedResource, cancellation);
|
||||
this._documents.add(document as extHostTypes.CustomDocument);
|
||||
this._documents.add(viewType, document as extHostTypes.CustomDocument);
|
||||
return {
|
||||
editable: !!entry.provider.editingDelegate,
|
||||
};
|
||||
@@ -534,7 +534,7 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
|
||||
const revivedResource = URI.revive(resource);
|
||||
const document = this.getCustomDocument(viewType, revivedResource);
|
||||
this._documents.delete(document);
|
||||
this._documents.delete(viewType, document);
|
||||
document._dispose();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
export interface IFullSemanticTokensDto {
|
||||
id: number;
|
||||
type: 'full';
|
||||
data: Uint32Array;
|
||||
}
|
||||
|
||||
export interface IDeltaSemanticTokensDto {
|
||||
id: number;
|
||||
type: 'delta';
|
||||
deltas: { start: number; deleteCount: number; data?: Uint32Array; }[];
|
||||
}
|
||||
|
||||
export type ISemanticTokensDto = IFullSemanticTokensDto | IDeltaSemanticTokensDto;
|
||||
|
||||
const enum EncodedSemanticTokensType {
|
||||
Full = 1,
|
||||
Delta = 2
|
||||
}
|
||||
|
||||
export function encodeSemanticTokensDto(semanticTokens: ISemanticTokensDto): VSBuffer {
|
||||
const buff = VSBuffer.alloc(encodedSize2(semanticTokens));
|
||||
let offset = 0;
|
||||
buff.writeUInt32BE(semanticTokens.id, offset); offset += 4;
|
||||
if (semanticTokens.type === 'full') {
|
||||
buff.writeUInt8(EncodedSemanticTokensType.Full, offset); offset += 1;
|
||||
buff.writeUInt32BE(semanticTokens.data.length, offset); offset += 4;
|
||||
for (const uint of semanticTokens.data) {
|
||||
buff.writeUInt32BE(uint, offset); offset += 4;
|
||||
}
|
||||
} else {
|
||||
buff.writeUInt8(EncodedSemanticTokensType.Delta, offset); offset += 1;
|
||||
buff.writeUInt32BE(semanticTokens.deltas.length, offset); offset += 4;
|
||||
for (const delta of semanticTokens.deltas) {
|
||||
buff.writeUInt32BE(delta.start, offset); offset += 4;
|
||||
buff.writeUInt32BE(delta.deleteCount, offset); offset += 4;
|
||||
if (delta.data) {
|
||||
buff.writeUInt32BE(delta.data.length, offset); offset += 4;
|
||||
for (const uint of delta.data) {
|
||||
buff.writeUInt32BE(uint, offset); offset += 4;
|
||||
}
|
||||
} else {
|
||||
buff.writeUInt32BE(0, offset); offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
|
||||
function encodedSize2(semanticTokens: ISemanticTokensDto): number {
|
||||
let result = 0;
|
||||
result += 4; // id
|
||||
result += 1; // type
|
||||
if (semanticTokens.type === 'full') {
|
||||
result += 4; // data length
|
||||
result += semanticTokens.data.byteLength;
|
||||
} else {
|
||||
result += 4; // delta count
|
||||
for (const delta of semanticTokens.deltas) {
|
||||
result += 4; // start
|
||||
result += 4; // deleteCount
|
||||
result += 4; // data length
|
||||
if (delta.data) {
|
||||
result += delta.data.byteLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function decodeSemanticTokensDto(buff: VSBuffer): ISemanticTokensDto {
|
||||
let offset = 0;
|
||||
const id = buff.readUInt32BE(offset); offset += 4;
|
||||
const type: EncodedSemanticTokensType = buff.readUInt8(offset); offset += 1;
|
||||
if (type === EncodedSemanticTokensType.Full) {
|
||||
const length = buff.readUInt32BE(offset); offset += 4;
|
||||
const data = new Uint32Array(length);
|
||||
for (let j = 0; j < length; j++) {
|
||||
data[j] = buff.readUInt32BE(offset); offset += 4;
|
||||
}
|
||||
return {
|
||||
id: id,
|
||||
type: 'full',
|
||||
data: data
|
||||
};
|
||||
}
|
||||
const deltaCount = buff.readUInt32BE(offset); offset += 4;
|
||||
let deltas: { start: number; deleteCount: number; data?: Uint32Array; }[] = [];
|
||||
for (let i = 0; i < deltaCount; i++) {
|
||||
const start = buff.readUInt32BE(offset); offset += 4;
|
||||
const deleteCount = buff.readUInt32BE(offset); offset += 4;
|
||||
const length = buff.readUInt32BE(offset); offset += 4;
|
||||
let data: Uint32Array | undefined;
|
||||
if (length > 0) {
|
||||
data = new Uint32Array(length);
|
||||
for (let j = 0; j < length; j++) {
|
||||
data[j] = buff.readUInt32BE(offset); offset += 4;
|
||||
}
|
||||
}
|
||||
deltas[i] = { start, deleteCount, data };
|
||||
}
|
||||
return {
|
||||
id: id,
|
||||
type: 'delta',
|
||||
deltas: deltas
|
||||
};
|
||||
}
|
||||
152
src/vs/workbench/api/common/shared/semanticTokensDto.ts
Normal file
152
src/vs/workbench/api/common/shared/semanticTokensDto.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
|
||||
export interface IFullSemanticTokensDto {
|
||||
id: number;
|
||||
type: 'full';
|
||||
data: Uint32Array;
|
||||
}
|
||||
|
||||
export interface IDeltaSemanticTokensDto {
|
||||
id: number;
|
||||
type: 'delta';
|
||||
deltas: { start: number; deleteCount: number; data?: Uint32Array; }[];
|
||||
}
|
||||
|
||||
export type ISemanticTokensDto = IFullSemanticTokensDto | IDeltaSemanticTokensDto;
|
||||
|
||||
const enum EncodedSemanticTokensType {
|
||||
Full = 1,
|
||||
Delta = 2
|
||||
}
|
||||
|
||||
function reverseEndianness(arr: Uint8Array): void {
|
||||
for (let i = 0, len = arr.length; i < len; i += 4) {
|
||||
// flip bytes 0<->3 and 1<->2
|
||||
const b0 = arr[i + 0];
|
||||
const b1 = arr[i + 1];
|
||||
const b2 = arr[i + 2];
|
||||
const b3 = arr[i + 3];
|
||||
arr[i + 0] = b3;
|
||||
arr[i + 1] = b2;
|
||||
arr[i + 2] = b1;
|
||||
arr[i + 3] = b0;
|
||||
}
|
||||
}
|
||||
|
||||
function toLittleEndianBuffer(arr: Uint32Array): VSBuffer {
|
||||
const uint8Arr = new Uint8Array(arr.buffer, arr.byteOffset, arr.length * 4);
|
||||
if (!platform.isLittleEndian()) {
|
||||
// the byte order must be changed
|
||||
reverseEndianness(uint8Arr);
|
||||
}
|
||||
return VSBuffer.wrap(uint8Arr);
|
||||
}
|
||||
|
||||
function fromLittleEndianBuffer(buff: VSBuffer): Uint32Array {
|
||||
const uint8Arr = buff.buffer;
|
||||
if (!platform.isLittleEndian()) {
|
||||
// the byte order must be changed
|
||||
reverseEndianness(uint8Arr);
|
||||
}
|
||||
if (uint8Arr.byteOffset % 4 === 0) {
|
||||
return new Uint32Array(uint8Arr.buffer, uint8Arr.byteOffset);
|
||||
} else {
|
||||
// unaligned memory access doesn't work on all platforms
|
||||
const data = new Uint8Array(uint8Arr.byteLength);
|
||||
data.set(uint8Arr);
|
||||
return new Uint32Array(data.buffer, data.byteOffset);
|
||||
}
|
||||
}
|
||||
|
||||
export function encodeSemanticTokensDto(semanticTokens: ISemanticTokensDto): VSBuffer {
|
||||
const dest = new Uint32Array(encodeSemanticTokensDtoSize(semanticTokens));
|
||||
let offset = 0;
|
||||
dest[offset++] = semanticTokens.id;
|
||||
if (semanticTokens.type === 'full') {
|
||||
dest[offset++] = EncodedSemanticTokensType.Full;
|
||||
dest[offset++] = semanticTokens.data.length;
|
||||
dest.set(semanticTokens.data, offset); offset += semanticTokens.data.length;
|
||||
} else {
|
||||
dest[offset++] = EncodedSemanticTokensType.Delta;
|
||||
dest[offset++] = semanticTokens.deltas.length;
|
||||
for (const delta of semanticTokens.deltas) {
|
||||
dest[offset++] = delta.start;
|
||||
dest[offset++] = delta.deleteCount;
|
||||
if (delta.data) {
|
||||
dest[offset++] = delta.data.length;
|
||||
dest.set(delta.data, offset); offset += delta.data.length;
|
||||
} else {
|
||||
dest[offset++] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return toLittleEndianBuffer(dest);
|
||||
}
|
||||
|
||||
function encodeSemanticTokensDtoSize(semanticTokens: ISemanticTokensDto): number {
|
||||
let result = 0;
|
||||
result += (
|
||||
+ 1 // id
|
||||
+ 1 // type
|
||||
);
|
||||
if (semanticTokens.type === 'full') {
|
||||
result += (
|
||||
+ 1 // data length
|
||||
+ semanticTokens.data.length
|
||||
);
|
||||
} else {
|
||||
result += (
|
||||
+ 1 // delta count
|
||||
);
|
||||
result += (
|
||||
+ 1 // start
|
||||
+ 1 // deleteCount
|
||||
+ 1 // data length
|
||||
) * semanticTokens.deltas.length;
|
||||
for (const delta of semanticTokens.deltas) {
|
||||
if (delta.data) {
|
||||
result += delta.data.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function decodeSemanticTokensDto(_buff: VSBuffer): ISemanticTokensDto {
|
||||
const src = fromLittleEndianBuffer(_buff);
|
||||
let offset = 0;
|
||||
const id = src[offset++];
|
||||
const type: EncodedSemanticTokensType = src[offset++];
|
||||
if (type === EncodedSemanticTokensType.Full) {
|
||||
const length = src[offset++];
|
||||
const data = src.subarray(offset, offset + length); offset += length;
|
||||
return {
|
||||
id: id,
|
||||
type: 'full',
|
||||
data: data
|
||||
};
|
||||
}
|
||||
const deltaCount = src[offset++];
|
||||
let deltas: { start: number; deleteCount: number; data?: Uint32Array; }[] = [];
|
||||
for (let i = 0; i < deltaCount; i++) {
|
||||
const start = src[offset++];
|
||||
const deleteCount = src[offset++];
|
||||
const length = src[offset++];
|
||||
let data: Uint32Array | undefined;
|
||||
if (length > 0) {
|
||||
data = src.subarray(offset, offset + length); offset += length;
|
||||
}
|
||||
deltas[i] = { start, deleteCount, data };
|
||||
}
|
||||
return {
|
||||
id: id,
|
||||
type: 'delta',
|
||||
deltas: deltas
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user