@theia/plugin-ext 1.71.0-next.72 → 1.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/lib/common/plugin-api-rpc.d.ts +71 -0
  2. package/lib/common/plugin-api-rpc.d.ts.map +1 -1
  3. package/lib/common/plugin-api-rpc.js +8 -1
  4. package/lib/common/plugin-api-rpc.js.map +1 -1
  5. package/lib/main/browser/menus/menus-contribution-handler.d.ts.map +1 -1
  6. package/lib/main/browser/menus/menus-contribution-handler.js +2 -0
  7. package/lib/main/browser/menus/menus-contribution-handler.js.map +1 -1
  8. package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts +1 -0
  9. package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts.map +1 -1
  10. package/lib/main/browser/menus/plugin-menu-command-adapter.js +12 -0
  11. package/lib/main/browser/menus/plugin-menu-command-adapter.js.map +1 -1
  12. package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts +1 -1
  13. package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts.map +1 -1
  14. package/lib/main/browser/menus/vscode-theia-menu-mappings.js +7 -0
  15. package/lib/main/browser/menus/vscode-theia-menu-mappings.js.map +1 -1
  16. package/lib/main/browser/scm-main.d.ts +33 -2
  17. package/lib/main/browser/scm-main.d.ts.map +1 -1
  18. package/lib/main/browser/scm-main.js +213 -2
  19. package/lib/main/browser/scm-main.js.map +1 -1
  20. package/lib/plugin/scm.d.ts +7 -1
  21. package/lib/plugin/scm.d.ts.map +1 -1
  22. package/lib/plugin/scm.js +165 -0
  23. package/lib/plugin/scm.js.map +1 -1
  24. package/lib/plugin/scm.spec.d.ts +2 -0
  25. package/lib/plugin/scm.spec.d.ts.map +1 -0
  26. package/lib/plugin/scm.spec.js +461 -0
  27. package/lib/plugin/scm.spec.js.map +1 -0
  28. package/package.json +30 -30
  29. package/src/common/plugin-api-rpc.ts +72 -0
  30. package/src/main/browser/menus/menus-contribution-handler.ts +2 -0
  31. package/src/main/browser/menus/plugin-menu-command-adapter.ts +14 -1
  32. package/src/main/browser/menus/vscode-theia-menu-mappings.ts +9 -0
  33. package/src/main/browser/scm-main.ts +247 -3
  34. package/src/plugin/scm.spec.ts +615 -0
  35. package/src/plugin/scm.ts +198 -2
@@ -962,6 +962,17 @@ export namespace ScmCommandArg {
962
962
  }
963
963
  }
964
964
 
965
+ export interface ScmHistoryItemCommandArg {
966
+ sourceControlHandle: number;
967
+ id: string;
968
+ type: 'historyItem' | 'historyItemRef';
969
+ }
970
+ export namespace ScmHistoryItemCommandArg {
971
+ export function is(arg: unknown): arg is ScmHistoryItemCommandArg {
972
+ return isObject(arg) && 'sourceControlHandle' in arg && 'id' in arg && 'type' in arg;
973
+ }
974
+ }
975
+
965
976
  export interface ScmExt {
966
977
  createSourceControl(plugin: Plugin, id: string, label: string, rootUri?: theia.Uri): theia.SourceControl;
967
978
  getLastInputBox(plugin: Plugin): theia.SourceControlInputBox | undefined;
@@ -970,6 +981,11 @@ export interface ScmExt {
970
981
  $validateInput(sourceControlHandle: number, value: string, cursorPosition: number): Promise<[string, number] | undefined>;
971
982
  $setSelectedSourceControl(selectedSourceControlHandle: number | undefined): Promise<void>;
972
983
  $provideOriginalResource(sourceControlHandle: number, uri: string, token: theia.CancellationToken): Promise<UriComponents | undefined>;
984
+ $provideHistoryItemRefs(sourceControlHandle: number, historyItemRefs: string[] | undefined, token: theia.CancellationToken): Promise<ScmHistoryItemRefDto[] | undefined>;
985
+ $provideHistoryItems(sourceControlHandle: number, options: ScmHistoryOptionsDto, token: theia.CancellationToken): Promise<ScmHistoryItemDto[] | undefined>;
986
+ $provideHistoryItemChanges(sourceControlHandle: number, historyItemId: string, historyItemParentId: string | undefined, token: theia.CancellationToken): Promise<ScmHistoryItemChangeDto[] | undefined>;
987
+ $resolveHistoryItem(sourceControlHandle: number, historyItemId: string, token: theia.CancellationToken): Promise<ScmHistoryItemDto | undefined>;
988
+ $resolveHistoryItemRefsCommonAncestor(sourceControlHandle: number, historyItemRefs: string[], token: theia.CancellationToken): Promise<string | undefined>;
973
989
  }
974
990
 
975
991
  export namespace TimelineCommandArg {
@@ -1054,6 +1070,8 @@ export interface ScmMain {
1054
1070
  $setInputBoxEnabled(sourceControlHandle: number, enabled: boolean): void;
1055
1071
 
1056
1072
  $setActionButton(sourceControlHandle: number, actionButton: ScmActionButton | undefined): void;
1073
+ $onDidChangeCurrentHistoryItemRefs(sourceControlHandle: number): void;
1074
+ $onDidChangeHistoryItemRefs(sourceControlHandle: number, event: ScmHistoryItemRefsChangeEventDto): void;
1057
1075
  }
1058
1076
 
1059
1077
  export interface SourceControlProviderFeatures {
@@ -1063,6 +1081,10 @@ export interface SourceControlProviderFeatures {
1063
1081
  acceptInputCommand?: Command;
1064
1082
  statusBarCommands?: Command[];
1065
1083
  contextValue?: string;
1084
+ hasHistoryProvider?: boolean;
1085
+ currentHistoryItemRef?: ScmHistoryItemRefDto;
1086
+ currentHistoryItemRemoteRef?: ScmHistoryItemRefDto;
1087
+ currentHistoryItemBaseRef?: ScmHistoryItemRefDto;
1066
1088
  }
1067
1089
 
1068
1090
  export interface SourceControlGroupFeatures {
@@ -1099,6 +1121,56 @@ export interface ScmRawResourceSplices {
1099
1121
  splices: ScmRawResourceSplice[]
1100
1122
  }
1101
1123
 
1124
+ export interface ScmHistoryItemRefDto {
1125
+ id: string;
1126
+ name: string;
1127
+ description?: string;
1128
+ revision?: string;
1129
+ icon?: UriComponents | { light: UriComponents; dark: UriComponents } | ThemeIcon;
1130
+ category?: string;
1131
+ }
1132
+
1133
+ export interface ScmHistoryItemRefsChangeEventDto {
1134
+ added: ScmHistoryItemRefDto[];
1135
+ removed: ScmHistoryItemRefDto[];
1136
+ modified: ScmHistoryItemRefDto[];
1137
+ }
1138
+
1139
+ export interface ScmHistoryItemStatisticsDto {
1140
+ files: number;
1141
+ insertions: number;
1142
+ deletions: number;
1143
+ }
1144
+
1145
+ export interface ScmHistoryItemDto {
1146
+ id: string;
1147
+ parentIds?: string[];
1148
+ subject: string;
1149
+ message?: string | MarkdownString;
1150
+ author?: string;
1151
+ authorEmail?: string;
1152
+ authorIcon?: UriComponents | { light: UriComponents; dark: UriComponents } | ThemeIcon;
1153
+ displayId?: string;
1154
+ timestamp?: number;
1155
+ tooltip?: string | MarkdownString;
1156
+ statistics?: ScmHistoryItemStatisticsDto;
1157
+ references?: ScmHistoryItemRefDto[];
1158
+ }
1159
+
1160
+ export interface ScmHistoryItemChangeDto {
1161
+ uri: UriComponents;
1162
+ originalUri?: UriComponents;
1163
+ modifiedUri?: UriComponents;
1164
+ renameUri?: UriComponents;
1165
+ }
1166
+
1167
+ export interface ScmHistoryOptionsDto {
1168
+ skip?: number;
1169
+ limit?: number | { id?: string };
1170
+ historyItemRefs?: string[];
1171
+ filterText?: string;
1172
+ }
1173
+
1102
1174
  export interface SourceControlResourceState {
1103
1175
  readonly handle: number
1104
1176
  /**
@@ -23,6 +23,7 @@ import { TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-too
23
23
  import { DeployedPlugin, IconUrl, Menu } from '../../../common';
24
24
  import { ScmWidget } from '@theia/scm/lib/browser/scm-widget';
25
25
  import { ScmRepositoriesWidget, SCM_SOURCE_CONTROL_TITLE_MENU } from '@theia/scm/lib/browser/scm-repositories-widget';
26
+ import { ScmHistoryGraphWidget, SCM_HISTORY_TITLE_MENU } from '@theia/scm/lib/browser/scm-history-graph-widget';
26
27
  import { KeybindingRegistry, QuickCommandService, codicon } from '@theia/core/lib/browser';
27
28
  import {
28
29
  CodeEditorWidgetUtil, codeToTheiaMappings, ContributionPoint,
@@ -63,6 +64,7 @@ export class MenusContributionPointHandler {
63
64
  });
64
65
  this.tabBarToolbar.registerMenuDelegate(PLUGIN_SCM_TITLE_MENU, widget => widget instanceof ScmWidget);
65
66
  this.tabBarToolbar.registerMenuDelegate(SCM_SOURCE_CONTROL_TITLE_MENU, widget => widget instanceof ScmRepositoriesWidget);
67
+ this.tabBarToolbar.registerMenuDelegate(SCM_HISTORY_TITLE_MENU, widget => widget instanceof ScmHistoryGraphWidget);
66
68
  this.tabBarToolbar.registerMenuDelegate(PLUGIN_VIEW_TITLE_MENU, widget => !CodeEditorWidgetUtil.is(widget));
67
69
  }
68
70
 
@@ -25,7 +25,7 @@ import { DirtyDiffWidget } from '@theia/scm/lib/browser/dirty-diff/dirty-diff-wi
25
25
  import { Change, LineRange } from '@theia/scm/lib/browser/dirty-diff/diff-computer';
26
26
  import { IChange } from '@theia/monaco-editor-core/esm/vs/editor/common/diff/legacyLinesDiffComputer';
27
27
  import { TimelineItem } from '@theia/timeline/lib/common/timeline-model';
28
- import { ScmCommandArg, TimelineCommandArg, TreeViewItemReference } from '../../../common';
28
+ import { ScmCommandArg, ScmHistoryItemCommandArg, TimelineCommandArg, TreeViewItemReference } from '../../../common';
29
29
  import { TestItemReference, TestMessageArg } from '../../../common/test-types';
30
30
  import { PluginScmProvider, PluginScmResource, PluginScmResourceGroup } from '../scm-main';
31
31
  import { TreeViewWidget } from '../view/tree-view-widget';
@@ -70,6 +70,9 @@ export class PluginMenuCommandAdapter {
70
70
  ['scm/resourceGroup/context', toScmArgs],
71
71
  ['scm/resourceState/context', toScmArgs],
72
72
  ['scm/repository', toScmArgs],
73
+ ['scm/history/title', () => [this.toScmArg(this.scmService.selectedRepository)]],
74
+ ['scm/historyItem/context', (...args) => this.toScmHistoryArgs(...args)],
75
+ ['scm/historyItemRef/context', (...args) => this.toScmHistoryArgs(...args)],
73
76
  ['scm/title', () => [this.toScmArg(this.scmService.selectedRepository)]],
74
77
  ['scm/sourceControl', toScmArgs],
75
78
  ['scm/sourceControl/title', () => [this.toScmArg(this.scmService.selectedRepository)]],
@@ -148,6 +151,16 @@ export class PluginMenuCommandAdapter {
148
151
  return scmArgs;
149
152
  }
150
153
 
154
+ protected toScmHistoryArgs(...args: any[]): any[] {
155
+ const result: any[] = [];
156
+ for (const arg of args) {
157
+ if (ScmHistoryItemCommandArg.is(arg) || ScmCommandArg.is(arg)) {
158
+ result.push(arg);
159
+ }
160
+ }
161
+ return result;
162
+ }
163
+
151
164
  protected toScmArg(arg: any): ScmCommandArg | undefined {
152
165
  if (arg instanceof ScmRepository && arg.provider instanceof PluginScmProvider) {
153
166
  return {
@@ -29,6 +29,9 @@ import { PLUGIN_SCM_CHANGE_TITLE_MENU } from '@theia/scm/lib/browser/dirty-diff/
29
29
  import {
30
30
  SCM_REPOSITORY_MENU, SCM_SOURCE_CONTROL_MENU, SCM_SOURCE_CONTROL_TITLE_MENU, SCM_TITLE_MENU
31
31
  } from '@theia/scm/lib/browser/scm-repositories-widget';
32
+ import {
33
+ SCM_HISTORY_TITLE_MENU, SCM_HISTORY_ITEM_CONTEXT_MENU, SCM_HISTORY_ITEM_REF_CONTEXT_MENU
34
+ } from '@theia/scm/lib/browser/scm-history-graph-widget';
32
35
  import { TIMELINE_ITEM_CONTEXT_MENU } from '@theia/timeline/lib/browser/timeline-tree-widget';
33
36
  import { COMMENT_CONTEXT, COMMENT_THREAD_CONTEXT, COMMENT_TITLE } from '../comments/comment-thread-widget';
34
37
  import { VIEW_ITEM_CONTEXT_MENU } from '../view/tree-view-widget';
@@ -65,6 +68,9 @@ export const implementedVSCodeContributionPoints = [
65
68
  'scm/repository',
66
69
  'scm/sourceControl',
67
70
  'scm/sourceControl/title',
71
+ 'scm/history/title',
72
+ 'scm/historyItem/context',
73
+ 'scm/historyItemRef/context',
68
74
  'scm/title',
69
75
  'timeline/item/context',
70
76
  'testing/item/context',
@@ -103,6 +109,9 @@ export const codeToTheiaMappings = new Map<string, MenuPath[]>([
103
109
  ['scm/repository', [SCM_REPOSITORY_MENU]],
104
110
  ['scm/sourceControl', [SCM_SOURCE_CONTROL_MENU]],
105
111
  ['scm/sourceControl/title', [SCM_SOURCE_CONTROL_TITLE_MENU]],
112
+ ['scm/history/title', [SCM_HISTORY_TITLE_MENU]],
113
+ ['scm/historyItem/context', [SCM_HISTORY_ITEM_CONTEXT_MENU]],
114
+ ['scm/historyItemRef/context', [SCM_HISTORY_ITEM_REF_CONTEXT_MENU]],
106
115
  ['scm/title', [SCM_TITLE_MENU]],
107
116
  ['testing/item/context', [TEST_VIEW_CONTEXT_MENU]],
108
117
  ['testing/message/context', [TEST_RUNS_CONTEXT_MENU]],
@@ -27,14 +27,24 @@ import {
27
27
  ScmMain,
28
28
  SourceControlProviderFeatures,
29
29
  ScmRawResourceSplices, ScmRawResourceGroup,
30
- ScmActionButton as RpcScmActionButton
30
+ ScmActionButton as RpcScmActionButton,
31
+ ScmHistoryItemRefDto,
32
+ ScmHistoryItemDto,
33
+ ScmHistoryItemChangeDto,
34
+ ScmHistoryOptionsDto,
35
+ ScmHistoryItemRefsChangeEventDto
31
36
  } from '../../common/plugin-api-rpc';
32
- import { ScmProvider, ScmResource, ScmResourceDecorations, ScmResourceGroup, ScmCommand, ScmActionButton } from '@theia/scm/lib/browser/scm-provider';
37
+ import {
38
+ ScmProvider, ScmResource, ScmResourceDecorations, ScmResourceGroup, ScmCommand, ScmActionButton,
39
+ ScmHistoryProvider, ScmHistoryItemRef, ScmHistoryItemRefsChangeEvent,
40
+ ScmHistoryOptions, ScmHistoryItem, ScmHistoryItemChange
41
+ } from '@theia/scm/lib/browser/scm-provider';
33
42
  import { ScmRepository } from '@theia/scm/lib/browser/scm-repository';
34
43
  import { ScmService } from '@theia/scm/lib/browser/scm-service';
35
44
  import { RPCProtocol } from '../../common/rpc-protocol';
36
45
  import { interfaces } from '@theia/core/shared/inversify';
37
46
  import { Emitter, Event } from '@theia/core/lib/common/event';
47
+ import { CancellationToken, CancellationTokenSource } from '@theia/core/lib/common/cancellation';
38
48
  import { DisposableCollection } from '@theia/core/lib/common/disposable';
39
49
  import URI from '@theia/core/lib/common/uri';
40
50
  import { URI as vscodeURI } from '@theia/core/shared/vscode-uri';
@@ -104,6 +114,198 @@ export class PluginScmResource implements ScmResource {
104
114
  }
105
115
  }
106
116
 
117
+ function historyItemRefFromDto(dto: ScmHistoryItemRefDto): ScmHistoryItemRef {
118
+ return {
119
+ id: dto.id,
120
+ name: dto.name,
121
+ description: dto.description,
122
+ revision: dto.revision,
123
+ icon: dto.icon ? (ThemeIcon.isThemeIcon(dto.icon) ? ThemeIcon.asClassName(dto.icon) :
124
+ 'light' in dto.icon ? vscodeURI.revive(dto.icon.light).toString() : vscodeURI.revive(dto.icon as UriComponents).toString()) : undefined,
125
+ category: dto.category,
126
+ };
127
+ }
128
+
129
+ function historyItemFromDto(dto: ScmHistoryItemDto): ScmHistoryItem {
130
+ return {
131
+ id: dto.id,
132
+ parentIds: dto.parentIds,
133
+ subject: dto.subject,
134
+ message: typeof dto.message === 'string' ? dto.message : dto.message?.value,
135
+ author: dto.author,
136
+ authorEmail: dto.authorEmail,
137
+ authorIcon: dto.authorIcon ? (ThemeIcon.isThemeIcon(dto.authorIcon) ? ThemeIcon.asClassName(dto.authorIcon) :
138
+ 'light' in dto.authorIcon ? vscodeURI.revive(dto.authorIcon.light).toString() : vscodeURI.revive(dto.authorIcon as UriComponents).toString()) : undefined,
139
+ displayId: dto.displayId,
140
+ timestamp: dto.timestamp,
141
+ tooltip: typeof dto.tooltip === 'string' ? dto.tooltip : dto.tooltip?.value,
142
+ statistics: dto.statistics ? {
143
+ files: dto.statistics.files,
144
+ insertions: dto.statistics.insertions,
145
+ deletions: dto.statistics.deletions,
146
+ } : undefined,
147
+ references: dto.references ? dto.references.map(historyItemRefFromDto) : undefined,
148
+ };
149
+ }
150
+
151
+ function historyItemChangeFromDto(dto: ScmHistoryItemChangeDto): ScmHistoryItemChange {
152
+ return {
153
+ uri: vscodeURI.revive(dto.uri).toString(),
154
+ originalUri: dto.originalUri ? vscodeURI.revive(dto.originalUri).toString() : undefined,
155
+ modifiedUri: dto.modifiedUri ? vscodeURI.revive(dto.modifiedUri).toString() : undefined,
156
+ renameUri: dto.renameUri ? vscodeURI.revive(dto.renameUri).toString() : undefined,
157
+ };
158
+ }
159
+
160
+ export class PluginScmHistoryProvider implements ScmHistoryProvider {
161
+
162
+ private readonly onDidChangeCurrentHistoryItemRefsEmitter = new Emitter<void>();
163
+ readonly onDidChangeCurrentHistoryItemRefs: Event<void> = this.onDidChangeCurrentHistoryItemRefsEmitter.event;
164
+
165
+ private readonly onDidChangeHistoryItemRefsEmitter = new Emitter<ScmHistoryItemRefsChangeEvent>();
166
+ readonly onDidChangeHistoryItemRefs: Event<ScmHistoryItemRefsChangeEvent> = this.onDidChangeHistoryItemRefsEmitter.event;
167
+
168
+ private _currentHistoryItemRef: ScmHistoryItemRef | undefined;
169
+ get currentHistoryItemRef(): ScmHistoryItemRef | undefined { return this._currentHistoryItemRef; }
170
+
171
+ private _currentHistoryItemRemoteRef: ScmHistoryItemRef | undefined;
172
+ get currentHistoryItemRemoteRef(): ScmHistoryItemRef | undefined { return this._currentHistoryItemRemoteRef; }
173
+
174
+ private _currentHistoryItemBaseRef: ScmHistoryItemRef | undefined;
175
+ get currentHistoryItemBaseRef(): ScmHistoryItemRef | undefined { return this._currentHistoryItemBaseRef; }
176
+
177
+ private readonly disposables = new DisposableCollection();
178
+ private pendingRequests = new Set<CancellationTokenSource>();
179
+
180
+ constructor(
181
+ private readonly proxy: ScmExt,
182
+ private readonly handle: number
183
+ ) {
184
+ this.disposables.push(this.onDidChangeCurrentHistoryItemRefsEmitter);
185
+ this.disposables.push(this.onDidChangeHistoryItemRefsEmitter);
186
+ }
187
+
188
+ updateFromFeatures(features: SourceControlProviderFeatures): void {
189
+ if (features.currentHistoryItemRef !== undefined) {
190
+ this._currentHistoryItemRef = features.currentHistoryItemRef ? historyItemRefFromDto(features.currentHistoryItemRef) : undefined;
191
+ }
192
+ if (features.currentHistoryItemRemoteRef !== undefined) {
193
+ this._currentHistoryItemRemoteRef = features.currentHistoryItemRemoteRef ? historyItemRefFromDto(features.currentHistoryItemRemoteRef) : undefined;
194
+ }
195
+ if (features.currentHistoryItemBaseRef !== undefined) {
196
+ this._currentHistoryItemBaseRef = features.currentHistoryItemBaseRef ? historyItemRefFromDto(features.currentHistoryItemBaseRef) : undefined;
197
+ }
198
+ }
199
+
200
+ fireDidChangeCurrentHistoryItemRefs(): void {
201
+ this.onDidChangeCurrentHistoryItemRefsEmitter.fire();
202
+ }
203
+
204
+ fireDidChangeHistoryItemRefs(event: ScmHistoryItemRefsChangeEventDto): void {
205
+ this.onDidChangeHistoryItemRefsEmitter.fire({
206
+ added: event.added.map(historyItemRefFromDto),
207
+ removed: event.removed.map(historyItemRefFromDto),
208
+ modified: event.modified.map(historyItemRefFromDto),
209
+ });
210
+ }
211
+
212
+ async provideHistoryItemRefs(historyItemRefs: string[] | undefined, token: CancellationToken): Promise<ScmHistoryItemRef[] | undefined> {
213
+ const cts = new CancellationTokenSource();
214
+ const listener = token.onCancellationRequested(() => cts.cancel());
215
+ this.pendingRequests.add(cts);
216
+ try {
217
+ const result = await this.proxy.$provideHistoryItemRefs(this.handle, historyItemRefs, cts.token);
218
+ if (!result) {
219
+ return undefined;
220
+ }
221
+ return result.map(historyItemRefFromDto);
222
+ } finally {
223
+ listener.dispose();
224
+ this.pendingRequests.delete(cts);
225
+ cts.dispose();
226
+ }
227
+ }
228
+
229
+ async provideHistoryItems(options: ScmHistoryOptions, token: CancellationToken): Promise<ScmHistoryItem[] | undefined> {
230
+ const dto: ScmHistoryOptionsDto = {
231
+ skip: options.skip,
232
+ limit: options.limit,
233
+ historyItemRefs: options.historyItemRefs ? [...options.historyItemRefs] : undefined,
234
+ filterText: options.filterText,
235
+ };
236
+ const cts = new CancellationTokenSource();
237
+ const listener = token.onCancellationRequested(() => cts.cancel());
238
+ this.pendingRequests.add(cts);
239
+ try {
240
+ const result = await this.proxy.$provideHistoryItems(this.handle, dto, cts.token);
241
+ if (!result) {
242
+ return undefined;
243
+ }
244
+ return result.map(historyItemFromDto);
245
+ } finally {
246
+ listener.dispose();
247
+ this.pendingRequests.delete(cts);
248
+ cts.dispose();
249
+ }
250
+ }
251
+
252
+ async provideHistoryItemChanges(historyItemId: string, historyItemParentId: string | undefined, token: CancellationToken): Promise<ScmHistoryItemChange[] | undefined> {
253
+ const cts = new CancellationTokenSource();
254
+ const listener = token.onCancellationRequested(() => cts.cancel());
255
+ this.pendingRequests.add(cts);
256
+ try {
257
+ const result = await this.proxy.$provideHistoryItemChanges(this.handle, historyItemId, historyItemParentId, cts.token);
258
+ if (!result) {
259
+ return undefined;
260
+ }
261
+ return result.map(historyItemChangeFromDto);
262
+ } finally {
263
+ listener.dispose();
264
+ this.pendingRequests.delete(cts);
265
+ cts.dispose();
266
+ }
267
+ }
268
+
269
+ async resolveHistoryItem(historyItemId: string, token: CancellationToken): Promise<ScmHistoryItem | undefined> {
270
+ const cts = new CancellationTokenSource();
271
+ const listener = token.onCancellationRequested(() => cts.cancel());
272
+ this.pendingRequests.add(cts);
273
+ try {
274
+ const result = await this.proxy.$resolveHistoryItem(this.handle, historyItemId, cts.token);
275
+ if (!result) {
276
+ return undefined;
277
+ }
278
+ return historyItemFromDto(result);
279
+ } finally {
280
+ listener.dispose();
281
+ this.pendingRequests.delete(cts);
282
+ cts.dispose();
283
+ }
284
+ }
285
+
286
+ async resolveHistoryItemRefsCommonAncestor(historyItemRefs: string[], token: CancellationToken): Promise<string | undefined> {
287
+ const cts = new CancellationTokenSource();
288
+ const listener = token.onCancellationRequested(() => cts.cancel());
289
+ this.pendingRequests.add(cts);
290
+ try {
291
+ return await this.proxy.$resolveHistoryItemRefsCommonAncestor(this.handle, historyItemRefs, cts.token) ?? undefined;
292
+ } finally {
293
+ listener.dispose();
294
+ this.pendingRequests.delete(cts);
295
+ cts.dispose();
296
+ }
297
+ }
298
+
299
+ dispose(): void {
300
+ for (const cts of this.pendingRequests) {
301
+ cts.cancel();
302
+ cts.dispose();
303
+ }
304
+ this.pendingRequests.clear();
305
+ this.disposables.dispose();
306
+ }
307
+ }
308
+
107
309
  export class PluginScmProvider implements ScmProvider {
108
310
 
109
311
  private _id = this.contextValue;
@@ -118,6 +320,11 @@ export class PluginScmProvider implements ScmProvider {
118
320
  private _actionButton: ScmActionButton | undefined;
119
321
  get actionButton(): ScmActionButton | undefined { return this._actionButton; }
120
322
 
323
+ private _historyProvider: PluginScmHistoryProvider | undefined;
324
+ get historyProvider(): ScmHistoryProvider | undefined {
325
+ return this._historyProvider;
326
+ }
327
+
121
328
  private features: SourceControlProviderFeatures = {};
122
329
 
123
330
  get providerContextValue(): string | undefined { return this.features.contextValue; }
@@ -172,8 +379,22 @@ export class PluginScmProvider implements ScmProvider {
172
379
 
173
380
  updateSourceControl(features: SourceControlProviderFeatures): void {
174
381
  this.features = { ...this.features, ...features };
382
+
383
+ if (typeof features.hasHistoryProvider !== 'undefined') {
384
+ if (features.hasHistoryProvider && !this._historyProvider) {
385
+ this._historyProvider = new PluginScmHistoryProvider(this.proxy, this.handle);
386
+ } else if (!features.hasHistoryProvider && this._historyProvider) {
387
+ this._historyProvider.dispose();
388
+ this._historyProvider = undefined;
389
+ }
390
+ }
391
+
175
392
  this.onDidChangeEmitter.fire();
176
393
 
394
+ if (this._historyProvider) {
395
+ this._historyProvider.updateFromFeatures(features);
396
+ }
397
+
177
398
  if (typeof features.commitTemplate !== 'undefined') {
178
399
  this.onDidChangeCommitTemplateEmitter.fire(this.commitTemplate!);
179
400
  }
@@ -303,7 +524,10 @@ export class PluginScmProvider implements ScmProvider {
303
524
  this.onDidChangeActionButtonEmitter.fire(actionButton);
304
525
  }
305
526
 
306
- dispose(): void { }
527
+ dispose(): void {
528
+ this._historyProvider?.dispose();
529
+ this._historyProvider = undefined;
530
+ }
307
531
  }
308
532
 
309
533
  export class ScmMainImpl implements ScmMain {
@@ -546,4 +770,24 @@ export class ScmMainImpl implements ScmMain {
546
770
 
547
771
  provider.updateActionButton(converted);
548
772
  }
773
+
774
+ $onDidChangeCurrentHistoryItemRefs(sourceControlHandle: number): void {
775
+ const repository = this.repositories.get(sourceControlHandle);
776
+ if (!repository) {
777
+ return;
778
+ }
779
+ const provider = repository.provider as PluginScmProvider;
780
+ const historyProvider = provider.historyProvider as PluginScmHistoryProvider | undefined;
781
+ historyProvider?.fireDidChangeCurrentHistoryItemRefs();
782
+ }
783
+
784
+ $onDidChangeHistoryItemRefs(sourceControlHandle: number, event: ScmHistoryItemRefsChangeEventDto): void {
785
+ const repository = this.repositories.get(sourceControlHandle);
786
+ if (!repository) {
787
+ return;
788
+ }
789
+ const provider = repository.provider as PluginScmProvider;
790
+ const historyProvider = provider.historyProvider as PluginScmHistoryProvider | undefined;
791
+ historyProvider?.fireDidChangeHistoryItemRefs(event);
792
+ }
549
793
  }