@codingame/monaco-vscode-scm-service-override 1.83.15
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/external/rollup-plugin-styles/dist/runtime/inject-css.js +3 -0
- package/external/tslib/tslib.es6.js +11 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +24 -0
- package/scm.d.ts +5 -0
- package/scm.js +17 -0
- package/vscode/src/vs/base/common/resourceTree.js +137 -0
- package/vscode/src/vs/workbench/contrib/scm/browser/activity.js +250 -0
- package/vscode/src/vs/workbench/contrib/scm/browser/media/scm.css.js +6 -0
- package/vscode/src/vs/workbench/contrib/scm/browser/menus.js +204 -0
- package/vscode/src/vs/workbench/contrib/scm/browser/scm.contribution.js +599 -0
- package/vscode/src/vs/workbench/contrib/scm/browser/scmRepositoriesViewPane.js +153 -0
- package/vscode/src/vs/workbench/contrib/scm/browser/scmRepositoryRenderer.js +114 -0
- package/vscode/src/vs/workbench/contrib/scm/browser/scmSyncViewPane.js +719 -0
- package/vscode/src/vs/workbench/contrib/scm/browser/scmViewPane.js +2245 -0
- package/vscode/src/vs/workbench/contrib/scm/browser/scmViewPaneContainer.js +49 -0
- package/vscode/src/vs/workbench/contrib/scm/browser/scmViewService.js +305 -0
- package/vscode/src/vs/workbench/contrib/scm/browser/util.js +86 -0
- package/vscode/src/vs/workbench/contrib/scm/common/quickDiffService.js +76 -0
- package/vscode/src/vs/workbench/contrib/scm/common/scmService.js +303 -0
|
@@ -0,0 +1,2245 @@
|
|
|
1
|
+
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
|
|
2
|
+
import './media/scm.css.js';
|
|
3
|
+
import { Event, Emitter } from 'monaco-editor/esm/vs/base/common/event.js';
|
|
4
|
+
import { basename, dirname } from 'monaco-editor/esm/vs/base/common/resources.js';
|
|
5
|
+
import { Disposable, DisposableStore, toDisposable, combinedDisposable, MutableDisposable, dispose } from 'monaco-editor/esm/vs/base/common/lifecycle.js';
|
|
6
|
+
import { ViewAction, ViewPane } from 'vscode/vscode/vs/workbench/browser/parts/views/viewPane';
|
|
7
|
+
import { append, $, asCSSUrl, Dimension, trackFocus, clearNode } from 'monaco-editor/esm/vs/base/browser/dom.js';
|
|
8
|
+
import { VIEW_PANE_ID, SCMInputChangeReason, ISCMViewService, ISCMService, REPOSITORIES_VIEW_PANE_ID } from 'vscode/vscode/vs/workbench/contrib/scm/common/scm';
|
|
9
|
+
import { ResourceLabels } from 'vscode/vscode/vs/workbench/browser/labels';
|
|
10
|
+
import { CountBadge } from 'monaco-editor/esm/vs/base/browser/ui/countBadge/countBadge.js';
|
|
11
|
+
import { IEditorService } from 'vscode/vscode/vs/workbench/services/editor/common/editorService';
|
|
12
|
+
import { IInstantiationService } from 'monaco-editor/esm/vs/platform/instantiation/common/instantiation.js';
|
|
13
|
+
import { IContextMenuService, IContextViewService } from 'monaco-editor/esm/vs/platform/contextview/browser/contextView.js';
|
|
14
|
+
import { RawContextKey, ContextKeyExpr, IContextKeyService } from 'monaco-editor/esm/vs/platform/contextkey/common/contextkey.js';
|
|
15
|
+
import { ICommandService } from 'monaco-editor/esm/vs/platform/commands/common/commands.js';
|
|
16
|
+
import { IKeybindingService } from 'monaco-editor/esm/vs/platform/keybinding/common/keybinding.js';
|
|
17
|
+
import { MenuId, MenuRegistry, registerAction2, MenuItemAction, IMenuService, Action2 } from 'monaco-editor/esm/vs/platform/actions/common/actions.js';
|
|
18
|
+
import { Action, Separator, ActionRunner } from 'monaco-editor/esm/vs/base/common/actions.js';
|
|
19
|
+
import { ActionBar } from 'monaco-editor/esm/vs/base/browser/ui/actionbar/actionbar.js';
|
|
20
|
+
import { IThemeService } from 'monaco-editor/esm/vs/platform/theme/common/themeService.js';
|
|
21
|
+
import { connectPrimaryMenuToInlineActionBar, getActionViewItemProvider, isSCMRepository, isSCMResourceGroup, isSCMInput, isSCMActionButton, collectContextMenuActions, isSCMResource } from './util.js';
|
|
22
|
+
import { WorkbenchCompressibleObjectTree } from 'monaco-editor/esm/vs/platform/list/browser/listService.js';
|
|
23
|
+
import { IConfigurationService } from 'monaco-editor/esm/vs/platform/configuration/common/configuration.js';
|
|
24
|
+
import { disposableTimeout, ThrottledDelayer } from 'monaco-editor/esm/vs/base/common/async.js';
|
|
25
|
+
import { ResourceTree } from '../../../../base/common/resourceTree.js';
|
|
26
|
+
import { Iterable } from 'monaco-editor/esm/vs/base/common/iterator.js';
|
|
27
|
+
import { URI } from 'monaco-editor/esm/vs/base/common/uri.js';
|
|
28
|
+
import { FileKind } from 'monaco-editor/esm/vs/platform/files/common/files.js';
|
|
29
|
+
import { compareFileNames, comparePaths } from 'monaco-editor/esm/vs/base/common/comparers.js';
|
|
30
|
+
import { createMatches } from 'monaco-editor/esm/vs/base/common/filters.js';
|
|
31
|
+
import { IViewDescriptorService } from 'vscode/vscode/vs/workbench/common/views';
|
|
32
|
+
import { localizeWithPath } from 'monaco-editor/esm/vs/nls.js';
|
|
33
|
+
import { flatten, coalesce } from 'monaco-editor/esm/vs/base/common/arrays.js';
|
|
34
|
+
import { memoize } from 'monaco-editor/esm/vs/base/common/decorators.js';
|
|
35
|
+
import { WillSaveStateReason, IStorageService } from 'monaco-editor/esm/vs/platform/storage/common/storage.js';
|
|
36
|
+
import { EditorResourceAccessor, SideBySideEditor } from 'vscode/vscode/vs/workbench/common/editor';
|
|
37
|
+
import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vscode/vscode/vs/workbench/common/theme';
|
|
38
|
+
import { CodeEditorWidget } from 'monaco-editor/esm/vs/editor/browser/widget/codeEditorWidget.js';
|
|
39
|
+
import { getSimpleEditorOptions } from 'vscode/vscode/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions';
|
|
40
|
+
import { IModelService } from 'monaco-editor/esm/vs/editor/common/services/model.js';
|
|
41
|
+
import { EditorExtensionsRegistry } from 'monaco-editor/esm/vs/editor/browser/editorExtensions.js';
|
|
42
|
+
import { MenuPreventer } from 'vscode/vscode/vs/workbench/contrib/codeEditor/browser/menuPreventer';
|
|
43
|
+
import { SelectionClipboardContributionID } from 'vscode/vscode/vs/workbench/contrib/codeEditor/browser/selectionClipboard';
|
|
44
|
+
import { ContextMenuController } from 'monaco-editor/esm/vs/editor/contrib/contextmenu/browser/contextmenu.js';
|
|
45
|
+
import * as platform from 'monaco-editor/esm/vs/base/common/platform.js';
|
|
46
|
+
import { format, compare } from 'monaco-editor/esm/vs/base/common/strings.js';
|
|
47
|
+
import { SuggestController } from 'monaco-editor/esm/vs/editor/contrib/suggest/browser/suggestController.js';
|
|
48
|
+
import { SnippetController2 } from 'monaco-editor/esm/vs/editor/contrib/snippet/browser/snippetController2.js';
|
|
49
|
+
import { ServiceCollection } from 'monaco-editor/esm/vs/platform/instantiation/common/serviceCollection.js';
|
|
50
|
+
import { ModesHoverController } from 'monaco-editor/esm/vs/editor/contrib/hover/browser/hover.js';
|
|
51
|
+
import { ColorDetector } from 'monaco-editor/esm/vs/editor/contrib/colorPicker/browser/colorDetector.js';
|
|
52
|
+
import { LinkDetector } from 'monaco-editor/esm/vs/editor/contrib/links/browser/links.js';
|
|
53
|
+
import { IOpenerService } from 'monaco-editor/esm/vs/platform/opener/common/opener.js';
|
|
54
|
+
import { ITelemetryService } from 'monaco-editor/esm/vs/platform/telemetry/common/telemetry.js';
|
|
55
|
+
import { ILanguageService } from 'monaco-editor/esm/vs/editor/common/languages/language.js';
|
|
56
|
+
import { ILabelService } from 'monaco-editor/esm/vs/platform/label/common/label.js';
|
|
57
|
+
import { DEFAULT_FONT_FAMILY } from 'vscode/vscode/vs/workbench/browser/style';
|
|
58
|
+
import { Codicon } from 'monaco-editor/esm/vs/base/common/codicons.js';
|
|
59
|
+
import { ThemeIcon } from 'monaco-editor/esm/vs/base/common/themables.js';
|
|
60
|
+
import { RepositoryRenderer } from './scmRepositoryRenderer.js';
|
|
61
|
+
import { ColorScheme } from 'monaco-editor/esm/vs/platform/theme/common/theme.js';
|
|
62
|
+
import { IUriIdentityService } from 'monaco-editor/esm/vs/platform/uriIdentity/common/uriIdentity.js';
|
|
63
|
+
import { API_OPEN_EDITOR_COMMAND_ID, API_OPEN_DIFF_EDITOR_COMMAND_ID } from 'vscode/vscode/vs/workbench/browser/parts/editor/editorCommands';
|
|
64
|
+
import { createAndFillInContextMenuActions } from 'monaco-editor/esm/vs/platform/actions/browser/menuEntryActionViewItem.js';
|
|
65
|
+
import { IWorkspaceContextService } from 'monaco-editor/esm/vs/platform/workspace/common/workspace.js';
|
|
66
|
+
import { MarkdownRenderer, openLinkFromMarkdown } from 'monaco-editor/esm/vs/editor/contrib/markdownRenderer/browser/markdownRenderer.js';
|
|
67
|
+
import { ButtonWithDropdown, Button } from 'monaco-editor/esm/vs/base/browser/ui/button/button.js';
|
|
68
|
+
import { INotificationService } from 'monaco-editor/esm/vs/platform/notification/common/notification.js';
|
|
69
|
+
import { RepositoryContextKeys } from './scmViewService.js';
|
|
70
|
+
import { DragAndDropController } from 'monaco-editor/esm/vs/editor/contrib/dnd/browser/dnd.js';
|
|
71
|
+
import { DropIntoEditorController } from 'monaco-editor/esm/vs/editor/contrib/dropOrPasteInto/browser/dropIntoEditorController.js';
|
|
72
|
+
import { MessageController } from 'monaco-editor/esm/vs/editor/contrib/message/browser/messageController.js';
|
|
73
|
+
import { registerColor, contrastBorder } from 'monaco-editor/esm/vs/platform/theme/common/colorRegistry.js';
|
|
74
|
+
import { defaultCountBadgeStyles, defaultButtonStyles } from 'monaco-editor/esm/vs/platform/theme/browser/defaultStyles.js';
|
|
75
|
+
import { InlineCompletionsController } from 'monaco-editor/esm/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsController.js';
|
|
76
|
+
import { CodeActionController } from 'monaco-editor/esm/vs/editor/contrib/codeAction/browser/codeActionController.js';
|
|
77
|
+
import { ITextModelService } from 'monaco-editor/esm/vs/editor/common/services/resolverService.js';
|
|
78
|
+
import { Schemas } from 'monaco-editor/esm/vs/base/common/network.js';
|
|
79
|
+
import { fillEditorsDragData } from 'vscode/vscode/vs/workbench/browser/dnd';
|
|
80
|
+
import { CodeDataTransfers } from 'monaco-editor/esm/vs/platform/dnd/browser/dnd.js';
|
|
81
|
+
import { FormatOnType } from 'monaco-editor/esm/vs/editor/contrib/format/browser/formatActions.js';
|
|
82
|
+
|
|
83
|
+
var ActionButtonRenderer_1, InputRenderer_1, ResourceGroupRenderer_1, ResourceRenderer_1, SCMInputWidget_1;
|
|
84
|
+
let ActionButtonRenderer = class ActionButtonRenderer {
|
|
85
|
+
static { ActionButtonRenderer_1 = this; }
|
|
86
|
+
static { this.DEFAULT_HEIGHT = 30; }
|
|
87
|
+
static { this.TEMPLATE_ID = 'actionButton'; }
|
|
88
|
+
get templateId() { return ActionButtonRenderer_1.TEMPLATE_ID; }
|
|
89
|
+
constructor(commandService, contextMenuService, notificationService) {
|
|
90
|
+
this.commandService = commandService;
|
|
91
|
+
this.contextMenuService = contextMenuService;
|
|
92
|
+
this.notificationService = notificationService;
|
|
93
|
+
this.actionButtons = ( new Map());
|
|
94
|
+
}
|
|
95
|
+
renderTemplate(container) {
|
|
96
|
+
container.parentElement.parentElement.querySelector('.monaco-tl-twistie').classList.add('force-no-twistie');
|
|
97
|
+
container.parentElement.parentElement.classList.add('cursor-default', 'force-no-hover');
|
|
98
|
+
const buttonContainer = append(container, $('.button-container'));
|
|
99
|
+
const actionButton = ( new SCMActionButton(
|
|
100
|
+
buttonContainer,
|
|
101
|
+
this.contextMenuService,
|
|
102
|
+
this.commandService,
|
|
103
|
+
this.notificationService
|
|
104
|
+
));
|
|
105
|
+
return { actionButton, disposable: Disposable.None, templateDisposable: actionButton };
|
|
106
|
+
}
|
|
107
|
+
renderElement(node, index, templateData, height) {
|
|
108
|
+
templateData.disposable.dispose();
|
|
109
|
+
const disposables = ( new DisposableStore());
|
|
110
|
+
const actionButton = node.element;
|
|
111
|
+
templateData.actionButton.setButton(node.element.button);
|
|
112
|
+
this.actionButtons.set(actionButton, templateData.actionButton);
|
|
113
|
+
disposables.add({ dispose: () => this.actionButtons.delete(actionButton) });
|
|
114
|
+
templateData.disposable = disposables;
|
|
115
|
+
}
|
|
116
|
+
renderCompressedElements() {
|
|
117
|
+
throw new Error('Should never happen since node is incompressible');
|
|
118
|
+
}
|
|
119
|
+
focusActionButton(actionButton) {
|
|
120
|
+
this.actionButtons.get(actionButton)?.focus();
|
|
121
|
+
}
|
|
122
|
+
disposeElement(node, index, template) {
|
|
123
|
+
template.disposable.dispose();
|
|
124
|
+
}
|
|
125
|
+
disposeTemplate(templateData) {
|
|
126
|
+
templateData.disposable.dispose();
|
|
127
|
+
templateData.templateDisposable.dispose();
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
ActionButtonRenderer = ActionButtonRenderer_1 = ( __decorate([
|
|
131
|
+
( __param(0, ICommandService)),
|
|
132
|
+
( __param(1, IContextMenuService)),
|
|
133
|
+
( __param(2, INotificationService))
|
|
134
|
+
], ActionButtonRenderer));
|
|
135
|
+
class SCMTreeDragAndDrop {
|
|
136
|
+
constructor(instantiationService) {
|
|
137
|
+
this.instantiationService = instantiationService;
|
|
138
|
+
}
|
|
139
|
+
getDragURI(element) {
|
|
140
|
+
if (isSCMResource(element)) {
|
|
141
|
+
return ( element.sourceUri.toString());
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
onDragStart(data, originalEvent) {
|
|
146
|
+
const items = SCMTreeDragAndDrop.getResourcesFromDragAndDropData(data);
|
|
147
|
+
if (originalEvent.dataTransfer && items?.length) {
|
|
148
|
+
this.instantiationService.invokeFunction(accessor => fillEditorsDragData(accessor, items, originalEvent));
|
|
149
|
+
const fileResources = ( items.filter(s => s.scheme === Schemas.file).map(r => r.fsPath));
|
|
150
|
+
if (fileResources.length) {
|
|
151
|
+
originalEvent.dataTransfer.setData(CodeDataTransfers.FILES, JSON.stringify(fileResources));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
getDragLabel(elements, originalEvent) {
|
|
156
|
+
if (elements.length === 1) {
|
|
157
|
+
const element = elements[0];
|
|
158
|
+
if (isSCMResource(element)) {
|
|
159
|
+
return basename(element.sourceUri);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return String(elements.length);
|
|
163
|
+
}
|
|
164
|
+
onDragOver(data, targetElement, targetIndex, originalEvent) {
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
drop(data, targetElement, targetIndex, originalEvent) { }
|
|
168
|
+
static getResourcesFromDragAndDropData(data) {
|
|
169
|
+
const uris = [];
|
|
170
|
+
for (const element of [...(data.context ?? []), ...data.elements]) {
|
|
171
|
+
if (isSCMResource(element)) {
|
|
172
|
+
uris.push(element.sourceUri);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return uris;
|
|
176
|
+
}
|
|
177
|
+
dispose() { }
|
|
178
|
+
}
|
|
179
|
+
let InputRenderer = class InputRenderer {
|
|
180
|
+
static { InputRenderer_1 = this; }
|
|
181
|
+
static { this.DEFAULT_HEIGHT = 26; }
|
|
182
|
+
static { this.TEMPLATE_ID = 'input'; }
|
|
183
|
+
get templateId() { return InputRenderer_1.TEMPLATE_ID; }
|
|
184
|
+
constructor(outerLayout, overflowWidgetsDomNode, updateHeight, instantiationService) {
|
|
185
|
+
this.outerLayout = outerLayout;
|
|
186
|
+
this.overflowWidgetsDomNode = overflowWidgetsDomNode;
|
|
187
|
+
this.updateHeight = updateHeight;
|
|
188
|
+
this.instantiationService = instantiationService;
|
|
189
|
+
this.inputWidgets = ( new Map());
|
|
190
|
+
this.contentHeights = ( new WeakMap());
|
|
191
|
+
this.editorSelections = ( new WeakMap());
|
|
192
|
+
}
|
|
193
|
+
renderTemplate(container) {
|
|
194
|
+
container.parentElement.parentElement.querySelector('.monaco-tl-twistie').classList.add('force-no-twistie');
|
|
195
|
+
container.parentElement.parentElement.classList.add('force-no-hover');
|
|
196
|
+
const templateDisposable = ( new DisposableStore());
|
|
197
|
+
const inputElement = append(container, $('.scm-input'));
|
|
198
|
+
const inputWidget = this.instantiationService.createInstance(SCMInputWidget, inputElement, this.overflowWidgetsDomNode);
|
|
199
|
+
templateDisposable.add(inputWidget);
|
|
200
|
+
return { inputWidget, inputWidgetHeight: InputRenderer_1.DEFAULT_HEIGHT, elementDisposables: ( new DisposableStore()), templateDisposable };
|
|
201
|
+
}
|
|
202
|
+
renderElement(node, index, templateData) {
|
|
203
|
+
const input = node.element;
|
|
204
|
+
templateData.inputWidget.setInput(input);
|
|
205
|
+
this.inputWidgets.set(input, templateData.inputWidget);
|
|
206
|
+
templateData.elementDisposables.add({
|
|
207
|
+
dispose: () => this.inputWidgets.delete(input)
|
|
208
|
+
});
|
|
209
|
+
const selections = this.editorSelections.get(input);
|
|
210
|
+
if (selections) {
|
|
211
|
+
templateData.inputWidget.selections = selections;
|
|
212
|
+
}
|
|
213
|
+
templateData.elementDisposables.add(toDisposable(() => {
|
|
214
|
+
const selections = templateData.inputWidget.selections;
|
|
215
|
+
if (selections) {
|
|
216
|
+
this.editorSelections.set(input, selections);
|
|
217
|
+
}
|
|
218
|
+
}));
|
|
219
|
+
const onDidChangeContentHeight = () => {
|
|
220
|
+
const contentHeight = templateData.inputWidget.getContentHeight();
|
|
221
|
+
this.contentHeights.set(input, contentHeight);
|
|
222
|
+
if (templateData.inputWidgetHeight !== contentHeight) {
|
|
223
|
+
this.updateHeight(input, contentHeight + 10);
|
|
224
|
+
templateData.inputWidgetHeight = contentHeight;
|
|
225
|
+
templateData.inputWidget.layout();
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
const startListeningContentHeightChange = () => {
|
|
229
|
+
templateData.elementDisposables.add(templateData.inputWidget.onDidChangeContentHeight(onDidChangeContentHeight));
|
|
230
|
+
onDidChangeContentHeight();
|
|
231
|
+
};
|
|
232
|
+
const timeout = disposableTimeout(startListeningContentHeightChange, 0);
|
|
233
|
+
templateData.elementDisposables.add(timeout);
|
|
234
|
+
const layoutEditor = () => templateData.inputWidget.layout();
|
|
235
|
+
templateData.elementDisposables.add(this.outerLayout.onDidChange(layoutEditor));
|
|
236
|
+
layoutEditor();
|
|
237
|
+
}
|
|
238
|
+
renderCompressedElements() {
|
|
239
|
+
throw new Error('Should never happen since node is incompressible');
|
|
240
|
+
}
|
|
241
|
+
disposeElement(group, index, template) {
|
|
242
|
+
template.elementDisposables.clear();
|
|
243
|
+
}
|
|
244
|
+
disposeTemplate(templateData) {
|
|
245
|
+
templateData.templateDisposable.dispose();
|
|
246
|
+
}
|
|
247
|
+
getHeight(input) {
|
|
248
|
+
return (this.contentHeights.get(input) ?? InputRenderer_1.DEFAULT_HEIGHT) + 10;
|
|
249
|
+
}
|
|
250
|
+
getRenderedInputWidget(input) {
|
|
251
|
+
return this.inputWidgets.get(input);
|
|
252
|
+
}
|
|
253
|
+
getFocusedInput() {
|
|
254
|
+
for (const [input, inputWidget] of this.inputWidgets) {
|
|
255
|
+
if (inputWidget.hasFocus()) {
|
|
256
|
+
return input;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
clearValidation() {
|
|
262
|
+
for (const [, inputWidget] of this.inputWidgets) {
|
|
263
|
+
inputWidget.clearValidation();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
InputRenderer = InputRenderer_1 = ( __decorate([
|
|
268
|
+
( __param(3, IInstantiationService))
|
|
269
|
+
], InputRenderer));
|
|
270
|
+
let ResourceGroupRenderer = class ResourceGroupRenderer {
|
|
271
|
+
static { ResourceGroupRenderer_1 = this; }
|
|
272
|
+
static { this.TEMPLATE_ID = 'resource group'; }
|
|
273
|
+
get templateId() { return ResourceGroupRenderer_1.TEMPLATE_ID; }
|
|
274
|
+
constructor(actionViewItemProvider, scmViewService) {
|
|
275
|
+
this.actionViewItemProvider = actionViewItemProvider;
|
|
276
|
+
this.scmViewService = scmViewService;
|
|
277
|
+
}
|
|
278
|
+
renderTemplate(container) {
|
|
279
|
+
container.parentElement.parentElement.querySelector('.monaco-tl-twistie').classList.add('force-twistie');
|
|
280
|
+
const element = append(container, $('.resource-group'));
|
|
281
|
+
const name = append(element, $('.name'));
|
|
282
|
+
const actionsContainer = append(element, $('.actions'));
|
|
283
|
+
const actionBar = ( new ActionBar(actionsContainer, { actionViewItemProvider: this.actionViewItemProvider }));
|
|
284
|
+
const countContainer = append(element, $('.count'));
|
|
285
|
+
const count = ( new CountBadge(countContainer, {}, defaultCountBadgeStyles));
|
|
286
|
+
const disposables = combinedDisposable(actionBar);
|
|
287
|
+
return { name, count, actionBar, elementDisposables: ( new DisposableStore()), disposables };
|
|
288
|
+
}
|
|
289
|
+
renderElement(node, index, template) {
|
|
290
|
+
const group = node.element;
|
|
291
|
+
template.name.textContent = group.label;
|
|
292
|
+
template.actionBar.clear();
|
|
293
|
+
template.actionBar.context = group;
|
|
294
|
+
template.count.setCount(group.elements.length);
|
|
295
|
+
const menus = this.scmViewService.menus.getRepositoryMenus(group.provider);
|
|
296
|
+
template.elementDisposables.add(connectPrimaryMenuToInlineActionBar(menus.getResourceGroupMenu(group), template.actionBar));
|
|
297
|
+
}
|
|
298
|
+
renderCompressedElements(node, index, templateData, height) {
|
|
299
|
+
throw new Error('Should never happen since node is incompressible');
|
|
300
|
+
}
|
|
301
|
+
disposeElement(group, index, template) {
|
|
302
|
+
template.elementDisposables.clear();
|
|
303
|
+
}
|
|
304
|
+
disposeTemplate(template) {
|
|
305
|
+
template.elementDisposables.dispose();
|
|
306
|
+
template.disposables.dispose();
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
ResourceGroupRenderer = ResourceGroupRenderer_1 = ( __decorate([
|
|
310
|
+
( __param(1, ISCMViewService))
|
|
311
|
+
], ResourceGroupRenderer));
|
|
312
|
+
class RepositoryPaneActionRunner extends ActionRunner {
|
|
313
|
+
constructor(getSelectedResources) {
|
|
314
|
+
super();
|
|
315
|
+
this.getSelectedResources = getSelectedResources;
|
|
316
|
+
}
|
|
317
|
+
async runAction(action, context) {
|
|
318
|
+
if (!(action instanceof MenuItemAction)) {
|
|
319
|
+
return super.runAction(action, context);
|
|
320
|
+
}
|
|
321
|
+
const selection = this.getSelectedResources();
|
|
322
|
+
const contextIsSelected = ( selection.some(s => s === context));
|
|
323
|
+
const actualContext = contextIsSelected ? selection : [context];
|
|
324
|
+
const args = flatten(( actualContext.map(e => ResourceTree.isResourceNode(e) ? ResourceTree.collect(e) : [e])));
|
|
325
|
+
await action.run(...args);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
let ResourceRenderer = class ResourceRenderer {
|
|
329
|
+
static { ResourceRenderer_1 = this; }
|
|
330
|
+
static { this.TEMPLATE_ID = 'resource'; }
|
|
331
|
+
get templateId() { return ResourceRenderer_1.TEMPLATE_ID; }
|
|
332
|
+
constructor(viewModelProvider, labels, actionViewItemProvider, actionRunner, labelService, scmViewService, themeService) {
|
|
333
|
+
this.viewModelProvider = viewModelProvider;
|
|
334
|
+
this.labels = labels;
|
|
335
|
+
this.actionViewItemProvider = actionViewItemProvider;
|
|
336
|
+
this.actionRunner = actionRunner;
|
|
337
|
+
this.labelService = labelService;
|
|
338
|
+
this.scmViewService = scmViewService;
|
|
339
|
+
this.themeService = themeService;
|
|
340
|
+
this.disposables = ( new DisposableStore());
|
|
341
|
+
this.renderedResources = ( new Map());
|
|
342
|
+
themeService.onDidColorThemeChange(this.onDidColorThemeChange, this, this.disposables);
|
|
343
|
+
}
|
|
344
|
+
renderTemplate(container) {
|
|
345
|
+
const element = append(container, $('.resource'));
|
|
346
|
+
const name = append(element, $('.name'));
|
|
347
|
+
const fileLabel = this.labels.create(name, { supportDescriptionHighlights: true, supportHighlights: true });
|
|
348
|
+
const actionsContainer = append(fileLabel.element, $('.actions'));
|
|
349
|
+
const actionBar = ( new ActionBar(actionsContainer, {
|
|
350
|
+
actionViewItemProvider: this.actionViewItemProvider,
|
|
351
|
+
actionRunner: this.actionRunner
|
|
352
|
+
}));
|
|
353
|
+
const decorationIcon = append(element, $('.decoration-icon'));
|
|
354
|
+
const actionBarMenuListener = ( new MutableDisposable());
|
|
355
|
+
const disposables = combinedDisposable(actionBar, fileLabel, actionBarMenuListener);
|
|
356
|
+
return { element, name, fileLabel, decorationIcon, actionBar, actionBarMenu: undefined, actionBarMenuListener, elementDisposables: ( new DisposableStore()), disposables };
|
|
357
|
+
}
|
|
358
|
+
renderElement(node, index, template) {
|
|
359
|
+
const resourceOrFolder = node.element;
|
|
360
|
+
const iconResource = ResourceTree.isResourceNode(resourceOrFolder) ? resourceOrFolder.element : resourceOrFolder;
|
|
361
|
+
const uri = ResourceTree.isResourceNode(resourceOrFolder) ? resourceOrFolder.uri : resourceOrFolder.sourceUri;
|
|
362
|
+
const fileKind = ResourceTree.isResourceNode(resourceOrFolder) ? FileKind.FOLDER : FileKind.FILE;
|
|
363
|
+
const viewModel = this.viewModelProvider();
|
|
364
|
+
const tooltip = !ResourceTree.isResourceNode(resourceOrFolder) && resourceOrFolder.decorations.tooltip || '';
|
|
365
|
+
let matches;
|
|
366
|
+
let descriptionMatches;
|
|
367
|
+
let strikethrough;
|
|
368
|
+
if (ResourceTree.isResourceNode(resourceOrFolder)) {
|
|
369
|
+
if (resourceOrFolder.element) {
|
|
370
|
+
const menus = this.scmViewService.menus.getRepositoryMenus(resourceOrFolder.element.resourceGroup.provider);
|
|
371
|
+
this._renderActionBar(template, resourceOrFolder, menus.getResourceMenu(resourceOrFolder.element));
|
|
372
|
+
template.element.classList.toggle('faded', resourceOrFolder.element.decorations.faded);
|
|
373
|
+
strikethrough = resourceOrFolder.element.decorations.strikeThrough;
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
const menus = this.scmViewService.menus.getRepositoryMenus(resourceOrFolder.context.provider);
|
|
377
|
+
this._renderActionBar(template, resourceOrFolder, menus.getResourceFolderMenu(resourceOrFolder.context));
|
|
378
|
+
matches = createMatches(node.filterData);
|
|
379
|
+
template.element.classList.remove('faded');
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
const menus = this.scmViewService.menus.getRepositoryMenus(resourceOrFolder.resourceGroup.provider);
|
|
384
|
+
this._renderActionBar(template, resourceOrFolder, menus.getResourceMenu(resourceOrFolder));
|
|
385
|
+
[matches, descriptionMatches] = this._processFilterData(uri, node.filterData);
|
|
386
|
+
template.element.classList.toggle('faded', resourceOrFolder.decorations.faded);
|
|
387
|
+
strikethrough = resourceOrFolder.decorations.strikeThrough;
|
|
388
|
+
}
|
|
389
|
+
const renderedData = {
|
|
390
|
+
tooltip,
|
|
391
|
+
uri,
|
|
392
|
+
fileLabelOptions: {
|
|
393
|
+
hidePath: viewModel.mode === "tree" ,
|
|
394
|
+
fileKind,
|
|
395
|
+
matches,
|
|
396
|
+
descriptionMatches,
|
|
397
|
+
strikethrough
|
|
398
|
+
},
|
|
399
|
+
iconResource
|
|
400
|
+
};
|
|
401
|
+
this.renderIcon(template, renderedData);
|
|
402
|
+
this.renderedResources.set(template, renderedData);
|
|
403
|
+
template.elementDisposables.add(toDisposable(() => this.renderedResources.delete(template)));
|
|
404
|
+
template.element.setAttribute('data-tooltip', tooltip);
|
|
405
|
+
}
|
|
406
|
+
disposeElement(resource, index, template) {
|
|
407
|
+
template.elementDisposables.clear();
|
|
408
|
+
}
|
|
409
|
+
renderCompressedElements(node, index, template, height) {
|
|
410
|
+
const compressed = node.element;
|
|
411
|
+
const folder = compressed.elements[compressed.elements.length - 1];
|
|
412
|
+
const label = ( compressed.elements.map(e => e.name));
|
|
413
|
+
const fileKind = FileKind.FOLDER;
|
|
414
|
+
const matches = createMatches(node.filterData);
|
|
415
|
+
template.fileLabel.setResource({ resource: folder.uri, name: label }, {
|
|
416
|
+
fileDecorations: { colors: false, badges: true },
|
|
417
|
+
fileKind,
|
|
418
|
+
matches,
|
|
419
|
+
separator: this.labelService.getSeparator(folder.uri.scheme)
|
|
420
|
+
});
|
|
421
|
+
const menus = this.scmViewService.menus.getRepositoryMenus(folder.context.provider);
|
|
422
|
+
this._renderActionBar(template, folder, menus.getResourceFolderMenu(folder.context));
|
|
423
|
+
template.name.classList.remove('strike-through');
|
|
424
|
+
template.element.classList.remove('faded');
|
|
425
|
+
template.decorationIcon.style.display = 'none';
|
|
426
|
+
template.decorationIcon.style.backgroundImage = '';
|
|
427
|
+
template.element.setAttribute('data-tooltip', '');
|
|
428
|
+
}
|
|
429
|
+
disposeCompressedElements(node, index, template, height) {
|
|
430
|
+
template.elementDisposables.clear();
|
|
431
|
+
}
|
|
432
|
+
disposeTemplate(template) {
|
|
433
|
+
template.elementDisposables.dispose();
|
|
434
|
+
template.disposables.dispose();
|
|
435
|
+
}
|
|
436
|
+
_renderActionBar(template, resourceOrFolder, menu) {
|
|
437
|
+
if (!template.actionBarMenu || template.actionBarMenu !== menu) {
|
|
438
|
+
template.actionBar.clear();
|
|
439
|
+
template.actionBarMenu = menu;
|
|
440
|
+
template.actionBarMenuListener.value = connectPrimaryMenuToInlineActionBar(menu, template.actionBar);
|
|
441
|
+
}
|
|
442
|
+
template.actionBar.context = resourceOrFolder;
|
|
443
|
+
}
|
|
444
|
+
_processFilterData(uri, filterData) {
|
|
445
|
+
if (!filterData) {
|
|
446
|
+
return [undefined, undefined];
|
|
447
|
+
}
|
|
448
|
+
if (!filterData.label) {
|
|
449
|
+
const matches = createMatches(filterData);
|
|
450
|
+
return [matches, undefined];
|
|
451
|
+
}
|
|
452
|
+
const fileName = basename(uri);
|
|
453
|
+
const label = filterData.label;
|
|
454
|
+
const pathLength = label.length - fileName.length;
|
|
455
|
+
const matches = createMatches(filterData.score);
|
|
456
|
+
if (label === fileName) {
|
|
457
|
+
return [matches, undefined];
|
|
458
|
+
}
|
|
459
|
+
const labelMatches = [];
|
|
460
|
+
const descriptionMatches = [];
|
|
461
|
+
for (const match of matches) {
|
|
462
|
+
if (match.start > pathLength) {
|
|
463
|
+
labelMatches.push({
|
|
464
|
+
start: match.start - pathLength,
|
|
465
|
+
end: match.end - pathLength
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
else if (match.end < pathLength) {
|
|
469
|
+
descriptionMatches.push(match);
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
labelMatches.push({
|
|
473
|
+
start: 0,
|
|
474
|
+
end: match.end - pathLength
|
|
475
|
+
});
|
|
476
|
+
descriptionMatches.push({
|
|
477
|
+
start: match.start,
|
|
478
|
+
end: pathLength
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return [labelMatches, descriptionMatches];
|
|
483
|
+
}
|
|
484
|
+
onDidColorThemeChange() {
|
|
485
|
+
for (const [template, data] of this.renderedResources) {
|
|
486
|
+
this.renderIcon(template, data);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
renderIcon(template, data) {
|
|
490
|
+
const theme = this.themeService.getColorTheme();
|
|
491
|
+
const icon = theme.type === ColorScheme.LIGHT ? data.iconResource?.decorations.icon : data.iconResource?.decorations.iconDark;
|
|
492
|
+
template.fileLabel.setFile(data.uri, {
|
|
493
|
+
...data.fileLabelOptions,
|
|
494
|
+
fileDecorations: { colors: false, badges: !icon },
|
|
495
|
+
});
|
|
496
|
+
if (icon) {
|
|
497
|
+
if (ThemeIcon.isThemeIcon(icon)) {
|
|
498
|
+
template.decorationIcon.className = `decoration-icon ${ThemeIcon.asClassName(icon)}`;
|
|
499
|
+
if (icon.color) {
|
|
500
|
+
template.decorationIcon.style.color = theme.getColor(icon.color.id)?.toString() ?? '';
|
|
501
|
+
}
|
|
502
|
+
template.decorationIcon.style.display = '';
|
|
503
|
+
template.decorationIcon.style.backgroundImage = '';
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
template.decorationIcon.className = 'decoration-icon';
|
|
507
|
+
template.decorationIcon.style.color = '';
|
|
508
|
+
template.decorationIcon.style.display = '';
|
|
509
|
+
template.decorationIcon.style.backgroundImage = asCSSUrl(icon);
|
|
510
|
+
}
|
|
511
|
+
template.decorationIcon.title = data.tooltip;
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
template.decorationIcon.className = 'decoration-icon';
|
|
515
|
+
template.decorationIcon.style.color = '';
|
|
516
|
+
template.decorationIcon.style.display = 'none';
|
|
517
|
+
template.decorationIcon.style.backgroundImage = '';
|
|
518
|
+
template.decorationIcon.title = '';
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
dispose() {
|
|
522
|
+
this.disposables.dispose();
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
ResourceRenderer = ResourceRenderer_1 = ( __decorate([
|
|
526
|
+
( __param(4, ILabelService)),
|
|
527
|
+
( __param(5, ISCMViewService)),
|
|
528
|
+
( __param(6, IThemeService))
|
|
529
|
+
], ResourceRenderer));
|
|
530
|
+
class ListDelegate {
|
|
531
|
+
constructor(inputRenderer) {
|
|
532
|
+
this.inputRenderer = inputRenderer;
|
|
533
|
+
}
|
|
534
|
+
getHeight(element) {
|
|
535
|
+
if (isSCMInput(element)) {
|
|
536
|
+
return this.inputRenderer.getHeight(element);
|
|
537
|
+
}
|
|
538
|
+
else if (isSCMActionButton(element)) {
|
|
539
|
+
return ActionButtonRenderer.DEFAULT_HEIGHT + 10;
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
return 22;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
getTemplateId(element) {
|
|
546
|
+
if (isSCMRepository(element)) {
|
|
547
|
+
return RepositoryRenderer.TEMPLATE_ID;
|
|
548
|
+
}
|
|
549
|
+
else if (isSCMInput(element)) {
|
|
550
|
+
return InputRenderer.TEMPLATE_ID;
|
|
551
|
+
}
|
|
552
|
+
else if (isSCMActionButton(element)) {
|
|
553
|
+
return ActionButtonRenderer.TEMPLATE_ID;
|
|
554
|
+
}
|
|
555
|
+
else if (ResourceTree.isResourceNode(element) || isSCMResource(element)) {
|
|
556
|
+
return ResourceRenderer.TEMPLATE_ID;
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
return ResourceGroupRenderer.TEMPLATE_ID;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
class SCMTreeFilter {
|
|
564
|
+
filter(element) {
|
|
565
|
+
if (ResourceTree.isResourceNode(element)) {
|
|
566
|
+
return true;
|
|
567
|
+
}
|
|
568
|
+
else if (isSCMResourceGroup(element)) {
|
|
569
|
+
return element.elements.length > 0 || !element.hideWhenEmpty;
|
|
570
|
+
}
|
|
571
|
+
else {
|
|
572
|
+
return true;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
class SCMTreeSorter {
|
|
577
|
+
get viewModel() { return this.viewModelProvider(); }
|
|
578
|
+
constructor(viewModelProvider) {
|
|
579
|
+
this.viewModelProvider = viewModelProvider;
|
|
580
|
+
}
|
|
581
|
+
compare(one, other) {
|
|
582
|
+
if (isSCMRepository(one)) {
|
|
583
|
+
if (!isSCMRepository(other)) {
|
|
584
|
+
throw new Error('Invalid comparison');
|
|
585
|
+
}
|
|
586
|
+
return 0;
|
|
587
|
+
}
|
|
588
|
+
if (isSCMInput(one)) {
|
|
589
|
+
return -1;
|
|
590
|
+
}
|
|
591
|
+
else if (isSCMInput(other)) {
|
|
592
|
+
return 1;
|
|
593
|
+
}
|
|
594
|
+
if (isSCMActionButton(one)) {
|
|
595
|
+
return -1;
|
|
596
|
+
}
|
|
597
|
+
else if (isSCMActionButton(other)) {
|
|
598
|
+
return 1;
|
|
599
|
+
}
|
|
600
|
+
if (isSCMResourceGroup(one)) {
|
|
601
|
+
if (!isSCMResourceGroup(other)) {
|
|
602
|
+
throw new Error('Invalid comparison');
|
|
603
|
+
}
|
|
604
|
+
return 0;
|
|
605
|
+
}
|
|
606
|
+
if (this.viewModel.mode === "list" ) {
|
|
607
|
+
if (this.viewModel.sortKey === "name" ) {
|
|
608
|
+
const oneName = basename(one.sourceUri);
|
|
609
|
+
const otherName = basename(other.sourceUri);
|
|
610
|
+
return compareFileNames(oneName, otherName);
|
|
611
|
+
}
|
|
612
|
+
if (this.viewModel.sortKey === "status" ) {
|
|
613
|
+
const oneTooltip = one.decorations.tooltip ?? '';
|
|
614
|
+
const otherTooltip = other.decorations.tooltip ?? '';
|
|
615
|
+
if (oneTooltip !== otherTooltip) {
|
|
616
|
+
return compare(oneTooltip, otherTooltip);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
const onePath = one.sourceUri.fsPath;
|
|
620
|
+
const otherPath = other.sourceUri.fsPath;
|
|
621
|
+
return comparePaths(onePath, otherPath);
|
|
622
|
+
}
|
|
623
|
+
const oneIsDirectory = ResourceTree.isResourceNode(one);
|
|
624
|
+
const otherIsDirectory = ResourceTree.isResourceNode(other);
|
|
625
|
+
if (oneIsDirectory !== otherIsDirectory) {
|
|
626
|
+
return oneIsDirectory ? -1 : 1;
|
|
627
|
+
}
|
|
628
|
+
const oneName = ResourceTree.isResourceNode(one) ? one.name : basename(one.sourceUri);
|
|
629
|
+
const otherName = ResourceTree.isResourceNode(other) ? other.name : basename(other.sourceUri);
|
|
630
|
+
return compareFileNames(oneName, otherName);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
SCMTreeSorter.__decorator = ( __decorate([
|
|
634
|
+
memoize
|
|
635
|
+
], SCMTreeSorter.prototype, "viewModel", null));
|
|
636
|
+
let SCMTreeKeyboardNavigationLabelProvider = class SCMTreeKeyboardNavigationLabelProvider {
|
|
637
|
+
constructor(viewModelProvider, labelService) {
|
|
638
|
+
this.viewModelProvider = viewModelProvider;
|
|
639
|
+
this.labelService = labelService;
|
|
640
|
+
}
|
|
641
|
+
getKeyboardNavigationLabel(element) {
|
|
642
|
+
if (ResourceTree.isResourceNode(element)) {
|
|
643
|
+
return element.name;
|
|
644
|
+
}
|
|
645
|
+
else if (isSCMRepository(element) || isSCMInput(element) || isSCMActionButton(element)) {
|
|
646
|
+
return undefined;
|
|
647
|
+
}
|
|
648
|
+
else if (isSCMResourceGroup(element)) {
|
|
649
|
+
return element.label;
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
const viewModel = this.viewModelProvider();
|
|
653
|
+
if (viewModel.mode === "list" ) {
|
|
654
|
+
const fileName = basename(element.sourceUri);
|
|
655
|
+
const filePath = this.labelService.getUriLabel(element.sourceUri, { relative: true });
|
|
656
|
+
return [fileName, filePath];
|
|
657
|
+
}
|
|
658
|
+
else {
|
|
659
|
+
return basename(element.sourceUri);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
getCompressedNodeKeyboardNavigationLabel(elements) {
|
|
664
|
+
const folders = elements;
|
|
665
|
+
return ( folders.map(e => e.name)).join('/');
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
SCMTreeKeyboardNavigationLabelProvider = ( __decorate([
|
|
669
|
+
( __param(1, ILabelService))
|
|
670
|
+
], SCMTreeKeyboardNavigationLabelProvider));
|
|
671
|
+
function getSCMResourceId(element) {
|
|
672
|
+
if (ResourceTree.isResourceNode(element)) {
|
|
673
|
+
const group = element.context;
|
|
674
|
+
return `folder:${group.provider.id}/${group.id}/$FOLDER/${( element.uri.toString())}`;
|
|
675
|
+
}
|
|
676
|
+
else if (isSCMRepository(element)) {
|
|
677
|
+
const provider = element.provider;
|
|
678
|
+
return `repo:${provider.id}`;
|
|
679
|
+
}
|
|
680
|
+
else if (isSCMInput(element)) {
|
|
681
|
+
const provider = element.repository.provider;
|
|
682
|
+
return `input:${provider.id}`;
|
|
683
|
+
}
|
|
684
|
+
else if (isSCMActionButton(element)) {
|
|
685
|
+
const provider = element.repository.provider;
|
|
686
|
+
return `actionButton:${provider.id}`;
|
|
687
|
+
}
|
|
688
|
+
else if (isSCMResource(element)) {
|
|
689
|
+
const group = element.resourceGroup;
|
|
690
|
+
const provider = group.provider;
|
|
691
|
+
return `resource:${provider.id}/${group.id}/${( element.sourceUri.toString())}`;
|
|
692
|
+
}
|
|
693
|
+
else {
|
|
694
|
+
const provider = element.provider;
|
|
695
|
+
return `group:${provider.id}/${element.id}`;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
class SCMResourceIdentityProvider {
|
|
699
|
+
getId(element) {
|
|
700
|
+
return getSCMResourceId(element);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
let SCMAccessibilityProvider = class SCMAccessibilityProvider {
|
|
704
|
+
constructor(labelService, workspaceContextService) {
|
|
705
|
+
this.labelService = labelService;
|
|
706
|
+
this.workspaceContextService = workspaceContextService;
|
|
707
|
+
}
|
|
708
|
+
getWidgetAriaLabel() {
|
|
709
|
+
return ( localizeWithPath(
|
|
710
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
711
|
+
'scm',
|
|
712
|
+
"Source Control Management"
|
|
713
|
+
));
|
|
714
|
+
}
|
|
715
|
+
getAriaLabel(element) {
|
|
716
|
+
if (ResourceTree.isResourceNode(element)) {
|
|
717
|
+
return this.labelService.getUriLabel(element.uri, { relative: true, noPrefix: true }) || element.name;
|
|
718
|
+
}
|
|
719
|
+
else if (isSCMRepository(element)) {
|
|
720
|
+
let folderName = '';
|
|
721
|
+
if (element.provider.rootUri) {
|
|
722
|
+
const folder = this.workspaceContextService.getWorkspaceFolder(element.provider.rootUri);
|
|
723
|
+
if (folder?.uri.toString() === ( element.provider.rootUri.toString())) {
|
|
724
|
+
folderName = folder.name;
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
folderName = basename(element.provider.rootUri);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return `${folderName} ${element.provider.label}`;
|
|
731
|
+
}
|
|
732
|
+
else if (isSCMInput(element)) {
|
|
733
|
+
return ( localizeWithPath(
|
|
734
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
735
|
+
'input',
|
|
736
|
+
"Source Control Input"
|
|
737
|
+
));
|
|
738
|
+
}
|
|
739
|
+
else if (isSCMActionButton(element)) {
|
|
740
|
+
return element.button?.command.title ?? '';
|
|
741
|
+
}
|
|
742
|
+
else if (isSCMResourceGroup(element)) {
|
|
743
|
+
return element.label;
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
const result = [];
|
|
747
|
+
result.push(basename(element.sourceUri));
|
|
748
|
+
if (element.decorations.tooltip) {
|
|
749
|
+
result.push(element.decorations.tooltip);
|
|
750
|
+
}
|
|
751
|
+
const path = this.labelService.getUriLabel(dirname(element.sourceUri), { relative: true, noPrefix: true });
|
|
752
|
+
if (path) {
|
|
753
|
+
result.push(path);
|
|
754
|
+
}
|
|
755
|
+
return result.join(', ');
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
SCMAccessibilityProvider = ( __decorate([
|
|
760
|
+
( __param(0, ILabelService)),
|
|
761
|
+
( __param(1, IWorkspaceContextService))
|
|
762
|
+
], SCMAccessibilityProvider));
|
|
763
|
+
function isRepositoryItem(item) {
|
|
764
|
+
return Array.isArray(item.groupItems);
|
|
765
|
+
}
|
|
766
|
+
function asTreeElement(node, forceIncompressible, viewState) {
|
|
767
|
+
const element = (node.childrenCount === 0 && node.element) ? node.element : node;
|
|
768
|
+
const collapsed = viewState ? viewState.collapsed.indexOf(getSCMResourceId(element)) > -1 : false;
|
|
769
|
+
return {
|
|
770
|
+
element,
|
|
771
|
+
children: ( Iterable.map(node.children, node => asTreeElement(node, false, viewState))),
|
|
772
|
+
incompressible: !!node.element || forceIncompressible,
|
|
773
|
+
collapsed,
|
|
774
|
+
collapsible: node.childrenCount > 0
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
const Menus = {
|
|
778
|
+
ViewSort: ( new MenuId('SCMViewSort')),
|
|
779
|
+
Repositories: ( new MenuId('SCMRepositories')),
|
|
780
|
+
};
|
|
781
|
+
const ContextKeys = {
|
|
782
|
+
ViewModelMode: ( new RawContextKey('scmViewModelMode', "list" )),
|
|
783
|
+
ViewModelSortKey: ( new RawContextKey('scmViewModelSortKey', "path" )),
|
|
784
|
+
ViewModelAreAllRepositoriesCollapsed: ( new RawContextKey('scmViewModelAreAllRepositoriesCollapsed', false)),
|
|
785
|
+
ViewModelIsAnyRepositoryCollapsible: ( new RawContextKey('scmViewModelIsAnyRepositoryCollapsible', false)),
|
|
786
|
+
SCMProvider: ( new RawContextKey('scmProvider', undefined)),
|
|
787
|
+
SCMProviderRootUri: ( new RawContextKey('scmProviderRootUri', undefined)),
|
|
788
|
+
SCMProviderHasRootUri: ( new RawContextKey('scmProviderHasRootUri', undefined)),
|
|
789
|
+
RepositoryCount: ( new RawContextKey('scmRepositoryCount', 0)),
|
|
790
|
+
RepositoryVisibilityCount: ( new RawContextKey('scmRepositoryVisibleCount', 0)),
|
|
791
|
+
RepositoryVisibility(repository) {
|
|
792
|
+
return ( new RawContextKey(`scmRepositoryVisible:${repository.provider.id}`, false));
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
MenuRegistry.appendMenuItem(MenuId.SCMTitle, {
|
|
796
|
+
title: ( localizeWithPath(
|
|
797
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
798
|
+
'sortAction',
|
|
799
|
+
"View & Sort"
|
|
800
|
+
)),
|
|
801
|
+
submenu: Menus.ViewSort,
|
|
802
|
+
when: ( ContextKeyExpr.and(( ContextKeyExpr.equals('view', VIEW_PANE_ID)), ( ContextKeys.RepositoryCount.notEqualsTo(0)))),
|
|
803
|
+
group: '0_view&sort'
|
|
804
|
+
});
|
|
805
|
+
MenuRegistry.appendMenuItem(Menus.ViewSort, {
|
|
806
|
+
title: ( localizeWithPath(
|
|
807
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
808
|
+
'repositories',
|
|
809
|
+
"Repositories"
|
|
810
|
+
)),
|
|
811
|
+
submenu: Menus.Repositories,
|
|
812
|
+
group: '0_repositories'
|
|
813
|
+
});
|
|
814
|
+
class RepositoryVisibilityAction extends Action2 {
|
|
815
|
+
constructor(repository) {
|
|
816
|
+
const title = repository.provider.rootUri ? basename(repository.provider.rootUri) : repository.provider.label;
|
|
817
|
+
super({
|
|
818
|
+
id: `workbench.scm.action.toggleRepositoryVisibility.${repository.provider.id}`,
|
|
819
|
+
title,
|
|
820
|
+
f1: false,
|
|
821
|
+
precondition: ( ContextKeyExpr.or(( ContextKeys.RepositoryVisibilityCount.notEqualsTo(1)), ( ContextKeys.RepositoryVisibility(repository).isEqualTo(false)))),
|
|
822
|
+
toggled: ( ContextKeys.RepositoryVisibility(repository).isEqualTo(true)),
|
|
823
|
+
menu: { id: Menus.Repositories, group: '0_repositories' }
|
|
824
|
+
});
|
|
825
|
+
this.repository = repository;
|
|
826
|
+
}
|
|
827
|
+
run(accessor) {
|
|
828
|
+
const scmViewService = accessor.get(ISCMViewService);
|
|
829
|
+
scmViewService.toggleVisibility(this.repository);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
let RepositoryVisibilityActionController = class RepositoryVisibilityActionController {
|
|
833
|
+
constructor(scmViewService, scmService, contextKeyService) {
|
|
834
|
+
this.scmViewService = scmViewService;
|
|
835
|
+
this.contextKeyService = contextKeyService;
|
|
836
|
+
this.items = ( new Map());
|
|
837
|
+
this.disposables = ( new DisposableStore());
|
|
838
|
+
this.repositoryCountContextKey = ContextKeys.RepositoryCount.bindTo(contextKeyService);
|
|
839
|
+
this.repositoryVisibilityCountContextKey = ContextKeys.RepositoryVisibilityCount.bindTo(contextKeyService);
|
|
840
|
+
scmViewService.onDidChangeVisibleRepositories(this.onDidChangeVisibleRepositories, this, this.disposables);
|
|
841
|
+
scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables);
|
|
842
|
+
scmService.onDidRemoveRepository(this.onDidRemoveRepository, this, this.disposables);
|
|
843
|
+
for (const repository of scmService.repositories) {
|
|
844
|
+
this.onDidAddRepository(repository);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
onDidAddRepository(repository) {
|
|
848
|
+
const action = registerAction2(class extends RepositoryVisibilityAction {
|
|
849
|
+
constructor() {
|
|
850
|
+
super(repository);
|
|
851
|
+
}
|
|
852
|
+
});
|
|
853
|
+
const contextKey = ContextKeys.RepositoryVisibility(repository).bindTo(this.contextKeyService);
|
|
854
|
+
contextKey.set(this.scmViewService.isVisible(repository));
|
|
855
|
+
this.items.set(repository, {
|
|
856
|
+
contextKey,
|
|
857
|
+
dispose() {
|
|
858
|
+
contextKey.reset();
|
|
859
|
+
action.dispose();
|
|
860
|
+
}
|
|
861
|
+
});
|
|
862
|
+
this.updateRepositoriesCounts();
|
|
863
|
+
}
|
|
864
|
+
onDidRemoveRepository(repository) {
|
|
865
|
+
this.items.get(repository)?.dispose();
|
|
866
|
+
this.items.delete(repository);
|
|
867
|
+
this.updateRepositoriesCounts();
|
|
868
|
+
}
|
|
869
|
+
onDidChangeVisibleRepositories() {
|
|
870
|
+
let count = 0;
|
|
871
|
+
for (const [repository, item] of this.items) {
|
|
872
|
+
const isVisible = this.scmViewService.isVisible(repository);
|
|
873
|
+
item.contextKey.set(isVisible);
|
|
874
|
+
if (isVisible) {
|
|
875
|
+
count++;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
this.repositoryCountContextKey.set(this.items.size);
|
|
879
|
+
this.repositoryVisibilityCountContextKey.set(count);
|
|
880
|
+
}
|
|
881
|
+
updateRepositoriesCounts() {
|
|
882
|
+
this.repositoryCountContextKey.set(this.items.size);
|
|
883
|
+
this.repositoryVisibilityCountContextKey.set(Iterable.reduce(( this.items.keys()), (r, repository) => r + (this.scmViewService.isVisible(repository) ? 1 : 0), 0));
|
|
884
|
+
}
|
|
885
|
+
dispose() {
|
|
886
|
+
this.disposables.dispose();
|
|
887
|
+
dispose(( this.items.values()));
|
|
888
|
+
this.items.clear();
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
RepositoryVisibilityActionController = ( __decorate([
|
|
892
|
+
( __param(0, ISCMViewService)),
|
|
893
|
+
( __param(1, ISCMService)),
|
|
894
|
+
( __param(2, IContextKeyService))
|
|
895
|
+
], RepositoryVisibilityActionController));
|
|
896
|
+
let ViewModel = class ViewModel {
|
|
897
|
+
get mode() { return this._mode; }
|
|
898
|
+
set mode(mode) {
|
|
899
|
+
if (this._mode === mode) {
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
this._mode = mode;
|
|
903
|
+
for (const [, item] of this.items) {
|
|
904
|
+
for (const groupItem of item.groupItems) {
|
|
905
|
+
groupItem.tree.clear();
|
|
906
|
+
if (mode === "tree" ) {
|
|
907
|
+
for (const resource of groupItem.resources) {
|
|
908
|
+
groupItem.tree.add(resource.sourceUri, resource);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
this.sortKey = this.getViewModelSortKey();
|
|
914
|
+
this.refresh();
|
|
915
|
+
this._onDidChangeMode.fire(mode);
|
|
916
|
+
this.modeContextKey.set(mode);
|
|
917
|
+
this.storageService.store(`scm.viewMode`, mode, 1 , 0 );
|
|
918
|
+
}
|
|
919
|
+
get sortKey() { return this._sortKey; }
|
|
920
|
+
set sortKey(sortKey) {
|
|
921
|
+
if (this._sortKey === sortKey) {
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
this._sortKey = sortKey;
|
|
925
|
+
this.refresh();
|
|
926
|
+
this._onDidChangeSortKey.fire(sortKey);
|
|
927
|
+
this.sortKeyContextKey.set(sortKey);
|
|
928
|
+
if (this._mode === "list" ) {
|
|
929
|
+
this.storageService.store(`scm.viewSortKey`, sortKey, 1 , 0 );
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
get treeViewState() {
|
|
933
|
+
if (this.visible && this._treeViewStateIsStale) {
|
|
934
|
+
this.updateViewState();
|
|
935
|
+
this._treeViewStateIsStale = false;
|
|
936
|
+
}
|
|
937
|
+
return this._treeViewState;
|
|
938
|
+
}
|
|
939
|
+
constructor(tree, inputRenderer, instantiationService, editorService, configurationService, scmViewService, storageService, uriIdentityService, contextKeyService) {
|
|
940
|
+
this.tree = tree;
|
|
941
|
+
this.inputRenderer = inputRenderer;
|
|
942
|
+
this.instantiationService = instantiationService;
|
|
943
|
+
this.editorService = editorService;
|
|
944
|
+
this.configurationService = configurationService;
|
|
945
|
+
this.scmViewService = scmViewService;
|
|
946
|
+
this.storageService = storageService;
|
|
947
|
+
this.uriIdentityService = uriIdentityService;
|
|
948
|
+
this._onDidChangeMode = ( new Emitter());
|
|
949
|
+
this.onDidChangeMode = this._onDidChangeMode.event;
|
|
950
|
+
this._onDidChangeSortKey = ( new Emitter());
|
|
951
|
+
this.onDidChangeSortKey = this._onDidChangeSortKey.event;
|
|
952
|
+
this.visible = false;
|
|
953
|
+
this._treeViewStateIsStale = false;
|
|
954
|
+
this.items = ( new Map());
|
|
955
|
+
this.visibilityDisposables = ( new DisposableStore());
|
|
956
|
+
this.alwaysShowRepositories = false;
|
|
957
|
+
this.showActionButton = false;
|
|
958
|
+
this.firstVisible = true;
|
|
959
|
+
this.disposables = ( new DisposableStore());
|
|
960
|
+
this._mode = this.getViewModelMode();
|
|
961
|
+
this._sortKey = this.getViewModelSortKey();
|
|
962
|
+
const storageViewState = this.storageService.get(`scm.viewState`, 1 );
|
|
963
|
+
if (storageViewState) {
|
|
964
|
+
try {
|
|
965
|
+
this._treeViewState = JSON.parse(storageViewState);
|
|
966
|
+
}
|
|
967
|
+
catch { }
|
|
968
|
+
}
|
|
969
|
+
this.modeContextKey = ContextKeys.ViewModelMode.bindTo(contextKeyService);
|
|
970
|
+
this.modeContextKey.set(this._mode);
|
|
971
|
+
this.sortKeyContextKey = ContextKeys.ViewModelSortKey.bindTo(contextKeyService);
|
|
972
|
+
this.sortKeyContextKey.set(this._sortKey);
|
|
973
|
+
this.areAllRepositoriesCollapsedContextKey = ContextKeys.ViewModelAreAllRepositoriesCollapsed.bindTo(contextKeyService);
|
|
974
|
+
this.isAnyRepositoryCollapsibleContextKey = ContextKeys.ViewModelIsAnyRepositoryCollapsible.bindTo(contextKeyService);
|
|
975
|
+
this.scmProviderContextKey = ContextKeys.SCMProvider.bindTo(contextKeyService);
|
|
976
|
+
this.scmProviderRootUriContextKey = ContextKeys.SCMProviderRootUri.bindTo(contextKeyService);
|
|
977
|
+
this.scmProviderHasRootUriContextKey = ContextKeys.SCMProviderHasRootUri.bindTo(contextKeyService);
|
|
978
|
+
configurationService.onDidChangeConfiguration(this.onDidChangeConfiguration, this, this.disposables);
|
|
979
|
+
this.onDidChangeConfiguration();
|
|
980
|
+
Event.filter(this.tree.onDidChangeCollapseState, e => isSCMRepository(e.node.element), this.disposables)(this.updateRepositoryCollapseAllContextKeys, this, this.disposables);
|
|
981
|
+
this.disposables.add(this.tree.onDidChangeCollapseState(() => this._treeViewStateIsStale = true));
|
|
982
|
+
this.disposables.add(this.storageService.onWillSaveState(e => {
|
|
983
|
+
if (e.reason === WillSaveStateReason.SHUTDOWN) {
|
|
984
|
+
this.storageService.store(`scm.viewState`, JSON.stringify(this.treeViewState), 1 , 1 );
|
|
985
|
+
}
|
|
986
|
+
this.mode = this.getViewModelMode();
|
|
987
|
+
this.sortKey = this.getViewModelSortKey();
|
|
988
|
+
}));
|
|
989
|
+
this.disposables.add(this.storageService.onDidChangeValue(1 , undefined, this.disposables)(e => {
|
|
990
|
+
switch (e.key) {
|
|
991
|
+
case 'scm.viewMode':
|
|
992
|
+
this.mode = this.getViewModelMode();
|
|
993
|
+
break;
|
|
994
|
+
case 'scm.viewSortKey':
|
|
995
|
+
this.sortKey = this.getViewModelSortKey();
|
|
996
|
+
break;
|
|
997
|
+
}
|
|
998
|
+
}));
|
|
999
|
+
}
|
|
1000
|
+
onDidChangeConfiguration(e) {
|
|
1001
|
+
if (!e || e.affectsConfiguration('scm.alwaysShowRepositories') || e.affectsConfiguration('scm.showActionButton')) {
|
|
1002
|
+
this.alwaysShowRepositories = this.configurationService.getValue('scm.alwaysShowRepositories');
|
|
1003
|
+
this.showActionButton = this.configurationService.getValue('scm.showActionButton');
|
|
1004
|
+
this.refresh();
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
_onDidChangeVisibleRepositories({ added, removed }) {
|
|
1008
|
+
for (const repository of added) {
|
|
1009
|
+
const disposable = combinedDisposable(repository.provider.groups.onDidSplice(splice => this._onDidSpliceGroups(item, splice)), repository.input.onDidChangeVisibility(() => this.refresh(item)), repository.provider.onDidChange(() => {
|
|
1010
|
+
if (this.showActionButton) {
|
|
1011
|
+
this.refresh(item);
|
|
1012
|
+
}
|
|
1013
|
+
}));
|
|
1014
|
+
const groupItems = ( repository.provider.groups.elements.map(group => this.createGroupItem(group)));
|
|
1015
|
+
const item = {
|
|
1016
|
+
element: repository, groupItems, dispose() {
|
|
1017
|
+
dispose(this.groupItems);
|
|
1018
|
+
disposable.dispose();
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1021
|
+
this.items.set(repository, item);
|
|
1022
|
+
}
|
|
1023
|
+
for (const repository of removed) {
|
|
1024
|
+
const item = this.items.get(repository);
|
|
1025
|
+
item.dispose();
|
|
1026
|
+
this.items.delete(repository);
|
|
1027
|
+
}
|
|
1028
|
+
this.refresh();
|
|
1029
|
+
}
|
|
1030
|
+
_onDidSpliceGroups(item, { start, deleteCount, toInsert }) {
|
|
1031
|
+
const itemsToInsert = ( toInsert.map(group => this.createGroupItem(group)));
|
|
1032
|
+
const itemsToDispose = item.groupItems.splice(start, deleteCount, ...itemsToInsert);
|
|
1033
|
+
for (const item of itemsToDispose) {
|
|
1034
|
+
item.dispose();
|
|
1035
|
+
}
|
|
1036
|
+
this.refresh();
|
|
1037
|
+
}
|
|
1038
|
+
createGroupItem(group) {
|
|
1039
|
+
const tree = ( new ResourceTree(
|
|
1040
|
+
group,
|
|
1041
|
+
group.provider.rootUri || URI.file('/'),
|
|
1042
|
+
this.uriIdentityService.extUri
|
|
1043
|
+
));
|
|
1044
|
+
const resources = [...group.elements];
|
|
1045
|
+
const disposable = combinedDisposable(group.onDidChange(() => this.tree.refilter()), group.onDidSplice(splice => this._onDidSpliceGroup(item, splice)));
|
|
1046
|
+
const item = { element: group, resources, tree, dispose() { disposable.dispose(); } };
|
|
1047
|
+
if (this._mode === "tree" ) {
|
|
1048
|
+
for (const resource of resources) {
|
|
1049
|
+
item.tree.add(resource.sourceUri, resource);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
return item;
|
|
1053
|
+
}
|
|
1054
|
+
_onDidSpliceGroup(item, { start, deleteCount, toInsert }) {
|
|
1055
|
+
const before = item.resources.length;
|
|
1056
|
+
const deleted = item.resources.splice(start, deleteCount, ...toInsert);
|
|
1057
|
+
const after = item.resources.length;
|
|
1058
|
+
if (this._mode === "tree" ) {
|
|
1059
|
+
for (const resource of deleted) {
|
|
1060
|
+
item.tree.delete(resource.sourceUri);
|
|
1061
|
+
}
|
|
1062
|
+
for (const resource of toInsert) {
|
|
1063
|
+
item.tree.add(resource.sourceUri, resource);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
if (before !== after && (before === 0 || after === 0)) {
|
|
1067
|
+
this.refresh();
|
|
1068
|
+
}
|
|
1069
|
+
else {
|
|
1070
|
+
this.refresh(item);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
setVisible(visible) {
|
|
1074
|
+
if (visible) {
|
|
1075
|
+
this.scmViewService.onDidChangeVisibleRepositories(this._onDidChangeVisibleRepositories, this, this.visibilityDisposables);
|
|
1076
|
+
this._onDidChangeVisibleRepositories({ added: this.scmViewService.visibleRepositories, removed: Iterable.empty() });
|
|
1077
|
+
if (typeof this.scrollTop === 'number') {
|
|
1078
|
+
this.tree.scrollTop = this.scrollTop;
|
|
1079
|
+
this.scrollTop = undefined;
|
|
1080
|
+
}
|
|
1081
|
+
this.editorService.onDidActiveEditorChange(this.onDidActiveEditorChange, this, this.visibilityDisposables);
|
|
1082
|
+
this.onDidActiveEditorChange();
|
|
1083
|
+
}
|
|
1084
|
+
else {
|
|
1085
|
+
this.updateViewState();
|
|
1086
|
+
this.visibilityDisposables.clear();
|
|
1087
|
+
this._onDidChangeVisibleRepositories({ added: Iterable.empty(), removed: [...( this.items.keys())] });
|
|
1088
|
+
this.scrollTop = this.tree.scrollTop;
|
|
1089
|
+
}
|
|
1090
|
+
this.visible = visible;
|
|
1091
|
+
this.updateRepositoryCollapseAllContextKeys();
|
|
1092
|
+
}
|
|
1093
|
+
refresh(item) {
|
|
1094
|
+
if (!this.alwaysShowRepositories && this.items.size === 1) {
|
|
1095
|
+
const provider = Iterable.first(( this.items.values())).element.provider;
|
|
1096
|
+
this.scmProviderContextKey.set(provider.contextValue);
|
|
1097
|
+
this.scmProviderRootUriContextKey.set(provider.rootUri?.toString());
|
|
1098
|
+
this.scmProviderHasRootUriContextKey.set(!!provider.rootUri);
|
|
1099
|
+
}
|
|
1100
|
+
else {
|
|
1101
|
+
this.scmProviderContextKey.set(undefined);
|
|
1102
|
+
this.scmProviderRootUriContextKey.set(undefined);
|
|
1103
|
+
this.scmProviderHasRootUriContextKey.set(false);
|
|
1104
|
+
}
|
|
1105
|
+
const focusedInput = this.inputRenderer.getFocusedInput();
|
|
1106
|
+
if (!this.alwaysShowRepositories && (this.items.size === 1 && (!item || isRepositoryItem(item)))) {
|
|
1107
|
+
const item = Iterable.first(( this.items.values()));
|
|
1108
|
+
this.tree.setChildren(null, this.render(item, this.treeViewState).children);
|
|
1109
|
+
}
|
|
1110
|
+
else if (item) {
|
|
1111
|
+
this.tree.setChildren(item.element, this.render(item, this.treeViewState).children);
|
|
1112
|
+
}
|
|
1113
|
+
else {
|
|
1114
|
+
const items = coalesce(( this.scmViewService.visibleRepositories.map(r => this.items.get(r))));
|
|
1115
|
+
this.tree.setChildren(null, ( items.map(item => this.render(item, this.treeViewState))));
|
|
1116
|
+
}
|
|
1117
|
+
if (focusedInput) {
|
|
1118
|
+
this.inputRenderer.getRenderedInputWidget(focusedInput)?.focus();
|
|
1119
|
+
}
|
|
1120
|
+
this.updateRepositoryCollapseAllContextKeys();
|
|
1121
|
+
}
|
|
1122
|
+
render(item, treeViewState) {
|
|
1123
|
+
if (isRepositoryItem(item)) {
|
|
1124
|
+
const children = [];
|
|
1125
|
+
const hasSomeChanges = ( item.groupItems.some(item => item.element.elements.length > 0));
|
|
1126
|
+
if (item.element.input.visible) {
|
|
1127
|
+
children.push({ element: item.element.input, incompressible: true, collapsible: false });
|
|
1128
|
+
}
|
|
1129
|
+
if (hasSomeChanges || (this.items.size === 1 && (!this.showActionButton || !item.element.provider.actionButton))) {
|
|
1130
|
+
children.push(...( item.groupItems.map(i => this.render(i, treeViewState))));
|
|
1131
|
+
}
|
|
1132
|
+
if (this.showActionButton && item.element.provider.actionButton) {
|
|
1133
|
+
const button = {
|
|
1134
|
+
element: {
|
|
1135
|
+
type: 'actionButton',
|
|
1136
|
+
repository: item.element,
|
|
1137
|
+
button: item.element.provider.actionButton,
|
|
1138
|
+
},
|
|
1139
|
+
incompressible: true,
|
|
1140
|
+
collapsible: false
|
|
1141
|
+
};
|
|
1142
|
+
children.push(button);
|
|
1143
|
+
}
|
|
1144
|
+
const collapsed = treeViewState ? treeViewState.collapsed.indexOf(getSCMResourceId(item.element)) > -1 : false;
|
|
1145
|
+
return { element: item.element, children, incompressible: true, collapsed, collapsible: true };
|
|
1146
|
+
}
|
|
1147
|
+
else {
|
|
1148
|
+
const children = this.mode === "list"
|
|
1149
|
+
? ( Iterable.map(item.resources, element => ({ element, incompressible: true })))
|
|
1150
|
+
: ( Iterable.map(item.tree.root.children, node => asTreeElement(node, true, treeViewState)));
|
|
1151
|
+
const collapsed = treeViewState ? treeViewState.collapsed.indexOf(getSCMResourceId(item.element)) > -1 : false;
|
|
1152
|
+
return { element: item.element, children, incompressible: true, collapsed, collapsible: true };
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
updateViewState() {
|
|
1156
|
+
const collapsed = [];
|
|
1157
|
+
const visit = (node) => {
|
|
1158
|
+
if (node.element && node.collapsible && node.collapsed) {
|
|
1159
|
+
collapsed.push(getSCMResourceId(node.element));
|
|
1160
|
+
}
|
|
1161
|
+
for (const child of node.children) {
|
|
1162
|
+
visit(child);
|
|
1163
|
+
}
|
|
1164
|
+
};
|
|
1165
|
+
visit(this.tree.getNode());
|
|
1166
|
+
this._treeViewState = { collapsed };
|
|
1167
|
+
}
|
|
1168
|
+
onDidActiveEditorChange() {
|
|
1169
|
+
if (!this.configurationService.getValue('scm.autoReveal')) {
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
if (this.firstVisible) {
|
|
1173
|
+
this.firstVisible = false;
|
|
1174
|
+
this.visibilityDisposables.add(disposableTimeout(() => this.onDidActiveEditorChange(), 250));
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
const uri = EditorResourceAccessor.getOriginalUri(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY });
|
|
1178
|
+
if (!uri) {
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
for (const repository of this.scmViewService.visibleRepositories) {
|
|
1182
|
+
const item = this.items.get(repository);
|
|
1183
|
+
if (!item) {
|
|
1184
|
+
continue;
|
|
1185
|
+
}
|
|
1186
|
+
for (let j = item.groupItems.length - 1; j >= 0; j--) {
|
|
1187
|
+
const groupItem = item.groupItems[j];
|
|
1188
|
+
const resource = this.mode === "tree"
|
|
1189
|
+
? groupItem.tree.getNode(uri)?.element
|
|
1190
|
+
: groupItem.resources.find(r => this.uriIdentityService.extUri.isEqual(r.sourceUri, uri));
|
|
1191
|
+
if (resource) {
|
|
1192
|
+
this.tree.reveal(resource);
|
|
1193
|
+
this.tree.setSelection([resource]);
|
|
1194
|
+
this.tree.setFocus([resource]);
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
focus() {
|
|
1201
|
+
if (this.tree.getFocus().length === 0) {
|
|
1202
|
+
for (const repository of this.scmViewService.visibleRepositories) {
|
|
1203
|
+
const widget = this.inputRenderer.getRenderedInputWidget(repository.input);
|
|
1204
|
+
if (widget) {
|
|
1205
|
+
widget.focus();
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
this.tree.domFocus();
|
|
1211
|
+
}
|
|
1212
|
+
updateRepositoryCollapseAllContextKeys() {
|
|
1213
|
+
if (!this.visible || this.scmViewService.visibleRepositories.length === 1) {
|
|
1214
|
+
this.isAnyRepositoryCollapsibleContextKey.set(false);
|
|
1215
|
+
this.areAllRepositoriesCollapsedContextKey.set(false);
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
this.isAnyRepositoryCollapsibleContextKey.set(( this.scmViewService.visibleRepositories.some(r => this.tree.hasElement(r) && this.tree.isCollapsible(r))));
|
|
1219
|
+
this.areAllRepositoriesCollapsedContextKey.set(this.scmViewService.visibleRepositories.every(r => this.tree.hasElement(r) && (!this.tree.isCollapsible(r) || this.tree.isCollapsed(r))));
|
|
1220
|
+
}
|
|
1221
|
+
collapseAllRepositories() {
|
|
1222
|
+
for (const repository of this.scmViewService.visibleRepositories) {
|
|
1223
|
+
if (this.tree.isCollapsible(repository)) {
|
|
1224
|
+
this.tree.collapse(repository);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
expandAllRepositories() {
|
|
1229
|
+
for (const repository of this.scmViewService.visibleRepositories) {
|
|
1230
|
+
if (this.tree.isCollapsible(repository)) {
|
|
1231
|
+
this.tree.expand(repository);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
getViewModelMode() {
|
|
1236
|
+
let mode = this.configurationService.getValue('scm.defaultViewMode') === 'list' ? "list" : "tree" ;
|
|
1237
|
+
const storageMode = this.storageService.get(`scm.viewMode`, 1 );
|
|
1238
|
+
if (typeof storageMode === 'string') {
|
|
1239
|
+
mode = storageMode;
|
|
1240
|
+
}
|
|
1241
|
+
return mode;
|
|
1242
|
+
}
|
|
1243
|
+
getViewModelSortKey() {
|
|
1244
|
+
if (this._mode === "tree" ) {
|
|
1245
|
+
return "path" ;
|
|
1246
|
+
}
|
|
1247
|
+
let viewSortKey;
|
|
1248
|
+
const viewSortKeyString = this.configurationService.getValue('scm.defaultViewSortKey');
|
|
1249
|
+
switch (viewSortKeyString) {
|
|
1250
|
+
case 'name':
|
|
1251
|
+
viewSortKey = "name" ;
|
|
1252
|
+
break;
|
|
1253
|
+
case 'status':
|
|
1254
|
+
viewSortKey = "status" ;
|
|
1255
|
+
break;
|
|
1256
|
+
default:
|
|
1257
|
+
viewSortKey = "path" ;
|
|
1258
|
+
break;
|
|
1259
|
+
}
|
|
1260
|
+
const storageSortKey = this.storageService.get(`scm.viewSortKey`, 1 );
|
|
1261
|
+
if (typeof storageSortKey === 'string') {
|
|
1262
|
+
viewSortKey = storageSortKey;
|
|
1263
|
+
}
|
|
1264
|
+
return viewSortKey;
|
|
1265
|
+
}
|
|
1266
|
+
dispose() {
|
|
1267
|
+
this.visibilityDisposables.dispose();
|
|
1268
|
+
this.disposables.dispose();
|
|
1269
|
+
dispose(( this.items.values()));
|
|
1270
|
+
this.items.clear();
|
|
1271
|
+
}
|
|
1272
|
+
};
|
|
1273
|
+
ViewModel = ( __decorate([
|
|
1274
|
+
( __param(2, IInstantiationService)),
|
|
1275
|
+
( __param(3, IEditorService)),
|
|
1276
|
+
( __param(4, IConfigurationService)),
|
|
1277
|
+
( __param(5, ISCMViewService)),
|
|
1278
|
+
( __param(6, IStorageService)),
|
|
1279
|
+
( __param(7, IUriIdentityService)),
|
|
1280
|
+
( __param(8, IContextKeyService))
|
|
1281
|
+
], ViewModel));
|
|
1282
|
+
class SetListViewModeAction extends ViewAction {
|
|
1283
|
+
constructor(menu = {}) {
|
|
1284
|
+
super({
|
|
1285
|
+
id: 'workbench.scm.action.setListViewMode',
|
|
1286
|
+
title: ( localizeWithPath(
|
|
1287
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
1288
|
+
'setListViewMode',
|
|
1289
|
+
"View as List"
|
|
1290
|
+
)),
|
|
1291
|
+
viewId: VIEW_PANE_ID,
|
|
1292
|
+
f1: false,
|
|
1293
|
+
icon: Codicon.listTree,
|
|
1294
|
+
toggled: ( ContextKeys.ViewModelMode.isEqualTo("list" )),
|
|
1295
|
+
menu: { id: Menus.ViewSort, group: '1_viewmode', ...menu }
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
async runInView(_, view) {
|
|
1299
|
+
view.viewModel.mode = "list" ;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
class SetListViewModeNavigationAction extends SetListViewModeAction {
|
|
1303
|
+
constructor() {
|
|
1304
|
+
super({
|
|
1305
|
+
id: MenuId.SCMTitle,
|
|
1306
|
+
when: ( ContextKeyExpr.and(( ContextKeyExpr.equals('view', VIEW_PANE_ID)), ( ContextKeys.RepositoryCount.notEqualsTo(0)), ( ContextKeys.ViewModelMode.isEqualTo("tree" )))),
|
|
1307
|
+
group: 'navigation',
|
|
1308
|
+
order: -1000
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
class SetTreeViewModeAction extends ViewAction {
|
|
1313
|
+
constructor(menu = {}) {
|
|
1314
|
+
super({
|
|
1315
|
+
id: 'workbench.scm.action.setTreeViewMode',
|
|
1316
|
+
title: ( localizeWithPath(
|
|
1317
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
1318
|
+
'setTreeViewMode',
|
|
1319
|
+
"View as Tree"
|
|
1320
|
+
)),
|
|
1321
|
+
viewId: VIEW_PANE_ID,
|
|
1322
|
+
f1: false,
|
|
1323
|
+
icon: Codicon.listFlat,
|
|
1324
|
+
toggled: ( ContextKeys.ViewModelMode.isEqualTo("tree" )),
|
|
1325
|
+
menu: { id: Menus.ViewSort, group: '1_viewmode', ...menu }
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1328
|
+
async runInView(_, view) {
|
|
1329
|
+
view.viewModel.mode = "tree" ;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
class SetTreeViewModeNavigationAction extends SetTreeViewModeAction {
|
|
1333
|
+
constructor() {
|
|
1334
|
+
super({
|
|
1335
|
+
id: MenuId.SCMTitle,
|
|
1336
|
+
when: ( ContextKeyExpr.and(( ContextKeyExpr.equals('view', VIEW_PANE_ID)), ( ContextKeys.RepositoryCount.notEqualsTo(0)), ( ContextKeys.ViewModelMode.isEqualTo("list" )))),
|
|
1337
|
+
group: 'navigation',
|
|
1338
|
+
order: -1000
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
registerAction2(SetListViewModeAction);
|
|
1343
|
+
registerAction2(SetTreeViewModeAction);
|
|
1344
|
+
registerAction2(SetListViewModeNavigationAction);
|
|
1345
|
+
registerAction2(SetTreeViewModeNavigationAction);
|
|
1346
|
+
class RepositorySortAction extends ViewAction {
|
|
1347
|
+
constructor(sortKey, title) {
|
|
1348
|
+
super({
|
|
1349
|
+
id: `workbench.scm.action.repositories.setSortKey.${sortKey}`,
|
|
1350
|
+
title,
|
|
1351
|
+
viewId: VIEW_PANE_ID,
|
|
1352
|
+
f1: false,
|
|
1353
|
+
toggled: ( RepositoryContextKeys.RepositorySortKey.isEqualTo(sortKey)),
|
|
1354
|
+
menu: [
|
|
1355
|
+
{
|
|
1356
|
+
id: Menus.Repositories,
|
|
1357
|
+
group: '1_sort'
|
|
1358
|
+
},
|
|
1359
|
+
{
|
|
1360
|
+
id: MenuId.ViewTitle,
|
|
1361
|
+
when: ( ContextKeyExpr.equals('view', REPOSITORIES_VIEW_PANE_ID)),
|
|
1362
|
+
group: '1_sort',
|
|
1363
|
+
},
|
|
1364
|
+
]
|
|
1365
|
+
});
|
|
1366
|
+
this.sortKey = sortKey;
|
|
1367
|
+
}
|
|
1368
|
+
runInView(accessor) {
|
|
1369
|
+
accessor.get(ISCMViewService).toggleSortKey(this.sortKey);
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
class RepositorySortByDiscoveryTimeAction extends RepositorySortAction {
|
|
1373
|
+
constructor() {
|
|
1374
|
+
super("discoveryTime" , ( localizeWithPath(
|
|
1375
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
1376
|
+
'repositorySortByDiscoveryTime',
|
|
1377
|
+
"Sort by Discovery Time"
|
|
1378
|
+
)));
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
class RepositorySortByNameAction extends RepositorySortAction {
|
|
1382
|
+
constructor() {
|
|
1383
|
+
super("name" , ( localizeWithPath(
|
|
1384
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
1385
|
+
'repositorySortByName',
|
|
1386
|
+
"Sort by Name"
|
|
1387
|
+
)));
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
class RepositorySortByPathAction extends RepositorySortAction {
|
|
1391
|
+
constructor() {
|
|
1392
|
+
super("path" , ( localizeWithPath(
|
|
1393
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
1394
|
+
'repositorySortByPath',
|
|
1395
|
+
"Sort by Path"
|
|
1396
|
+
)));
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
registerAction2(RepositorySortByDiscoveryTimeAction);
|
|
1400
|
+
registerAction2(RepositorySortByNameAction);
|
|
1401
|
+
registerAction2(RepositorySortByPathAction);
|
|
1402
|
+
class SetSortKeyAction extends ViewAction {
|
|
1403
|
+
constructor(sortKey, title) {
|
|
1404
|
+
super({
|
|
1405
|
+
id: `workbench.scm.action.setSortKey.${sortKey}`,
|
|
1406
|
+
title,
|
|
1407
|
+
viewId: VIEW_PANE_ID,
|
|
1408
|
+
f1: false,
|
|
1409
|
+
toggled: ( ContextKeys.ViewModelSortKey.isEqualTo(sortKey)),
|
|
1410
|
+
precondition: ( ContextKeys.ViewModelMode.isEqualTo("list" )),
|
|
1411
|
+
menu: { id: Menus.ViewSort, group: '2_sort' }
|
|
1412
|
+
});
|
|
1413
|
+
this.sortKey = sortKey;
|
|
1414
|
+
}
|
|
1415
|
+
async runInView(_, view) {
|
|
1416
|
+
view.viewModel.sortKey = this.sortKey;
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
class SetSortByNameAction extends SetSortKeyAction {
|
|
1420
|
+
constructor() {
|
|
1421
|
+
super("name" , ( localizeWithPath(
|
|
1422
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
1423
|
+
'sortChangesByName',
|
|
1424
|
+
"Sort Changes by Name"
|
|
1425
|
+
)));
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
class SetSortByPathAction extends SetSortKeyAction {
|
|
1429
|
+
constructor() {
|
|
1430
|
+
super("path" , ( localizeWithPath(
|
|
1431
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
1432
|
+
'sortChangesByPath',
|
|
1433
|
+
"Sort Changes by Path"
|
|
1434
|
+
)));
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
class SetSortByStatusAction extends SetSortKeyAction {
|
|
1438
|
+
constructor() {
|
|
1439
|
+
super("status" , ( localizeWithPath(
|
|
1440
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
1441
|
+
'sortChangesByStatus',
|
|
1442
|
+
"Sort Changes by Status"
|
|
1443
|
+
)));
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
registerAction2(SetSortByNameAction);
|
|
1447
|
+
registerAction2(SetSortByPathAction);
|
|
1448
|
+
registerAction2(SetSortByStatusAction);
|
|
1449
|
+
class CollapseAllRepositoriesAction extends ViewAction {
|
|
1450
|
+
constructor() {
|
|
1451
|
+
super({
|
|
1452
|
+
id: `workbench.scm.action.collapseAllRepositories`,
|
|
1453
|
+
title: ( localizeWithPath(
|
|
1454
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
1455
|
+
'collapse all',
|
|
1456
|
+
"Collapse All Repositories"
|
|
1457
|
+
)),
|
|
1458
|
+
viewId: VIEW_PANE_ID,
|
|
1459
|
+
f1: false,
|
|
1460
|
+
icon: Codicon.collapseAll,
|
|
1461
|
+
menu: {
|
|
1462
|
+
id: MenuId.SCMTitle,
|
|
1463
|
+
group: 'navigation',
|
|
1464
|
+
when: ( ContextKeyExpr.and(( ContextKeyExpr.equals('view', VIEW_PANE_ID)), ( ContextKeys.ViewModelIsAnyRepositoryCollapsible.isEqualTo(true)), ( ContextKeys.ViewModelAreAllRepositoriesCollapsed.isEqualTo(false))))
|
|
1465
|
+
}
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
async runInView(_, view) {
|
|
1469
|
+
view.viewModel.collapseAllRepositories();
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
class ExpandAllRepositoriesAction extends ViewAction {
|
|
1473
|
+
constructor() {
|
|
1474
|
+
super({
|
|
1475
|
+
id: `workbench.scm.action.expandAllRepositories`,
|
|
1476
|
+
title: ( localizeWithPath(
|
|
1477
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
1478
|
+
'expand all',
|
|
1479
|
+
"Expand All Repositories"
|
|
1480
|
+
)),
|
|
1481
|
+
viewId: VIEW_PANE_ID,
|
|
1482
|
+
f1: false,
|
|
1483
|
+
icon: Codicon.expandAll,
|
|
1484
|
+
menu: {
|
|
1485
|
+
id: MenuId.SCMTitle,
|
|
1486
|
+
group: 'navigation',
|
|
1487
|
+
when: ( ContextKeyExpr.and(( ContextKeyExpr.equals('view', VIEW_PANE_ID)), ( ContextKeys.ViewModelIsAnyRepositoryCollapsible.isEqualTo(true)), ( ContextKeys.ViewModelAreAllRepositoriesCollapsed.isEqualTo(true))))
|
|
1488
|
+
}
|
|
1489
|
+
});
|
|
1490
|
+
}
|
|
1491
|
+
async runInView(_, view) {
|
|
1492
|
+
view.viewModel.expandAllRepositories();
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
registerAction2(CollapseAllRepositoriesAction);
|
|
1496
|
+
registerAction2(ExpandAllRepositoriesAction);
|
|
1497
|
+
let SCMInputWidget = class SCMInputWidget {
|
|
1498
|
+
static { SCMInputWidget_1 = this; }
|
|
1499
|
+
static { this.ValidationTimeouts = {
|
|
1500
|
+
[2 ]: 5000,
|
|
1501
|
+
[1 ]: 8000,
|
|
1502
|
+
[0 ]: 10000
|
|
1503
|
+
}; }
|
|
1504
|
+
get input() {
|
|
1505
|
+
return this.model?.input;
|
|
1506
|
+
}
|
|
1507
|
+
async setInput(input) {
|
|
1508
|
+
if (input === this.input) {
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1511
|
+
this.clearValidation();
|
|
1512
|
+
this.editorContainer.classList.remove('synthetic-focus');
|
|
1513
|
+
this.repositoryDisposables.clear();
|
|
1514
|
+
this.repositoryIdContextKey.set(input?.repository.id);
|
|
1515
|
+
if (!input) {
|
|
1516
|
+
this.model?.textModelRef?.dispose();
|
|
1517
|
+
this.inputEditor.setModel(undefined);
|
|
1518
|
+
this.model = undefined;
|
|
1519
|
+
return;
|
|
1520
|
+
}
|
|
1521
|
+
const uri = input.repository.provider.inputBoxDocumentUri;
|
|
1522
|
+
if (this.configurationService.getValue('editor.wordBasedSuggestions', { resource: uri }) !== false) {
|
|
1523
|
+
this.configurationService.updateValue('editor.wordBasedSuggestions', false, { resource: uri }, 8 );
|
|
1524
|
+
}
|
|
1525
|
+
const modelValue = { input, textModelRef: undefined };
|
|
1526
|
+
this.model = modelValue;
|
|
1527
|
+
const modelRef = await this.textModelService.createModelReference(uri);
|
|
1528
|
+
if (this.model !== modelValue) {
|
|
1529
|
+
modelRef.dispose();
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
modelValue.textModelRef = modelRef;
|
|
1533
|
+
const textModel = modelRef.object.textEditorModel;
|
|
1534
|
+
this.inputEditor.setModel(textModel);
|
|
1535
|
+
const validationDelayer = ( new ThrottledDelayer(200));
|
|
1536
|
+
const validate = async () => {
|
|
1537
|
+
const position = this.inputEditor.getSelection()?.getStartPosition();
|
|
1538
|
+
const offset = position && textModel.getOffsetAt(position);
|
|
1539
|
+
const value = textModel.getValue();
|
|
1540
|
+
this.setValidation(await input.validateInput(value, offset || 0));
|
|
1541
|
+
};
|
|
1542
|
+
const triggerValidation = () => validationDelayer.trigger(validate);
|
|
1543
|
+
this.repositoryDisposables.add(validationDelayer);
|
|
1544
|
+
this.repositoryDisposables.add(this.inputEditor.onDidChangeCursorPosition(triggerValidation));
|
|
1545
|
+
const opts = this.modelService.getCreationOptions(textModel.getLanguageId(), textModel.uri, textModel.isForSimpleWidget);
|
|
1546
|
+
const onEnter = Event.filter(this.inputEditor.onKeyDown, e => e.keyCode === 3 , this.repositoryDisposables);
|
|
1547
|
+
this.repositoryDisposables.add(onEnter(() => textModel.detectIndentation(opts.insertSpaces, opts.tabSize)));
|
|
1548
|
+
textModel.setValue(input.value);
|
|
1549
|
+
this.repositoryDisposables.add(input.onDidChange(({ value, reason }) => {
|
|
1550
|
+
if (value === textModel.getValue()) {
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1553
|
+
textModel.setValue(value);
|
|
1554
|
+
const position = reason === SCMInputChangeReason.HistoryPrevious
|
|
1555
|
+
? textModel.getFullModelRange().getStartPosition()
|
|
1556
|
+
: textModel.getFullModelRange().getEndPosition();
|
|
1557
|
+
this.inputEditor.setPosition(position);
|
|
1558
|
+
this.inputEditor.revealPositionInCenterIfOutsideViewport(position);
|
|
1559
|
+
}));
|
|
1560
|
+
this.repositoryDisposables.add(input.onDidChangeFocus(() => this.focus()));
|
|
1561
|
+
this.repositoryDisposables.add(input.onDidChangeValidationMessage((e) => this.setValidation(e, { focus: true, timeout: true })));
|
|
1562
|
+
this.repositoryDisposables.add(input.onDidChangeValidateInput((e) => triggerValidation()));
|
|
1563
|
+
const updatePlaceholderVisibility = () => this.placeholderTextContainer.classList.toggle('hidden', textModel.getValueLength() > 0);
|
|
1564
|
+
this.repositoryDisposables.add(textModel.onDidChangeContent(() => {
|
|
1565
|
+
input.setValue(textModel.getValue(), true);
|
|
1566
|
+
updatePlaceholderVisibility();
|
|
1567
|
+
triggerValidation();
|
|
1568
|
+
}));
|
|
1569
|
+
updatePlaceholderVisibility();
|
|
1570
|
+
const updatePlaceholderText = () => {
|
|
1571
|
+
const binding = this.keybindingService.lookupKeybinding('scm.acceptInput');
|
|
1572
|
+
const label = binding ? binding.getLabel() : (platform.isMacintosh ? 'Cmd+Enter' : 'Ctrl+Enter');
|
|
1573
|
+
const placeholderText = format(input.placeholder, label);
|
|
1574
|
+
this.inputEditor.updateOptions({ ariaLabel: placeholderText });
|
|
1575
|
+
this.placeholderTextContainer.textContent = placeholderText;
|
|
1576
|
+
};
|
|
1577
|
+
this.repositoryDisposables.add(input.onDidChangePlaceholder(updatePlaceholderText));
|
|
1578
|
+
this.repositoryDisposables.add(this.keybindingService.onDidUpdateKeybindings(updatePlaceholderText));
|
|
1579
|
+
updatePlaceholderText();
|
|
1580
|
+
let commitTemplate = '';
|
|
1581
|
+
const updateTemplate = () => {
|
|
1582
|
+
if (typeof input.repository.provider.commitTemplate === 'undefined' || !input.visible) {
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1585
|
+
const oldCommitTemplate = commitTemplate;
|
|
1586
|
+
commitTemplate = input.repository.provider.commitTemplate;
|
|
1587
|
+
const value = textModel.getValue();
|
|
1588
|
+
if (value && value !== oldCommitTemplate) {
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
textModel.setValue(commitTemplate);
|
|
1592
|
+
};
|
|
1593
|
+
this.repositoryDisposables.add(input.repository.provider.onDidChangeCommitTemplate(updateTemplate, this));
|
|
1594
|
+
updateTemplate();
|
|
1595
|
+
const updateEnablement = (enabled) => {
|
|
1596
|
+
this.inputEditor.updateOptions({ readOnly: !enabled });
|
|
1597
|
+
};
|
|
1598
|
+
this.repositoryDisposables.add(input.onDidChangeEnablement(enabled => updateEnablement(enabled)));
|
|
1599
|
+
updateEnablement(input.enabled);
|
|
1600
|
+
}
|
|
1601
|
+
get selections() {
|
|
1602
|
+
return this.inputEditor.getSelections();
|
|
1603
|
+
}
|
|
1604
|
+
set selections(selections) {
|
|
1605
|
+
if (selections) {
|
|
1606
|
+
this.inputEditor.setSelections(selections);
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
setValidation(validation, options) {
|
|
1610
|
+
if (this._validationTimer) {
|
|
1611
|
+
clearTimeout(this._validationTimer);
|
|
1612
|
+
this._validationTimer = 0;
|
|
1613
|
+
}
|
|
1614
|
+
this.validation = validation;
|
|
1615
|
+
this.renderValidation();
|
|
1616
|
+
if (options?.focus && !this.hasFocus()) {
|
|
1617
|
+
this.focus();
|
|
1618
|
+
}
|
|
1619
|
+
if (validation && options?.timeout) {
|
|
1620
|
+
this._validationTimer = setTimeout(() => this.setValidation(undefined), SCMInputWidget_1.ValidationTimeouts[validation.type]);
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
constructor(container, overflowWidgetsDomNode, contextKeyService, modelService, textModelService, keybindingService, configurationService, instantiationService, scmViewService, contextViewService, openerService) {
|
|
1624
|
+
this.modelService = modelService;
|
|
1625
|
+
this.textModelService = textModelService;
|
|
1626
|
+
this.keybindingService = keybindingService;
|
|
1627
|
+
this.configurationService = configurationService;
|
|
1628
|
+
this.instantiationService = instantiationService;
|
|
1629
|
+
this.scmViewService = scmViewService;
|
|
1630
|
+
this.contextViewService = contextViewService;
|
|
1631
|
+
this.openerService = openerService;
|
|
1632
|
+
this.defaultInputFontFamily = DEFAULT_FONT_FAMILY;
|
|
1633
|
+
this.disposables = ( new DisposableStore());
|
|
1634
|
+
this.repositoryDisposables = ( new DisposableStore());
|
|
1635
|
+
this.validationDisposable = Disposable.None;
|
|
1636
|
+
this.validationHasFocus = false;
|
|
1637
|
+
this.lastLayoutWasTrash = false;
|
|
1638
|
+
this.shouldFocusAfterLayout = false;
|
|
1639
|
+
this.element = append(container, $('.scm-editor'));
|
|
1640
|
+
this.editorContainer = append(this.element, $('.scm-editor-container'));
|
|
1641
|
+
this.placeholderTextContainer = append(this.editorContainer, $('.scm-editor-placeholder'));
|
|
1642
|
+
const fontFamily = this.getInputEditorFontFamily();
|
|
1643
|
+
const fontSize = this.getInputEditorFontSize();
|
|
1644
|
+
const lineHeight = this.computeLineHeight(fontSize);
|
|
1645
|
+
this.setPlaceholderFontStyles(fontFamily, fontSize, lineHeight);
|
|
1646
|
+
const contextKeyService2 = contextKeyService.createScoped(this.element);
|
|
1647
|
+
this.repositoryIdContextKey = contextKeyService2.createKey('scmRepository', undefined);
|
|
1648
|
+
const editorOptions = {
|
|
1649
|
+
...getSimpleEditorOptions(configurationService),
|
|
1650
|
+
lineDecorationsWidth: 6,
|
|
1651
|
+
dragAndDrop: true,
|
|
1652
|
+
cursorWidth: 1,
|
|
1653
|
+
fontSize: fontSize,
|
|
1654
|
+
lineHeight: lineHeight,
|
|
1655
|
+
fontFamily: fontFamily,
|
|
1656
|
+
wrappingStrategy: 'advanced',
|
|
1657
|
+
wrappingIndent: 'none',
|
|
1658
|
+
padding: { top: 2, bottom: 2 },
|
|
1659
|
+
quickSuggestions: false,
|
|
1660
|
+
scrollbar: { alwaysConsumeMouseWheel: false },
|
|
1661
|
+
overflowWidgetsDomNode,
|
|
1662
|
+
formatOnType: true,
|
|
1663
|
+
renderWhitespace: 'none',
|
|
1664
|
+
dropIntoEditor: { enabled: true }
|
|
1665
|
+
};
|
|
1666
|
+
const codeEditorWidgetOptions = {
|
|
1667
|
+
isSimpleWidget: true,
|
|
1668
|
+
contributions: EditorExtensionsRegistry.getSomeEditorContributions([
|
|
1669
|
+
ColorDetector.ID,
|
|
1670
|
+
ContextMenuController.ID,
|
|
1671
|
+
DragAndDropController.ID,
|
|
1672
|
+
DropIntoEditorController.ID,
|
|
1673
|
+
LinkDetector.ID,
|
|
1674
|
+
MenuPreventer.ID,
|
|
1675
|
+
MessageController.ID,
|
|
1676
|
+
ModesHoverController.ID,
|
|
1677
|
+
SelectionClipboardContributionID,
|
|
1678
|
+
SnippetController2.ID,
|
|
1679
|
+
SuggestController.ID,
|
|
1680
|
+
InlineCompletionsController.ID,
|
|
1681
|
+
CodeActionController.ID,
|
|
1682
|
+
FormatOnType.ID
|
|
1683
|
+
])
|
|
1684
|
+
};
|
|
1685
|
+
const services = ( new ServiceCollection([IContextKeyService, contextKeyService2]));
|
|
1686
|
+
const instantiationService2 = instantiationService.createChild(services);
|
|
1687
|
+
this.inputEditor = instantiationService2.createInstance(CodeEditorWidget, this.editorContainer, editorOptions, codeEditorWidgetOptions);
|
|
1688
|
+
this.disposables.add(this.inputEditor);
|
|
1689
|
+
this.disposables.add(this.inputEditor.onDidFocusEditorText(() => {
|
|
1690
|
+
if (this.input?.repository) {
|
|
1691
|
+
this.scmViewService.focus(this.input.repository);
|
|
1692
|
+
}
|
|
1693
|
+
this.editorContainer.classList.add('synthetic-focus');
|
|
1694
|
+
this.renderValidation();
|
|
1695
|
+
}));
|
|
1696
|
+
this.disposables.add(this.inputEditor.onDidBlurEditorText(() => {
|
|
1697
|
+
this.editorContainer.classList.remove('synthetic-focus');
|
|
1698
|
+
setTimeout(() => {
|
|
1699
|
+
if (!this.validation || !this.validationHasFocus) {
|
|
1700
|
+
this.clearValidation();
|
|
1701
|
+
}
|
|
1702
|
+
}, 0);
|
|
1703
|
+
}));
|
|
1704
|
+
const firstLineKey = contextKeyService2.createKey('scmInputIsInFirstPosition', false);
|
|
1705
|
+
const lastLineKey = contextKeyService2.createKey('scmInputIsInLastPosition', false);
|
|
1706
|
+
this.disposables.add(this.inputEditor.onDidChangeCursorPosition(({ position }) => {
|
|
1707
|
+
const viewModel = this.inputEditor._getViewModel();
|
|
1708
|
+
const lastLineNumber = viewModel.getLineCount();
|
|
1709
|
+
const lastLineCol = viewModel.getLineLength(lastLineNumber) + 1;
|
|
1710
|
+
const viewPosition = viewModel.coordinatesConverter.convertModelPositionToViewPosition(position);
|
|
1711
|
+
firstLineKey.set(viewPosition.lineNumber === 1 && viewPosition.column === 1);
|
|
1712
|
+
lastLineKey.set(viewPosition.lineNumber === lastLineNumber && viewPosition.column === lastLineCol);
|
|
1713
|
+
}));
|
|
1714
|
+
const relevantSettings = [
|
|
1715
|
+
'scm.inputFontFamily',
|
|
1716
|
+
'editor.fontFamily',
|
|
1717
|
+
'scm.inputFontSize',
|
|
1718
|
+
'editor.accessibilitySupport',
|
|
1719
|
+
'editor.cursorBlinking'
|
|
1720
|
+
];
|
|
1721
|
+
const onRelevantSettingChanged = Event.filter(this.configurationService.onDidChangeConfiguration, (e) => {
|
|
1722
|
+
for (const setting of relevantSettings) {
|
|
1723
|
+
if (e.affectsConfiguration(setting)) {
|
|
1724
|
+
return true;
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
return false;
|
|
1728
|
+
}, this.disposables);
|
|
1729
|
+
this.disposables.add(onRelevantSettingChanged(() => {
|
|
1730
|
+
const fontFamily = this.getInputEditorFontFamily();
|
|
1731
|
+
const fontSize = this.getInputEditorFontSize();
|
|
1732
|
+
const lineHeight = this.computeLineHeight(fontSize);
|
|
1733
|
+
const accessibilitySupport = this.configurationService.getValue('editor.accessibilitySupport');
|
|
1734
|
+
const cursorBlinking = this.configurationService.getValue('editor.cursorBlinking');
|
|
1735
|
+
this.inputEditor.updateOptions({
|
|
1736
|
+
fontFamily: fontFamily,
|
|
1737
|
+
fontSize: fontSize,
|
|
1738
|
+
lineHeight: lineHeight,
|
|
1739
|
+
accessibilitySupport,
|
|
1740
|
+
cursorBlinking
|
|
1741
|
+
});
|
|
1742
|
+
this.setPlaceholderFontStyles(fontFamily, fontSize, lineHeight);
|
|
1743
|
+
}));
|
|
1744
|
+
this.onDidChangeContentHeight = Event.signal(Event.filter(this.inputEditor.onDidContentSizeChange, e => e.contentHeightChanged, this.disposables));
|
|
1745
|
+
}
|
|
1746
|
+
getContentHeight() {
|
|
1747
|
+
const editorContentHeight = this.inputEditor.getContentHeight();
|
|
1748
|
+
return Math.min(editorContentHeight, 134);
|
|
1749
|
+
}
|
|
1750
|
+
layout() {
|
|
1751
|
+
const editorHeight = this.getContentHeight();
|
|
1752
|
+
const dimension = ( new Dimension(this.element.clientWidth - 2, editorHeight));
|
|
1753
|
+
if (dimension.width < 0) {
|
|
1754
|
+
this.lastLayoutWasTrash = true;
|
|
1755
|
+
return;
|
|
1756
|
+
}
|
|
1757
|
+
this.lastLayoutWasTrash = false;
|
|
1758
|
+
this.inputEditor.layout(dimension);
|
|
1759
|
+
this.renderValidation();
|
|
1760
|
+
if (this.shouldFocusAfterLayout) {
|
|
1761
|
+
this.shouldFocusAfterLayout = false;
|
|
1762
|
+
this.focus();
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
focus() {
|
|
1766
|
+
if (this.lastLayoutWasTrash) {
|
|
1767
|
+
this.lastLayoutWasTrash = false;
|
|
1768
|
+
this.shouldFocusAfterLayout = true;
|
|
1769
|
+
return;
|
|
1770
|
+
}
|
|
1771
|
+
this.inputEditor.focus();
|
|
1772
|
+
this.editorContainer.classList.add('synthetic-focus');
|
|
1773
|
+
}
|
|
1774
|
+
hasFocus() {
|
|
1775
|
+
return this.inputEditor.hasTextFocus();
|
|
1776
|
+
}
|
|
1777
|
+
renderValidation() {
|
|
1778
|
+
this.clearValidation();
|
|
1779
|
+
this.editorContainer.classList.toggle('validation-info', this.validation?.type === 2 );
|
|
1780
|
+
this.editorContainer.classList.toggle('validation-warning', this.validation?.type === 1 );
|
|
1781
|
+
this.editorContainer.classList.toggle('validation-error', this.validation?.type === 0 );
|
|
1782
|
+
if (!this.validation || !this.inputEditor.hasTextFocus()) {
|
|
1783
|
+
return;
|
|
1784
|
+
}
|
|
1785
|
+
const disposables = ( new DisposableStore());
|
|
1786
|
+
this.validationDisposable = this.contextViewService.showContextView({
|
|
1787
|
+
getAnchor: () => this.editorContainer,
|
|
1788
|
+
render: container => {
|
|
1789
|
+
this.editorContainer.style.borderBottomLeftRadius = '0';
|
|
1790
|
+
this.editorContainer.style.borderBottomRightRadius = '0';
|
|
1791
|
+
const validationContainer = append(container, $('.scm-editor-validation-container'));
|
|
1792
|
+
validationContainer.classList.toggle('validation-info', this.validation.type === 2 );
|
|
1793
|
+
validationContainer.classList.toggle('validation-warning', this.validation.type === 1 );
|
|
1794
|
+
validationContainer.classList.toggle('validation-error', this.validation.type === 0 );
|
|
1795
|
+
validationContainer.style.width = `${this.editorContainer.clientWidth + 2}px`;
|
|
1796
|
+
const element = append(validationContainer, $('.scm-editor-validation'));
|
|
1797
|
+
const message = this.validation.message;
|
|
1798
|
+
if (typeof message === 'string') {
|
|
1799
|
+
element.textContent = message;
|
|
1800
|
+
}
|
|
1801
|
+
else {
|
|
1802
|
+
const tracker = trackFocus(element);
|
|
1803
|
+
disposables.add(tracker);
|
|
1804
|
+
disposables.add(tracker.onDidFocus(() => (this.validationHasFocus = true)));
|
|
1805
|
+
disposables.add(tracker.onDidBlur(() => {
|
|
1806
|
+
this.validationHasFocus = false;
|
|
1807
|
+
this.editorContainer.style.borderBottomLeftRadius = '2px';
|
|
1808
|
+
this.editorContainer.style.borderBottomRightRadius = '2px';
|
|
1809
|
+
this.contextViewService.hideContextView();
|
|
1810
|
+
}));
|
|
1811
|
+
const renderer = disposables.add(this.instantiationService.createInstance(MarkdownRenderer, {}));
|
|
1812
|
+
const renderedMarkdown = renderer.render(message, {
|
|
1813
|
+
actionHandler: {
|
|
1814
|
+
callback: (link) => {
|
|
1815
|
+
openLinkFromMarkdown(this.openerService, link, message.isTrusted);
|
|
1816
|
+
this.editorContainer.style.borderBottomLeftRadius = '2px';
|
|
1817
|
+
this.editorContainer.style.borderBottomRightRadius = '2px';
|
|
1818
|
+
this.contextViewService.hideContextView();
|
|
1819
|
+
},
|
|
1820
|
+
disposables: disposables
|
|
1821
|
+
},
|
|
1822
|
+
});
|
|
1823
|
+
disposables.add(renderedMarkdown);
|
|
1824
|
+
element.appendChild(renderedMarkdown.element);
|
|
1825
|
+
}
|
|
1826
|
+
const actionsContainer = append(validationContainer, $('.scm-editor-validation-actions'));
|
|
1827
|
+
const actionbar = ( new ActionBar(actionsContainer));
|
|
1828
|
+
const action = ( new Action('scmInputWidget.validationMessage.close', ( localizeWithPath('vs/workbench/contrib/scm/browser/scmViewPane', 'label.close', "Close")), ThemeIcon.asClassName(Codicon.close), true, () => {
|
|
1829
|
+
this.contextViewService.hideContextView();
|
|
1830
|
+
this.editorContainer.style.borderBottomLeftRadius = '2px';
|
|
1831
|
+
this.editorContainer.style.borderBottomRightRadius = '2px';
|
|
1832
|
+
}));
|
|
1833
|
+
disposables.add(actionbar);
|
|
1834
|
+
actionbar.push(action, { icon: true, label: false });
|
|
1835
|
+
return Disposable.None;
|
|
1836
|
+
},
|
|
1837
|
+
onHide: () => {
|
|
1838
|
+
this.validationHasFocus = false;
|
|
1839
|
+
this.editorContainer.style.borderBottomLeftRadius = '2px';
|
|
1840
|
+
this.editorContainer.style.borderBottomRightRadius = '2px';
|
|
1841
|
+
disposables.dispose();
|
|
1842
|
+
},
|
|
1843
|
+
anchorAlignment: 0
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
getInputEditorFontFamily() {
|
|
1847
|
+
const inputFontFamily = this.configurationService.getValue('scm.inputFontFamily').trim();
|
|
1848
|
+
if (inputFontFamily.toLowerCase() === 'editor') {
|
|
1849
|
+
return this.configurationService.getValue('editor.fontFamily').trim();
|
|
1850
|
+
}
|
|
1851
|
+
if (inputFontFamily.length !== 0 && inputFontFamily.toLowerCase() !== 'default') {
|
|
1852
|
+
return inputFontFamily;
|
|
1853
|
+
}
|
|
1854
|
+
return this.defaultInputFontFamily;
|
|
1855
|
+
}
|
|
1856
|
+
getInputEditorFontSize() {
|
|
1857
|
+
return this.configurationService.getValue('scm.inputFontSize');
|
|
1858
|
+
}
|
|
1859
|
+
computeLineHeight(fontSize) {
|
|
1860
|
+
return Math.round(fontSize * 1.5);
|
|
1861
|
+
}
|
|
1862
|
+
setPlaceholderFontStyles(fontFamily, fontSize, lineHeight) {
|
|
1863
|
+
this.placeholderTextContainer.style.fontFamily = fontFamily;
|
|
1864
|
+
this.placeholderTextContainer.style.fontSize = `${fontSize}px`;
|
|
1865
|
+
this.placeholderTextContainer.style.lineHeight = `${lineHeight}px`;
|
|
1866
|
+
}
|
|
1867
|
+
clearValidation() {
|
|
1868
|
+
this.validationDisposable.dispose();
|
|
1869
|
+
this.validationHasFocus = false;
|
|
1870
|
+
}
|
|
1871
|
+
dispose() {
|
|
1872
|
+
this.setInput(undefined);
|
|
1873
|
+
this.repositoryDisposables.dispose();
|
|
1874
|
+
this.clearValidation();
|
|
1875
|
+
this.disposables.dispose();
|
|
1876
|
+
}
|
|
1877
|
+
};
|
|
1878
|
+
SCMInputWidget = SCMInputWidget_1 = ( __decorate([
|
|
1879
|
+
( __param(2, IContextKeyService)),
|
|
1880
|
+
( __param(3, IModelService)),
|
|
1881
|
+
( __param(4, ITextModelService)),
|
|
1882
|
+
( __param(5, IKeybindingService)),
|
|
1883
|
+
( __param(6, IConfigurationService)),
|
|
1884
|
+
( __param(7, IInstantiationService)),
|
|
1885
|
+
( __param(8, ISCMViewService)),
|
|
1886
|
+
( __param(9, IContextViewService)),
|
|
1887
|
+
( __param(10, IOpenerService))
|
|
1888
|
+
], SCMInputWidget));
|
|
1889
|
+
let SCMViewPane = class SCMViewPane extends ViewPane {
|
|
1890
|
+
get viewModel() { return this._viewModel; }
|
|
1891
|
+
constructor(options, scmService, scmViewService, keybindingService, themeService, contextMenuService, commandService, editorService, instantiationService, viewDescriptorService, configurationService, contextKeyService, menuService, openerService, telemetryService) {
|
|
1892
|
+
super({ ...options, titleMenuId: MenuId.SCMTitle }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
|
|
1893
|
+
this.scmService = scmService;
|
|
1894
|
+
this.scmViewService = scmViewService;
|
|
1895
|
+
this.commandService = commandService;
|
|
1896
|
+
this.editorService = editorService;
|
|
1897
|
+
this.menuService = menuService;
|
|
1898
|
+
this.disposables = ( new DisposableStore());
|
|
1899
|
+
this._onDidLayout = ( new Emitter());
|
|
1900
|
+
this.layoutCache = {
|
|
1901
|
+
height: undefined,
|
|
1902
|
+
width: undefined,
|
|
1903
|
+
onDidChange: this._onDidLayout.event
|
|
1904
|
+
};
|
|
1905
|
+
this._register(this.instantiationService.createInstance(ScmInputContentProvider));
|
|
1906
|
+
this._register(Event.any(this.scmService.onDidAddRepository, this.scmService.onDidRemoveRepository)(() => this._onDidChangeViewWelcomeState.fire()));
|
|
1907
|
+
}
|
|
1908
|
+
renderBody(container) {
|
|
1909
|
+
super.renderBody(container);
|
|
1910
|
+
this.listContainer = append(container, $('.scm-view.show-file-icons'));
|
|
1911
|
+
const overflowWidgetsDomNode = $('.scm-overflow-widgets-container.monaco-editor');
|
|
1912
|
+
const updateActionsVisibility = () => this.listContainer.classList.toggle('show-actions', this.configurationService.getValue('scm.alwaysShowActions'));
|
|
1913
|
+
this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.alwaysShowActions'), this.disposables)(updateActionsVisibility));
|
|
1914
|
+
updateActionsVisibility();
|
|
1915
|
+
const updateProviderCountVisibility = () => {
|
|
1916
|
+
const value = this.configurationService.getValue('scm.providerCountBadge');
|
|
1917
|
+
this.listContainer.classList.toggle('hide-provider-counts', value === 'hidden');
|
|
1918
|
+
this.listContainer.classList.toggle('auto-provider-counts', value === 'auto');
|
|
1919
|
+
};
|
|
1920
|
+
this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.providerCountBadge'), this.disposables)(updateProviderCountVisibility));
|
|
1921
|
+
updateProviderCountVisibility();
|
|
1922
|
+
this.inputRenderer = this.instantiationService.createInstance(InputRenderer, this.layoutCache, overflowWidgetsDomNode, (input, height) => this.tree.updateElementHeight(input, height));
|
|
1923
|
+
const delegate = ( new ListDelegate(this.inputRenderer));
|
|
1924
|
+
this.actionButtonRenderer = this.instantiationService.createInstance(ActionButtonRenderer);
|
|
1925
|
+
this.listLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility });
|
|
1926
|
+
this._register(this.listLabels);
|
|
1927
|
+
const actionRunner = ( new RepositoryPaneActionRunner(() => this.getSelectedResources()));
|
|
1928
|
+
this._register(actionRunner);
|
|
1929
|
+
this._register(actionRunner.onWillRun(() => this.tree.domFocus()));
|
|
1930
|
+
const renderers = [
|
|
1931
|
+
this.instantiationService.createInstance(RepositoryRenderer, getActionViewItemProvider(this.instantiationService)),
|
|
1932
|
+
this.inputRenderer,
|
|
1933
|
+
this.actionButtonRenderer,
|
|
1934
|
+
this.instantiationService.createInstance(ResourceGroupRenderer, getActionViewItemProvider(this.instantiationService)),
|
|
1935
|
+
this._register(this.instantiationService.createInstance(ResourceRenderer, () => this._viewModel, this.listLabels, getActionViewItemProvider(this.instantiationService), actionRunner))
|
|
1936
|
+
];
|
|
1937
|
+
const filter = ( new SCMTreeFilter());
|
|
1938
|
+
const sorter = ( new SCMTreeSorter(() => this._viewModel));
|
|
1939
|
+
const keyboardNavigationLabelProvider = this.instantiationService.createInstance(SCMTreeKeyboardNavigationLabelProvider, () => this._viewModel);
|
|
1940
|
+
const identityProvider = ( new SCMResourceIdentityProvider());
|
|
1941
|
+
const dnd = ( new SCMTreeDragAndDrop(this.instantiationService));
|
|
1942
|
+
this.tree = this.instantiationService.createInstance(WorkbenchCompressibleObjectTree, 'SCM Tree Repo', this.listContainer, delegate, renderers, {
|
|
1943
|
+
transformOptimization: false,
|
|
1944
|
+
identityProvider,
|
|
1945
|
+
dnd,
|
|
1946
|
+
horizontalScrolling: false,
|
|
1947
|
+
setRowLineHeight: false,
|
|
1948
|
+
filter,
|
|
1949
|
+
sorter,
|
|
1950
|
+
keyboardNavigationLabelProvider,
|
|
1951
|
+
overrideStyles: {
|
|
1952
|
+
listBackground: this.viewDescriptorService.getViewLocationById(this.id) === 1 ? PANEL_BACKGROUND : SIDE_BAR_BACKGROUND
|
|
1953
|
+
},
|
|
1954
|
+
accessibilityProvider: this.instantiationService.createInstance(SCMAccessibilityProvider)
|
|
1955
|
+
});
|
|
1956
|
+
this._register(this.tree.onDidOpen(this.open, this));
|
|
1957
|
+
this._register(this.tree.onContextMenu(this.onListContextMenu, this));
|
|
1958
|
+
this._register(this.tree.onDidScroll(this.inputRenderer.clearValidation, this.inputRenderer));
|
|
1959
|
+
this._register(this.tree);
|
|
1960
|
+
append(this.listContainer, overflowWidgetsDomNode);
|
|
1961
|
+
this._register(this.instantiationService.createInstance(RepositoryVisibilityActionController));
|
|
1962
|
+
this._viewModel = this.instantiationService.createInstance(ViewModel, this.tree, this.inputRenderer);
|
|
1963
|
+
this._register(this._viewModel);
|
|
1964
|
+
this.listContainer.classList.add('file-icon-themable-tree');
|
|
1965
|
+
this.listContainer.classList.add('show-file-icons');
|
|
1966
|
+
this.updateIndentStyles(this.themeService.getFileIconTheme());
|
|
1967
|
+
this._register(this.themeService.onDidFileIconThemeChange(this.updateIndentStyles, this));
|
|
1968
|
+
this._register(this._viewModel.onDidChangeMode(this.onDidChangeMode, this));
|
|
1969
|
+
this._register(this.onDidChangeBodyVisibility(this._viewModel.setVisible, this._viewModel));
|
|
1970
|
+
this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.alwaysShowRepositories'), this.disposables)(this.updateActions, this));
|
|
1971
|
+
this.updateActions();
|
|
1972
|
+
}
|
|
1973
|
+
updateIndentStyles(theme) {
|
|
1974
|
+
this.listContainer.classList.toggle('list-view-mode', this._viewModel.mode === "list" );
|
|
1975
|
+
this.listContainer.classList.toggle('tree-view-mode', this._viewModel.mode === "tree" );
|
|
1976
|
+
this.listContainer.classList.toggle('align-icons-and-twisties', (this._viewModel.mode === "list" && theme.hasFileIcons) || (theme.hasFileIcons && !theme.hasFolderIcons));
|
|
1977
|
+
this.listContainer.classList.toggle('hide-arrows', this._viewModel.mode === "tree" && theme.hidesExplorerArrows === true);
|
|
1978
|
+
}
|
|
1979
|
+
onDidChangeMode() {
|
|
1980
|
+
this.updateIndentStyles(this.themeService.getFileIconTheme());
|
|
1981
|
+
}
|
|
1982
|
+
layoutBody(height = this.layoutCache.height, width = this.layoutCache.width) {
|
|
1983
|
+
if (height === undefined) {
|
|
1984
|
+
return;
|
|
1985
|
+
}
|
|
1986
|
+
if (width !== undefined) {
|
|
1987
|
+
super.layoutBody(height, width);
|
|
1988
|
+
}
|
|
1989
|
+
this.layoutCache.height = height;
|
|
1990
|
+
this.layoutCache.width = width;
|
|
1991
|
+
this._onDidLayout.fire();
|
|
1992
|
+
this.listContainer.style.height = `${height}px`;
|
|
1993
|
+
this.tree.layout(height, width);
|
|
1994
|
+
}
|
|
1995
|
+
focus() {
|
|
1996
|
+
super.focus();
|
|
1997
|
+
if (this.isExpanded()) {
|
|
1998
|
+
this._viewModel.focus();
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
async open(e) {
|
|
2002
|
+
if (!e.element) {
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
else if (isSCMRepository(e.element)) {
|
|
2006
|
+
this.scmViewService.focus(e.element);
|
|
2007
|
+
return;
|
|
2008
|
+
}
|
|
2009
|
+
else if (isSCMResourceGroup(e.element)) {
|
|
2010
|
+
const provider = e.element.provider;
|
|
2011
|
+
const repository = Iterable.find(this.scmService.repositories, r => r.provider === provider);
|
|
2012
|
+
if (repository) {
|
|
2013
|
+
this.scmViewService.focus(repository);
|
|
2014
|
+
}
|
|
2015
|
+
return;
|
|
2016
|
+
}
|
|
2017
|
+
else if (ResourceTree.isResourceNode(e.element)) {
|
|
2018
|
+
const provider = e.element.context.provider;
|
|
2019
|
+
const repository = Iterable.find(this.scmService.repositories, r => r.provider === provider);
|
|
2020
|
+
if (repository) {
|
|
2021
|
+
this.scmViewService.focus(repository);
|
|
2022
|
+
}
|
|
2023
|
+
return;
|
|
2024
|
+
}
|
|
2025
|
+
else if (isSCMInput(e.element)) {
|
|
2026
|
+
this.scmViewService.focus(e.element.repository);
|
|
2027
|
+
const widget = this.inputRenderer.getRenderedInputWidget(e.element);
|
|
2028
|
+
if (widget) {
|
|
2029
|
+
widget.focus();
|
|
2030
|
+
this.tree.setFocus([], e.browserEvent);
|
|
2031
|
+
const selection = this.tree.getSelection();
|
|
2032
|
+
if (selection.length === 1 && selection[0] === e.element) {
|
|
2033
|
+
setTimeout(() => this.tree.setSelection([]));
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
return;
|
|
2037
|
+
}
|
|
2038
|
+
else if (isSCMActionButton(e.element)) {
|
|
2039
|
+
this.scmViewService.focus(e.element.repository);
|
|
2040
|
+
this.actionButtonRenderer.focusActionButton(e.element);
|
|
2041
|
+
this.tree.setFocus([], e.browserEvent);
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
2044
|
+
if (e.element.command?.id === API_OPEN_EDITOR_COMMAND_ID || e.element.command?.id === API_OPEN_DIFF_EDITOR_COMMAND_ID) {
|
|
2045
|
+
await this.commandService.executeCommand(e.element.command.id, ...(e.element.command.arguments || []), e);
|
|
2046
|
+
}
|
|
2047
|
+
else {
|
|
2048
|
+
await e.element.open(!!e.editorOptions.preserveFocus);
|
|
2049
|
+
if (e.editorOptions.pinned) {
|
|
2050
|
+
const activeEditorPane = this.editorService.activeEditorPane;
|
|
2051
|
+
activeEditorPane?.group.pinEditor(activeEditorPane.input);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
const provider = e.element.resourceGroup.provider;
|
|
2055
|
+
const repository = Iterable.find(this.scmService.repositories, r => r.provider === provider);
|
|
2056
|
+
if (repository) {
|
|
2057
|
+
this.scmViewService.focus(repository);
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
onListContextMenu(e) {
|
|
2061
|
+
if (!e.element) {
|
|
2062
|
+
const menu = this.menuService.createMenu(Menus.ViewSort, this.contextKeyService);
|
|
2063
|
+
const actions = [];
|
|
2064
|
+
createAndFillInContextMenuActions(menu, undefined, actions);
|
|
2065
|
+
return this.contextMenuService.showContextMenu({
|
|
2066
|
+
getAnchor: () => e.anchor,
|
|
2067
|
+
getActions: () => actions,
|
|
2068
|
+
onHide: () => {
|
|
2069
|
+
menu.dispose();
|
|
2070
|
+
}
|
|
2071
|
+
});
|
|
2072
|
+
}
|
|
2073
|
+
const element = e.element;
|
|
2074
|
+
let context = element;
|
|
2075
|
+
let actions = [];
|
|
2076
|
+
if (isSCMRepository(element)) {
|
|
2077
|
+
const menus = this.scmViewService.menus.getRepositoryMenus(element.provider);
|
|
2078
|
+
const menu = menus.repositoryMenu;
|
|
2079
|
+
context = element.provider;
|
|
2080
|
+
actions = collectContextMenuActions(menu);
|
|
2081
|
+
}
|
|
2082
|
+
else if (isSCMInput(element) || isSCMActionButton(element)) ;
|
|
2083
|
+
else if (isSCMResourceGroup(element)) {
|
|
2084
|
+
const menus = this.scmViewService.menus.getRepositoryMenus(element.provider);
|
|
2085
|
+
const menu = menus.getResourceGroupMenu(element);
|
|
2086
|
+
actions = collectContextMenuActions(menu);
|
|
2087
|
+
}
|
|
2088
|
+
else if (ResourceTree.isResourceNode(element)) {
|
|
2089
|
+
if (element.element) {
|
|
2090
|
+
const menus = this.scmViewService.menus.getRepositoryMenus(element.element.resourceGroup.provider);
|
|
2091
|
+
const menu = menus.getResourceMenu(element.element);
|
|
2092
|
+
actions = collectContextMenuActions(menu);
|
|
2093
|
+
}
|
|
2094
|
+
else {
|
|
2095
|
+
const menus = this.scmViewService.menus.getRepositoryMenus(element.context.provider);
|
|
2096
|
+
const menu = menus.getResourceFolderMenu(element.context);
|
|
2097
|
+
actions = collectContextMenuActions(menu);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
else {
|
|
2101
|
+
const menus = this.scmViewService.menus.getRepositoryMenus(element.resourceGroup.provider);
|
|
2102
|
+
const menu = menus.getResourceMenu(element);
|
|
2103
|
+
actions = collectContextMenuActions(menu);
|
|
2104
|
+
}
|
|
2105
|
+
const actionRunner = ( new RepositoryPaneActionRunner(() => this.getSelectedResources()));
|
|
2106
|
+
actionRunner.onWillRun(() => this.tree.domFocus());
|
|
2107
|
+
this.contextMenuService.showContextMenu({
|
|
2108
|
+
getAnchor: () => e.anchor,
|
|
2109
|
+
getActions: () => actions,
|
|
2110
|
+
getActionsContext: () => context,
|
|
2111
|
+
actionRunner
|
|
2112
|
+
});
|
|
2113
|
+
}
|
|
2114
|
+
getSelectedResources() {
|
|
2115
|
+
return this.tree.getSelection()
|
|
2116
|
+
.filter(r => !!r && !isSCMResourceGroup(r));
|
|
2117
|
+
}
|
|
2118
|
+
shouldShowWelcome() {
|
|
2119
|
+
return this.scmService.repositoryCount === 0;
|
|
2120
|
+
}
|
|
2121
|
+
getActionsContext() {
|
|
2122
|
+
return this.scmViewService.visibleRepositories.length === 1 ? this.scmViewService.visibleRepositories[0].provider : undefined;
|
|
2123
|
+
}
|
|
2124
|
+
dispose() {
|
|
2125
|
+
this.disposables.dispose();
|
|
2126
|
+
super.dispose();
|
|
2127
|
+
}
|
|
2128
|
+
};
|
|
2129
|
+
SCMViewPane = ( __decorate([
|
|
2130
|
+
( __param(1, ISCMService)),
|
|
2131
|
+
( __param(2, ISCMViewService)),
|
|
2132
|
+
( __param(3, IKeybindingService)),
|
|
2133
|
+
( __param(4, IThemeService)),
|
|
2134
|
+
( __param(5, IContextMenuService)),
|
|
2135
|
+
( __param(6, ICommandService)),
|
|
2136
|
+
( __param(7, IEditorService)),
|
|
2137
|
+
( __param(8, IInstantiationService)),
|
|
2138
|
+
( __param(9, IViewDescriptorService)),
|
|
2139
|
+
( __param(10, IConfigurationService)),
|
|
2140
|
+
( __param(11, IContextKeyService)),
|
|
2141
|
+
( __param(12, IMenuService)),
|
|
2142
|
+
( __param(13, IOpenerService)),
|
|
2143
|
+
( __param(14, ITelemetryService))
|
|
2144
|
+
], SCMViewPane));
|
|
2145
|
+
registerColor('scm.providerBorder', { dark: '#454545', light: '#C8C8C8', hcDark: contrastBorder, hcLight: contrastBorder }, ( localizeWithPath(
|
|
2146
|
+
'vs/workbench/contrib/scm/browser/scmViewPane',
|
|
2147
|
+
'scm.providerBorder',
|
|
2148
|
+
"SCM Provider separator border."
|
|
2149
|
+
)));
|
|
2150
|
+
class SCMActionButton {
|
|
2151
|
+
constructor(container, contextMenuService, commandService, notificationService) {
|
|
2152
|
+
this.container = container;
|
|
2153
|
+
this.contextMenuService = contextMenuService;
|
|
2154
|
+
this.commandService = commandService;
|
|
2155
|
+
this.notificationService = notificationService;
|
|
2156
|
+
this.disposables = ( new MutableDisposable());
|
|
2157
|
+
}
|
|
2158
|
+
dispose() {
|
|
2159
|
+
this.disposables?.dispose();
|
|
2160
|
+
}
|
|
2161
|
+
setButton(button) {
|
|
2162
|
+
this.clear();
|
|
2163
|
+
if (!button) {
|
|
2164
|
+
return;
|
|
2165
|
+
}
|
|
2166
|
+
if (button.secondaryCommands?.length) {
|
|
2167
|
+
const actions = [];
|
|
2168
|
+
for (let index = 0; index < button.secondaryCommands.length; index++) {
|
|
2169
|
+
const commands = button.secondaryCommands[index];
|
|
2170
|
+
for (const command of commands) {
|
|
2171
|
+
actions.push(( new Action(
|
|
2172
|
+
command.id,
|
|
2173
|
+
command.title,
|
|
2174
|
+
undefined,
|
|
2175
|
+
true,
|
|
2176
|
+
async () => await this.executeCommand(command.id, ...(command.arguments || []))
|
|
2177
|
+
)));
|
|
2178
|
+
}
|
|
2179
|
+
if (commands.length) {
|
|
2180
|
+
actions.push(( new Separator()));
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
actions.pop();
|
|
2184
|
+
this.button = ( new ButtonWithDropdown(this.container, {
|
|
2185
|
+
actions: actions,
|
|
2186
|
+
addPrimaryActionToDropdown: false,
|
|
2187
|
+
contextMenuProvider: this.contextMenuService,
|
|
2188
|
+
title: button.command.tooltip,
|
|
2189
|
+
supportIcons: true,
|
|
2190
|
+
...defaultButtonStyles
|
|
2191
|
+
}));
|
|
2192
|
+
}
|
|
2193
|
+
else {
|
|
2194
|
+
this.button = ( new Button(
|
|
2195
|
+
this.container,
|
|
2196
|
+
{ supportIcons: true, supportShortLabel: !!button.description, title: button.command.tooltip, ...defaultButtonStyles }
|
|
2197
|
+
));
|
|
2198
|
+
}
|
|
2199
|
+
this.button.enabled = button.enabled;
|
|
2200
|
+
this.button.label = button.command.title;
|
|
2201
|
+
if (this.button instanceof Button && button.description) {
|
|
2202
|
+
this.button.labelShort = button.description;
|
|
2203
|
+
}
|
|
2204
|
+
this.button.onDidClick(async () => await this.executeCommand(button.command.id, ...(button.command.arguments || [])), null, this.disposables.value);
|
|
2205
|
+
this.disposables.value.add(this.button);
|
|
2206
|
+
}
|
|
2207
|
+
focus() {
|
|
2208
|
+
this.button?.focus();
|
|
2209
|
+
}
|
|
2210
|
+
clear() {
|
|
2211
|
+
this.disposables.value = ( new DisposableStore());
|
|
2212
|
+
this.button = undefined;
|
|
2213
|
+
clearNode(this.container);
|
|
2214
|
+
}
|
|
2215
|
+
async executeCommand(commandId, ...args) {
|
|
2216
|
+
try {
|
|
2217
|
+
await this.commandService.executeCommand(commandId, ...args);
|
|
2218
|
+
}
|
|
2219
|
+
catch (ex) {
|
|
2220
|
+
this.notificationService.error(ex);
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
let ScmInputContentProvider = class ScmInputContentProvider extends Disposable {
|
|
2225
|
+
constructor(textModelService, _modelService, _languageService) {
|
|
2226
|
+
super();
|
|
2227
|
+
this._modelService = _modelService;
|
|
2228
|
+
this._languageService = _languageService;
|
|
2229
|
+
this._register(textModelService.registerTextModelContentProvider(Schemas.vscodeSourceControl, this));
|
|
2230
|
+
}
|
|
2231
|
+
async provideTextContent(resource) {
|
|
2232
|
+
const existing = this._modelService.getModel(resource);
|
|
2233
|
+
if (existing) {
|
|
2234
|
+
return existing;
|
|
2235
|
+
}
|
|
2236
|
+
return this._modelService.createModel('', this._languageService.createById('scminput'), resource);
|
|
2237
|
+
}
|
|
2238
|
+
};
|
|
2239
|
+
ScmInputContentProvider = ( __decorate([
|
|
2240
|
+
( __param(0, ITextModelService)),
|
|
2241
|
+
( __param(1, IModelService)),
|
|
2242
|
+
( __param(2, ILanguageService))
|
|
2243
|
+
], ScmInputContentProvider));
|
|
2244
|
+
|
|
2245
|
+
export { ActionButtonRenderer, SCMAccessibilityProvider, SCMActionButton, SCMTreeKeyboardNavigationLabelProvider, SCMTreeSorter, SCMViewPane };
|