@theia/scm 1.45.0 → 1.46.0-next.72

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 (94) hide show
  1. package/README.md +31 -31
  2. package/lib/browser/decorations/scm-decorations-service.d.ts +14 -14
  3. package/lib/browser/decorations/scm-decorations-service.js +101 -101
  4. package/lib/browser/decorations/scm-navigator-decorator.d.ts +25 -25
  5. package/lib/browser/decorations/scm-navigator-decorator.js +132 -132
  6. package/lib/browser/decorations/scm-tab-bar-decorator.d.ts +17 -17
  7. package/lib/browser/decorations/scm-tab-bar-decorator.js +93 -93
  8. package/lib/browser/dirty-diff/content-lines.d.ts +12 -12
  9. package/lib/browser/dirty-diff/content-lines.js +106 -106
  10. package/lib/browser/dirty-diff/content-lines.spec.d.ts +1 -1
  11. package/lib/browser/dirty-diff/content-lines.spec.js +39 -39
  12. package/lib/browser/dirty-diff/diff-computer.d.ts +29 -29
  13. package/lib/browser/dirty-diff/diff-computer.js +102 -102
  14. package/lib/browser/dirty-diff/diff-computer.spec.d.ts +1 -1
  15. package/lib/browser/dirty-diff/diff-computer.spec.js +315 -315
  16. package/lib/browser/dirty-diff/dirty-diff-decorator.d.ts +14 -14
  17. package/lib/browser/dirty-diff/dirty-diff-decorator.js +98 -98
  18. package/lib/browser/dirty-diff/dirty-diff-module.d.ts +3 -3
  19. package/lib/browser/dirty-diff/dirty-diff-module.js +24 -24
  20. package/lib/browser/scm-amend-component.d.ts +123 -123
  21. package/lib/browser/scm-amend-component.js +463 -463
  22. package/lib/browser/scm-amend-widget.d.ts +20 -20
  23. package/lib/browser/scm-amend-widget.js +101 -101
  24. package/lib/browser/scm-avatar-service.d.ts +3 -3
  25. package/lib/browser/scm-avatar-service.js +36 -36
  26. package/lib/browser/scm-commit-widget.d.ts +52 -52
  27. package/lib/browser/scm-commit-widget.js +199 -199
  28. package/lib/browser/scm-context-key-service.d.ts +10 -10
  29. package/lib/browser/scm-context-key-service.js +58 -58
  30. package/lib/browser/scm-contribution.d.ts +83 -83
  31. package/lib/browser/scm-contribution.js +356 -356
  32. package/lib/browser/scm-frontend-module.d.ts +6 -6
  33. package/lib/browser/scm-frontend-module.js +130 -130
  34. package/lib/browser/scm-groups-tree-model.d.ts +14 -14
  35. package/lib/browser/scm-groups-tree-model.js +97 -97
  36. package/lib/browser/scm-input.d.ts +53 -53
  37. package/lib/browser/scm-input.js +127 -127
  38. package/lib/browser/scm-layout-migrations.d.ts +9 -9
  39. package/lib/browser/scm-layout-migrations.js +79 -79
  40. package/lib/browser/scm-no-repository-widget.d.ts +8 -8
  41. package/lib/browser/scm-no-repository-widget.js +49 -49
  42. package/lib/browser/scm-preferences.d.ts +11 -11
  43. package/lib/browser/scm-preferences.js +51 -51
  44. package/lib/browser/scm-provider.d.ts +58 -58
  45. package/lib/browser/scm-provider.js +19 -19
  46. package/lib/browser/scm-quick-open-service.d.ts +11 -11
  47. package/lib/browser/scm-quick-open-service.js +73 -73
  48. package/lib/browser/scm-repository.d.ts +17 -17
  49. package/lib/browser/scm-repository.js +41 -41
  50. package/lib/browser/scm-service.d.ts +26 -26
  51. package/lib/browser/scm-service.js +108 -108
  52. package/lib/browser/scm-tree-label-provider.d.ts +7 -7
  53. package/lib/browser/scm-tree-label-provider.js +57 -57
  54. package/lib/browser/scm-tree-model.d.ts +74 -74
  55. package/lib/browser/scm-tree-model.js +351 -351
  56. package/lib/browser/scm-tree-widget.d.ts +208 -208
  57. package/lib/browser/scm-tree-widget.js +703 -703
  58. package/lib/browser/scm-widget.d.ts +40 -40
  59. package/lib/browser/scm-widget.js +218 -218
  60. package/package.json +6 -6
  61. package/src/browser/decorations/scm-decorations-service.ts +78 -78
  62. package/src/browser/decorations/scm-navigator-decorator.ts +121 -121
  63. package/src/browser/decorations/scm-tab-bar-decorator.ts +83 -83
  64. package/src/browser/dirty-diff/content-lines.spec.ts +42 -42
  65. package/src/browser/dirty-diff/content-lines.ts +112 -112
  66. package/src/browser/dirty-diff/diff-computer.spec.ts +387 -387
  67. package/src/browser/dirty-diff/diff-computer.ts +129 -129
  68. package/src/browser/dirty-diff/dirty-diff-decorator.ts +107 -107
  69. package/src/browser/dirty-diff/dirty-diff-module.ts +24 -24
  70. package/src/browser/scm-amend-component.tsx +600 -600
  71. package/src/browser/scm-amend-widget.tsx +77 -77
  72. package/src/browser/scm-avatar-service.ts +27 -27
  73. package/src/browser/scm-commit-widget.tsx +215 -215
  74. package/src/browser/scm-context-key-service.ts +46 -46
  75. package/src/browser/scm-contribution.ts +361 -361
  76. package/src/browser/scm-frontend-module.ts +149 -149
  77. package/src/browser/scm-groups-tree-model.ts +78 -78
  78. package/src/browser/scm-input.ts +164 -164
  79. package/src/browser/scm-layout-migrations.ts +64 -64
  80. package/src/browser/scm-no-repository-widget.tsx +41 -41
  81. package/src/browser/scm-preferences.ts +63 -63
  82. package/src/browser/scm-provider.ts +91 -91
  83. package/src/browser/scm-quick-open-service.ts +48 -48
  84. package/src/browser/scm-repository.ts +52 -52
  85. package/src/browser/scm-service.ts +108 -108
  86. package/src/browser/scm-tree-label-provider.ts +44 -44
  87. package/src/browser/scm-tree-model.ts +405 -405
  88. package/src/browser/scm-tree-widget.tsx +838 -838
  89. package/src/browser/scm-widget.tsx +204 -204
  90. package/src/browser/style/dirty-diff-decorator.css +52 -52
  91. package/src/browser/style/dirty-diff.css +50 -50
  92. package/src/browser/style/index.css +271 -271
  93. package/src/browser/style/scm-amend-component.css +94 -94
  94. package/src/browser/style/scm.svg +4 -4
@@ -1,704 +1,704 @@
1
- "use strict";
2
- // *****************************************************************************
3
- // Copyright (C) 2020 Arm and others.
4
- //
5
- // This program and the accompanying materials are made available under the
6
- // terms of the Eclipse Public License v. 2.0 which is available at
7
- // http://www.eclipse.org/legal/epl-2.0.
8
- //
9
- // This Source Code may also be made available under the following Secondary
10
- // Licenses when the conditions for such availability set forth in the Eclipse
11
- // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
- // with the GNU Classpath Exception which is available at
13
- // https://www.gnu.org/software/classpath/license.html.
14
- //
15
- // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
- // *****************************************************************************
17
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
18
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
19
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
20
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
21
- return c > 3 && r && Object.defineProperty(target, key, r), r;
22
- };
23
- var __metadata = (this && this.__metadata) || function (k, v) {
24
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25
- };
26
- var __param = (this && this.__param) || function (paramIndex, decorator) {
27
- return function (target, key) { decorator(target, key, paramIndex); }
28
- };
29
- var ScmTreeWidget_1;
30
- Object.defineProperty(exports, "__esModule", { value: true });
31
- exports.ScmInlineAction = exports.ScmInlineActions = exports.ScmResourceFolderElement = exports.ScmResourceGroupElement = exports.ScmResourceComponent = exports.ScmElement = exports.ScmTreeWidget = void 0;
32
- /* eslint-disable no-null/no-null, @typescript-eslint/no-explicit-any */
33
- const React = require("@theia/core/shared/react");
34
- const inversify_1 = require("@theia/core/shared/inversify");
35
- const uri_1 = require("@theia/core/lib/common/uri");
36
- const os_1 = require("@theia/core/lib/common/os");
37
- const disposable_1 = require("@theia/core/lib/common/disposable");
38
- const tree_1 = require("@theia/core/lib/browser/tree");
39
- const scm_tree_model_1 = require("./scm-tree-model");
40
- const menu_1 = require("@theia/core/lib/common/menu");
41
- const browser_1 = require("@theia/core/lib/browser");
42
- const scm_context_key_service_1 = require("./scm-context-key-service");
43
- const browser_2 = require("@theia/editor/lib/browser");
44
- const icon_theme_service_1 = require("@theia/core/lib/browser/icon-theme-service");
45
- const color_registry_1 = require("@theia/core/lib/browser/color-registry");
46
- const decorations_service_1 = require("@theia/core/lib/browser/decorations-service");
47
- const files_1 = require("@theia/filesystem/lib/common/files");
48
- const theming_1 = require("@theia/core/lib/browser/theming");
49
- let ScmTreeWidget = ScmTreeWidget_1 = class ScmTreeWidget extends tree_1.TreeWidget {
50
- constructor(props, treeModel, contextMenuRenderer) {
51
- super(props, treeModel, contextMenuRenderer);
52
- this.id = ScmTreeWidget_1.ID;
53
- this.addClass('groups-outer-container');
54
- }
55
- init() {
56
- super.init();
57
- this.toDispose.push(this.themeService.onDidColorThemeChange(() => this.update()));
58
- }
59
- set viewMode(id) {
60
- // Close the search box because the structure of the tree will change dramatically
61
- // and the search results will be out of date.
62
- this.searchBox.hide();
63
- this.model.viewMode = id;
64
- }
65
- get viewMode() {
66
- return this.model.viewMode;
67
- }
68
- /**
69
- * Render the node given the tree node and node properties.
70
- * @param node the tree node.
71
- * @param props the node properties.
72
- */
73
- renderNode(node, props) {
74
- var _a;
75
- if (!tree_1.TreeNode.isVisible(node)) {
76
- return undefined;
77
- }
78
- const attributes = this.createNodeAttributes(node, props);
79
- const label = this.labelProvider.getName(node);
80
- const searchHighlights = (_a = this.searchHighlights) === null || _a === void 0 ? void 0 : _a.get(node.id);
81
- // The group nodes should not be subject to highlighting.
82
- const caption = (searchHighlights && !scm_tree_model_1.ScmFileChangeGroupNode.is(node)) ? this.toReactNode(label, searchHighlights) : label;
83
- if (scm_tree_model_1.ScmFileChangeGroupNode.is(node)) {
84
- const content = React.createElement(ScmResourceGroupElement, { key: `${node.groupId}`, model: this.model, treeNode: node, renderExpansionToggle: () => this.renderExpansionToggle(node, props), commandExecutor: this.menuCommandExecutor, contextMenuRenderer: this.contextMenuRenderer, menus: this.menus, contextKeys: this.contextKeys, labelProvider: this.labelProvider, corePreferences: this.corePreferences, caption: caption });
85
- return React.createElement('div', attributes, content);
86
- }
87
- if (scm_tree_model_1.ScmFileChangeFolderNode.is(node)) {
88
- const content = React.createElement(ScmResourceFolderElement, { key: String(node.sourceUri), model: this.model, treeNode: node, sourceUri: node.sourceUri, renderExpansionToggle: () => this.renderExpansionToggle(node, props), commandExecutor: this.menuCommandExecutor, contextMenuRenderer: this.contextMenuRenderer, menus: this.menus, contextKeys: this.contextKeys, labelProvider: this.labelProvider, corePreferences: this.corePreferences, caption: caption });
89
- return React.createElement('div', attributes, content);
90
- }
91
- if (scm_tree_model_1.ScmFileChangeNode.is(node)) {
92
- const parentPath = (node.parent && scm_tree_model_1.ScmFileChangeFolderNode.is(node.parent))
93
- ? new uri_1.default(node.parent.sourceUri) : new uri_1.default(this.model.rootUri);
94
- const content = React.createElement(ScmResourceComponent, { key: node.sourceUri, model: this.model, treeNode: node, contextMenuRenderer: this.contextMenuRenderer, commandExecutor: this.menuCommandExecutor, menus: this.menus, contextKeys: this.contextKeys, labelProvider: this.labelProvider, corePreferences: this.corePreferences, caption: caption, ...{
95
- ...this.props,
96
- parentPath,
97
- sourceUri: node.sourceUri,
98
- decoration: this.decorationsService.getDecoration(new uri_1.default(node.sourceUri), true)[0],
99
- colors: this.colors,
100
- isLightTheme: this.isCurrentThemeLight(),
101
- renderExpansionToggle: () => this.renderExpansionToggle(node, props),
102
- } });
103
- return React.createElement('div', attributes, content);
104
- }
105
- return super.renderNode(node, props);
106
- }
107
- createContainerAttributes() {
108
- if (this.model.canTabToWidget()) {
109
- return {
110
- ...super.createContainerAttributes(),
111
- tabIndex: 0
112
- };
113
- }
114
- return super.createContainerAttributes();
115
- }
116
- /**
117
- * The ARROW_LEFT key controls both the movement around the file tree and also
118
- * the movement through the change chunks within a file.
119
- *
120
- * If the selected tree node is a folder then the ARROW_LEFT key behaves exactly
121
- * as it does in explorer. It collapses the tree node if the folder is expanded and
122
- * it moves the selection up to the parent folder if the folder is collapsed (no-op if no parent folder, as
123
- * group headers are not selectable). This behavior is the default behavior implemented
124
- * in the TreeWidget super class.
125
- *
126
- * If the selected tree node is a file then the ARROW_LEFT key moves up through the
127
- * change chunks within each file. If the selected chunk is the first chunk in the file
128
- * then the file selection is moved to the previous file (no-op if no previous file).
129
- *
130
- * Note that when cursoring through change chunks, the ARROW_LEFT key cannot be used to
131
- * move up through the parent folders of the file tree. If users want to do this, using
132
- * keys only, then they must press ARROW_UP repeatedly until the selected node is the folder
133
- * node and then press ARROW_LEFT.
134
- */
135
- async handleLeft(event) {
136
- if (this.model.selectedNodes.length === 1) {
137
- const selectedNode = this.model.selectedNodes[0];
138
- if (scm_tree_model_1.ScmFileChangeNode.is(selectedNode)) {
139
- const selectedResource = this.model.getResourceFromNode(selectedNode);
140
- if (!selectedResource) {
141
- return super.handleLeft(event);
142
- }
143
- const widget = await this.openResource(selectedResource);
144
- if (widget) {
145
- const diffNavigator = this.diffNavigatorProvider(widget.editor);
146
- if (diffNavigator.hasPrevious()) {
147
- diffNavigator.previous();
148
- }
149
- else {
150
- const previousNode = this.moveToPreviousFileNode();
151
- if (previousNode) {
152
- const previousResource = this.model.getResourceFromNode(previousNode);
153
- if (previousResource) {
154
- this.openResource(previousResource);
155
- }
156
- }
157
- }
158
- return;
159
- }
160
- }
161
- }
162
- return super.handleLeft(event);
163
- }
164
- /**
165
- * The ARROW_RIGHT key controls both the movement around the file tree and also
166
- * the movement through the change chunks within a file.
167
- *
168
- * If the selected tree node is a folder then the ARROW_RIGHT key behaves exactly
169
- * as it does in explorer. It expands the tree node if the folder is collapsed and
170
- * it moves the selection to the first child node if the folder is expanded.
171
- * This behavior is the default behavior implemented
172
- * in the TreeWidget super class.
173
- *
174
- * If the selected tree node is a file then the ARROW_RIGHT key moves down through the
175
- * change chunks within each file. If the selected chunk is the last chunk in the file
176
- * then the file selection is moved to the next file (no-op if no next file).
177
- */
178
- async handleRight(event) {
179
- if (this.model.selectedNodes.length === 0) {
180
- const firstNode = this.getFirstSelectableNode();
181
- // Selects the first visible resource as none are selected.
182
- if (!firstNode) {
183
- return;
184
- }
185
- this.model.selectNode(firstNode);
186
- return;
187
- }
188
- if (this.model.selectedNodes.length === 1) {
189
- const selectedNode = this.model.selectedNodes[0];
190
- if (scm_tree_model_1.ScmFileChangeNode.is(selectedNode)) {
191
- const selectedResource = this.model.getResourceFromNode(selectedNode);
192
- if (!selectedResource) {
193
- return super.handleRight(event);
194
- }
195
- const widget = await this.openResource(selectedResource);
196
- if (widget) {
197
- const diffNavigator = this.diffNavigatorProvider(widget.editor);
198
- if (diffNavigator.hasNext()) {
199
- diffNavigator.next();
200
- }
201
- else {
202
- const nextNode = this.moveToNextFileNode();
203
- if (nextNode) {
204
- const nextResource = this.model.getResourceFromNode(nextNode);
205
- if (nextResource) {
206
- this.openResource(nextResource);
207
- }
208
- }
209
- }
210
- }
211
- return;
212
- }
213
- }
214
- return super.handleRight(event);
215
- }
216
- handleEnter(event) {
217
- if (this.model.selectedNodes.length === 1) {
218
- const selectedNode = this.model.selectedNodes[0];
219
- if (scm_tree_model_1.ScmFileChangeNode.is(selectedNode)) {
220
- const selectedResource = this.model.getResourceFromNode(selectedNode);
221
- if (selectedResource) {
222
- this.openResource(selectedResource);
223
- }
224
- return;
225
- }
226
- }
227
- super.handleEnter(event);
228
- }
229
- async goToPreviousChange() {
230
- if (this.model.selectedNodes.length === 1) {
231
- const selectedNode = this.model.selectedNodes[0];
232
- if (scm_tree_model_1.ScmFileChangeNode.is(selectedNode)) {
233
- if (scm_tree_model_1.ScmFileChangeNode.is(selectedNode)) {
234
- const selectedResource = this.model.getResourceFromNode(selectedNode);
235
- if (!selectedResource) {
236
- return;
237
- }
238
- const widget = await this.openResource(selectedResource);
239
- if (widget) {
240
- const diffNavigator = this.diffNavigatorProvider(widget.editor);
241
- if (diffNavigator.hasPrevious()) {
242
- diffNavigator.previous();
243
- }
244
- else {
245
- const previousNode = this.moveToPreviousFileNode();
246
- if (previousNode) {
247
- const previousResource = this.model.getResourceFromNode(previousNode);
248
- if (previousResource) {
249
- this.openResource(previousResource);
250
- }
251
- }
252
- }
253
- }
254
- }
255
- }
256
- }
257
- }
258
- async goToNextChange() {
259
- if (this.model.selectedNodes.length === 0) {
260
- const firstNode = this.getFirstSelectableNode();
261
- // Selects the first visible resource as none are selected.
262
- if (!firstNode) {
263
- return;
264
- }
265
- this.model.selectNode(firstNode);
266
- return;
267
- }
268
- if (this.model.selectedNodes.length === 1) {
269
- const selectedNode = this.model.selectedNodes[0];
270
- if (scm_tree_model_1.ScmFileChangeNode.is(selectedNode)) {
271
- const selectedResource = this.model.getResourceFromNode(selectedNode);
272
- if (!selectedResource) {
273
- return;
274
- }
275
- const widget = await this.openResource(selectedResource);
276
- if (widget) {
277
- const diffNavigator = this.diffNavigatorProvider(widget.editor);
278
- if (diffNavigator.hasNext()) {
279
- diffNavigator.next();
280
- }
281
- else {
282
- const nextNode = this.moveToNextFileNode();
283
- if (nextNode) {
284
- const nextResource = this.model.getResourceFromNode(nextNode);
285
- if (nextResource) {
286
- this.openResource(nextResource);
287
- }
288
- }
289
- }
290
- }
291
- }
292
- }
293
- }
294
- selectNodeByUri(uri) {
295
- for (const group of this.model.groups) {
296
- const sourceUri = new uri_1.default(uri.path.toString());
297
- const id = `${group.id}:${sourceUri.toString()}`;
298
- const node = this.model.getNode(id);
299
- if (tree_1.SelectableTreeNode.is(node)) {
300
- this.model.selectNode(node);
301
- return;
302
- }
303
- }
304
- }
305
- getFirstSelectableNode() {
306
- if (this.model.root) {
307
- const root = this.model.root;
308
- const groupNode = root.children[0];
309
- return groupNode.children[0];
310
- }
311
- }
312
- moveToPreviousFileNode() {
313
- let previousNode = this.model.getPrevSelectableNode();
314
- while (previousNode) {
315
- if (scm_tree_model_1.ScmFileChangeNode.is(previousNode)) {
316
- this.model.selectNode(previousNode);
317
- return previousNode;
318
- }
319
- previousNode = this.model.getPrevSelectableNode(previousNode);
320
- }
321
- ;
322
- }
323
- moveToNextFileNode() {
324
- let nextNode = this.model.getNextSelectableNode();
325
- while (nextNode) {
326
- if (scm_tree_model_1.ScmFileChangeNode.is(nextNode)) {
327
- this.model.selectNode(nextNode);
328
- return nextNode;
329
- }
330
- nextNode = this.model.getNextSelectableNode(nextNode);
331
- }
332
- ;
333
- }
334
- async openResource(resource) {
335
- try {
336
- await resource.open();
337
- }
338
- catch (e) {
339
- console.error('Failed to open a SCM resource', e);
340
- return undefined;
341
- }
342
- let standaloneEditor;
343
- const resourcePath = resource.sourceUri.path.toString();
344
- for (const widget of this.editorManager.all) {
345
- const resourceUri = widget.editor.document.uri;
346
- const editorResourcePath = new uri_1.default(resourceUri).path.toString();
347
- if (resourcePath === editorResourcePath) {
348
- if (widget.editor.uri.scheme === browser_1.DiffUris.DIFF_SCHEME) {
349
- // prefer diff editor
350
- return widget;
351
- }
352
- else {
353
- standaloneEditor = widget;
354
- }
355
- }
356
- if (widget.editor.uri.scheme === browser_1.DiffUris.DIFF_SCHEME
357
- && resourceUri === resource.sourceUri.toString()) {
358
- return widget;
359
- }
360
- }
361
- // fallback to standalone editor
362
- return standaloneEditor;
363
- }
364
- getPaddingLeft(node, props) {
365
- if (this.viewMode === 'list') {
366
- if (props.depth === 1) {
367
- return this.props.expansionTogglePadding;
368
- }
369
- }
370
- return super.getPaddingLeft(node, props);
371
- }
372
- getDepthPadding(depth) {
373
- return super.getDepthPadding(depth) + 5;
374
- }
375
- isCurrentThemeLight() {
376
- const type = this.themeService.getCurrentTheme().type;
377
- return type.toLocaleLowerCase().includes('light');
378
- }
379
- needsExpansionTogglePadding(node) {
380
- const theme = this.iconThemeService.getDefinition(this.iconThemeService.current);
381
- if (theme && (theme.hidesExplorerArrows || (theme.hasFileIcons && !theme.hasFolderIcons))) {
382
- return false;
383
- }
384
- return super.needsExpansionTogglePadding(node);
385
- }
386
- };
387
- ScmTreeWidget.ID = 'scm-resource-widget';
388
- ScmTreeWidget.RESOURCE_GROUP_CONTEXT_MENU = ['RESOURCE_GROUP_CONTEXT_MENU'];
389
- ScmTreeWidget.RESOURCE_GROUP_INLINE_MENU = ['RESOURCE_GROUP_CONTEXT_MENU', 'inline'];
390
- ScmTreeWidget.RESOURCE_FOLDER_CONTEXT_MENU = ['RESOURCE_FOLDER_CONTEXT_MENU'];
391
- ScmTreeWidget.RESOURCE_FOLDER_INLINE_MENU = ['RESOURCE_FOLDER_CONTEXT_MENU', 'inline'];
392
- ScmTreeWidget.RESOURCE_CONTEXT_MENU = ['RESOURCE_CONTEXT_MENU'];
393
- ScmTreeWidget.RESOURCE_INLINE_MENU = ['RESOURCE_CONTEXT_MENU', 'inline'];
394
- __decorate([
395
- (0, inversify_1.inject)(menu_1.MenuCommandExecutor),
396
- __metadata("design:type", Object)
397
- ], ScmTreeWidget.prototype, "menuCommandExecutor", void 0);
398
- __decorate([
399
- (0, inversify_1.inject)(menu_1.MenuModelRegistry),
400
- __metadata("design:type", menu_1.MenuModelRegistry)
401
- ], ScmTreeWidget.prototype, "menus", void 0);
402
- __decorate([
403
- (0, inversify_1.inject)(scm_context_key_service_1.ScmContextKeyService),
404
- __metadata("design:type", scm_context_key_service_1.ScmContextKeyService)
405
- ], ScmTreeWidget.prototype, "contextKeys", void 0);
406
- __decorate([
407
- (0, inversify_1.inject)(browser_2.EditorManager),
408
- __metadata("design:type", browser_2.EditorManager)
409
- ], ScmTreeWidget.prototype, "editorManager", void 0);
410
- __decorate([
411
- (0, inversify_1.inject)(browser_2.DiffNavigatorProvider),
412
- __metadata("design:type", Function)
413
- ], ScmTreeWidget.prototype, "diffNavigatorProvider", void 0);
414
- __decorate([
415
- (0, inversify_1.inject)(icon_theme_service_1.IconThemeService),
416
- __metadata("design:type", icon_theme_service_1.IconThemeService)
417
- ], ScmTreeWidget.prototype, "iconThemeService", void 0);
418
- __decorate([
419
- (0, inversify_1.inject)(decorations_service_1.DecorationsService),
420
- __metadata("design:type", Object)
421
- ], ScmTreeWidget.prototype, "decorationsService", void 0);
422
- __decorate([
423
- (0, inversify_1.inject)(color_registry_1.ColorRegistry),
424
- __metadata("design:type", color_registry_1.ColorRegistry)
425
- ], ScmTreeWidget.prototype, "colors", void 0);
426
- __decorate([
427
- (0, inversify_1.inject)(theming_1.ThemeService),
428
- __metadata("design:type", theming_1.ThemeService)
429
- ], ScmTreeWidget.prototype, "themeService", void 0);
430
- __decorate([
431
- (0, inversify_1.postConstruct)(),
432
- __metadata("design:type", Function),
433
- __metadata("design:paramtypes", []),
434
- __metadata("design:returntype", void 0)
435
- ], ScmTreeWidget.prototype, "init", null);
436
- ScmTreeWidget = ScmTreeWidget_1 = __decorate([
437
- (0, inversify_1.injectable)(),
438
- __param(0, (0, inversify_1.inject)(tree_1.TreeProps)),
439
- __param(1, (0, inversify_1.inject)(tree_1.TreeModel)),
440
- __param(2, (0, inversify_1.inject)(browser_1.ContextMenuRenderer)),
441
- __metadata("design:paramtypes", [Object, scm_tree_model_1.ScmTreeModel,
442
- browser_1.ContextMenuRenderer])
443
- ], ScmTreeWidget);
444
- exports.ScmTreeWidget = ScmTreeWidget;
445
- (function (ScmTreeWidget) {
446
- let Styles;
447
- (function (Styles) {
448
- Styles.NO_SELECT = 'no-select';
449
- })(Styles = ScmTreeWidget.Styles || (ScmTreeWidget.Styles = {}));
450
- })(ScmTreeWidget = exports.ScmTreeWidget || (exports.ScmTreeWidget = {}));
451
- exports.ScmTreeWidget = ScmTreeWidget;
452
- class ScmElement extends React.Component {
453
- constructor(props) {
454
- super(props);
455
- this.toDisposeOnUnmount = new disposable_1.DisposableCollection();
456
- this.detectHover = (element) => {
457
- if (element) {
458
- window.requestAnimationFrame(() => {
459
- const hover = element.matches(':hover');
460
- this.setState({ hover });
461
- });
462
- }
463
- };
464
- this.showHover = () => this.setState({ hover: true });
465
- this.hideHover = () => this.setState({ hover: false });
466
- this.renderContextMenu = (event) => {
467
- event.preventDefault();
468
- const { treeNode: node, contextMenuRenderer } = this.props;
469
- this.props.model.execInNodeContext(node, () => {
470
- contextMenuRenderer.render({
471
- menuPath: this.contextMenuPath,
472
- anchor: event.nativeEvent,
473
- args: this.contextMenuArgs
474
- });
475
- });
476
- };
477
- this.state = {
478
- hover: false
479
- };
480
- const setState = this.setState.bind(this);
481
- this.setState = newState => {
482
- if (!this.toDisposeOnUnmount.disposed) {
483
- setState(newState);
484
- }
485
- };
486
- }
487
- componentDidMount() {
488
- this.toDisposeOnUnmount.push(disposable_1.Disposable.create(() => { }));
489
- }
490
- componentWillUnmount() {
491
- this.toDisposeOnUnmount.dispose();
492
- }
493
- }
494
- exports.ScmElement = ScmElement;
495
- class ScmResourceComponent extends ScmElement {
496
- constructor() {
497
- super(...arguments);
498
- this.open = () => {
499
- const resource = this.props.model.getResourceFromNode(this.props.treeNode);
500
- if (resource) {
501
- resource.open();
502
- }
503
- };
504
- this.contextMenuPath = ScmTreeWidget.RESOURCE_CONTEXT_MENU;
505
- /**
506
- * Handle the single clicking of nodes present in the widget.
507
- */
508
- this.handleClick = (event) => {
509
- if (!this.hasCtrlCmdOrShiftMask(event)) {
510
- // Determine the behavior based on the preference value.
511
- const isSingle = this.props.corePreferences && this.props.corePreferences['workbench.list.openMode'] === 'singleClick';
512
- if (isSingle) {
513
- this.open();
514
- }
515
- }
516
- };
517
- /**
518
- * Handle the double clicking of nodes present in the widget.
519
- */
520
- this.handleDoubleClick = () => {
521
- // Determine the behavior based on the preference value.
522
- const isDouble = this.props.corePreferences && this.props.corePreferences['workbench.list.openMode'] === 'doubleClick';
523
- // Nodes should only be opened through double clicking if the correct preference is set.
524
- if (isDouble) {
525
- this.open();
526
- }
527
- };
528
- }
529
- render() {
530
- var _a;
531
- const { hover } = this.state;
532
- const { model, treeNode, colors, parentPath, sourceUri, decoration, labelProvider, commandExecutor, menus, contextKeys, caption, isLightTheme } = this.props;
533
- const resourceUri = new uri_1.default(sourceUri);
534
- const decorationIcon = treeNode.decorations;
535
- const themedIcon = isLightTheme ? decorationIcon === null || decorationIcon === void 0 ? void 0 : decorationIcon.icon : decorationIcon === null || decorationIcon === void 0 ? void 0 : decorationIcon.iconDark;
536
- const classNames = themedIcon ? ['decoration-icon', themedIcon] : ['decoration-icon', 'status'];
537
- const icon = labelProvider.getIcon(resourceUri);
538
- const color = decoration && decoration.colorId && !themedIcon ? `var(${colors.toCssVariableName(decoration.colorId)})` : '';
539
- const letter = decoration && decoration.letter && !themedIcon ? decoration.letter : '';
540
- const tooltip = decoration && decoration.tooltip || '';
541
- const textDecoration = ((_a = treeNode.decorations) === null || _a === void 0 ? void 0 : _a.strikeThrough) === true ? 'line-through' : 'normal';
542
- const relativePath = parentPath.relative(resourceUri.parent);
543
- const path = relativePath ? relativePath.fsPath() : labelProvider.getLongName(resourceUri.parent);
544
- const title = tooltip.length !== 0
545
- ? `${resourceUri.path.fsPath()} • ${tooltip}`
546
- : resourceUri.path.fsPath();
547
- return React.createElement("div", { key: sourceUri, className: `scmItem ${tree_1.TREE_NODE_SEGMENT_CLASS} ${tree_1.TREE_NODE_SEGMENT_GROW_CLASS}`, onContextMenu: this.renderContextMenu, onMouseEnter: this.showHover, onMouseLeave: this.hideHover, ref: this.detectHover, title: title, onClick: this.handleClick, onDoubleClick: this.handleDoubleClick },
548
- React.createElement("span", { className: icon + ' file-icon' }),
549
- this.props.renderExpansionToggle(),
550
- React.createElement("div", { className: `noWrapInfo ${tree_1.TREE_NODE_SEGMENT_GROW_CLASS}` },
551
- React.createElement("span", { className: 'name', style: { textDecoration } }, caption),
552
- React.createElement("span", { className: 'path', style: { textDecoration } }, path)),
553
- React.createElement(ScmInlineActions, { ...{
554
- hover,
555
- menu: menus.getMenu(ScmTreeWidget.RESOURCE_INLINE_MENU),
556
- menuPath: ScmTreeWidget.RESOURCE_INLINE_MENU,
557
- commandExecutor,
558
- args: this.contextMenuArgs,
559
- contextKeys,
560
- model,
561
- treeNode
562
- } },
563
- React.createElement("div", { title: tooltip, className: classNames.join(' '), style: { color } }, letter)));
564
- }
565
- get contextMenuArgs() {
566
- if (!this.props.model.selectedNodes.some(node => scm_tree_model_1.ScmFileChangeNode.is(node) && node.sourceUri === this.props.sourceUri)) {
567
- // Clicked node is not in selection, so ignore selection and action on just clicked node
568
- return this.singleNodeArgs;
569
- }
570
- else {
571
- return this.props.model.getSelectionArgs(this.props.model.selectedNodes);
572
- }
573
- }
574
- get singleNodeArgs() {
575
- const selectedResource = this.props.model.getResourceFromNode(this.props.treeNode);
576
- if (selectedResource) {
577
- return [selectedResource];
578
- }
579
- else {
580
- // Repository status not yet available. Empty args disables the action.
581
- return [];
582
- }
583
- }
584
- hasCtrlCmdOrShiftMask(event) {
585
- const { metaKey, ctrlKey, shiftKey } = event;
586
- return (os_1.isOSX && metaKey) || ctrlKey || shiftKey;
587
- }
588
- }
589
- exports.ScmResourceComponent = ScmResourceComponent;
590
- class ScmResourceGroupElement extends ScmElement {
591
- constructor() {
592
- super(...arguments);
593
- this.contextMenuPath = ScmTreeWidget.RESOURCE_GROUP_CONTEXT_MENU;
594
- }
595
- render() {
596
- const { hover } = this.state;
597
- const { model, treeNode, menus, commandExecutor, contextKeys, caption } = this.props;
598
- return React.createElement("div", { className: `theia-header scm-theia-header ${tree_1.TREE_NODE_SEGMENT_GROW_CLASS}`, onContextMenu: this.renderContextMenu, onMouseEnter: this.showHover, onMouseLeave: this.hideHover, ref: this.detectHover },
599
- this.props.renderExpansionToggle(),
600
- React.createElement("div", { className: `noWrapInfo ${tree_1.TREE_NODE_SEGMENT_GROW_CLASS}` }, caption),
601
- React.createElement(ScmInlineActions, { ...{
602
- hover,
603
- args: this.contextMenuArgs,
604
- menu: menus.getMenu(ScmTreeWidget.RESOURCE_GROUP_INLINE_MENU),
605
- menuPath: ScmTreeWidget.RESOURCE_GROUP_INLINE_MENU,
606
- commandExecutor,
607
- contextKeys,
608
- model,
609
- treeNode
610
- } }, this.renderChangeCount()));
611
- }
612
- renderChangeCount() {
613
- const group = this.props.model.getResourceGroupFromNode(this.props.treeNode);
614
- return React.createElement("div", { className: 'notification-count-container scm-change-count' },
615
- React.createElement("span", { className: 'notification-count' }, group ? group.resources.length : 0));
616
- }
617
- get contextMenuArgs() {
618
- const group = this.props.model.getResourceGroupFromNode(this.props.treeNode);
619
- if (group) {
620
- return [group];
621
- }
622
- else {
623
- // Repository status not yet available. Empty args disables the action.
624
- return [];
625
- }
626
- }
627
- }
628
- exports.ScmResourceGroupElement = ScmResourceGroupElement;
629
- class ScmResourceFolderElement extends ScmElement {
630
- constructor() {
631
- super(...arguments);
632
- this.contextMenuPath = ScmTreeWidget.RESOURCE_FOLDER_CONTEXT_MENU;
633
- }
634
- render() {
635
- const { hover } = this.state;
636
- const { model, treeNode, sourceUri, labelProvider, commandExecutor, menus, contextKeys, caption } = this.props;
637
- const sourceFileStat = files_1.FileStat.dir(sourceUri);
638
- const icon = labelProvider.getIcon(sourceFileStat);
639
- const title = new uri_1.default(sourceUri).path.fsPath();
640
- return React.createElement("div", { key: sourceUri, className: `scmItem ${tree_1.TREE_NODE_SEGMENT_CLASS} ${tree_1.TREE_NODE_SEGMENT_GROW_CLASS} ${ScmTreeWidget.Styles.NO_SELECT}`, title: title, onContextMenu: this.renderContextMenu, onMouseEnter: this.showHover, onMouseLeave: this.hideHover, ref: this.detectHover },
641
- this.props.renderExpansionToggle(),
642
- React.createElement("span", { className: icon + ' file-icon' }),
643
- React.createElement("div", { className: `noWrapInfo ${tree_1.TREE_NODE_SEGMENT_GROW_CLASS}` },
644
- React.createElement("span", { className: 'name' }, caption)),
645
- React.createElement(ScmInlineActions, { ...{
646
- hover,
647
- menu: menus.getMenu(ScmTreeWidget.RESOURCE_FOLDER_INLINE_MENU),
648
- menuPath: ScmTreeWidget.RESOURCE_FOLDER_INLINE_MENU,
649
- commandExecutor,
650
- args: this.contextMenuArgs,
651
- contextKeys,
652
- model,
653
- treeNode
654
- } }));
655
- }
656
- get contextMenuArgs() {
657
- if (!this.props.model.selectedNodes.some(node => scm_tree_model_1.ScmFileChangeFolderNode.is(node) && node.sourceUri === this.props.sourceUri)) {
658
- // Clicked node is not in selection, so ignore selection and action on just clicked node
659
- return this.singleNodeArgs;
660
- }
661
- else {
662
- return this.props.model.getSelectionArgs(this.props.model.selectedNodes);
663
- }
664
- }
665
- get singleNodeArgs() {
666
- return this.props.model.getResourcesFromFolderNode(this.props.treeNode);
667
- }
668
- }
669
- exports.ScmResourceFolderElement = ScmResourceFolderElement;
670
- class ScmInlineActions extends React.Component {
671
- render() {
672
- const { hover, menu, menuPath, args, commandExecutor, model, treeNode, contextKeys, children } = this.props;
673
- return React.createElement("div", { className: 'theia-scm-inline-actions-container' },
674
- React.createElement("div", { className: 'theia-scm-inline-actions' }, hover && menu.children
675
- .map((node, index) => node instanceof menu_1.ActionMenuNode &&
676
- React.createElement(ScmInlineAction, { key: index, ...{ node, menuPath, args, commandExecutor, model, treeNode, contextKeys } }))),
677
- children);
678
- }
679
- }
680
- exports.ScmInlineActions = ScmInlineActions;
681
- class ScmInlineAction extends React.Component {
682
- constructor() {
683
- super(...arguments);
684
- this.execute = (event) => {
685
- event.stopPropagation();
686
- const { commandExecutor, menuPath, node, args } = this.props;
687
- commandExecutor.executeCommand([menuPath[0]], node.command, ...args);
688
- };
689
- }
690
- render() {
691
- const { node, model, treeNode, args, commandExecutor, menuPath, contextKeys } = this.props;
692
- let isActive = false;
693
- model.execInNodeContext(treeNode, () => {
694
- isActive = contextKeys.match(node.when);
695
- });
696
- if (!commandExecutor.isVisible(menuPath, node.command, ...args) || !isActive) {
697
- return false;
698
- }
699
- return React.createElement("div", { className: 'theia-scm-inline-action' },
700
- React.createElement("a", { className: `${node.icon} ${browser_1.ACTION_ITEM}`, title: node.label, onClick: this.execute }));
701
- }
702
- }
703
- exports.ScmInlineAction = ScmInlineAction;
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2020 Arm and others.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
18
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
19
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
20
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
21
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
22
+ };
23
+ var __metadata = (this && this.__metadata) || function (k, v) {
24
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25
+ };
26
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
27
+ return function (target, key) { decorator(target, key, paramIndex); }
28
+ };
29
+ var ScmTreeWidget_1;
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.ScmInlineAction = exports.ScmInlineActions = exports.ScmResourceFolderElement = exports.ScmResourceGroupElement = exports.ScmResourceComponent = exports.ScmElement = exports.ScmTreeWidget = void 0;
32
+ /* eslint-disable no-null/no-null, @typescript-eslint/no-explicit-any */
33
+ const React = require("@theia/core/shared/react");
34
+ const inversify_1 = require("@theia/core/shared/inversify");
35
+ const uri_1 = require("@theia/core/lib/common/uri");
36
+ const os_1 = require("@theia/core/lib/common/os");
37
+ const disposable_1 = require("@theia/core/lib/common/disposable");
38
+ const tree_1 = require("@theia/core/lib/browser/tree");
39
+ const scm_tree_model_1 = require("./scm-tree-model");
40
+ const menu_1 = require("@theia/core/lib/common/menu");
41
+ const browser_1 = require("@theia/core/lib/browser");
42
+ const scm_context_key_service_1 = require("./scm-context-key-service");
43
+ const browser_2 = require("@theia/editor/lib/browser");
44
+ const icon_theme_service_1 = require("@theia/core/lib/browser/icon-theme-service");
45
+ const color_registry_1 = require("@theia/core/lib/browser/color-registry");
46
+ const decorations_service_1 = require("@theia/core/lib/browser/decorations-service");
47
+ const files_1 = require("@theia/filesystem/lib/common/files");
48
+ const theming_1 = require("@theia/core/lib/browser/theming");
49
+ let ScmTreeWidget = ScmTreeWidget_1 = class ScmTreeWidget extends tree_1.TreeWidget {
50
+ constructor(props, treeModel, contextMenuRenderer) {
51
+ super(props, treeModel, contextMenuRenderer);
52
+ this.id = ScmTreeWidget_1.ID;
53
+ this.addClass('groups-outer-container');
54
+ }
55
+ init() {
56
+ super.init();
57
+ this.toDispose.push(this.themeService.onDidColorThemeChange(() => this.update()));
58
+ }
59
+ set viewMode(id) {
60
+ // Close the search box because the structure of the tree will change dramatically
61
+ // and the search results will be out of date.
62
+ this.searchBox.hide();
63
+ this.model.viewMode = id;
64
+ }
65
+ get viewMode() {
66
+ return this.model.viewMode;
67
+ }
68
+ /**
69
+ * Render the node given the tree node and node properties.
70
+ * @param node the tree node.
71
+ * @param props the node properties.
72
+ */
73
+ renderNode(node, props) {
74
+ var _a;
75
+ if (!tree_1.TreeNode.isVisible(node)) {
76
+ return undefined;
77
+ }
78
+ const attributes = this.createNodeAttributes(node, props);
79
+ const label = this.labelProvider.getName(node);
80
+ const searchHighlights = (_a = this.searchHighlights) === null || _a === void 0 ? void 0 : _a.get(node.id);
81
+ // The group nodes should not be subject to highlighting.
82
+ const caption = (searchHighlights && !scm_tree_model_1.ScmFileChangeGroupNode.is(node)) ? this.toReactNode(label, searchHighlights) : label;
83
+ if (scm_tree_model_1.ScmFileChangeGroupNode.is(node)) {
84
+ const content = React.createElement(ScmResourceGroupElement, { key: `${node.groupId}`, model: this.model, treeNode: node, renderExpansionToggle: () => this.renderExpansionToggle(node, props), commandExecutor: this.menuCommandExecutor, contextMenuRenderer: this.contextMenuRenderer, menus: this.menus, contextKeys: this.contextKeys, labelProvider: this.labelProvider, corePreferences: this.corePreferences, caption: caption });
85
+ return React.createElement('div', attributes, content);
86
+ }
87
+ if (scm_tree_model_1.ScmFileChangeFolderNode.is(node)) {
88
+ const content = React.createElement(ScmResourceFolderElement, { key: String(node.sourceUri), model: this.model, treeNode: node, sourceUri: node.sourceUri, renderExpansionToggle: () => this.renderExpansionToggle(node, props), commandExecutor: this.menuCommandExecutor, contextMenuRenderer: this.contextMenuRenderer, menus: this.menus, contextKeys: this.contextKeys, labelProvider: this.labelProvider, corePreferences: this.corePreferences, caption: caption });
89
+ return React.createElement('div', attributes, content);
90
+ }
91
+ if (scm_tree_model_1.ScmFileChangeNode.is(node)) {
92
+ const parentPath = (node.parent && scm_tree_model_1.ScmFileChangeFolderNode.is(node.parent))
93
+ ? new uri_1.default(node.parent.sourceUri) : new uri_1.default(this.model.rootUri);
94
+ const content = React.createElement(ScmResourceComponent, { key: node.sourceUri, model: this.model, treeNode: node, contextMenuRenderer: this.contextMenuRenderer, commandExecutor: this.menuCommandExecutor, menus: this.menus, contextKeys: this.contextKeys, labelProvider: this.labelProvider, corePreferences: this.corePreferences, caption: caption, ...{
95
+ ...this.props,
96
+ parentPath,
97
+ sourceUri: node.sourceUri,
98
+ decoration: this.decorationsService.getDecoration(new uri_1.default(node.sourceUri), true)[0],
99
+ colors: this.colors,
100
+ isLightTheme: this.isCurrentThemeLight(),
101
+ renderExpansionToggle: () => this.renderExpansionToggle(node, props),
102
+ } });
103
+ return React.createElement('div', attributes, content);
104
+ }
105
+ return super.renderNode(node, props);
106
+ }
107
+ createContainerAttributes() {
108
+ if (this.model.canTabToWidget()) {
109
+ return {
110
+ ...super.createContainerAttributes(),
111
+ tabIndex: 0
112
+ };
113
+ }
114
+ return super.createContainerAttributes();
115
+ }
116
+ /**
117
+ * The ARROW_LEFT key controls both the movement around the file tree and also
118
+ * the movement through the change chunks within a file.
119
+ *
120
+ * If the selected tree node is a folder then the ARROW_LEFT key behaves exactly
121
+ * as it does in explorer. It collapses the tree node if the folder is expanded and
122
+ * it moves the selection up to the parent folder if the folder is collapsed (no-op if no parent folder, as
123
+ * group headers are not selectable). This behavior is the default behavior implemented
124
+ * in the TreeWidget super class.
125
+ *
126
+ * If the selected tree node is a file then the ARROW_LEFT key moves up through the
127
+ * change chunks within each file. If the selected chunk is the first chunk in the file
128
+ * then the file selection is moved to the previous file (no-op if no previous file).
129
+ *
130
+ * Note that when cursoring through change chunks, the ARROW_LEFT key cannot be used to
131
+ * move up through the parent folders of the file tree. If users want to do this, using
132
+ * keys only, then they must press ARROW_UP repeatedly until the selected node is the folder
133
+ * node and then press ARROW_LEFT.
134
+ */
135
+ async handleLeft(event) {
136
+ if (this.model.selectedNodes.length === 1) {
137
+ const selectedNode = this.model.selectedNodes[0];
138
+ if (scm_tree_model_1.ScmFileChangeNode.is(selectedNode)) {
139
+ const selectedResource = this.model.getResourceFromNode(selectedNode);
140
+ if (!selectedResource) {
141
+ return super.handleLeft(event);
142
+ }
143
+ const widget = await this.openResource(selectedResource);
144
+ if (widget) {
145
+ const diffNavigator = this.diffNavigatorProvider(widget.editor);
146
+ if (diffNavigator.hasPrevious()) {
147
+ diffNavigator.previous();
148
+ }
149
+ else {
150
+ const previousNode = this.moveToPreviousFileNode();
151
+ if (previousNode) {
152
+ const previousResource = this.model.getResourceFromNode(previousNode);
153
+ if (previousResource) {
154
+ this.openResource(previousResource);
155
+ }
156
+ }
157
+ }
158
+ return;
159
+ }
160
+ }
161
+ }
162
+ return super.handleLeft(event);
163
+ }
164
+ /**
165
+ * The ARROW_RIGHT key controls both the movement around the file tree and also
166
+ * the movement through the change chunks within a file.
167
+ *
168
+ * If the selected tree node is a folder then the ARROW_RIGHT key behaves exactly
169
+ * as it does in explorer. It expands the tree node if the folder is collapsed and
170
+ * it moves the selection to the first child node if the folder is expanded.
171
+ * This behavior is the default behavior implemented
172
+ * in the TreeWidget super class.
173
+ *
174
+ * If the selected tree node is a file then the ARROW_RIGHT key moves down through the
175
+ * change chunks within each file. If the selected chunk is the last chunk in the file
176
+ * then the file selection is moved to the next file (no-op if no next file).
177
+ */
178
+ async handleRight(event) {
179
+ if (this.model.selectedNodes.length === 0) {
180
+ const firstNode = this.getFirstSelectableNode();
181
+ // Selects the first visible resource as none are selected.
182
+ if (!firstNode) {
183
+ return;
184
+ }
185
+ this.model.selectNode(firstNode);
186
+ return;
187
+ }
188
+ if (this.model.selectedNodes.length === 1) {
189
+ const selectedNode = this.model.selectedNodes[0];
190
+ if (scm_tree_model_1.ScmFileChangeNode.is(selectedNode)) {
191
+ const selectedResource = this.model.getResourceFromNode(selectedNode);
192
+ if (!selectedResource) {
193
+ return super.handleRight(event);
194
+ }
195
+ const widget = await this.openResource(selectedResource);
196
+ if (widget) {
197
+ const diffNavigator = this.diffNavigatorProvider(widget.editor);
198
+ if (diffNavigator.hasNext()) {
199
+ diffNavigator.next();
200
+ }
201
+ else {
202
+ const nextNode = this.moveToNextFileNode();
203
+ if (nextNode) {
204
+ const nextResource = this.model.getResourceFromNode(nextNode);
205
+ if (nextResource) {
206
+ this.openResource(nextResource);
207
+ }
208
+ }
209
+ }
210
+ }
211
+ return;
212
+ }
213
+ }
214
+ return super.handleRight(event);
215
+ }
216
+ handleEnter(event) {
217
+ if (this.model.selectedNodes.length === 1) {
218
+ const selectedNode = this.model.selectedNodes[0];
219
+ if (scm_tree_model_1.ScmFileChangeNode.is(selectedNode)) {
220
+ const selectedResource = this.model.getResourceFromNode(selectedNode);
221
+ if (selectedResource) {
222
+ this.openResource(selectedResource);
223
+ }
224
+ return;
225
+ }
226
+ }
227
+ super.handleEnter(event);
228
+ }
229
+ async goToPreviousChange() {
230
+ if (this.model.selectedNodes.length === 1) {
231
+ const selectedNode = this.model.selectedNodes[0];
232
+ if (scm_tree_model_1.ScmFileChangeNode.is(selectedNode)) {
233
+ if (scm_tree_model_1.ScmFileChangeNode.is(selectedNode)) {
234
+ const selectedResource = this.model.getResourceFromNode(selectedNode);
235
+ if (!selectedResource) {
236
+ return;
237
+ }
238
+ const widget = await this.openResource(selectedResource);
239
+ if (widget) {
240
+ const diffNavigator = this.diffNavigatorProvider(widget.editor);
241
+ if (diffNavigator.hasPrevious()) {
242
+ diffNavigator.previous();
243
+ }
244
+ else {
245
+ const previousNode = this.moveToPreviousFileNode();
246
+ if (previousNode) {
247
+ const previousResource = this.model.getResourceFromNode(previousNode);
248
+ if (previousResource) {
249
+ this.openResource(previousResource);
250
+ }
251
+ }
252
+ }
253
+ }
254
+ }
255
+ }
256
+ }
257
+ }
258
+ async goToNextChange() {
259
+ if (this.model.selectedNodes.length === 0) {
260
+ const firstNode = this.getFirstSelectableNode();
261
+ // Selects the first visible resource as none are selected.
262
+ if (!firstNode) {
263
+ return;
264
+ }
265
+ this.model.selectNode(firstNode);
266
+ return;
267
+ }
268
+ if (this.model.selectedNodes.length === 1) {
269
+ const selectedNode = this.model.selectedNodes[0];
270
+ if (scm_tree_model_1.ScmFileChangeNode.is(selectedNode)) {
271
+ const selectedResource = this.model.getResourceFromNode(selectedNode);
272
+ if (!selectedResource) {
273
+ return;
274
+ }
275
+ const widget = await this.openResource(selectedResource);
276
+ if (widget) {
277
+ const diffNavigator = this.diffNavigatorProvider(widget.editor);
278
+ if (diffNavigator.hasNext()) {
279
+ diffNavigator.next();
280
+ }
281
+ else {
282
+ const nextNode = this.moveToNextFileNode();
283
+ if (nextNode) {
284
+ const nextResource = this.model.getResourceFromNode(nextNode);
285
+ if (nextResource) {
286
+ this.openResource(nextResource);
287
+ }
288
+ }
289
+ }
290
+ }
291
+ }
292
+ }
293
+ }
294
+ selectNodeByUri(uri) {
295
+ for (const group of this.model.groups) {
296
+ const sourceUri = new uri_1.default(uri.path.toString());
297
+ const id = `${group.id}:${sourceUri.toString()}`;
298
+ const node = this.model.getNode(id);
299
+ if (tree_1.SelectableTreeNode.is(node)) {
300
+ this.model.selectNode(node);
301
+ return;
302
+ }
303
+ }
304
+ }
305
+ getFirstSelectableNode() {
306
+ if (this.model.root) {
307
+ const root = this.model.root;
308
+ const groupNode = root.children[0];
309
+ return groupNode.children[0];
310
+ }
311
+ }
312
+ moveToPreviousFileNode() {
313
+ let previousNode = this.model.getPrevSelectableNode();
314
+ while (previousNode) {
315
+ if (scm_tree_model_1.ScmFileChangeNode.is(previousNode)) {
316
+ this.model.selectNode(previousNode);
317
+ return previousNode;
318
+ }
319
+ previousNode = this.model.getPrevSelectableNode(previousNode);
320
+ }
321
+ ;
322
+ }
323
+ moveToNextFileNode() {
324
+ let nextNode = this.model.getNextSelectableNode();
325
+ while (nextNode) {
326
+ if (scm_tree_model_1.ScmFileChangeNode.is(nextNode)) {
327
+ this.model.selectNode(nextNode);
328
+ return nextNode;
329
+ }
330
+ nextNode = this.model.getNextSelectableNode(nextNode);
331
+ }
332
+ ;
333
+ }
334
+ async openResource(resource) {
335
+ try {
336
+ await resource.open();
337
+ }
338
+ catch (e) {
339
+ console.error('Failed to open a SCM resource', e);
340
+ return undefined;
341
+ }
342
+ let standaloneEditor;
343
+ const resourcePath = resource.sourceUri.path.toString();
344
+ for (const widget of this.editorManager.all) {
345
+ const resourceUri = widget.editor.document.uri;
346
+ const editorResourcePath = new uri_1.default(resourceUri).path.toString();
347
+ if (resourcePath === editorResourcePath) {
348
+ if (widget.editor.uri.scheme === browser_1.DiffUris.DIFF_SCHEME) {
349
+ // prefer diff editor
350
+ return widget;
351
+ }
352
+ else {
353
+ standaloneEditor = widget;
354
+ }
355
+ }
356
+ if (widget.editor.uri.scheme === browser_1.DiffUris.DIFF_SCHEME
357
+ && resourceUri === resource.sourceUri.toString()) {
358
+ return widget;
359
+ }
360
+ }
361
+ // fallback to standalone editor
362
+ return standaloneEditor;
363
+ }
364
+ getPaddingLeft(node, props) {
365
+ if (this.viewMode === 'list') {
366
+ if (props.depth === 1) {
367
+ return this.props.expansionTogglePadding;
368
+ }
369
+ }
370
+ return super.getPaddingLeft(node, props);
371
+ }
372
+ getDepthPadding(depth) {
373
+ return super.getDepthPadding(depth) + 5;
374
+ }
375
+ isCurrentThemeLight() {
376
+ const type = this.themeService.getCurrentTheme().type;
377
+ return type.toLocaleLowerCase().includes('light');
378
+ }
379
+ needsExpansionTogglePadding(node) {
380
+ const theme = this.iconThemeService.getDefinition(this.iconThemeService.current);
381
+ if (theme && (theme.hidesExplorerArrows || (theme.hasFileIcons && !theme.hasFolderIcons))) {
382
+ return false;
383
+ }
384
+ return super.needsExpansionTogglePadding(node);
385
+ }
386
+ };
387
+ ScmTreeWidget.ID = 'scm-resource-widget';
388
+ ScmTreeWidget.RESOURCE_GROUP_CONTEXT_MENU = ['RESOURCE_GROUP_CONTEXT_MENU'];
389
+ ScmTreeWidget.RESOURCE_GROUP_INLINE_MENU = ['RESOURCE_GROUP_CONTEXT_MENU', 'inline'];
390
+ ScmTreeWidget.RESOURCE_FOLDER_CONTEXT_MENU = ['RESOURCE_FOLDER_CONTEXT_MENU'];
391
+ ScmTreeWidget.RESOURCE_FOLDER_INLINE_MENU = ['RESOURCE_FOLDER_CONTEXT_MENU', 'inline'];
392
+ ScmTreeWidget.RESOURCE_CONTEXT_MENU = ['RESOURCE_CONTEXT_MENU'];
393
+ ScmTreeWidget.RESOURCE_INLINE_MENU = ['RESOURCE_CONTEXT_MENU', 'inline'];
394
+ __decorate([
395
+ (0, inversify_1.inject)(menu_1.MenuCommandExecutor),
396
+ __metadata("design:type", Object)
397
+ ], ScmTreeWidget.prototype, "menuCommandExecutor", void 0);
398
+ __decorate([
399
+ (0, inversify_1.inject)(menu_1.MenuModelRegistry),
400
+ __metadata("design:type", menu_1.MenuModelRegistry)
401
+ ], ScmTreeWidget.prototype, "menus", void 0);
402
+ __decorate([
403
+ (0, inversify_1.inject)(scm_context_key_service_1.ScmContextKeyService),
404
+ __metadata("design:type", scm_context_key_service_1.ScmContextKeyService)
405
+ ], ScmTreeWidget.prototype, "contextKeys", void 0);
406
+ __decorate([
407
+ (0, inversify_1.inject)(browser_2.EditorManager),
408
+ __metadata("design:type", browser_2.EditorManager)
409
+ ], ScmTreeWidget.prototype, "editorManager", void 0);
410
+ __decorate([
411
+ (0, inversify_1.inject)(browser_2.DiffNavigatorProvider),
412
+ __metadata("design:type", Function)
413
+ ], ScmTreeWidget.prototype, "diffNavigatorProvider", void 0);
414
+ __decorate([
415
+ (0, inversify_1.inject)(icon_theme_service_1.IconThemeService),
416
+ __metadata("design:type", icon_theme_service_1.IconThemeService)
417
+ ], ScmTreeWidget.prototype, "iconThemeService", void 0);
418
+ __decorate([
419
+ (0, inversify_1.inject)(decorations_service_1.DecorationsService),
420
+ __metadata("design:type", Object)
421
+ ], ScmTreeWidget.prototype, "decorationsService", void 0);
422
+ __decorate([
423
+ (0, inversify_1.inject)(color_registry_1.ColorRegistry),
424
+ __metadata("design:type", color_registry_1.ColorRegistry)
425
+ ], ScmTreeWidget.prototype, "colors", void 0);
426
+ __decorate([
427
+ (0, inversify_1.inject)(theming_1.ThemeService),
428
+ __metadata("design:type", theming_1.ThemeService)
429
+ ], ScmTreeWidget.prototype, "themeService", void 0);
430
+ __decorate([
431
+ (0, inversify_1.postConstruct)(),
432
+ __metadata("design:type", Function),
433
+ __metadata("design:paramtypes", []),
434
+ __metadata("design:returntype", void 0)
435
+ ], ScmTreeWidget.prototype, "init", null);
436
+ ScmTreeWidget = ScmTreeWidget_1 = __decorate([
437
+ (0, inversify_1.injectable)(),
438
+ __param(0, (0, inversify_1.inject)(tree_1.TreeProps)),
439
+ __param(1, (0, inversify_1.inject)(tree_1.TreeModel)),
440
+ __param(2, (0, inversify_1.inject)(browser_1.ContextMenuRenderer)),
441
+ __metadata("design:paramtypes", [Object, scm_tree_model_1.ScmTreeModel,
442
+ browser_1.ContextMenuRenderer])
443
+ ], ScmTreeWidget);
444
+ exports.ScmTreeWidget = ScmTreeWidget;
445
+ (function (ScmTreeWidget) {
446
+ let Styles;
447
+ (function (Styles) {
448
+ Styles.NO_SELECT = 'no-select';
449
+ })(Styles = ScmTreeWidget.Styles || (ScmTreeWidget.Styles = {}));
450
+ })(ScmTreeWidget = exports.ScmTreeWidget || (exports.ScmTreeWidget = {}));
451
+ exports.ScmTreeWidget = ScmTreeWidget;
452
+ class ScmElement extends React.Component {
453
+ constructor(props) {
454
+ super(props);
455
+ this.toDisposeOnUnmount = new disposable_1.DisposableCollection();
456
+ this.detectHover = (element) => {
457
+ if (element) {
458
+ window.requestAnimationFrame(() => {
459
+ const hover = element.matches(':hover');
460
+ this.setState({ hover });
461
+ });
462
+ }
463
+ };
464
+ this.showHover = () => this.setState({ hover: true });
465
+ this.hideHover = () => this.setState({ hover: false });
466
+ this.renderContextMenu = (event) => {
467
+ event.preventDefault();
468
+ const { treeNode: node, contextMenuRenderer } = this.props;
469
+ this.props.model.execInNodeContext(node, () => {
470
+ contextMenuRenderer.render({
471
+ menuPath: this.contextMenuPath,
472
+ anchor: event.nativeEvent,
473
+ args: this.contextMenuArgs
474
+ });
475
+ });
476
+ };
477
+ this.state = {
478
+ hover: false
479
+ };
480
+ const setState = this.setState.bind(this);
481
+ this.setState = newState => {
482
+ if (!this.toDisposeOnUnmount.disposed) {
483
+ setState(newState);
484
+ }
485
+ };
486
+ }
487
+ componentDidMount() {
488
+ this.toDisposeOnUnmount.push(disposable_1.Disposable.create(() => { }));
489
+ }
490
+ componentWillUnmount() {
491
+ this.toDisposeOnUnmount.dispose();
492
+ }
493
+ }
494
+ exports.ScmElement = ScmElement;
495
+ class ScmResourceComponent extends ScmElement {
496
+ constructor() {
497
+ super(...arguments);
498
+ this.open = () => {
499
+ const resource = this.props.model.getResourceFromNode(this.props.treeNode);
500
+ if (resource) {
501
+ resource.open();
502
+ }
503
+ };
504
+ this.contextMenuPath = ScmTreeWidget.RESOURCE_CONTEXT_MENU;
505
+ /**
506
+ * Handle the single clicking of nodes present in the widget.
507
+ */
508
+ this.handleClick = (event) => {
509
+ if (!this.hasCtrlCmdOrShiftMask(event)) {
510
+ // Determine the behavior based on the preference value.
511
+ const isSingle = this.props.corePreferences && this.props.corePreferences['workbench.list.openMode'] === 'singleClick';
512
+ if (isSingle) {
513
+ this.open();
514
+ }
515
+ }
516
+ };
517
+ /**
518
+ * Handle the double clicking of nodes present in the widget.
519
+ */
520
+ this.handleDoubleClick = () => {
521
+ // Determine the behavior based on the preference value.
522
+ const isDouble = this.props.corePreferences && this.props.corePreferences['workbench.list.openMode'] === 'doubleClick';
523
+ // Nodes should only be opened through double clicking if the correct preference is set.
524
+ if (isDouble) {
525
+ this.open();
526
+ }
527
+ };
528
+ }
529
+ render() {
530
+ var _a;
531
+ const { hover } = this.state;
532
+ const { model, treeNode, colors, parentPath, sourceUri, decoration, labelProvider, commandExecutor, menus, contextKeys, caption, isLightTheme } = this.props;
533
+ const resourceUri = new uri_1.default(sourceUri);
534
+ const decorationIcon = treeNode.decorations;
535
+ const themedIcon = isLightTheme ? decorationIcon === null || decorationIcon === void 0 ? void 0 : decorationIcon.icon : decorationIcon === null || decorationIcon === void 0 ? void 0 : decorationIcon.iconDark;
536
+ const classNames = themedIcon ? ['decoration-icon', themedIcon] : ['decoration-icon', 'status'];
537
+ const icon = labelProvider.getIcon(resourceUri);
538
+ const color = decoration && decoration.colorId && !themedIcon ? `var(${colors.toCssVariableName(decoration.colorId)})` : '';
539
+ const letter = decoration && decoration.letter && !themedIcon ? decoration.letter : '';
540
+ const tooltip = decoration && decoration.tooltip || '';
541
+ const textDecoration = ((_a = treeNode.decorations) === null || _a === void 0 ? void 0 : _a.strikeThrough) === true ? 'line-through' : 'normal';
542
+ const relativePath = parentPath.relative(resourceUri.parent);
543
+ const path = relativePath ? relativePath.fsPath() : labelProvider.getLongName(resourceUri.parent);
544
+ const title = tooltip.length !== 0
545
+ ? `${resourceUri.path.fsPath()} • ${tooltip}`
546
+ : resourceUri.path.fsPath();
547
+ return React.createElement("div", { key: sourceUri, className: `scmItem ${tree_1.TREE_NODE_SEGMENT_CLASS} ${tree_1.TREE_NODE_SEGMENT_GROW_CLASS}`, onContextMenu: this.renderContextMenu, onMouseEnter: this.showHover, onMouseLeave: this.hideHover, ref: this.detectHover, title: title, onClick: this.handleClick, onDoubleClick: this.handleDoubleClick },
548
+ React.createElement("span", { className: icon + ' file-icon' }),
549
+ this.props.renderExpansionToggle(),
550
+ React.createElement("div", { className: `noWrapInfo ${tree_1.TREE_NODE_SEGMENT_GROW_CLASS}` },
551
+ React.createElement("span", { className: 'name', style: { textDecoration } }, caption),
552
+ React.createElement("span", { className: 'path', style: { textDecoration } }, path)),
553
+ React.createElement(ScmInlineActions, { ...{
554
+ hover,
555
+ menu: menus.getMenu(ScmTreeWidget.RESOURCE_INLINE_MENU),
556
+ menuPath: ScmTreeWidget.RESOURCE_INLINE_MENU,
557
+ commandExecutor,
558
+ args: this.contextMenuArgs,
559
+ contextKeys,
560
+ model,
561
+ treeNode
562
+ } },
563
+ React.createElement("div", { title: tooltip, className: classNames.join(' '), style: { color } }, letter)));
564
+ }
565
+ get contextMenuArgs() {
566
+ if (!this.props.model.selectedNodes.some(node => scm_tree_model_1.ScmFileChangeNode.is(node) && node.sourceUri === this.props.sourceUri)) {
567
+ // Clicked node is not in selection, so ignore selection and action on just clicked node
568
+ return this.singleNodeArgs;
569
+ }
570
+ else {
571
+ return this.props.model.getSelectionArgs(this.props.model.selectedNodes);
572
+ }
573
+ }
574
+ get singleNodeArgs() {
575
+ const selectedResource = this.props.model.getResourceFromNode(this.props.treeNode);
576
+ if (selectedResource) {
577
+ return [selectedResource];
578
+ }
579
+ else {
580
+ // Repository status not yet available. Empty args disables the action.
581
+ return [];
582
+ }
583
+ }
584
+ hasCtrlCmdOrShiftMask(event) {
585
+ const { metaKey, ctrlKey, shiftKey } = event;
586
+ return (os_1.isOSX && metaKey) || ctrlKey || shiftKey;
587
+ }
588
+ }
589
+ exports.ScmResourceComponent = ScmResourceComponent;
590
+ class ScmResourceGroupElement extends ScmElement {
591
+ constructor() {
592
+ super(...arguments);
593
+ this.contextMenuPath = ScmTreeWidget.RESOURCE_GROUP_CONTEXT_MENU;
594
+ }
595
+ render() {
596
+ const { hover } = this.state;
597
+ const { model, treeNode, menus, commandExecutor, contextKeys, caption } = this.props;
598
+ return React.createElement("div", { className: `theia-header scm-theia-header ${tree_1.TREE_NODE_SEGMENT_GROW_CLASS}`, onContextMenu: this.renderContextMenu, onMouseEnter: this.showHover, onMouseLeave: this.hideHover, ref: this.detectHover },
599
+ this.props.renderExpansionToggle(),
600
+ React.createElement("div", { className: `noWrapInfo ${tree_1.TREE_NODE_SEGMENT_GROW_CLASS}` }, caption),
601
+ React.createElement(ScmInlineActions, { ...{
602
+ hover,
603
+ args: this.contextMenuArgs,
604
+ menu: menus.getMenu(ScmTreeWidget.RESOURCE_GROUP_INLINE_MENU),
605
+ menuPath: ScmTreeWidget.RESOURCE_GROUP_INLINE_MENU,
606
+ commandExecutor,
607
+ contextKeys,
608
+ model,
609
+ treeNode
610
+ } }, this.renderChangeCount()));
611
+ }
612
+ renderChangeCount() {
613
+ const group = this.props.model.getResourceGroupFromNode(this.props.treeNode);
614
+ return React.createElement("div", { className: 'notification-count-container scm-change-count' },
615
+ React.createElement("span", { className: 'notification-count' }, group ? group.resources.length : 0));
616
+ }
617
+ get contextMenuArgs() {
618
+ const group = this.props.model.getResourceGroupFromNode(this.props.treeNode);
619
+ if (group) {
620
+ return [group];
621
+ }
622
+ else {
623
+ // Repository status not yet available. Empty args disables the action.
624
+ return [];
625
+ }
626
+ }
627
+ }
628
+ exports.ScmResourceGroupElement = ScmResourceGroupElement;
629
+ class ScmResourceFolderElement extends ScmElement {
630
+ constructor() {
631
+ super(...arguments);
632
+ this.contextMenuPath = ScmTreeWidget.RESOURCE_FOLDER_CONTEXT_MENU;
633
+ }
634
+ render() {
635
+ const { hover } = this.state;
636
+ const { model, treeNode, sourceUri, labelProvider, commandExecutor, menus, contextKeys, caption } = this.props;
637
+ const sourceFileStat = files_1.FileStat.dir(sourceUri);
638
+ const icon = labelProvider.getIcon(sourceFileStat);
639
+ const title = new uri_1.default(sourceUri).path.fsPath();
640
+ return React.createElement("div", { key: sourceUri, className: `scmItem ${tree_1.TREE_NODE_SEGMENT_CLASS} ${tree_1.TREE_NODE_SEGMENT_GROW_CLASS} ${ScmTreeWidget.Styles.NO_SELECT}`, title: title, onContextMenu: this.renderContextMenu, onMouseEnter: this.showHover, onMouseLeave: this.hideHover, ref: this.detectHover },
641
+ this.props.renderExpansionToggle(),
642
+ React.createElement("span", { className: icon + ' file-icon' }),
643
+ React.createElement("div", { className: `noWrapInfo ${tree_1.TREE_NODE_SEGMENT_GROW_CLASS}` },
644
+ React.createElement("span", { className: 'name' }, caption)),
645
+ React.createElement(ScmInlineActions, { ...{
646
+ hover,
647
+ menu: menus.getMenu(ScmTreeWidget.RESOURCE_FOLDER_INLINE_MENU),
648
+ menuPath: ScmTreeWidget.RESOURCE_FOLDER_INLINE_MENU,
649
+ commandExecutor,
650
+ args: this.contextMenuArgs,
651
+ contextKeys,
652
+ model,
653
+ treeNode
654
+ } }));
655
+ }
656
+ get contextMenuArgs() {
657
+ if (!this.props.model.selectedNodes.some(node => scm_tree_model_1.ScmFileChangeFolderNode.is(node) && node.sourceUri === this.props.sourceUri)) {
658
+ // Clicked node is not in selection, so ignore selection and action on just clicked node
659
+ return this.singleNodeArgs;
660
+ }
661
+ else {
662
+ return this.props.model.getSelectionArgs(this.props.model.selectedNodes);
663
+ }
664
+ }
665
+ get singleNodeArgs() {
666
+ return this.props.model.getResourcesFromFolderNode(this.props.treeNode);
667
+ }
668
+ }
669
+ exports.ScmResourceFolderElement = ScmResourceFolderElement;
670
+ class ScmInlineActions extends React.Component {
671
+ render() {
672
+ const { hover, menu, menuPath, args, commandExecutor, model, treeNode, contextKeys, children } = this.props;
673
+ return React.createElement("div", { className: 'theia-scm-inline-actions-container' },
674
+ React.createElement("div", { className: 'theia-scm-inline-actions' }, hover && menu.children
675
+ .map((node, index) => node instanceof menu_1.ActionMenuNode &&
676
+ React.createElement(ScmInlineAction, { key: index, ...{ node, menuPath, args, commandExecutor, model, treeNode, contextKeys } }))),
677
+ children);
678
+ }
679
+ }
680
+ exports.ScmInlineActions = ScmInlineActions;
681
+ class ScmInlineAction extends React.Component {
682
+ constructor() {
683
+ super(...arguments);
684
+ this.execute = (event) => {
685
+ event.stopPropagation();
686
+ const { commandExecutor, menuPath, node, args } = this.props;
687
+ commandExecutor.executeCommand([menuPath[0]], node.command, ...args);
688
+ };
689
+ }
690
+ render() {
691
+ const { node, model, treeNode, args, commandExecutor, menuPath, contextKeys } = this.props;
692
+ let isActive = false;
693
+ model.execInNodeContext(treeNode, () => {
694
+ isActive = contextKeys.match(node.when);
695
+ });
696
+ if (!commandExecutor.isVisible(menuPath, node.command, ...args) || !isActive) {
697
+ return false;
698
+ }
699
+ return React.createElement("div", { className: 'theia-scm-inline-action' },
700
+ React.createElement("a", { className: `${node.icon} ${browser_1.ACTION_ITEM}`, title: node.label, onClick: this.execute }));
701
+ }
702
+ }
703
+ exports.ScmInlineAction = ScmInlineAction;
704
704
  //# sourceMappingURL=scm-tree-widget.js.map