Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/files/browser/files.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { URI } from '../../../../base/common/uri.js';
7
import { IListService } from '../../../../platform/list/browser/listService.js';
8
import { OpenEditor, ISortOrderConfiguration } from '../common/files.js';
9
import { EditorResourceAccessor, SideBySideEditor, IEditorIdentifier } from '../../../common/editor.js';
10
import { List } from '../../../../base/browser/ui/list/listWidget.js';
11
import { IEditorService } from '../../../services/editor/common/editorService.js';
12
import { ExplorerItem } from '../common/explorerModel.js';
13
import { coalesce } from '../../../../base/common/arrays.js';
14
import { AsyncDataTree } from '../../../../base/browser/ui/tree/asyncDataTree.js';
15
import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js';
16
import { IEditableData } from '../../../common/views.js';
17
import { createDecorator, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
18
import { ResourceFileEdit } from '../../../../editor/browser/services/bulkEditService.js';
19
import { ProgressLocation } from '../../../../platform/progress/common/progress.js';
20
import { isActiveElement } from '../../../../base/browser/dom.js';
21
22
export interface IExplorerService {
23
readonly _serviceBrand: undefined;
24
readonly roots: ExplorerItem[];
25
readonly sortOrderConfiguration: ISortOrderConfiguration;
26
27
getContext(respectMultiSelection: boolean, ignoreNestedChildren?: boolean): ExplorerItem[];
28
hasViewFocus(): boolean;
29
setEditable(stat: ExplorerItem, data: IEditableData | null): Promise<void>;
30
getEditable(): { stat: ExplorerItem; data: IEditableData } | undefined;
31
getEditableData(stat: ExplorerItem): IEditableData | undefined;
32
// If undefined is passed checks if any element is currently being edited.
33
isEditable(stat: ExplorerItem | undefined): boolean;
34
findClosest(resource: URI): ExplorerItem | null;
35
findClosestRoot(resource: URI): ExplorerItem | null;
36
refresh(): Promise<void>;
37
setToCopy(stats: ExplorerItem[], cut: boolean): Promise<void>;
38
isCut(stat: ExplorerItem): boolean;
39
applyBulkEdit(edit: ResourceFileEdit[], options: { undoLabel: string; progressLabel: string; confirmBeforeUndo?: boolean; progressLocation?: ProgressLocation.Explorer | ProgressLocation.Window }): Promise<void>;
40
41
/**
42
* Selects and reveal the file element provided by the given resource if its found in the explorer.
43
* Will try to resolve the path in case the explorer is not yet expanded to the file yet.
44
*/
45
select(resource: URI, reveal?: boolean | string): Promise<void>;
46
47
registerView(contextAndRefreshProvider: IExplorerView): void;
48
}
49
50
export const IExplorerService = createDecorator<IExplorerService>('explorerService');
51
52
export interface IExplorerView {
53
autoReveal: boolean | 'force' | 'focusNoScroll';
54
getContext(respectMultiSelection: boolean): ExplorerItem[];
55
refresh(recursive: boolean, item?: ExplorerItem, cancelEditing?: boolean): Promise<void>;
56
selectResource(resource: URI | undefined, reveal?: boolean | string, retry?: number): Promise<void>;
57
setTreeInput(): Promise<void>;
58
itemsCopied(tats: ExplorerItem[], cut: boolean, previousCut: ExplorerItem[] | undefined): void;
59
setEditable(stat: ExplorerItem, isEditing: boolean): Promise<void>;
60
isItemVisible(item: ExplorerItem): boolean;
61
isItemCollapsed(item: ExplorerItem): boolean;
62
hasFocus(): boolean;
63
getFocus(): ExplorerItem[];
64
focusNext(): void;
65
focusLast(): void;
66
hasPhantomElements(): boolean;
67
}
68
69
function getFocus(listService: IListService): unknown | undefined {
70
const list = listService.lastFocusedList;
71
const element = list?.getHTMLElement();
72
if (element && isActiveElement(element)) {
73
let focus: unknown;
74
if (list instanceof List) {
75
const focused = list.getFocusedElements();
76
if (focused.length) {
77
focus = focused[0];
78
}
79
} else if (list instanceof AsyncDataTree) {
80
const focused = list.getFocus();
81
if (focused.length) {
82
focus = focused[0];
83
}
84
}
85
86
return focus;
87
}
88
89
return undefined;
90
}
91
92
// Commands can get executed from a command palette, from a context menu or from some list using a keybinding
93
// To cover all these cases we need to properly compute the resource on which the command is being executed
94
export function getResourceForCommand(commandArg: unknown, editorService: IEditorService, listService: IListService): URI | undefined {
95
if (URI.isUri(commandArg)) {
96
return commandArg;
97
}
98
99
const focus = getFocus(listService);
100
if (focus instanceof ExplorerItem) {
101
return focus.resource;
102
} else if (focus instanceof OpenEditor) {
103
return focus.getResource();
104
}
105
106
return EditorResourceAccessor.getOriginalUri(editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY });
107
}
108
109
export function getMultiSelectedResources(commandArg: unknown, listService: IListService, editorSerice: IEditorService, editorGroupService: IEditorGroupsService, explorerService: IExplorerService): Array<URI> {
110
const list = listService.lastFocusedList;
111
const element = list?.getHTMLElement();
112
if (element && isActiveElement(element)) {
113
// Explorer
114
if (list instanceof AsyncDataTree && list.getFocus().every(item => item instanceof ExplorerItem)) {
115
// Explorer
116
const context = explorerService.getContext(true, true);
117
if (context.length) {
118
return context.map(c => c.resource);
119
}
120
}
121
122
// Open editors view
123
if (list instanceof List) {
124
const selection = coalesce(list.getSelectedElements().filter(s => s instanceof OpenEditor).map((oe: OpenEditor) => oe.getResource()));
125
const focusedElements = list.getFocusedElements();
126
const focus = focusedElements.length ? focusedElements[0] : undefined;
127
let mainUriStr: string | undefined = undefined;
128
if (URI.isUri(commandArg)) {
129
mainUriStr = commandArg.toString();
130
} else if (focus instanceof OpenEditor) {
131
const focusedResource = focus.getResource();
132
mainUriStr = focusedResource ? focusedResource.toString() : undefined;
133
}
134
// We only respect the selection if it contains the main element.
135
const mainIndex = selection.findIndex(s => s.toString() === mainUriStr);
136
if (mainIndex !== -1) {
137
// Move the main resource to the front of the selection.
138
const mainResource = selection[mainIndex];
139
selection.splice(mainIndex, 1);
140
selection.unshift(mainResource);
141
return selection;
142
}
143
}
144
}
145
146
// Check for tabs multiselect
147
const activeGroup = editorGroupService.activeGroup;
148
const selection = activeGroup.selectedEditors;
149
if (selection.length > 1 && URI.isUri(commandArg)) {
150
// If the resource is part of the tabs selection, return all selected tabs/resources.
151
// It's possible that multiple tabs are selected but the action was applied to a resource that is not part of the selection.
152
const mainEditorSelectionIndex = selection.findIndex(e => e.matches({ resource: commandArg }));
153
if (mainEditorSelectionIndex !== -1) {
154
const mainEditor = selection[mainEditorSelectionIndex];
155
selection.splice(mainEditorSelectionIndex, 1);
156
selection.unshift(mainEditor);
157
return selection.map(editor => EditorResourceAccessor.getOriginalUri(editor)).filter(uri => !!uri);
158
}
159
}
160
161
const result = getResourceForCommand(commandArg, editorSerice, listService);
162
return !!result ? [result] : [];
163
}
164
165
export function getOpenEditorsViewMultiSelection(accessor: ServicesAccessor): Array<IEditorIdentifier> | undefined {
166
const list = accessor.get(IListService).lastFocusedList;
167
const element = list?.getHTMLElement();
168
if (element && isActiveElement(element)) {
169
// Open editors view
170
if (list instanceof List) {
171
const selection = coalesce(list.getSelectedElements().filter(s => s instanceof OpenEditor));
172
const focusedElements = list.getFocusedElements();
173
const focus = focusedElements.length ? focusedElements[0] : undefined;
174
let mainEditor: IEditorIdentifier | undefined = undefined;
175
if (focus instanceof OpenEditor) {
176
mainEditor = focus;
177
}
178
// We only respect the selection if it contains the main element.
179
if (selection.some(s => s === mainEditor)) {
180
return selection;
181
}
182
return mainEditor ? [mainEditor] : undefined;
183
}
184
}
185
186
return undefined;
187
}
188
189