mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-26 11:38:51 +01:00
Merge remote-tracking branch 'origin/main' into rebornix/notebook-commenting
This commit is contained in:
@@ -1325,6 +1325,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
WorkspaceTrustState: extHostTypes.WorkspaceTrustState,
|
||||
LanguageStatusSeverity: extHostTypes.LanguageStatusSeverity,
|
||||
QuickPickItemKind: extHostTypes.QuickPickItemKind,
|
||||
TextTabInput: extHostTypes.TextTabInput,
|
||||
TextDiffTabInput: extHostTypes.TextDiffTabInput,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@ export type CommentThreadChanges<T = IRange> = Partial<{
|
||||
comments: CommentChanges[];
|
||||
collapseState: languages.CommentThreadCollapsibleState;
|
||||
canReply: boolean;
|
||||
state: languages.CommentThreadState;
|
||||
}>;
|
||||
|
||||
export interface MainThreadCommentsShape extends IDisposable {
|
||||
@@ -609,10 +610,55 @@ export interface ExtHostEditorInsetsShape {
|
||||
|
||||
//#region --- tabs model
|
||||
|
||||
export const enum TabInputKind {
|
||||
UnknownInput,
|
||||
TextInput,
|
||||
TextDiffInput,
|
||||
NotebookInput,
|
||||
NotebookDiffInput,
|
||||
CustomEditorInput
|
||||
}
|
||||
|
||||
export interface UnknownInputDto {
|
||||
kind: TabInputKind.UnknownInput;
|
||||
}
|
||||
|
||||
export interface TextInputDto {
|
||||
kind: TabInputKind.TextInput;
|
||||
uri: UriComponents;
|
||||
}
|
||||
|
||||
export interface TextDiffInputDto {
|
||||
kind: TabInputKind.TextDiffInput;
|
||||
original: UriComponents;
|
||||
modified: UriComponents;
|
||||
}
|
||||
|
||||
export interface NotebookInputDto {
|
||||
kind: TabInputKind.NotebookInput;
|
||||
notebookType: string;
|
||||
uri: UriComponents;
|
||||
}
|
||||
|
||||
export interface NotebookDiffInputDto {
|
||||
kind: TabInputKind.NotebookDiffInput;
|
||||
notebookType: string;
|
||||
original: UriComponents;
|
||||
modified: UriComponents;
|
||||
}
|
||||
|
||||
export interface CustomInputDto {
|
||||
kind: TabInputKind.CustomEditorInput;
|
||||
viewType: string;
|
||||
uri: UriComponents;
|
||||
}
|
||||
|
||||
export type AnyInputDto = UnknownInputDto | TextInputDto | TextDiffInputDto | NotebookInputDto | NotebookDiffInputDto | CustomInputDto;
|
||||
|
||||
export interface MainThreadEditorTabsShape extends IDisposable {
|
||||
// manage tabs: move, close, rearrange etc
|
||||
$moveTab(tabId: string, index: number, viewColumn: EditorGroupColumn): void;
|
||||
$closeTab(tabId: string, preserveFocus: boolean): Promise<void>;
|
||||
$closeTab(tabIds: string[], preserveFocus?: boolean): Promise<void>;
|
||||
}
|
||||
|
||||
export interface IEditorTabGroupDto {
|
||||
@@ -634,6 +680,7 @@ export interface IEditorTabDto {
|
||||
id: string;
|
||||
viewColumn: EditorGroupColumn;
|
||||
label: string;
|
||||
input: AnyInputDto;
|
||||
resource?: UriComponents;
|
||||
editorId?: string;
|
||||
isActive: boolean;
|
||||
@@ -644,8 +691,11 @@ export interface IEditorTabDto {
|
||||
}
|
||||
|
||||
export interface IExtHostEditorTabsShape {
|
||||
// Accepts a whole new model
|
||||
$acceptEditorTabModel(tabGroups: IEditorTabGroupDto[]): void;
|
||||
// Only when group property changes (not the tabs inside)
|
||||
$acceptTabGroupUpdate(groupDto: IEditorTabGroupDto): void;
|
||||
// Only when tab property changes
|
||||
$acceptTabUpdate(groupId: number, tabDto: IEditorTabDto): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as types from 'vs/workbench/api/common/extHostTypes';
|
||||
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import type * as vscode from 'vscode';
|
||||
import { ExtHostCommentsShape, IMainContext, MainContext, CommentThreadChanges, CommentChanges } from './extHost.protocol';
|
||||
import { ExtHostCommands } from './extHostCommands';
|
||||
@@ -222,6 +223,7 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
|
||||
comments: vscode.Comment[];
|
||||
collapsibleState: vscode.CommentThreadCollapsibleState;
|
||||
canReply: boolean;
|
||||
state: vscode.CommentThreadState;
|
||||
}>;
|
||||
|
||||
class ExtHostCommentThread implements vscode.CommentThread {
|
||||
@@ -325,6 +327,20 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
|
||||
this._onDidUpdateCommentThread.fire();
|
||||
}
|
||||
|
||||
private _state?: vscode.CommentThreadState;
|
||||
|
||||
get state(): vscode.CommentThreadState {
|
||||
checkProposedApiEnabled(this.extensionDescription, 'commentsResolvedState');
|
||||
return this._state!;
|
||||
}
|
||||
|
||||
set state(newState: vscode.CommentThreadState) {
|
||||
checkProposedApiEnabled(this.extensionDescription, 'commentsResolvedState');
|
||||
this._state = newState;
|
||||
this.modifications.state = newState;
|
||||
this._onDidUpdateCommentThread.fire();
|
||||
}
|
||||
|
||||
private _localDisposables: types.Disposable[];
|
||||
|
||||
private _isDiposed: boolean;
|
||||
@@ -397,6 +413,8 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
|
||||
set contextValue(value: string | undefined) { that.contextValue = value; },
|
||||
get label() { return that.label; },
|
||||
set label(value: string | undefined) { that.label = value; },
|
||||
get state() { return that.state; },
|
||||
set state(value: vscode.CommentThreadState) { that.state = value; },
|
||||
dispose: () => {
|
||||
that.dispose();
|
||||
}
|
||||
@@ -441,6 +459,9 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
|
||||
if (modified('canReply')) {
|
||||
formattedModifications.canReply = this.canReply;
|
||||
}
|
||||
if (modified('state')) {
|
||||
formattedModifications.state = convertToState(this._state);
|
||||
}
|
||||
this.modifications = {};
|
||||
|
||||
proxy.$updateCommentThread(
|
||||
@@ -660,5 +681,17 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
|
||||
return languages.CommentThreadCollapsibleState.Collapsed;
|
||||
}
|
||||
|
||||
function convertToState(kind: vscode.CommentThreadState | undefined): languages.CommentThreadState {
|
||||
if (kind !== undefined) {
|
||||
switch (kind) {
|
||||
case types.CommentThreadState.Unresolved:
|
||||
return languages.CommentThreadState.Unresolved;
|
||||
case types.CommentThreadState.Resolved:
|
||||
return languages.CommentThreadState.Resolved;
|
||||
}
|
||||
}
|
||||
return languages.CommentThreadState.Unresolved;
|
||||
}
|
||||
|
||||
return new ExtHostCommentsImpl();
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
import type * as vscode from 'vscode';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { IEditorTabDto, IEditorTabGroupDto, IExtHostEditorTabsShape, MainContext, MainThreadEditorTabsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IEditorTabDto, IEditorTabGroupDto, IExtHostEditorTabsShape, MainContext, MainThreadEditorTabsShape, TabInputKind } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ViewColumn } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { TextDiffTabInput, TextTabInput, ViewColumn } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
|
||||
export interface IExtHostEditorTabs extends IExtHostEditorTabsShape {
|
||||
@@ -19,25 +19,104 @@ export interface IExtHostEditorTabs extends IExtHostEditorTabsShape {
|
||||
|
||||
export const IExtHostEditorTabs = createDecorator<IExtHostEditorTabs>('IExtHostEditorTabs');
|
||||
|
||||
type AnyTab = TextTabInput | TextDiffTabInput;
|
||||
|
||||
class ExtHostEditorTab {
|
||||
private _apiObject: vscode.Tab | undefined;
|
||||
private _dto!: IEditorTabDto;
|
||||
private _input: AnyTab | undefined;
|
||||
private readonly _proxy: MainThreadEditorTabsShape;
|
||||
private readonly _activeTabIdGetter: () => string;
|
||||
|
||||
constructor(dto: IEditorTabDto, proxy: MainThreadEditorTabsShape, activeTabIdGetter: () => string) {
|
||||
this._proxy = proxy;
|
||||
this._activeTabIdGetter = activeTabIdGetter;
|
||||
this.acceptDtoUpdate(dto);
|
||||
}
|
||||
|
||||
get apiObject(): vscode.Tab {
|
||||
// Don't want to lose reference to parent `this` in the getters
|
||||
const that = this;
|
||||
if (!this._apiObject) {
|
||||
this._apiObject = Object.freeze({
|
||||
get isActive() {
|
||||
// We use a getter function here to always ensure at most 1 active tab per group and prevent iteration for being required
|
||||
return that._dto.id === that._activeTabIdGetter();
|
||||
},
|
||||
get label() {
|
||||
return that._dto.label;
|
||||
},
|
||||
get input() {
|
||||
return that._input;
|
||||
},
|
||||
get resource() {
|
||||
return URI.revive(that._dto.resource);
|
||||
},
|
||||
get viewType() {
|
||||
return that._dto.editorId;
|
||||
},
|
||||
get isDirty() {
|
||||
return that._dto.isDirty;
|
||||
},
|
||||
get isPinned() {
|
||||
return that._dto.isDirty;
|
||||
},
|
||||
get viewColumn() {
|
||||
return typeConverters.ViewColumn.to(that._dto.viewColumn);
|
||||
},
|
||||
get kind() {
|
||||
return that._dto.kind;
|
||||
},
|
||||
get additionalResourcesAndViewTypes() {
|
||||
return that._dto.additionalResourcesAndViewTypes.map(({ resource, viewId }) => ({ resource: URI.revive(resource), viewType: viewId }));
|
||||
},
|
||||
move: async (index: number, viewColumn: ViewColumn) => {
|
||||
this._proxy.$moveTab(that._dto.id, index, typeConverters.ViewColumn.from(viewColumn));
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return this._apiObject;
|
||||
}
|
||||
|
||||
get tabId(): string {
|
||||
return this._dto.id;
|
||||
}
|
||||
|
||||
acceptDtoUpdate(dto: IEditorTabDto) {
|
||||
this._dto = dto;
|
||||
this._input = this._initInput();
|
||||
}
|
||||
|
||||
private _initInput() {
|
||||
switch (this._dto.input.kind) {
|
||||
case TabInputKind.TextInput:
|
||||
return new TextTabInput(URI.revive(this._dto.input.uri));
|
||||
case TabInputKind.TextDiffInput:
|
||||
return new TextDiffTabInput(URI.revive(this._dto.input.original), URI.revive(this._dto.input.modified));
|
||||
// TODO@lramos15 support all the cases
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
class ExtHostEditorTabGroup {
|
||||
|
||||
private _apiObject: vscode.TabGroup | undefined;
|
||||
private _dto: IEditorTabGroupDto;
|
||||
private _tabs: ExtHostEditorTab[] = [];
|
||||
private _proxy: MainThreadEditorTabsShape;
|
||||
private _activeTabId: string = '';
|
||||
private _activeGroupIdGetter: () => number | undefined;
|
||||
|
||||
constructor(dto: IEditorTabGroupDto, proxy: MainThreadEditorTabsShape, activeGroupIdGetter: () => number | undefined) {
|
||||
this._dto = dto;
|
||||
this._proxy = proxy;
|
||||
this._activeGroupIdGetter = activeGroupIdGetter;
|
||||
// Construct all tabs from the given dto
|
||||
for (const tabDto of dto.tabs) {
|
||||
if (tabDto.isActive) {
|
||||
this._activeTabId = tabDto.id;
|
||||
}
|
||||
this._tabs.push(new ExtHostEditorTab(tabDto, proxy, this.activeTabId));
|
||||
this._tabs.push(new ExtHostEditorTab(tabDto, proxy, () => this.activeTabId()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,9 +147,12 @@ class ExtHostEditorTabGroup {
|
||||
return this._dto.groupId;
|
||||
}
|
||||
|
||||
get tabs(): ExtHostEditorTab[] {
|
||||
return this._tabs;
|
||||
}
|
||||
|
||||
acceptGroupDtoUpdate(dto: IEditorTabGroupDto) {
|
||||
this._dto = dto;
|
||||
this._tabs = dto.tabs.map(tab => new ExtHostEditorTab(tab, this._proxy, this.activeTabId));
|
||||
}
|
||||
|
||||
acceptTabDtoUpdate(dto: IEditorTabDto) {
|
||||
@@ -87,63 +169,48 @@ class ExtHostEditorTabGroup {
|
||||
activeTabId(): string {
|
||||
return this._activeTabId;
|
||||
}
|
||||
|
||||
findExtHostTabFromApi(apiTab: vscode.Tab): ExtHostEditorTab | undefined {
|
||||
return this._tabs.find(extHostTab => extHostTab.apiObject === apiTab);
|
||||
}
|
||||
}
|
||||
|
||||
class ExtHostEditorTab {
|
||||
private _apiObject: vscode.Tab | undefined;
|
||||
private _dto: IEditorTabDto;
|
||||
private _proxy: MainThreadEditorTabsShape;
|
||||
private _activeTabIdGetter: () => string;
|
||||
class ExtHostTabGroups {
|
||||
|
||||
constructor(dto: IEditorTabDto, proxy: MainThreadEditorTabsShape, activeTabIdGetter: () => string) {
|
||||
this._dto = dto;
|
||||
this._proxy = proxy;
|
||||
this._activeTabIdGetter = activeTabIdGetter;
|
||||
}
|
||||
private _apiObject: vscode.TabGroups | undefined;
|
||||
|
||||
get apiObject(): vscode.Tab {
|
||||
// Don't want to lose reference to parent `this` in the getters
|
||||
const that = this;
|
||||
private _tabGroups: ExtHostEditorTabGroup[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly _onDidChangeTagGroup: vscode.Event<void>,
|
||||
private readonly _onDidChangeActiveTabGroup: vscode.Event<vscode.TabGroup | undefined>,
|
||||
private readonly _getActiveTabGroupdId: () => number | undefined,
|
||||
private readonly _proxy: MainThreadEditorTabsShape
|
||||
) { }
|
||||
|
||||
get apiObject() {
|
||||
if (!this._apiObject) {
|
||||
this._apiObject = Object.freeze({
|
||||
get isActive() {
|
||||
// We use a getter function here to always ensure at most 1 active tab per group and prevent iteration for being required
|
||||
return that._dto.id === that._activeTabIdGetter();
|
||||
const that = this;
|
||||
this._apiObject = Object.freeze<vscode.TabGroups>({
|
||||
onDidChangeTabGroup: that._onDidChangeTagGroup, // never changes -> simple value
|
||||
onDidChangeActiveTabGroup: that._onDidChangeActiveTabGroup,
|
||||
get groups() { // dynamic -> getters
|
||||
return Object.freeze(that._tabGroups.map(group => group.apiObject));
|
||||
},
|
||||
get label() {
|
||||
return that._dto.label;
|
||||
get activeTabGroup() {
|
||||
const activeTabGroupId = that._getActiveTabGroupdId();
|
||||
if (activeTabGroupId === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return that._tabGroups.find(candidate => candidate.groupId === activeTabGroupId)?.apiObject;
|
||||
},
|
||||
get resource() {
|
||||
return URI.revive(that._dto.resource);
|
||||
},
|
||||
get viewType() {
|
||||
return that._dto.editorId;
|
||||
},
|
||||
get isDirty() {
|
||||
return that._dto.isDirty;
|
||||
},
|
||||
get isPinned() {
|
||||
return that._dto.isDirty;
|
||||
},
|
||||
get viewColumn() {
|
||||
return typeConverters.ViewColumn.to(that._dto.viewColumn);
|
||||
},
|
||||
get kind() {
|
||||
return that._dto.kind;
|
||||
},
|
||||
get additionalResourcesAndViewTypes() {
|
||||
return that._dto.additionalResourcesAndViewTypes.map(({ resource, viewId }) => ({ resource: URI.revive(resource), viewType: viewId }));
|
||||
},
|
||||
move: async (index: number, viewColumn: ViewColumn) => {
|
||||
this._proxy.$moveTab(that._dto.id, index, typeConverters.ViewColumn.from(viewColumn));
|
||||
return;
|
||||
},
|
||||
close: async (preserveFocus) => {
|
||||
this._proxy.$closeTab(that._dto.id, preserveFocus);
|
||||
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);
|
||||
}
|
||||
this._proxy.$closeTab(extHostTabIds, preserveFocus);
|
||||
return;
|
||||
}
|
||||
});
|
||||
@@ -151,14 +218,20 @@ class ExtHostEditorTab {
|
||||
return this._apiObject;
|
||||
}
|
||||
|
||||
get tabId(): string {
|
||||
return this._dto.id;
|
||||
acceptTabGroups(groups: ExtHostEditorTabGroup[]) {
|
||||
this._tabGroups = groups;
|
||||
}
|
||||
|
||||
acceptDtoUpdate(dto: IEditorTabDto) {
|
||||
this._dto = dto;
|
||||
private findExtHostTabFromApi(apiTab: vscode.Tab): ExtHostEditorTab | undefined {
|
||||
for (const group of this._tabGroups) {
|
||||
for (const tab of group.tabs) {
|
||||
if (tab.apiObject === apiTab) {
|
||||
return tab;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ExtHostEditorTabs implements IExtHostEditorTabs {
|
||||
@@ -171,21 +244,17 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs {
|
||||
|
||||
private _activeGroupId: number | undefined;
|
||||
|
||||
private _tabGroups: vscode.TabGroups = {
|
||||
groups: [],
|
||||
activeTabGroup: undefined,
|
||||
onDidChangeTabGroup: this._onDidChangeTabGroup.event,
|
||||
onDidChangeActiveTabGroup: this._onDidChangeActiveTabGroup.event
|
||||
};
|
||||
private readonly _tabGroups: ExtHostTabGroups;
|
||||
|
||||
private _extHostTabGroups: ExtHostEditorTabGroup[] = [];
|
||||
|
||||
constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) {
|
||||
this._proxy = extHostRpc.getProxy(MainContext.MainThreadEditorTabs);
|
||||
this._tabGroups = new ExtHostTabGroups(this._onDidChangeTabGroup.event, this._onDidChangeActiveTabGroup.event, () => this.activeGroupIdGetter(), this._proxy);
|
||||
}
|
||||
|
||||
get tabGroups(): vscode.TabGroups {
|
||||
return this._tabGroups;
|
||||
return this._tabGroups.apiObject;
|
||||
}
|
||||
|
||||
activeGroupIdGetter(): number | undefined {
|
||||
@@ -193,23 +262,18 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs {
|
||||
}
|
||||
|
||||
$acceptEditorTabModel(tabGroups: IEditorTabGroupDto[]): void {
|
||||
// Clears the tab groups array
|
||||
this._tabGroups.groups.length = 0;
|
||||
|
||||
this._extHostTabGroups = tabGroups.map(tabGroup => {
|
||||
const group = new ExtHostEditorTabGroup(tabGroup, this._proxy, this.activeGroupIdGetter);
|
||||
const group = new ExtHostEditorTabGroup(tabGroup, this._proxy, () => this.activeGroupIdGetter());
|
||||
return group;
|
||||
});
|
||||
for (const group of this._extHostTabGroups) {
|
||||
this._tabGroups.groups.push(group.apiObject);
|
||||
}
|
||||
|
||||
// Set the active tab group id
|
||||
const activeTabGroupId = tabGroups.find(group => group.isActive === true)?.groupId;
|
||||
const activeTabGroup = activeTabGroupId ? this._extHostTabGroups.find(group => group.groupId === activeTabGroupId) : undefined;
|
||||
if (activeTabGroupId !== this._activeGroupId) {
|
||||
this._tabGroups.acceptTabGroups(this._extHostTabGroups);
|
||||
if (this._activeGroupId !== activeTabGroupId) {
|
||||
this._activeGroupId = activeTabGroupId;
|
||||
// TODO @lramos15 how do we set this without messing up readonly
|
||||
this._tabGroups.activeTabGroup = activeTabGroup?.apiObject;
|
||||
this._onDidChangeActiveTabGroup.fire(activeTabGroup?.apiObject);
|
||||
this._onDidChangeActiveTabGroup.fire(this._tabGroups.apiObject.activeTabGroup);
|
||||
}
|
||||
this._onDidChangeTabGroup.fire();
|
||||
}
|
||||
@@ -225,7 +289,6 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs {
|
||||
this._activeGroupId = groupDto.groupId;
|
||||
if (oldActiveGroupId !== this._activeGroupId) {
|
||||
this._onDidChangeActiveTabGroup.fire(group.apiObject);
|
||||
this._tabGroups.activeTabGroup = group.apiObject;
|
||||
}
|
||||
}
|
||||
this._onDidChangeTabGroup.fire();
|
||||
|
||||
@@ -3595,3 +3595,13 @@ export class TypeHierarchyItem {
|
||||
this.selectionRange = selectionRange;
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
export class TextTabInput {
|
||||
constructor(readonly uri: URI) { }
|
||||
}
|
||||
|
||||
export class TextDiffTabInput {
|
||||
constructor(readonly original: URI, readonly modified: URI) { }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user