mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-24 02:28:34 +01:00
Merge remote-tracking branch 'origin/main' into hediet/tokenization
This commit is contained in:
@@ -304,7 +304,7 @@ export class MainThreadDocumentsAndEditors {
|
||||
this._mainThreadDocuments = this._toDispose.add(new MainThreadDocuments(extHostContext, this._modelService, this._textFileService, fileService, textModelResolverService, environmentService, uriIdentityService, workingCopyFileService, pathService));
|
||||
extHostContext.set(MainContext.MainThreadDocuments, this._mainThreadDocuments);
|
||||
|
||||
this._mainThreadEditors = this._toDispose.add(new MainThreadTextEditors(this, extHostContext, codeEditorService, this._editorService, this._editorGroupService, instantiationService));
|
||||
this._mainThreadEditors = this._toDispose.add(new MainThreadTextEditors(this, extHostContext, codeEditorService, this._editorService, this._editorGroupService));
|
||||
extHostContext.set(MainContext.MainThreadTextEditors, this._mainThreadEditors);
|
||||
|
||||
// It is expected that the ctor of the state computer calls our `_onDelta`.
|
||||
|
||||
@@ -561,5 +561,22 @@ export class MainThreadEditorTabs implements MainThreadEditorTabsShape {
|
||||
// TODO @jrieken This isn't quite right how can we say true for some but not others?
|
||||
return results.every(result => result);
|
||||
}
|
||||
|
||||
async $closeGroup(groupIds: number[], preserveFocus?: boolean): Promise<boolean> {
|
||||
const groupCloseResults: boolean[] = [];
|
||||
for (const groupId of groupIds) {
|
||||
const group = this._editorGroupsService.getGroup(groupId);
|
||||
if (group) {
|
||||
// TODO @lramos15 change this to use group.closeAllEditors once it
|
||||
// is enriched to return a boolean
|
||||
groupCloseResults.push(await group.closeEditors([...group.editors], { preserveFocus }));
|
||||
// Make sure group is empty but still there before removing it
|
||||
if (group.count === 0 && this._editorGroupsService.getGroup(group.id)) {
|
||||
this._editorGroupsService.removeGroup(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
return groupCloseResults.every(result => result);
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { IDecorationOptions, IDecorationRenderOptions } from 'vs/editor/common/e
|
||||
import { ISingleEditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { ITextEditorOptions, IResourceEditorInput, EditorActivation, EditorResolution } from 'vs/platform/editor/common/editor';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor';
|
||||
import { ExtHostContext, ExtHostEditorsShape, IApplyEditsOptions, ITextDocumentShowOptions, ITextEditorConfigurationUpdate, ITextEditorPositionData, IUndoStopOptions, MainThreadTextEditorsShape, TextEditorRevealType } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { editorGroupToColumn, columnToEditorGroup, EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
|
||||
@@ -27,13 +27,6 @@ import { ILineChange } from 'vs/editor/common/diff/diffComputer';
|
||||
import { IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
||||
import { IEditorControl } from 'vs/workbench/common/editor';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { DataTransferConverter } from 'vs/workbench/api/common/shared/dataTransfer';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IDataTransfer, IDataTransferItem } from 'vs/workbench/common/dnd';
|
||||
import { extractEditorsDropData } from 'vs/workbench/browser/dnd';
|
||||
import { Mimes } from 'vs/base/common/mime';
|
||||
import { distinct } from 'vs/base/common/arrays';
|
||||
import { performSnippetEdit } from 'vs/editor/contrib/snippet/browser/snippetController2';
|
||||
|
||||
export interface IMainThreadEditorLocator {
|
||||
getEditor(id: string): MainThreadTextEditor | undefined;
|
||||
@@ -51,7 +44,6 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
private _textEditorsListenersMap: { [editorId: string]: IDisposable[] };
|
||||
private _editorPositionData: ITextEditorPositionData | null;
|
||||
private _registeredDecorationTypes: { [decorationType: string]: boolean };
|
||||
private readonly _dropIntoEditorListeners = new Map<ICodeEditor, IDisposable>();
|
||||
|
||||
constructor(
|
||||
private readonly _editorLocator: IMainThreadEditorLocator,
|
||||
@@ -59,7 +51,6 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
) {
|
||||
this._instanceId = String(++MainThreadTextEditors.INSTANCE_COUNT);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditors);
|
||||
@@ -71,22 +62,6 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
this._toDispose.add(this._editorGroupService.onDidRemoveGroup(() => this._updateActiveAndVisibleTextEditors()));
|
||||
this._toDispose.add(this._editorGroupService.onDidMoveGroup(() => this._updateActiveAndVisibleTextEditors()));
|
||||
|
||||
const registerDropListenerOnEditor = (editor: ICodeEditor) => {
|
||||
this._dropIntoEditorListeners.get(editor)?.dispose();
|
||||
this._dropIntoEditorListeners.set(editor, editor.onDropIntoEditor(e => this.onDropIntoEditor(editor, e.position, e.event)));
|
||||
};
|
||||
|
||||
this._toDispose.add(_codeEditorService.onCodeEditorAdd(registerDropListenerOnEditor));
|
||||
|
||||
this._toDispose.add(_codeEditorService.onCodeEditorRemove(editor => {
|
||||
this._dropIntoEditorListeners.get(editor)?.dispose();
|
||||
this._dropIntoEditorListeners.delete(editor);
|
||||
}));
|
||||
|
||||
for (const editor of this._codeEditorService.listCodeEditors()) {
|
||||
registerDropListenerOnEditor(editor);
|
||||
}
|
||||
|
||||
this._registeredDecorationTypes = Object.create(null);
|
||||
}
|
||||
|
||||
@@ -99,8 +74,6 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
for (let decorationType in this._registeredDecorationTypes) {
|
||||
this._codeEditorService.removeDecorationType(decorationType);
|
||||
}
|
||||
dispose(this._dropIntoEditorListeners.values());
|
||||
this._dropIntoEditorListeners.clear();
|
||||
this._registeredDecorationTypes = Object.create(null);
|
||||
}
|
||||
|
||||
@@ -140,59 +113,6 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
return result;
|
||||
}
|
||||
|
||||
private async onDropIntoEditor(editor: ICodeEditor, position: IPosition, dragEvent: DragEvent) {
|
||||
if (!dragEvent.dataTransfer || !editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
const id = this._editorLocator.getIdOfCodeEditor(editor);
|
||||
if (typeof id !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
const modelVersionNow = editor.getModel().getVersionId();
|
||||
|
||||
const textEditorDataTransfer: IDataTransfer = new Map<string, IDataTransferItem>();
|
||||
for (const item of dragEvent.dataTransfer.items) {
|
||||
if (item.kind === 'string') {
|
||||
const type = item.type;
|
||||
const asStringValue = new Promise<string>(resolve => item.getAsString(resolve));
|
||||
textEditorDataTransfer.set(type, {
|
||||
asString: () => asStringValue,
|
||||
value: undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!textEditorDataTransfer.has(Mimes.uriList.toLowerCase())) {
|
||||
const editorData = (await this._instantiationService.invokeFunction(extractEditorsDropData, dragEvent))
|
||||
.filter(input => input.resource)
|
||||
.map(input => input.resource!.toString());
|
||||
|
||||
if (editorData.length) {
|
||||
const str = distinct(editorData).join('\n');
|
||||
textEditorDataTransfer.set(Mimes.uriList.toLowerCase(), {
|
||||
asString: () => Promise.resolve(str),
|
||||
value: undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (textEditorDataTransfer.size === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dataTransferDto = await DataTransferConverter.toDataTransferDTO(textEditorDataTransfer);
|
||||
const edits = await this._proxy.$textEditorHandleDrop(id, position, dataTransferDto);
|
||||
if (edits.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (editor.getModel().getVersionId() === modelVersionNow) {
|
||||
const [first] = edits; // TODO@jrieken define how to pick the "one snippet edit";
|
||||
performSnippetEdit(editor, first);
|
||||
}
|
||||
}
|
||||
|
||||
// --- from extension host process
|
||||
|
||||
async $tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise<string | undefined> {
|
||||
|
||||
@@ -3,43 +3,49 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import * as languages from 'vs/editor/common/languages';
|
||||
import * as search from 'vs/workbench/contrib/search/common/search';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Position as EditorPosition } from 'vs/editor/common/core/position';
|
||||
import { Range as EditorRange, IRange } from 'vs/editor/common/core/range';
|
||||
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, ILocationLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto, ISuggestDataDtoField, ISuggestResultDtoField, ICodeActionProviderMetadataDto, ILanguageWordDefinitionDto, IdentifiableInlineCompletions, IdentifiableInlineCompletion, ITypeHierarchyItemDto, IInlayHintDto } from '../common/extHost.protocol';
|
||||
import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';
|
||||
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/languages/languageConfiguration';
|
||||
import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
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 * as typeh from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { decodeSemanticTokensDto } from 'vs/editor/common/services/semanticTokensDto';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
import { CancellationError } from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Position as EditorPosition } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range as EditorRange } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import * as languages from 'vs/editor/common/languages';
|
||||
import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
import { IndentationRule, LanguageConfiguration, OnEnterRule } from 'vs/editor/common/languages/languageConfiguration';
|
||||
import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
|
||||
import { decodeSemanticTokensDto } from 'vs/editor/common/services/semanticTokensDto';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { DataTransferConverter } from 'vs/workbench/api/common/shared/dataTransfer';
|
||||
import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import * as search from 'vs/workbench/contrib/search/common/search';
|
||||
import * as typeh from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy';
|
||||
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostLanguageFeaturesShape, ICallHierarchyItemDto, ICodeActionDto, ICodeActionProviderMetadataDto, IdentifiableInlineCompletion, IdentifiableInlineCompletions, IDocumentFilterDto, IIndentationRuleDto, IInlayHintDto, ILanguageConfigurationDto, ILanguageWordDefinitionDto, ILinkDto, ILocationDto, ILocationLinkDto, IOnEnterRuleDto, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape, reviveWorkspaceEditDto } from '../common/extHost.protocol';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
|
||||
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
|
||||
export class MainThreadLanguageFeatures extends Disposable implements MainThreadLanguageFeaturesShape {
|
||||
|
||||
private readonly _proxy: ExtHostLanguageFeaturesShape;
|
||||
private readonly _registrations = new Map<number, IDisposable>();
|
||||
|
||||
private readonly _dropIntoEditorListeners = new Map<ICodeEditor, IDisposable>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@ILanguageService private readonly _languageService: ILanguageService,
|
||||
@ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService,
|
||||
@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostLanguageFeatures);
|
||||
|
||||
if (this._languageService) {
|
||||
@@ -71,11 +77,16 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
for (const registration of this._registrations.values()) {
|
||||
registration.dispose();
|
||||
}
|
||||
this._registrations.clear();
|
||||
|
||||
dispose(this._dropIntoEditorListeners.values());
|
||||
this._dropIntoEditorListeners.clear();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
$unregister(handle: number): void {
|
||||
@@ -850,6 +861,17 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
// --- document drop Edits
|
||||
|
||||
$registerDocumentOnDropProvider(handle: number, selector: IDocumentFilterDto[]): void {
|
||||
this._registrations.set(handle, this._languageFeaturesService.documentOnDropEditProvider.register(selector, {
|
||||
provideDocumentOnDropEdits: async (model, position, dataTransfer, token) => {
|
||||
const dataTransferDto = await DataTransferConverter.toDataTransferDTO(dataTransfer);
|
||||
return this._proxy.$provideDocumentOnDropEdits(handle, model.uri, position, dataTransferDto, token);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export class MainThreadDocumentSemanticTokensProvider implements languages.DocumentSemanticTokensProvider {
|
||||
|
||||
@@ -510,7 +510,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
containerTitle: item.contextualTitle || viewContainer?.title,
|
||||
canToggleVisibility: true,
|
||||
canMoveView: viewContainer?.id !== REMOTE,
|
||||
treeView: type === ViewType.Tree ? this.instantiationService.createInstance(CustomTreeView, item.id, item.name) : undefined,
|
||||
treeView: type === ViewType.Tree ? this.instantiationService.createInstance(CustomTreeView, item.id, item.name, extension.description.identifier.value) : undefined,
|
||||
collapsed: this.showCollapsed(container) || initialVisibility === InitialVisibility.Collapsed,
|
||||
order: order,
|
||||
extensionId: extension.description.identifier,
|
||||
|
||||
@@ -532,6 +532,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
},
|
||||
createLanguageStatusItem(id: string, selector: vscode.DocumentSelector): vscode.LanguageStatusItem {
|
||||
return extHostLanguages.createLanguageStatusItem(extension, id, selector);
|
||||
},
|
||||
registerDocumentOnDropProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentOnDropProvider): vscode.Disposable {
|
||||
checkProposedApiEnabled(extension, 'textEditorDrop');
|
||||
return extHostLanguageFeatures.registerDocumentOnDropProvider(extension, selector, provider);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -669,7 +673,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
checkProposedApiEnabled(extension, 'editorInsets');
|
||||
return extHostEditorInsets.createWebviewEditorInset(editor, line, height, options, extension);
|
||||
},
|
||||
createTerminal(nameOrOptions?: vscode.TerminalOptions | vscode.ExtensionTerminalOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
|
||||
createTerminal(nameOrOptions?: vscode.TerminalOptions | vscode.ExtensionTerminalOptions | string, shellPath?: string, shellArgs?: readonly string[] | string): vscode.Terminal {
|
||||
if (typeof nameOrOptions === 'object') {
|
||||
if ('pty' in nameOrOptions) {
|
||||
return extHostTerminalService.createExtensionTerminal(nameOrOptions);
|
||||
@@ -872,10 +876,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
onWillSaveTextDocument: (listener, thisArgs?, disposables?) => {
|
||||
return extHostDocumentSaveParticipant.getOnWillSaveTextDocumentEvent(extension)(listener, thisArgs, disposables);
|
||||
},
|
||||
onWillDropOnTextEditor: (listener, thisArgs?, disposables?) => {
|
||||
checkProposedApiEnabled(extension, 'textEditorDrop');
|
||||
return extHostEditors.onWillDropOnTextEditor(listener, thisArgs, disposables);
|
||||
},
|
||||
get notebookDocuments(): vscode.NotebookDocument[] {
|
||||
return extHostNotebook.notebookDocuments.map(d => d.apiNotebook);
|
||||
},
|
||||
@@ -1131,6 +1131,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
},
|
||||
createConcatTextDocument(notebook, selector) {
|
||||
checkProposedApiEnabled(extension, 'notebookConcatTextDocument');
|
||||
extHostApiDeprecation.report('notebookConcatTextDocument', extension, 'This proposal is not on track for finalization and will be removed.');
|
||||
return new ExtHostNotebookConcatDocument(extHostNotebookDocuments, extHostDocuments, notebook, selector);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -257,7 +257,7 @@ export interface MainThreadTextEditorsShape extends IDisposable {
|
||||
}
|
||||
|
||||
export interface MainThreadTreeViewsShape extends IDisposable {
|
||||
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: string[]; dragMimeTypes: string[]; hasHandleDrag: boolean; hasHandleDrop: boolean }): Promise<void>;
|
||||
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: readonly string[]; dragMimeTypes: readonly string[]; hasHandleDrag: boolean; hasHandleDrop: boolean }): Promise<void>;
|
||||
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Promise<void>;
|
||||
$reveal(treeViewId: string, itemInfo: { item: ITreeItem; parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise<void>;
|
||||
$setMessage(treeViewId: string, message: string): void;
|
||||
@@ -390,6 +390,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
||||
$registerSelectionRangeProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerTypeHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerDocumentOnDropProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$setLanguageConfiguration(handle: number, languageId: string, configuration: ILanguageConfigurationDto): void;
|
||||
}
|
||||
|
||||
@@ -676,6 +677,7 @@ export interface MainThreadEditorTabsShape extends IDisposable {
|
||||
// manage tabs: move, close, rearrange etc
|
||||
$moveTab(tabId: string, index: number, viewColumn: EditorGroupColumn, preserveFocus?: boolean): void;
|
||||
$closeTab(tabIds: string[], preserveFocus?: boolean): Promise<boolean>;
|
||||
$closeGroup(groupIds: number[], preservceFocus?: boolean): Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface IEditorTabGroupDto {
|
||||
@@ -1329,7 +1331,6 @@ export interface ISelectionChangeEvent {
|
||||
export interface ExtHostEditorsShape {
|
||||
$acceptEditorPropertiesChanged(id: string, props: IEditorPropertiesChangeData): void;
|
||||
$acceptEditorPositionData(data: ITextEditorPositionData): void;
|
||||
$textEditorHandleDrop(id: string, position: IPosition, dataTransferDto: DataTransferDTO): Promise<Dto<languages.SnippetTextEdit[]>>;
|
||||
}
|
||||
|
||||
export interface IDocumentsAndEditorsDelta {
|
||||
@@ -1734,6 +1735,7 @@ export interface ExtHostLanguageFeaturesShape {
|
||||
$provideTypeHierarchySupertypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
|
||||
$provideTypeHierarchySubtypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
|
||||
$releaseTypeHierarchy(handle: number, sessionId: string): void;
|
||||
$provideDocumentOnDropEdits(handle: number, resource: UriComponents, position: IPosition, dataTransferDto: DataTransferDTO, token: CancellationToken): Promise<Dto<languages.SnippetTextEdit> | undefined>;
|
||||
}
|
||||
|
||||
export interface ExtHostQuickOpenShape {
|
||||
|
||||
@@ -953,7 +953,7 @@ export class ExtHostVariableResolverService extends AbstractVariableResolverServ
|
||||
if (activeEditor) {
|
||||
return activeEditor.document.uri;
|
||||
}
|
||||
const activeTab = editorTabs.tabGroups.groups.find(group => group.isActive)?.activeTab;
|
||||
const activeTab = editorTabs.tabGroups.all.find(group => group.isActive)?.activeTab;
|
||||
if (activeTab !== undefined) {
|
||||
// Resolve a resource from the tab
|
||||
if (activeTab.kind instanceof TextDiffTabInput || activeTab.kind instanceof NotebookDiffEditorTabInput) {
|
||||
|
||||
@@ -36,9 +36,9 @@ class ExtHostEditorTab {
|
||||
}
|
||||
|
||||
get apiObject(): vscode.Tab {
|
||||
// Don't want to lose reference to parent `this` in the getters
|
||||
const that = this;
|
||||
if (!this._apiObject) {
|
||||
// Don't want to lose reference to parent `this` in the getters
|
||||
const that = this;
|
||||
const obj: vscode.Tab = {
|
||||
get isActive() {
|
||||
// We use a getter function here to always ensure at most 1 active tab per group and prevent iteration for being required
|
||||
@@ -120,9 +120,9 @@ class ExtHostEditorTabGroup {
|
||||
}
|
||||
|
||||
get apiObject(): vscode.TabGroup {
|
||||
// Don't want to lose reference to parent `this` in the getters
|
||||
const that = this;
|
||||
if (!this._apiObject) {
|
||||
// Don't want to lose reference to parent `this` in the getters
|
||||
const that = this;
|
||||
const obj: vscode.TabGroup = {
|
||||
get isActive() {
|
||||
// We use a getter function here to always ensure at most 1 active group and prevent iteration for being required
|
||||
@@ -201,10 +201,8 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly _proxy: MainThreadEditorTabsShape;
|
||||
private readonly _onDidChangeTabs = new Emitter<vscode.Tab[]>();
|
||||
private readonly _onDidChangeActiveTab = new Emitter<vscode.Tab>();
|
||||
private readonly _onDidChangeTabs = new Emitter<vscode.TabChangeEvent>();
|
||||
private readonly _onDidChangeTabGroups = new Emitter<vscode.TabGroup[]>();
|
||||
private readonly _onDidChangeActiveTabGroup = new Emitter<vscode.TabGroup>();
|
||||
|
||||
// Have to use ! because this gets initialized via an RPC proxy
|
||||
private _activeGroupId!: number;
|
||||
@@ -223,11 +221,9 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs {
|
||||
const obj: vscode.TabGroups = {
|
||||
// never changes -> simple value
|
||||
onDidChangeTabGroups: that._onDidChangeTabGroups.event,
|
||||
onDidChangeActiveTabGroup: that._onDidChangeActiveTabGroup.event,
|
||||
onDidChangeTabs: that._onDidChangeTabs.event,
|
||||
onDidChangeActiveTab: that._onDidChangeActiveTab.event,
|
||||
// dynamic -> getters
|
||||
get groups() {
|
||||
get all() {
|
||||
return Object.freeze(that._extHostTabGroups.map(group => group.apiObject));
|
||||
},
|
||||
get activeTabGroup() {
|
||||
@@ -235,17 +231,18 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs {
|
||||
const activeTabGroup = assertIsDefined(that._extHostTabGroups.find(candidate => candidate.groupId === activeTabGroupId)?.apiObject);
|
||||
return activeTabGroup;
|
||||
},
|
||||
close: async (tab: vscode.Tab | vscode.Tab[], preserveFocus?: boolean) => {
|
||||
const tabs = Array.isArray(tab) ? tab : [tab];
|
||||
const extHostTabIds: string[] = [];
|
||||
for (const tab of tabs) {
|
||||
const extHostTab = this._findExtHostTabFromApi(tab);
|
||||
if (!extHostTab) {
|
||||
throw new Error('Tab close: Invalid tab not found!');
|
||||
}
|
||||
extHostTabIds.push(extHostTab.tabId);
|
||||
close: async (tabOrTabGroup: vscode.Tab | readonly vscode.Tab[] | vscode.TabGroup | readonly vscode.TabGroup[], preserveFocus?: boolean) => {
|
||||
const tabsOrTabGroups = Array.isArray(tabOrTabGroup) ? tabOrTabGroup : [tabOrTabGroup];
|
||||
if (!tabsOrTabGroups.length) {
|
||||
return true;
|
||||
}
|
||||
// Check which type was passed in and call the appropriate close
|
||||
// Casting is needed as typescript doesn't seem to infer enough from this
|
||||
if (isTabGroup(tabsOrTabGroups[0])) {
|
||||
return this._closeGroups(tabsOrTabGroups as vscode.TabGroup[], preserveFocus);
|
||||
} else {
|
||||
return this._closeTabs(tabsOrTabGroups as vscode.Tab[], preserveFocus);
|
||||
}
|
||||
return this._proxy.$closeTab(extHostTabIds, preserveFocus);
|
||||
},
|
||||
move: async (tab: vscode.Tab, viewColumn: ViewColumn, index: number, preservceFocus?: boolean) => {
|
||||
const extHostTab = this._findExtHostTabFromApi(tab);
|
||||
@@ -261,17 +258,6 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs {
|
||||
return this._apiObject;
|
||||
}
|
||||
|
||||
private _findExtHostTabFromApi(apiTab: vscode.Tab): ExtHostEditorTab | undefined {
|
||||
for (const group of this._extHostTabGroups) {
|
||||
for (const tab of group.tabs) {
|
||||
if (tab.apiObject === apiTab) {
|
||||
return tab;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$acceptEditorTabModel(tabGroups: IEditorTabGroupDto[]): void {
|
||||
|
||||
this._extHostTabGroups = tabGroups.map(tabGroup => {
|
||||
@@ -283,7 +269,6 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs {
|
||||
const activeTabGroupId = assertIsDefined(tabGroups.find(group => group.isActive === true)?.groupId);
|
||||
if (activeTabGroupId !== undefined && this._activeGroupId !== activeTabGroupId) {
|
||||
this._activeGroupId = activeTabGroupId;
|
||||
this._onDidChangeActiveTabGroup.fire(this.tabGroups.activeTabGroup);
|
||||
}
|
||||
this._onDidChangeTabGroups.fire(this._extHostTabGroups.map(g => g.apiObject));
|
||||
}
|
||||
@@ -295,11 +280,7 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs {
|
||||
}
|
||||
group.acceptGroupDtoUpdate(groupDto);
|
||||
if (groupDto.isActive) {
|
||||
const oldActiveGroupId = this._activeGroupId;
|
||||
this._activeGroupId = groupDto.groupId;
|
||||
if (oldActiveGroupId !== this._activeGroupId) {
|
||||
this._onDidChangeActiveTabGroup.fire(group.apiObject);
|
||||
}
|
||||
}
|
||||
this._onDidChangeTabGroups.fire([group.apiObject]);
|
||||
}
|
||||
@@ -310,12 +291,79 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs {
|
||||
throw new Error('Update Tabs IPC call received before group creation.');
|
||||
}
|
||||
const tab = group.acceptTabOperation(operation);
|
||||
// We don't want to fire a change event with a closed tab to prevent an invalid tabs from being received
|
||||
if (operation.kind !== TabModelOperationKind.TAB_CLOSE) {
|
||||
this._onDidChangeTabs.fire([tab.apiObject]);
|
||||
if (tab.apiObject.isActive) {
|
||||
this._onDidChangeActiveTab.fire(tab.apiObject);
|
||||
}
|
||||
|
||||
// Construct the tab change event based on the operation
|
||||
switch (operation.kind) {
|
||||
case TabModelOperationKind.TAB_OPEN:
|
||||
this._onDidChangeTabs.fire({
|
||||
added: [tab.apiObject],
|
||||
removed: [],
|
||||
changed: []
|
||||
});
|
||||
return;
|
||||
case TabModelOperationKind.TAB_CLOSE:
|
||||
this._onDidChangeTabs.fire({
|
||||
added: [],
|
||||
removed: [tab.apiObject],
|
||||
changed: []
|
||||
});
|
||||
return;
|
||||
case TabModelOperationKind.TAB_UPDATE:
|
||||
this._onDidChangeTabs.fire({
|
||||
added: [],
|
||||
removed: [],
|
||||
changed: [tab.apiObject]
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private _findExtHostTabFromApi(apiTab: vscode.Tab): ExtHostEditorTab | undefined {
|
||||
for (const group of this._extHostTabGroups) {
|
||||
for (const tab of group.tabs) {
|
||||
if (tab.apiObject === apiTab) {
|
||||
return tab;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private _findExtHostTabGroupFromApi(apiTabGroup: vscode.TabGroup): ExtHostEditorTabGroup | undefined {
|
||||
return this._extHostTabGroups.find(candidate => candidate.apiObject === apiTabGroup);
|
||||
}
|
||||
|
||||
private async _closeTabs(tabs: vscode.Tab[], preserveFocus?: boolean): Promise<boolean> {
|
||||
const extHostTabIds: string[] = [];
|
||||
for (const tab of tabs) {
|
||||
const extHostTab = this._findExtHostTabFromApi(tab);
|
||||
if (!extHostTab) {
|
||||
throw new Error('Tab close: Invalid tab not found!');
|
||||
}
|
||||
extHostTabIds.push(extHostTab.tabId);
|
||||
}
|
||||
return this._proxy.$closeTab(extHostTabIds, preserveFocus);
|
||||
}
|
||||
|
||||
private async _closeGroups(groups: vscode.TabGroup[], preserverFoucs?: boolean): Promise<boolean> {
|
||||
const extHostGroupIds: number[] = [];
|
||||
for (const group of groups) {
|
||||
const extHostGroup = this._findExtHostTabGroupFromApi(group);
|
||||
if (!extHostGroup) {
|
||||
throw new Error('Group close: Invalid group not found!');
|
||||
}
|
||||
extHostGroupIds.push(extHostGroup.groupId);
|
||||
}
|
||||
return this._proxy.$closeGroup(extHostGroupIds, preserverFoucs);
|
||||
}
|
||||
}
|
||||
|
||||
//#region Utils
|
||||
function isTabGroup(obj: unknown): obj is vscode.TabGroup {
|
||||
const tabGroup = obj as vscode.TabGroup;
|
||||
if (tabGroup.tabs !== undefined) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
@@ -35,6 +35,8 @@ import { isCancellationError } from 'vs/base/common/errors';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { raceCancellationError } from 'vs/base/common/async';
|
||||
import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { DataTransferConverter, DataTransferDTO } from 'vs/workbench/api/common/shared/dataTransfer';
|
||||
import { Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
|
||||
// --- adapter
|
||||
|
||||
@@ -1712,6 +1714,27 @@ class TypeHierarchyAdapter {
|
||||
return map?.get(itemId);
|
||||
}
|
||||
}
|
||||
|
||||
class DocumentOnDropAdapter {
|
||||
|
||||
constructor(
|
||||
private readonly _documents: ExtHostDocuments,
|
||||
private readonly _provider: vscode.DocumentOnDropProvider
|
||||
) { }
|
||||
|
||||
async provideDocumentOnDropEdits(uri: URI, position: IPosition, dataTransferDto: DataTransferDTO, token: CancellationToken): Promise<Dto<languages.SnippetTextEdit> | undefined> {
|
||||
const doc = this._documents.getDocument(uri);
|
||||
const pos = typeConvert.Position.to(position);
|
||||
const dataTransfer = DataTransferConverter.toDataTransfer(dataTransferDto);
|
||||
|
||||
const edit = await this._provider.provideDocumentOnDropEdits(doc, pos, dataTransfer, token);
|
||||
if (!edit) {
|
||||
return undefined;
|
||||
}
|
||||
return typeConvert.SnippetTextEdit.from(edit);
|
||||
}
|
||||
}
|
||||
|
||||
type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
|
||||
| DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter
|
||||
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
|
||||
@@ -1720,7 +1743,8 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov
|
||||
| SelectionRangeAdapter | CallHierarchyAdapter | TypeHierarchyAdapter
|
||||
| DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter
|
||||
| EvaluatableExpressionAdapter | InlineValuesAdapter
|
||||
| LinkedEditingRangeAdapter | InlayHintsAdapter | InlineCompletionAdapter | InlineCompletionAdapterNew;
|
||||
| LinkedEditingRangeAdapter | InlayHintsAdapter | InlineCompletionAdapter | InlineCompletionAdapterNew
|
||||
| DocumentOnDropAdapter;
|
||||
|
||||
class AdapterData {
|
||||
constructor(
|
||||
@@ -2341,6 +2365,18 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
|
||||
this._withAdapter(handle, TypeHierarchyAdapter, adapter => Promise.resolve(adapter.releaseSession(sessionId)), undefined, undefined);
|
||||
}
|
||||
|
||||
// --- Document on drop
|
||||
|
||||
registerDocumentOnDropProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentOnDropProvider) {
|
||||
const handle = this._addNewAdapter(new DocumentOnDropAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerDocumentOnDropProvider(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideDocumentOnDropEdits(handle: number, resource: UriComponents, position: IPosition, dataTransferDto: DataTransferDTO, token: CancellationToken): Promise<Dto<languages.SnippetTextEdit> | undefined> {
|
||||
return this._withAdapter(handle, DocumentOnDropAdapter, adapter => Promise.resolve(adapter.provideDocumentOnDropEdits(URI.revive(resource), position, dataTransferDto, token)), undefined, undefined);
|
||||
}
|
||||
|
||||
// --- configuration
|
||||
|
||||
private static _serializeRegExp(regExp: RegExp): extHostProtocol.IRegExpDto {
|
||||
|
||||
@@ -38,7 +38,7 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, ID
|
||||
onDidChangeTerminalState: Event<vscode.Terminal>;
|
||||
onDidWriteTerminalData: Event<vscode.TerminalDataWriteEvent>;
|
||||
|
||||
createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal;
|
||||
createTerminal(name?: string, shellPath?: string, shellArgs?: readonly string[] | string): vscode.Terminal;
|
||||
createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal;
|
||||
createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal;
|
||||
attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void;
|
||||
|
||||
@@ -3,20 +3,15 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AsyncEmitter, Emitter, Event } from 'vs/base/common/event';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtHostEditorsShape, IEditorPropertiesChangeData, IMainContext, ITextDocumentShowOptions, ITextEditorPositionData, MainContext, MainThreadTextEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { ExtHostTextEditor, TextEditorDecorationType } from 'vs/workbench/api/common/extHostTextEditor';
|
||||
import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { SnippetTextEdit, TextEditorSelectionChangeKind } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { TextEditorSelectionChangeKind } from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as vscode from 'vscode';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { DataTransferConverter, DataTransferDTO } from 'vs/workbench/api/common/shared/dataTransfer';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import * as languages from 'vs/editor/common/languages';
|
||||
|
||||
export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
|
||||
@@ -26,7 +21,6 @@ export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
private readonly _onDidChangeTextEditorViewColumn = new Emitter<vscode.TextEditorViewColumnChangeEvent>();
|
||||
private readonly _onDidChangeActiveTextEditor = new Emitter<vscode.TextEditor | undefined>();
|
||||
private readonly _onDidChangeVisibleTextEditors = new Emitter<vscode.TextEditor[]>();
|
||||
private readonly _onWillDropOnTextEditor = new AsyncEmitter<vscode.TextEditorDropEvent>();
|
||||
|
||||
readonly onDidChangeTextEditorSelection: Event<vscode.TextEditorSelectionChangeEvent> = this._onDidChangeTextEditorSelection.event;
|
||||
readonly onDidChangeTextEditorOptions: Event<vscode.TextEditorOptionsChangeEvent> = this._onDidChangeTextEditorOptions.event;
|
||||
@@ -34,7 +28,6 @@ export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
readonly onDidChangeTextEditorViewColumn: Event<vscode.TextEditorViewColumnChangeEvent> = this._onDidChangeTextEditorViewColumn.event;
|
||||
readonly onDidChangeActiveTextEditor: Event<vscode.TextEditor | undefined> = this._onDidChangeActiveTextEditor.event;
|
||||
readonly onDidChangeVisibleTextEditors: Event<vscode.TextEditor[]> = this._onDidChangeVisibleTextEditors.event;
|
||||
readonly onWillDropOnTextEditor: Event<vscode.TextEditorDropEvent> = this._onWillDropOnTextEditor.event;
|
||||
|
||||
private readonly _proxy: MainThreadTextEditorsShape;
|
||||
|
||||
@@ -166,33 +159,4 @@ export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
getDiffInformation(id: string): Promise<vscode.LineChange[]> {
|
||||
return Promise.resolve(this._proxy.$getDiffInformation(id));
|
||||
}
|
||||
|
||||
// --- Text editor drag and drop
|
||||
|
||||
async $textEditorHandleDrop(id: string, position: IPosition, dataTransferDto: DataTransferDTO): Promise<Dto<languages.SnippetTextEdit[]>> {
|
||||
const textEditor = this._extHostDocumentsAndEditors.getEditor(id);
|
||||
if (!textEditor) {
|
||||
throw new Error('Unknown text editor');
|
||||
}
|
||||
|
||||
const pos = TypeConverters.Position.to(position);
|
||||
const dataTransfer = DataTransferConverter.toDataTransfer(dataTransferDto);
|
||||
|
||||
const event = Object.freeze({
|
||||
editor: textEditor.value,
|
||||
position: pos,
|
||||
dataTransfer: dataTransfer
|
||||
});
|
||||
|
||||
const edits: SnippetTextEdit[] = [];
|
||||
|
||||
await this._onWillDropOnTextEditor.fireAsync(event, CancellationToken.None, async p => {
|
||||
const value = await p;
|
||||
if (value instanceof SnippetTextEdit) {
|
||||
edits.push(value);
|
||||
}
|
||||
});
|
||||
|
||||
return edits.map(TypeConverters.SnippetTextEdit.from);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1594,7 +1594,10 @@ export class CompletionList {
|
||||
|
||||
@es5ClassCompat
|
||||
export class InlineSuggestion implements vscode.InlineCompletionItem {
|
||||
insertText?: string;
|
||||
|
||||
insertText?: string | SnippetString;
|
||||
|
||||
filterText?: string;
|
||||
|
||||
/**
|
||||
* @deprecated Use `insertText` instead. Will be removed eventually.
|
||||
@@ -1604,7 +1607,7 @@ export class InlineSuggestion implements vscode.InlineCompletionItem {
|
||||
range?: Range;
|
||||
command?: vscode.Command;
|
||||
|
||||
constructor(insertText: string, range?: Range, command?: vscode.Command) {
|
||||
constructor(insertText: string | SnippetString, range?: Range, command?: vscode.Command) {
|
||||
this.insertText = insertText;
|
||||
this.range = range;
|
||||
this.command = command;
|
||||
|
||||
@@ -35,7 +35,7 @@ suite('ExtHostEditorTabs', function () {
|
||||
})
|
||||
);
|
||||
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 0);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 0);
|
||||
// Active group should never be undefined (there is always an active group). Ensure accessing it undefined throws.
|
||||
// TODO @lramos15 Add a throw on the main side when a model is sent without an active group
|
||||
assert.throws(() => extHostEditorTabs.tabGroups.activeTabGroup);
|
||||
@@ -63,8 +63,8 @@ suite('ExtHostEditorTabs', function () {
|
||||
groupId: 12,
|
||||
tabs: [tab]
|
||||
}]);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
const [first] = extHostEditorTabs.tabGroups.groups;
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
const [first] = extHostEditorTabs.tabGroups.all;
|
||||
assert.ok(first.activeTab);
|
||||
assert.strictEqual(first.tabs.indexOf(first.activeTab), 0);
|
||||
|
||||
@@ -75,8 +75,8 @@ suite('ExtHostEditorTabs', function () {
|
||||
groupId: 12,
|
||||
tabs: [tab]
|
||||
}]);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
const [first] = extHostEditorTabs.tabGroups.groups;
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
const [first] = extHostEditorTabs.tabGroups.all;
|
||||
assert.ok(first.activeTab);
|
||||
assert.strictEqual(first.tabs.indexOf(first.activeTab), 0);
|
||||
}
|
||||
@@ -95,8 +95,8 @@ suite('ExtHostEditorTabs', function () {
|
||||
groupId: 12,
|
||||
tabs: []
|
||||
}]);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
const [first] = extHostEditorTabs.tabGroups.groups;
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
const [first] = extHostEditorTabs.tabGroups.all;
|
||||
assert.strictEqual(first.activeTab, undefined);
|
||||
assert.strictEqual(first.tabs.length, 0);
|
||||
});
|
||||
@@ -121,7 +121,7 @@ suite('ExtHostEditorTabs', function () {
|
||||
}]);
|
||||
assert.ok(extHostEditorTabs.tabGroups.activeTabGroup);
|
||||
const activeTabGroup: vscode.TabGroup = extHostEditorTabs.tabGroups.activeTabGroup;
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
assert.strictEqual(activeTabGroup.tabs.length, 0);
|
||||
assert.strictEqual(count, 1);
|
||||
});
|
||||
@@ -147,76 +147,14 @@ suite('ExtHostEditorTabs', function () {
|
||||
groupId: 12,
|
||||
tabs: [tab]
|
||||
}]);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
const [first] = extHostEditorTabs.tabGroups.groups;
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
const [first] = extHostEditorTabs.tabGroups.all;
|
||||
assert.ok(first.activeTab);
|
||||
assert.strictEqual(first.tabs.indexOf(first.activeTab), 0);
|
||||
assert.strictEqual(first.activeTab, first.tabs[0]);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup, first);
|
||||
});
|
||||
|
||||
// TODO @lramos15 Change this test because now it only fires when id changes
|
||||
test.skip('onDidChangeActiveTabGroup fires properly', function () {
|
||||
const extHostEditorTabs = new ExtHostEditorTabs(
|
||||
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
|
||||
// override/implement $moveTab or $closeTab
|
||||
})
|
||||
);
|
||||
|
||||
let count = 0;
|
||||
let activeTabGroupFromEvent: vscode.TabGroup | undefined = undefined;
|
||||
extHostEditorTabs.tabGroups.onDidChangeActiveTabGroup((tabGroup) => {
|
||||
count++;
|
||||
activeTabGroupFromEvent = tabGroup;
|
||||
});
|
||||
|
||||
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 0);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup, undefined);
|
||||
assert.strictEqual(count, 0);
|
||||
const tabModel = [{
|
||||
isActive: true,
|
||||
viewColumn: 0,
|
||||
groupId: 12,
|
||||
tabs: [],
|
||||
activeTab: undefined
|
||||
}];
|
||||
extHostEditorTabs.$acceptEditorTabModel(tabModel);
|
||||
assert.ok(extHostEditorTabs.tabGroups.activeTabGroup);
|
||||
let activeTabGroup: vscode.TabGroup = extHostEditorTabs.tabGroups.activeTabGroup;
|
||||
assert.strictEqual(count, 1);
|
||||
assert.strictEqual(activeTabGroup, activeTabGroupFromEvent);
|
||||
// Firing again with same model shouldn't cause a change
|
||||
extHostEditorTabs.$acceptEditorTabModel(tabModel);
|
||||
assert.strictEqual(count, 1);
|
||||
// Changing a property should fire a change
|
||||
tabModel[0].viewColumn = 1;
|
||||
extHostEditorTabs.$acceptEditorTabModel(tabModel);
|
||||
assert.strictEqual(count, 2);
|
||||
activeTabGroup = extHostEditorTabs.tabGroups.activeTabGroup;
|
||||
assert.strictEqual(activeTabGroup, activeTabGroupFromEvent);
|
||||
// Changing the active tab group should fire a change
|
||||
tabModel[0].isActive = false;
|
||||
tabModel.push({
|
||||
isActive: true,
|
||||
viewColumn: 0,
|
||||
groupId: 13,
|
||||
tabs: [],
|
||||
activeTab: undefined
|
||||
});
|
||||
extHostEditorTabs.$acceptEditorTabModel(tabModel);
|
||||
assert.strictEqual(count, 3);
|
||||
activeTabGroup = extHostEditorTabs.tabGroups.activeTabGroup;
|
||||
assert.strictEqual(activeTabGroup, activeTabGroupFromEvent);
|
||||
|
||||
// Empty tab model should fire a change and return undefined
|
||||
extHostEditorTabs.$acceptEditorTabModel([]);
|
||||
assert.strictEqual(count, 4);
|
||||
activeTabGroup = extHostEditorTabs.tabGroups.activeTabGroup;
|
||||
assert.strictEqual(activeTabGroup, undefined);
|
||||
assert.strictEqual(activeTabGroup, activeTabGroupFromEvent);
|
||||
});
|
||||
|
||||
test('Ensure reference stability', function () {
|
||||
|
||||
const extHostEditorTabs = new ExtHostEditorTabs(
|
||||
@@ -234,7 +172,7 @@ suite('ExtHostEditorTabs', function () {
|
||||
groupId: 12,
|
||||
tabs: [tabDto]
|
||||
}]);
|
||||
let all = extHostEditorTabs.tabGroups.groups.map(group => group.tabs).flat();
|
||||
let all = extHostEditorTabs.tabGroups.all.map(group => group.tabs).flat();
|
||||
assert.strictEqual(all.length, 1);
|
||||
const apiTab1 = all[0];
|
||||
assert.ok(apiTab1.kind instanceof TextTabInput);
|
||||
@@ -255,7 +193,7 @@ suite('ExtHostEditorTabs', function () {
|
||||
groupId: 12
|
||||
});
|
||||
|
||||
all = extHostEditorTabs.tabGroups.groups.map(group => group.tabs).flat();
|
||||
all = extHostEditorTabs.tabGroups.all.map(group => group.tabs).flat();
|
||||
assert.strictEqual(all.length, 1);
|
||||
const apiTab2 = all[0];
|
||||
assert.ok(apiTab1.kind instanceof TextTabInput);
|
||||
@@ -301,7 +239,7 @@ suite('ExtHostEditorTabs', function () {
|
||||
tabs: [tabDtoAAA, tabDtoBBB]
|
||||
}]);
|
||||
|
||||
let all = extHostEditorTabs.tabGroups.groups.map(group => group.tabs).flat();
|
||||
let all = extHostEditorTabs.tabGroups.all.map(group => group.tabs).flat();
|
||||
assert.strictEqual(all.length, 2);
|
||||
|
||||
const activeTab1 = extHostEditorTabs.tabGroups.activeTabGroup?.activeTab;
|
||||
@@ -341,7 +279,7 @@ suite('ExtHostEditorTabs', function () {
|
||||
});
|
||||
assert.throws(() => {
|
||||
// @ts-expect-error write to readonly prop
|
||||
extHostEditorTabs.tabGroups.groups.length = 0;
|
||||
extHostEditorTabs.tabGroups.all.length = 0;
|
||||
});
|
||||
assert.throws(() => {
|
||||
// @ts-expect-error write to readonly prop
|
||||
@@ -379,7 +317,7 @@ suite('ExtHostEditorTabs', function () {
|
||||
groupId: 12,
|
||||
tabs: [tab]
|
||||
}]);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
const activeTab = extHostEditorTabs.tabGroups.activeTabGroup?.activeTab;
|
||||
assert.ok(activeTab);
|
||||
extHostEditorTabs.tabGroups.close(activeTab, false);
|
||||
@@ -418,12 +356,12 @@ suite('ExtHostEditorTabs', function () {
|
||||
tabs: [tabDto]
|
||||
}]);
|
||||
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.map(g => g.tabs).flat().length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 1);
|
||||
|
||||
const tab = extHostEditorTabs.tabGroups.groups[0].tabs[0];
|
||||
const tab = extHostEditorTabs.tabGroups.all[0].tabs[0];
|
||||
|
||||
const p = new Promise<vscode.Tab[]>(resolve => extHostEditorTabs.tabGroups.onDidChangeTabs(resolve));
|
||||
const p = new Promise<vscode.TabChangeEvent>(resolve => extHostEditorTabs.tabGroups.onDidChangeTabs(resolve));
|
||||
|
||||
extHostEditorTabs.$acceptTabOperation({
|
||||
groupId: 12,
|
||||
@@ -432,7 +370,7 @@ suite('ExtHostEditorTabs', function () {
|
||||
tabDto: { ...tabDto, label: 'NEW LABEL' }
|
||||
});
|
||||
|
||||
const changedTab = (await p)[0];
|
||||
const changedTab = (await p).changed[0];
|
||||
|
||||
assert.ok(tab === changedTab);
|
||||
assert.strictEqual(changedTab.label, 'NEW LABEL');
|
||||
@@ -472,8 +410,8 @@ suite('ExtHostEditorTabs', function () {
|
||||
tabs: [tab1, tab2, tab3]
|
||||
}]);
|
||||
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.map(g => g.tabs).flat().length, 3);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 3);
|
||||
|
||||
// Active tab is correct
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup?.activeTab, extHostEditorTabs.tabGroups.activeTabGroup?.tabs[0]);
|
||||
@@ -503,8 +441,8 @@ suite('ExtHostEditorTabs', function () {
|
||||
groupId: 12,
|
||||
tabs: [tab3]
|
||||
}]);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.map(g => g.tabs).flat().length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup?.activeTab, extHostEditorTabs.tabGroups.activeTabGroup?.tabs[0]);
|
||||
|
||||
// Closing out all tabs returns undefine active tab
|
||||
@@ -514,94 +452,11 @@ suite('ExtHostEditorTabs', function () {
|
||||
groupId: 12,
|
||||
tabs: []
|
||||
}]);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.map(g => g.tabs).flat().length, 0);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 0);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup?.activeTab, undefined);
|
||||
});
|
||||
|
||||
test('Active tab change event', function () {
|
||||
|
||||
const extHostEditorTabs = new ExtHostEditorTabs(
|
||||
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
|
||||
// override/implement $moveTab or $closeTab
|
||||
})
|
||||
);
|
||||
|
||||
let activeTabChangeCount = 0;
|
||||
extHostEditorTabs.tabGroups.onDidChangeActiveTab((activeTab) => {
|
||||
if (activeTab.isActive === false) {
|
||||
throw new Error('Active tab changed fired on inactive tab');
|
||||
}
|
||||
activeTabChangeCount++;
|
||||
});
|
||||
|
||||
const tab1: IEditorTabDto = createTabDto({
|
||||
id: 'uniquestring',
|
||||
isActive: true,
|
||||
label: 'label1',
|
||||
});
|
||||
|
||||
const tab2: IEditorTabDto = createTabDto({
|
||||
isActive: false,
|
||||
id: 'uniquestring2',
|
||||
label: 'label2',
|
||||
});
|
||||
|
||||
const tab3: IEditorTabDto = createTabDto({
|
||||
isActive: false,
|
||||
id: 'uniquestring3',
|
||||
label: 'label3',
|
||||
});
|
||||
|
||||
extHostEditorTabs.$acceptEditorTabModel([{
|
||||
isActive: true,
|
||||
viewColumn: 0,
|
||||
groupId: 12,
|
||||
tabs: [tab1, tab2, tab3]
|
||||
}]);
|
||||
|
||||
// Accepting a model doesn't fire an active tab change event
|
||||
assert.strictEqual(activeTabChangeCount, 0);
|
||||
|
||||
// Switching active tab works
|
||||
tab1.isActive = false;
|
||||
tab2.isActive = true;
|
||||
|
||||
extHostEditorTabs.$acceptTabOperation({
|
||||
groupId: 12,
|
||||
index: 0,
|
||||
kind: TabModelOperationKind.TAB_UPDATE,
|
||||
tabDto: tab1
|
||||
});
|
||||
extHostEditorTabs.$acceptTabOperation({
|
||||
groupId: 12,
|
||||
index: 1,
|
||||
kind: TabModelOperationKind.TAB_UPDATE,
|
||||
tabDto: tab2
|
||||
});
|
||||
// The active tab changed so it is fired once
|
||||
assert.strictEqual(activeTabChangeCount, 1);
|
||||
|
||||
//Closing tabs out works
|
||||
tab3.isActive = true;
|
||||
extHostEditorTabs.$acceptEditorTabModel([{
|
||||
isActive: true,
|
||||
viewColumn: 0,
|
||||
groupId: 12,
|
||||
tabs: [tab3]
|
||||
}]);
|
||||
// Accepting a model doesn't fire an active tab change event
|
||||
assert.strictEqual(activeTabChangeCount, 1);
|
||||
tab3.label = 'Foobar';
|
||||
extHostEditorTabs.$acceptTabOperation({
|
||||
groupId: 12,
|
||||
index: 0,
|
||||
kind: TabModelOperationKind.TAB_UPDATE,
|
||||
tabDto: tab3
|
||||
});
|
||||
// Something related to the active tab changed
|
||||
assert.strictEqual(activeTabChangeCount, 2);
|
||||
});
|
||||
test('Tab operations patches open and close correctly', function () {
|
||||
const extHostEditorTabs = new ExtHostEditorTabs(
|
||||
SingleProxyRPCProtocol(new class extends mock<MainThreadEditorTabsShape>() {
|
||||
@@ -634,8 +489,8 @@ suite('ExtHostEditorTabs', function () {
|
||||
tabs: [tab1, tab2, tab3]
|
||||
}]);
|
||||
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.map(g => g.tabs).flat().length, 3);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 3);
|
||||
|
||||
// Close tab 2
|
||||
extHostEditorTabs.$acceptTabOperation({
|
||||
@@ -644,8 +499,8 @@ suite('ExtHostEditorTabs', function () {
|
||||
kind: TabModelOperationKind.TAB_CLOSE,
|
||||
tabDto: tab2
|
||||
});
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.map(g => g.tabs).flat().length, 2);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 2);
|
||||
|
||||
// Close active tab and update tab 3 to be active
|
||||
extHostEditorTabs.$acceptTabOperation({
|
||||
@@ -654,8 +509,8 @@ suite('ExtHostEditorTabs', function () {
|
||||
kind: TabModelOperationKind.TAB_CLOSE,
|
||||
tabDto: tab1
|
||||
});
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.map(g => g.tabs).flat().length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 1);
|
||||
tab3.isActive = true;
|
||||
extHostEditorTabs.$acceptTabOperation({
|
||||
groupId: 12,
|
||||
@@ -663,9 +518,9 @@ suite('ExtHostEditorTabs', function () {
|
||||
kind: TabModelOperationKind.TAB_UPDATE,
|
||||
tabDto: tab3
|
||||
});
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.map(g => g.tabs).flat().length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups[0]?.activeTab?.label, 'label3');
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all[0]?.activeTab?.label, 'label3');
|
||||
|
||||
// Open tab 2 back
|
||||
extHostEditorTabs.$acceptTabOperation({
|
||||
@@ -674,8 +529,8 @@ suite('ExtHostEditorTabs', function () {
|
||||
kind: TabModelOperationKind.TAB_OPEN,
|
||||
tabDto: tab2
|
||||
});
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups.map(g => g.tabs).flat().length, 2);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.groups[0]?.tabs[1]?.label, 'label2');
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 1);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all.map(g => g.tabs).flat().length, 2);
|
||||
assert.strictEqual(extHostEditorTabs.tabGroups.all[0]?.tabs[1]?.label, 'label2');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user