@theia/plugin-ext 1.71.0-next.8 → 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.
- package/lib/common/plugin-api-rpc.d.ts +76 -0
- package/lib/common/plugin-api-rpc.d.ts.map +1 -1
- package/lib/common/plugin-api-rpc.js +9 -1
- package/lib/common/plugin-api-rpc.js.map +1 -1
- package/lib/hosted/browser/hosted-plugin.d.ts.map +1 -1
- package/lib/hosted/browser/hosted-plugin.js +13 -6
- package/lib/hosted/browser/hosted-plugin.js.map +1 -1
- package/lib/main/browser/main-context.d.ts.map +1 -1
- package/lib/main/browser/main-context.js +2 -6
- package/lib/main/browser/main-context.js.map +1 -1
- package/lib/main/browser/main-file-system-event-service.d.ts +10 -2
- package/lib/main/browser/main-file-system-event-service.d.ts.map +1 -1
- package/lib/main/browser/main-file-system-event-service.js +19 -2
- package/lib/main/browser/main-file-system-event-service.js.map +1 -1
- package/lib/main/browser/menus/menus-contribution-handler.d.ts.map +1 -1
- package/lib/main/browser/menus/menus-contribution-handler.js +2 -0
- package/lib/main/browser/menus/menus-contribution-handler.js.map +1 -1
- package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts +1 -0
- package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts.map +1 -1
- package/lib/main/browser/menus/plugin-menu-command-adapter.js +13 -1
- package/lib/main/browser/menus/plugin-menu-command-adapter.js.map +1 -1
- package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts +1 -1
- package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts.map +1 -1
- package/lib/main/browser/menus/vscode-theia-menu-mappings.js +9 -2
- package/lib/main/browser/menus/vscode-theia-menu-mappings.js.map +1 -1
- package/lib/main/browser/scm-main.d.ts +33 -2
- package/lib/main/browser/scm-main.d.ts.map +1 -1
- package/lib/main/browser/scm-main.js +237 -3
- package/lib/main/browser/scm-main.js.map +1 -1
- package/lib/main/browser/scm-main.spec.d.ts +2 -0
- package/lib/main/browser/scm-main.spec.d.ts.map +1 -0
- package/lib/main/browser/scm-main.spec.js +87 -0
- package/lib/main/browser/scm-main.spec.js.map +1 -0
- package/lib/main/browser/test-main.d.ts +3 -2
- package/lib/main/browser/test-main.d.ts.map +1 -1
- package/lib/main/browser/test-main.js +12 -1
- package/lib/main/browser/test-main.js.map +1 -1
- package/lib/plugin/file-system-event-service-ext-impl.d.ts +11 -5
- package/lib/plugin/file-system-event-service-ext-impl.d.ts.map +1 -1
- package/lib/plugin/file-system-event-service-ext-impl.js +28 -9
- package/lib/plugin/file-system-event-service-ext-impl.js.map +1 -1
- package/lib/plugin/plugin-context.js +4 -4
- package/lib/plugin/plugin-context.js.map +1 -1
- package/lib/plugin/scm.d.ts +8 -2
- package/lib/plugin/scm.d.ts.map +1 -1
- package/lib/plugin/scm.js +188 -5
- package/lib/plugin/scm.js.map +1 -1
- package/lib/plugin/scm.spec.d.ts +2 -0
- package/lib/plugin/scm.spec.d.ts.map +1 -0
- package/lib/plugin/scm.spec.js +461 -0
- package/lib/plugin/scm.spec.js.map +1 -0
- package/lib/plugin/terminal-ext.d.ts +13 -3
- package/lib/plugin/terminal-ext.d.ts.map +1 -1
- package/lib/plugin/terminal-ext.js +51 -10
- package/lib/plugin/terminal-ext.js.map +1 -1
- package/lib/plugin/terminal-ext.spec.d.ts +2 -0
- package/lib/plugin/terminal-ext.spec.d.ts.map +1 -0
- package/lib/plugin/terminal-ext.spec.js +285 -0
- package/lib/plugin/terminal-ext.spec.js.map +1 -0
- package/lib/plugin/test-item.d.ts.map +1 -1
- package/lib/plugin/test-item.js +8 -3
- package/lib/plugin/test-item.js.map +1 -1
- package/lib/plugin/tests.d.ts.map +1 -1
- package/lib/plugin/tests.js +15 -3
- package/lib/plugin/tests.js.map +1 -1
- package/lib/plugin/type-converters.d.ts +2 -2
- package/lib/plugin/type-converters.d.ts.map +1 -1
- package/lib/plugin/type-converters.js +3 -9
- package/lib/plugin/type-converters.js.map +1 -1
- package/lib/plugin/types-impl.d.ts +1 -1
- package/lib/plugin/types-impl.d.ts.map +1 -1
- package/lib/plugin/types-impl.js +1 -1
- package/lib/plugin/types-impl.js.map +1 -1
- package/lib/plugin/workspace.d.ts.map +1 -1
- package/lib/plugin/workspace.js +17 -3
- package/lib/plugin/workspace.js.map +1 -1
- package/package.json +39 -39
- package/src/common/plugin-api-rpc.ts +78 -0
- package/src/hosted/browser/hosted-plugin.ts +13 -6
- package/src/main/browser/main-context.ts +3 -7
- package/src/main/browser/main-file-system-event-service.ts +26 -6
- package/src/main/browser/menus/menus-contribution-handler.ts +2 -0
- package/src/main/browser/menus/plugin-menu-command-adapter.ts +15 -2
- package/src/main/browser/menus/vscode-theia-menu-mappings.ts +12 -3
- package/src/main/browser/scm-main.spec.ts +105 -0
- package/src/main/browser/scm-main.ts +272 -4
- package/src/main/browser/test-main.ts +13 -3
- package/src/plugin/file-system-event-service-ext-impl.ts +40 -14
- package/src/plugin/plugin-context.ts +7 -7
- package/src/plugin/scm.spec.ts +615 -0
- package/src/plugin/scm.ts +224 -6
- package/src/plugin/terminal-ext.spec.ts +350 -0
- package/src/plugin/terminal-ext.ts +58 -12
- package/src/plugin/test-item.ts +8 -3
- package/src/plugin/tests.ts +14 -3
- package/src/plugin/type-converters.ts +7 -13
- package/src/plugin/types-impl.ts +2 -2
- package/src/plugin/workspace.ts +17 -3
package/package.json
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theia/plugin-ext",
|
|
3
|
-
"version": "1.71.0
|
|
3
|
+
"version": "1.71.0",
|
|
4
4
|
"description": "Theia - Plugin Extension",
|
|
5
5
|
"main": "lib/common/index.js",
|
|
6
6
|
"typings": "lib/common/index.d.ts",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@theia/ai-mcp": "1.71.0
|
|
9
|
-
"@theia/bulk-edit": "1.71.0
|
|
10
|
-
"@theia/callhierarchy": "1.71.0
|
|
11
|
-
"@theia/console": "1.71.0
|
|
12
|
-
"@theia/core": "1.71.0
|
|
13
|
-
"@theia/debug": "1.71.0
|
|
14
|
-
"@theia/editor": "1.71.0
|
|
15
|
-
"@theia/editor-preview": "1.71.0
|
|
16
|
-
"@theia/file-search": "1.71.0
|
|
17
|
-
"@theia/filesystem": "1.71.0
|
|
18
|
-
"@theia/markers": "1.71.0
|
|
19
|
-
"@theia/messages": "1.71.0
|
|
20
|
-
"@theia/monaco": "1.71.0
|
|
8
|
+
"@theia/ai-mcp": "1.71.0",
|
|
9
|
+
"@theia/bulk-edit": "1.71.0",
|
|
10
|
+
"@theia/callhierarchy": "1.71.0",
|
|
11
|
+
"@theia/console": "1.71.0",
|
|
12
|
+
"@theia/core": "1.71.0",
|
|
13
|
+
"@theia/debug": "1.71.0",
|
|
14
|
+
"@theia/editor": "1.71.0",
|
|
15
|
+
"@theia/editor-preview": "1.71.0",
|
|
16
|
+
"@theia/file-search": "1.71.0",
|
|
17
|
+
"@theia/filesystem": "1.71.0",
|
|
18
|
+
"@theia/markers": "1.71.0",
|
|
19
|
+
"@theia/messages": "1.71.0",
|
|
20
|
+
"@theia/monaco": "1.71.0",
|
|
21
21
|
"@theia/monaco-editor-core": "1.108.201",
|
|
22
|
-
"@theia/navigator": "1.71.0
|
|
23
|
-
"@theia/notebook": "1.71.0
|
|
24
|
-
"@theia/output": "1.71.0
|
|
25
|
-
"@theia/plugin": "1.71.0
|
|
26
|
-
"@theia/preferences": "1.71.0
|
|
27
|
-
"@theia/scm": "1.71.0
|
|
28
|
-
"@theia/search-in-workspace": "1.71.0
|
|
29
|
-
"@theia/task": "1.71.0
|
|
30
|
-
"@theia/terminal": "1.71.0
|
|
31
|
-
"@theia/test": "1.71.0
|
|
32
|
-
"@theia/timeline": "1.71.0
|
|
33
|
-
"@theia/typehierarchy": "1.71.0
|
|
34
|
-
"@theia/variable-resolver": "1.71.0
|
|
35
|
-
"@theia/workspace": "1.71.0
|
|
36
|
-
"@types/mime": "^2.0.
|
|
37
|
-
"@vscode/debugprotocol": "^1.
|
|
22
|
+
"@theia/navigator": "1.71.0",
|
|
23
|
+
"@theia/notebook": "1.71.0",
|
|
24
|
+
"@theia/output": "1.71.0",
|
|
25
|
+
"@theia/plugin": "1.71.0",
|
|
26
|
+
"@theia/preferences": "1.71.0",
|
|
27
|
+
"@theia/scm": "1.71.0",
|
|
28
|
+
"@theia/search-in-workspace": "1.71.0",
|
|
29
|
+
"@theia/task": "1.71.0",
|
|
30
|
+
"@theia/terminal": "1.71.0",
|
|
31
|
+
"@theia/test": "1.71.0",
|
|
32
|
+
"@theia/timeline": "1.71.0",
|
|
33
|
+
"@theia/typehierarchy": "1.71.0",
|
|
34
|
+
"@theia/variable-resolver": "1.71.0",
|
|
35
|
+
"@theia/workspace": "1.71.0",
|
|
36
|
+
"@types/mime": "^2.0.3",
|
|
37
|
+
"@vscode/debugprotocol": "^1.68.0",
|
|
38
38
|
"@vscode/proxy-agent": "^0.13.2",
|
|
39
|
-
"async-mutex": "^0.4.
|
|
39
|
+
"async-mutex": "^0.4.1",
|
|
40
40
|
"decompress": "^4.2.1",
|
|
41
41
|
"escape-html": "^1.0.3",
|
|
42
|
-
"filenamify": "^4.
|
|
42
|
+
"filenamify": "^4.3.0",
|
|
43
43
|
"is-electron": "^2.2.0",
|
|
44
|
-
"jsonc-parser": "^2.
|
|
44
|
+
"jsonc-parser": "^2.3.1",
|
|
45
45
|
"lodash.clonedeep": "^4.5.0",
|
|
46
|
-
"macaddress": "^0.5.
|
|
47
|
-
"mime": "^2.
|
|
46
|
+
"macaddress": "^0.5.4",
|
|
47
|
+
"mime": "^2.6.0",
|
|
48
48
|
"node-pty": "1.2.0-beta.12",
|
|
49
|
-
"semver": "^7.
|
|
49
|
+
"semver": "^7.7.4",
|
|
50
50
|
"tslib": "^2.6.2",
|
|
51
51
|
"vhost": "^3.0.2",
|
|
52
|
-
"vscode-textmate": "^9.2
|
|
52
|
+
"vscode-textmate": "^9.3.2"
|
|
53
53
|
},
|
|
54
54
|
"publishConfig": {
|
|
55
55
|
"access": "public"
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"watch": "theiaext watch"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
92
|
-
"@theia/ext-scripts": "1.
|
|
92
|
+
"@theia/ext-scripts": "1.71.0",
|
|
93
93
|
"@types/decompress": "^4.2.2",
|
|
94
94
|
"@types/escape-html": "^0.0.20",
|
|
95
95
|
"@types/lodash.clonedeep": "^4.5.3"
|
|
@@ -97,5 +97,5 @@
|
|
|
97
97
|
"nyc": {
|
|
98
98
|
"extends": "../../configs/nyc.json"
|
|
99
99
|
},
|
|
100
|
-
"gitHead": "
|
|
100
|
+
"gitHead": "d8a596fc99f0a8e68b466828ed162569d79e3a71"
|
|
101
101
|
}
|
|
@@ -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
|
/**
|
|
@@ -2120,6 +2192,11 @@ export interface ExtHostFileSystemEventServiceShape {
|
|
|
2120
2192
|
$onDidRunFileOperation(operation: files.FileOperation, target: UriComponents, source: UriComponents | undefined): void;
|
|
2121
2193
|
}
|
|
2122
2194
|
|
|
2195
|
+
export interface MainFileSystemEventServiceShape {
|
|
2196
|
+
$watch(session: number, resource: UriComponents, opts: files.WatchOptions): void;
|
|
2197
|
+
$unwatch(session: number): void;
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2123
2200
|
export interface ClipboardMain {
|
|
2124
2201
|
$readText(): Promise<string>;
|
|
2125
2202
|
$writeText(value: string): Promise<void>;
|
|
@@ -2384,6 +2461,7 @@ export const PLUGIN_RPC_CONTEXT = {
|
|
|
2384
2461
|
TASKS_MAIN: createProxyIdentifier<TasksMain>('TasksMain'),
|
|
2385
2462
|
DEBUG_MAIN: createProxyIdentifier<DebugMain>('DebugMain'),
|
|
2386
2463
|
FILE_SYSTEM_MAIN: createProxyIdentifier<FileSystemMain>('FileSystemMain'),
|
|
2464
|
+
FILE_SYSTEM_EVENT_SERVICE_MAIN: createProxyIdentifier<MainFileSystemEventServiceShape>('FileSystemEventServiceMain'),
|
|
2387
2465
|
SCM_MAIN: createProxyIdentifier<ScmMain>('ScmMain'),
|
|
2388
2466
|
SECRETS_MAIN: createProxyIdentifier<SecretsMain>('SecretsMain'),
|
|
2389
2467
|
DECORATIONS_MAIN: createProxyIdentifier<DecorationsMain>('DecorationsMain'),
|
|
@@ -267,10 +267,12 @@ export class HostedPluginSupport extends AbstractHostedPluginSupport<PluginManag
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
protected override async beforeLoadContributions(toDisconnect: DisposableCollection): Promise<void> {
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
|
|
270
|
+
// Make sure the shell is attached so that registries (commands, menus, views, etc.)
|
|
271
|
+
// are ready to accept contributions. We intentionally do NOT wait for initialized_layout
|
|
272
|
+
// here, because layout restoration may depend on plugin-provided file system providers
|
|
273
|
+
// (e.g. git: scheme for merge editors), and those providers are registered during
|
|
274
|
+
// startPlugins which runs after this point. Waiting for initialized_layout would deadlock.
|
|
275
|
+
await this.appState.reachedState('attached_shell');
|
|
274
276
|
this.workspaceTrusted = await this.workspaceTrustService.getWorkspaceTrust();
|
|
275
277
|
}
|
|
276
278
|
|
|
@@ -464,12 +466,17 @@ export class HostedPluginSupport extends AbstractHostedPluginSupport<PluginManag
|
|
|
464
466
|
}
|
|
465
467
|
|
|
466
468
|
protected ensureFileSystemActivation(event: FileSystemProviderActivationEvent): void {
|
|
467
|
-
event.waitUntil(
|
|
469
|
+
event.waitUntil((async () => {
|
|
470
|
+
// Wait until plugins are synced so that activation events are recorded
|
|
471
|
+
// and will be replayed when managers start. This does not depend on
|
|
472
|
+
// layout initialization, so it cannot deadlock.
|
|
473
|
+
await this.willStart;
|
|
474
|
+
await this.activateByFileSystem(event);
|
|
468
475
|
if (!this.fileService.hasProvider(event.scheme)) {
|
|
469
476
|
return waitForEvent(Event.filter(this.fileService.onDidChangeFileSystemProviderRegistrations,
|
|
470
477
|
({ added, scheme }) => added && scheme === event.scheme), 3000);
|
|
471
478
|
}
|
|
472
|
-
}));
|
|
479
|
+
})());
|
|
473
480
|
}
|
|
474
481
|
|
|
475
482
|
protected ensureCommandHandlerRegistration(event: WillExecuteCommandEvent): void {
|
|
@@ -171,15 +171,11 @@ export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container
|
|
|
171
171
|
rpc.set(PLUGIN_RPC_CONTEXT.DEBUG_MAIN, debugMain);
|
|
172
172
|
|
|
173
173
|
const fs = new FileSystemMainImpl(rpc, container);
|
|
174
|
-
const fsEventService = new MainFileSystemEventService(rpc, container);
|
|
175
|
-
const disposeFS = fs.dispose.bind(fs);
|
|
176
|
-
fs.dispose = () => {
|
|
177
|
-
fsEventService.dispose();
|
|
178
|
-
disposeFS();
|
|
179
|
-
};
|
|
180
|
-
|
|
181
174
|
rpc.set(PLUGIN_RPC_CONTEXT.FILE_SYSTEM_MAIN, fs);
|
|
182
175
|
|
|
176
|
+
const fsEventService = new MainFileSystemEventService(rpc, container);
|
|
177
|
+
rpc.set(PLUGIN_RPC_CONTEXT.FILE_SYSTEM_EVENT_SERVICE_MAIN, fsEventService);
|
|
178
|
+
|
|
183
179
|
const scmMain = new ScmMainImpl(rpc, container);
|
|
184
180
|
rpc.set(PLUGIN_RPC_CONTEXT.SCM_MAIN, scmMain);
|
|
185
181
|
|
|
@@ -21,21 +21,24 @@
|
|
|
21
21
|
|
|
22
22
|
import { interfaces } from '@theia/core/shared/inversify';
|
|
23
23
|
import { RPCProtocol } from '../../common/rpc-protocol';
|
|
24
|
-
import { MAIN_RPC_CONTEXT, FileSystemEvents } from '../../common/plugin-api-rpc';
|
|
25
|
-
import {
|
|
24
|
+
import { MAIN_RPC_CONTEXT, FileSystemEvents, MainFileSystemEventServiceShape } from '../../common/plugin-api-rpc';
|
|
25
|
+
import { UriComponents } from '../../common/uri-components';
|
|
26
|
+
import { URI } from '@theia/core';
|
|
27
|
+
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
|
|
26
28
|
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
|
27
|
-
import { FileChangeType } from '@theia/filesystem/lib/common/files';
|
|
29
|
+
import { FileChangeType, WatchOptions } from '@theia/filesystem/lib/common/files';
|
|
28
30
|
|
|
29
|
-
export class MainFileSystemEventService {
|
|
31
|
+
export class MainFileSystemEventService implements MainFileSystemEventServiceShape {
|
|
30
32
|
|
|
31
33
|
private readonly toDispose = new DisposableCollection();
|
|
34
|
+
private readonly watches = new Map<number, Disposable>();
|
|
32
35
|
|
|
33
36
|
constructor(
|
|
34
37
|
rpc: RPCProtocol,
|
|
35
|
-
container: interfaces.Container
|
|
38
|
+
container: interfaces.Container,
|
|
39
|
+
private readonly fileService = container.get(FileService)
|
|
36
40
|
) {
|
|
37
41
|
const proxy = rpc.getProxy(MAIN_RPC_CONTEXT.ExtHostFileSystemEventService);
|
|
38
|
-
const fileService = container.get(FileService);
|
|
39
42
|
|
|
40
43
|
this.toDispose.push(fileService.onDidFilesChange(event => {
|
|
41
44
|
// file system events - (changes the editor and others make)
|
|
@@ -73,4 +76,21 @@ export class MainFileSystemEventService {
|
|
|
73
76
|
dispose(): void {
|
|
74
77
|
this.toDispose.dispose();
|
|
75
78
|
}
|
|
79
|
+
|
|
80
|
+
$watch(session: number, resource: UriComponents, options: WatchOptions): void {
|
|
81
|
+
if (this.watches.has(session)) {
|
|
82
|
+
throw new Error(`There is already a watch request for the key ${session}`);
|
|
83
|
+
}
|
|
84
|
+
const watch = this.fileService.watch(URI.fromComponents(resource), options);
|
|
85
|
+
this.toDispose.push(watch);
|
|
86
|
+
this.watches.set(session, watch);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
$unwatch(session: number): void {
|
|
90
|
+
const watch = this.watches.get(session);
|
|
91
|
+
if (watch) {
|
|
92
|
+
watch.dispose();
|
|
93
|
+
this.watches.delete(session);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
76
96
|
}
|
|
@@ -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';
|
|
@@ -69,9 +69,12 @@ export class PluginMenuCommandAdapter {
|
|
|
69
69
|
['scm/resourceFolder/context', toScmArgs],
|
|
70
70
|
['scm/resourceGroup/context', toScmArgs],
|
|
71
71
|
['scm/resourceState/context', toScmArgs],
|
|
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)],
|
|
72
76
|
['scm/title', () => [this.toScmArg(this.scmService.selectedRepository)]],
|
|
73
77
|
['scm/sourceControl', toScmArgs],
|
|
74
|
-
['scm/sourceControl/context', toScmArgs],
|
|
75
78
|
['scm/sourceControl/title', () => [this.toScmArg(this.scmService.selectedRepository)]],
|
|
76
79
|
['testing/message/context', toTestMessageArgs],
|
|
77
80
|
['testing/profiles/context', noArgs],
|
|
@@ -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 {
|
|
@@ -27,8 +27,11 @@ import { NAVIGATOR_CONTEXT_MENU } from '@theia/navigator/lib/browser/navigator-c
|
|
|
27
27
|
import { ScmTreeWidget } from '@theia/scm/lib/browser/scm-tree-widget';
|
|
28
28
|
import { PLUGIN_SCM_CHANGE_TITLE_MENU } from '@theia/scm/lib/browser/dirty-diff/dirty-diff-widget';
|
|
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';
|
|
@@ -62,9 +65,12 @@ export const implementedVSCodeContributionPoints = [
|
|
|
62
65
|
'scm/resourceFolder/context',
|
|
63
66
|
'scm/resourceGroup/context',
|
|
64
67
|
'scm/resourceState/context',
|
|
68
|
+
'scm/repository',
|
|
65
69
|
'scm/sourceControl',
|
|
66
|
-
'scm/sourceControl/context',
|
|
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',
|
|
@@ -100,9 +106,12 @@ export const codeToTheiaMappings = new Map<string, MenuPath[]>([
|
|
|
100
106
|
['scm/resourceFolder/context', [ScmTreeWidget.RESOURCE_FOLDER_CONTEXT_MENU]],
|
|
101
107
|
['scm/resourceGroup/context', [ScmTreeWidget.RESOURCE_GROUP_CONTEXT_MENU]],
|
|
102
108
|
['scm/resourceState/context', [ScmTreeWidget.RESOURCE_CONTEXT_MENU]],
|
|
109
|
+
['scm/repository', [SCM_REPOSITORY_MENU]],
|
|
103
110
|
['scm/sourceControl', [SCM_SOURCE_CONTROL_MENU]],
|
|
104
|
-
['scm/sourceControl/context', [SCM_SOURCE_CONTROL_CONTEXT_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]],
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource GmbH and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { expect } from 'chai';
|
|
18
|
+
import { ScmService } from '@theia/scm/lib/browser/scm-service';
|
|
19
|
+
import { ScmMainImpl } from './scm-main';
|
|
20
|
+
|
|
21
|
+
interface ScmMainInternals {
|
|
22
|
+
repositories: Map<number, unknown>;
|
|
23
|
+
repositoryDisposables: Map<number, { dispose(): void }>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function createScmMainImpl(scmService: ScmService): ScmMainImpl {
|
|
27
|
+
// Bypass the constructor's RPC/container wiring. ScmMainImpl's $register and
|
|
28
|
+
// $unregister only touch the proxy for input box validation and selection
|
|
29
|
+
// forwarding — not exercised in this test — so we can stub those safely.
|
|
30
|
+
const proxy = new Proxy({}, {
|
|
31
|
+
get: () => (): unknown => undefined
|
|
32
|
+
});
|
|
33
|
+
const impl = Object.create(ScmMainImpl.prototype) as ScmMainImpl;
|
|
34
|
+
const anyImpl = impl as unknown as Record<string, unknown>;
|
|
35
|
+
anyImpl.proxy = proxy;
|
|
36
|
+
anyImpl.scmService = scmService;
|
|
37
|
+
anyImpl.repositories = new Map();
|
|
38
|
+
anyImpl.repositoryDisposables = new Map();
|
|
39
|
+
anyImpl.disposables = { push: (): void => { } };
|
|
40
|
+
anyImpl.colors = { toCssVariableName: (x: string) => x };
|
|
41
|
+
anyImpl.sharedStyle = { toIconClass: () => ({ object: { iconClass: '' }, dispose: () => { } }) };
|
|
42
|
+
return impl;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
describe('ScmMainImpl - cascade dispose of children on $unregisterSourceControl', () => {
|
|
46
|
+
let scmService: ScmService;
|
|
47
|
+
let impl: ScmMainImpl;
|
|
48
|
+
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
scmService = new ScmService();
|
|
51
|
+
// Stub the optional context key dependency used by ScmService.
|
|
52
|
+
(scmService as unknown as Record<string, unknown>).contextKeys = {};
|
|
53
|
+
impl = createScmMainImpl(scmService);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should unregister worktree children when their parent is unregistered', async () => {
|
|
57
|
+
// Parent
|
|
58
|
+
await impl.$registerSourceControl(1, 'git', 'Main', { scheme: 'file', path: '/repo', authority: '', query: '', fragment: '' });
|
|
59
|
+
// Two worktree children pointing at the parent
|
|
60
|
+
await impl.$registerSourceControl(2, 'git', 'WT-A', { scheme: 'file', path: '/wt-a', authority: '', query: '', fragment: '' }, 1);
|
|
61
|
+
await impl.$registerSourceControl(3, 'git', 'WT-B', { scheme: 'file', path: '/wt-b', authority: '', query: '', fragment: '' }, 1);
|
|
62
|
+
|
|
63
|
+
expect(scmService.repositories).to.have.length(3);
|
|
64
|
+
|
|
65
|
+
const removed: unknown[] = [];
|
|
66
|
+
scmService.onDidRemoveRepository(r => removed.push(r));
|
|
67
|
+
|
|
68
|
+
await impl.$unregisterSourceControl(1);
|
|
69
|
+
|
|
70
|
+
// Parent and both children must be removed from the service.
|
|
71
|
+
expect(scmService.repositories).to.have.length(0);
|
|
72
|
+
expect(removed).to.have.length(3);
|
|
73
|
+
|
|
74
|
+
// Internal bookkeeping must be clean.
|
|
75
|
+
const internals = impl as unknown as ScmMainInternals;
|
|
76
|
+
expect(internals.repositories.size).to.equal(0);
|
|
77
|
+
expect(internals.repositoryDisposables.size).to.equal(0);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should leave unrelated repositories untouched when a parent is unregistered', async () => {
|
|
81
|
+
await impl.$registerSourceControl(1, 'git', 'Main', { scheme: 'file', path: '/repo', authority: '', query: '', fragment: '' });
|
|
82
|
+
await impl.$registerSourceControl(2, 'git', 'WT-A', { scheme: 'file', path: '/wt-a', authority: '', query: '', fragment: '' }, 1);
|
|
83
|
+
// An independent repository (no parent)
|
|
84
|
+
await impl.$registerSourceControl(3, 'git', 'Other', { scheme: 'file', path: '/other', authority: '', query: '', fragment: '' });
|
|
85
|
+
|
|
86
|
+
await impl.$unregisterSourceControl(1);
|
|
87
|
+
|
|
88
|
+
const remaining = scmService.repositories;
|
|
89
|
+
expect(remaining).to.have.length(1);
|
|
90
|
+
expect(remaining[0].provider.rootUri).to.include('/other');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should not crash when the child was already unregistered before the parent', async () => {
|
|
94
|
+
await impl.$registerSourceControl(1, 'git', 'Main', { scheme: 'file', path: '/repo', authority: '', query: '', fragment: '' });
|
|
95
|
+
await impl.$registerSourceControl(2, 'git', 'WT-A', { scheme: 'file', path: '/wt-a', authority: '', query: '', fragment: '' }, 1);
|
|
96
|
+
|
|
97
|
+
// Plugin-side unregister for the child arrives first (race scenario).
|
|
98
|
+
await impl.$unregisterSourceControl(2);
|
|
99
|
+
expect(scmService.repositories).to.have.length(1);
|
|
100
|
+
|
|
101
|
+
// Now the parent is unregistered — cascade should find no child and succeed.
|
|
102
|
+
await impl.$unregisterSourceControl(1);
|
|
103
|
+
expect(scmService.repositories).to.have.length(0);
|
|
104
|
+
});
|
|
105
|
+
});
|