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