UNPKG

@codingame/monaco-vscode-extensions-service-override

Version:

VSCode public API plugged on the monaco editor - extensions service-override

403 lines (399 loc) 17.6 kB
import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6'; import { Disposable, DisposableMap, DisposableStore } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle'; import { ExtHostContext, MainContext } from '@codingame/monaco-vscode-api/vscode/vs/workbench/api/common/extHost.protocol'; import { Extensions, NoTreeViewError, ResolvableTreeItem } from '@codingame/monaco-vscode-api/vscode/vs/workbench/common/views'; import { extHostNamedCustomer } from '../../services/extensions/common/extHostCustomers.js'; import { distinct } from '@codingame/monaco-vscode-api/vscode/vs/base/common/arrays'; import { INotificationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/notification/common/notification.service'; import { isUndefinedOrNull, isNumber } from '@codingame/monaco-vscode-api/vscode/vs/base/common/types'; import { Registry } from '@codingame/monaco-vscode-api/vscode/vs/platform/registry/common/platform'; import { IExtensionService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extensions.service'; import { ILogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log.service'; import { VSDataTransfer, UriList, createStringDataTransferItem } from '@codingame/monaco-vscode-api/vscode/vs/base/common/dataTransfer'; import { Mimes } from '@codingame/monaco-vscode-api/vscode/vs/base/common/mime'; import { URI } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uri'; import { DataTransferFileCache } from '../common/shared/dataTransferCache.js'; import { DataTransfer } from '@codingame/monaco-vscode-api/vscode/vs/workbench/api/common/extHostTypeConverters'; import { IViewsService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/views/common/viewsService.service'; import { ITelemetryService } from '@codingame/monaco-vscode-api/vscode/vs/platform/telemetry/common/telemetry.service'; let MainThreadTreeViews = class MainThreadTreeViews extends Disposable { constructor( extHostContext, viewsService, notificationService, extensionService, logService, telemetryService ) { super(); this.viewsService = viewsService; this.notificationService = notificationService; this.extensionService = extensionService; this.logService = logService; this.telemetryService = telemetryService; this._dataProviders = this._register(( new DisposableMap())); this._dndControllers = ( new Map()); this._proxy = ( extHostContext.getProxy(ExtHostContext.ExtHostTreeViews)); } async $registerTreeViewDataProvider(treeViewId, options) { this.logService.trace("MainThreadTreeViews#$registerTreeViewDataProvider", treeViewId, options); this.extensionService.whenInstalledExtensionsRegistered().then(() => { const dataProvider = ( new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService)); const disposables = ( new DisposableStore()); this._dataProviders.set(treeViewId, { dataProvider, dispose: () => disposables.dispose() }); const dndController = (options.hasHandleDrag || options.hasHandleDrop) ? ( new TreeViewDragAndDropController( treeViewId, options.dropMimeTypes, options.dragMimeTypes, options.hasHandleDrag, this._proxy )) : undefined; const viewer = this.getTreeView(treeViewId); if (viewer) { viewer.showCollapseAllAction = options.showCollapseAll; viewer.canSelectMany = options.canSelectMany; viewer.manuallyManageCheckboxes = options.manuallyManageCheckboxes; viewer.dragAndDropController = dndController; if (dndController) { this._dndControllers.set(treeViewId, dndController); } viewer.dataProvider = dataProvider; this.registerListeners(treeViewId, viewer, disposables); this._proxy.$setVisible(treeViewId, viewer.visible); } else { this.notificationService.error("No view is registered with id: " + treeViewId); } }); } $reveal(treeViewId, itemInfo, options) { this.logService.trace( "MainThreadTreeViews#$reveal", treeViewId, itemInfo?.item, itemInfo?.parentChain, options ); return this.viewsService.openView(treeViewId, options.focus).then(() => { const viewer = this.getTreeView(treeViewId); if (viewer && itemInfo) { return this.reveal( viewer, this._dataProviders.get(treeViewId).dataProvider, itemInfo.item, itemInfo.parentChain, options ); } return undefined; }); } $refresh(treeViewId, itemsToRefreshByHandle) { this.logService.trace("MainThreadTreeViews#$refresh", treeViewId, itemsToRefreshByHandle); const viewer = this.getTreeView(treeViewId); const dataProvider = this._dataProviders.get(treeViewId); if (viewer && dataProvider) { const itemsToRefresh = dataProvider.dataProvider.getItemsToRefresh(itemsToRefreshByHandle); return viewer.refresh( itemsToRefresh.items.length ? itemsToRefresh.items : undefined, itemsToRefresh.checkboxes.length ? itemsToRefresh.checkboxes : undefined ); } return Promise.resolve(); } $setMessage(treeViewId, message) { this.logService.trace("MainThreadTreeViews#$setMessage", treeViewId, ( message.toString())); const viewer = this.getTreeView(treeViewId); if (viewer) { viewer.message = message; } } $setTitle(treeViewId, title, description) { this.logService.trace("MainThreadTreeViews#$setTitle", treeViewId, title, description); const viewer = this.getTreeView(treeViewId); if (viewer) { viewer.title = title; viewer.description = description; } } $setBadge(treeViewId, badge) { this.logService.trace("MainThreadTreeViews#$setBadge", treeViewId, badge?.value, badge?.tooltip); const viewer = this.getTreeView(treeViewId); if (viewer) { viewer.badge = badge; } } $resolveDropFileData(destinationViewId, requestId, dataItemId) { const controller = this._dndControllers.get(destinationViewId); if (!controller) { throw ( new Error("Unknown tree")); } return controller.resolveDropFileData(requestId, dataItemId); } async $disposeTree(treeViewId) { const viewer = this.getTreeView(treeViewId); if (viewer) { viewer.dataProvider = undefined; } this._dataProviders.deleteAndDispose(treeViewId); } $logResolveTreeNodeFailure(extensionId) { this.telemetryService.publicLog2("treeView.resolveFailure", { extensionId }); } async reveal(treeView, dataProvider, itemIn, parentChain, options) { options = options ? options : { select: false, focus: false }; const select = isUndefinedOrNull(options.select) ? false : options.select; const focus = isUndefinedOrNull(options.focus) ? false : options.focus; let expand = Math.min( isNumber(options.expand) ? options.expand : options.expand === true ? 1 : 0, 3 ); if (dataProvider.isEmpty()) { await treeView.refresh(); } for (const parent of parentChain) { const parentItem = dataProvider.getItem(parent.handle); if (parentItem) { await treeView.expand(parentItem); } } const item = dataProvider.getItem(itemIn.handle); if (item) { await treeView.reveal(item); if (select) { treeView.setSelection([item]); } if (focus === false) { treeView.setFocus(); } else if (focus) { treeView.setFocus(item); } let itemsToExpand = [item]; for (; itemsToExpand.length > 0 && expand > 0; expand--) { await treeView.expand(itemsToExpand); itemsToExpand = itemsToExpand.reduce((result, itemValue) => { const item = dataProvider.getItem(itemValue.handle); if (item && item.children && item.children.length) { result.push(...item.children); } return result; }, []); } } } registerListeners(treeViewId, treeView, disposables) { disposables.add( treeView.onDidExpandItem(item => this._proxy.$setExpanded(treeViewId, item.handle, true)) ); disposables.add( treeView.onDidCollapseItem(item => this._proxy.$setExpanded(treeViewId, item.handle, false)) ); disposables.add( treeView.onDidChangeSelectionAndFocus(items => this._proxy.$setSelectionAndFocus(treeViewId, ( items.selection.map(( { handle } ) => handle)), items.focus.handle)) ); disposables.add( treeView.onDidChangeVisibility(isVisible => this._proxy.$setVisible(treeViewId, isVisible)) ); disposables.add(treeView.onDidChangeCheckboxState(items => { this._proxy.$changeCheckboxState(treeViewId, ( items.map(item => { return { treeItemHandle: item.handle, newState: item.checkbox?.isChecked ?? false }; }))); })); } getTreeView(treeViewId) { const viewDescriptor = ( Registry.as(Extensions.ViewsRegistry)).getView(treeViewId); return viewDescriptor ? viewDescriptor.treeView : null; } dispose() { for (const dataprovider of this._dataProviders) { const treeView = this.getTreeView(dataprovider[0]); if (treeView) { treeView.dataProvider = undefined; } } this._dataProviders.dispose(); this._dndControllers.clear(); super.dispose(); } }; MainThreadTreeViews = __decorate([extHostNamedCustomer(MainContext.MainThreadTreeViews), ( __param(1, IViewsService)), ( __param(2, INotificationService)), ( __param(3, IExtensionService)), ( __param(4, ILogService)), ( __param(5, ITelemetryService))], MainThreadTreeViews); class TreeViewDragAndDropController { constructor(treeViewId, dropMimeTypes, dragMimeTypes, hasWillDrop, _proxy) { this.treeViewId = treeViewId; this.dropMimeTypes = dropMimeTypes; this.dragMimeTypes = dragMimeTypes; this.hasWillDrop = hasWillDrop; this._proxy = _proxy; this.dataTransfersCache = ( new DataTransferFileCache()); } async handleDrop( dataTransfer, targetTreeItem, token, operationUuid, sourceTreeId, sourceTreeItemHandles ) { const request = this.dataTransfersCache.add(dataTransfer); try { const dataTransferDto = await DataTransfer.fromList(dataTransfer); if (token.isCancellationRequested) { return; } return await this._proxy.$handleDrop( this.treeViewId, request.id, dataTransferDto, targetTreeItem?.handle, token, operationUuid, sourceTreeId, sourceTreeItemHandles ); } finally { request.dispose(); } } async handleDrag(sourceTreeItemHandles, operationUuid, token) { if (!this.hasWillDrop) { return; } const additionalDataTransferDTO = await this._proxy.$handleDrag(this.treeViewId, sourceTreeItemHandles, operationUuid, token); if (!additionalDataTransferDTO) { return; } const additionalDataTransfer = ( new VSDataTransfer()); additionalDataTransferDTO.items.forEach(([type, item]) => { const value = type === Mimes.uriList && item.uriListData ? UriList.create(( item.uriListData.map(part => typeof part === "string" ? part : URI.revive(part)))) : item.asString; additionalDataTransfer.replace(type, createStringDataTransferItem(value)); }); return additionalDataTransfer; } resolveDropFileData(requestId, dataItemId) { return this.dataTransfersCache.resolveFileData(requestId, dataItemId); } } class TreeViewDataProvider { constructor(treeViewId, _proxy, notificationService) { this.treeViewId = treeViewId; this._proxy = _proxy; this.notificationService = notificationService; this.itemsMap = ( new Map()); this.hasResolve = this._proxy.$hasResolve(this.treeViewId); } async getChildren(treeItem) { const batches = await this.getChildrenBatch(treeItem ? [treeItem] : undefined); return batches?.[0]; } getChildrenBatch(treeItems) { if (!treeItems) { this.itemsMap.clear(); } return this._proxy.$getChildren(this.treeViewId, treeItems ? ( treeItems.map(item => item.handle)) : undefined).then(children => { const convertedChildren = this.convertTransferChildren(treeItems ?? [], children); return this.postGetChildren(convertedChildren); }, err => { if (!NoTreeViewError.is(err)) { this.notificationService.error(err); } return []; }); } convertTransferChildren(parents, children) { const convertedChildren = Array(parents.length); if (children) { for (const childGroup of children) { const childGroupIndex = childGroup[0]; convertedChildren[childGroupIndex] = childGroup.slice(1); } } return convertedChildren; } getItemsToRefresh(itemsToRefreshByHandle) { const itemsToRefresh = []; const checkboxesToRefresh = []; if (itemsToRefreshByHandle) { for (const newTreeItemHandle of ( Object.keys(itemsToRefreshByHandle))) { const currentTreeItem = this.getItem(newTreeItemHandle); if (currentTreeItem) { const newTreeItem = itemsToRefreshByHandle[newTreeItemHandle]; if (currentTreeItem.checkbox?.isChecked !== newTreeItem.checkbox?.isChecked) { checkboxesToRefresh.push(currentTreeItem); } this.updateTreeItem(currentTreeItem, newTreeItem); if (newTreeItemHandle === newTreeItem.handle) { itemsToRefresh.push(currentTreeItem); } else { this.itemsMap.delete(newTreeItemHandle); this.itemsMap.set(currentTreeItem.handle, currentTreeItem); const parent = newTreeItem.parentHandle ? this.itemsMap.get(newTreeItem.parentHandle) : null; if (parent) { itemsToRefresh.push(parent); } } } } } return { items: itemsToRefresh, checkboxes: checkboxesToRefresh }; } getItem(treeItemHandle) { return this.itemsMap.get(treeItemHandle); } isEmpty() { return this.itemsMap.size === 0; } async postGetChildren(elementGroups) { if (elementGroups === undefined) { return undefined; } const resultGroups = []; const hasResolve = await this.hasResolve; if (elementGroups) { for (const elements of elementGroups) { const result = []; resultGroups.push(result); if (!elements) { continue; } for (const element of elements) { const resolvable = ( new ResolvableTreeItem(element, hasResolve ? token => { return this._proxy.$resolve(this.treeViewId, element.handle, token); } : undefined)); this.itemsMap.set(element.handle, resolvable); result.push(resolvable); } } } return resultGroups; } updateTreeItem(current, treeItem) { treeItem.children = treeItem.children ? treeItem.children : undefined; if (current) { const properties = distinct([...( Object.keys(current instanceof ResolvableTreeItem ? current.asTreeItem() : current)), ...( Object.keys(treeItem))]); for (const property of properties) { current[property] = treeItem[property]; } if (current instanceof ResolvableTreeItem) { current.resetResolve(); } } } } export { MainThreadTreeViews };