@theia/plugin-ext 1.34.0-next.7 → 1.34.0
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/lib/common/plugin-api-rpc.d.ts +30 -10
- package/lib/common/plugin-api-rpc.d.ts.map +1 -1
- package/lib/common/plugin-api-rpc.js +23 -11
- package/lib/common/plugin-api-rpc.js.map +1 -1
- package/lib/common/plugin-protocol.d.ts +15 -0
- package/lib/common/plugin-protocol.d.ts.map +1 -1
- package/lib/common/plugin-protocol.js.map +1 -1
- package/lib/common/rpc-protocol.d.ts.map +1 -1
- package/lib/common/rpc-protocol.js +3 -4
- package/lib/common/rpc-protocol.js.map +1 -1
- package/lib/common/types.d.ts +1 -1
- package/lib/common/types.d.ts.map +1 -1
- package/lib/common/types.js +2 -3
- package/lib/common/types.js.map +1 -1
- package/lib/hosted/browser/hosted-plugin.d.ts +1 -0
- package/lib/hosted/browser/hosted-plugin.d.ts.map +1 -1
- package/lib/hosted/browser/hosted-plugin.js +3 -0
- package/lib/hosted/browser/hosted-plugin.js.map +1 -1
- package/lib/hosted/node/hosted-plugin-localization-service.d.ts.map +1 -1
- package/lib/hosted/node/hosted-plugin-localization-service.js +2 -2
- package/lib/hosted/node/hosted-plugin-localization-service.js.map +1 -1
- package/lib/hosted/node/plugin-host.d.ts +1 -1
- package/lib/hosted/node/plugin-host.d.ts.map +1 -1
- package/lib/hosted/node/plugin-host.js +1 -2
- package/lib/hosted/node/plugin-host.js.map +1 -1
- package/lib/hosted/node/scanners/scanner-theia.d.ts +2 -1
- package/lib/hosted/node/scanners/scanner-theia.d.ts.map +1 -1
- package/lib/hosted/node/scanners/scanner-theia.js +13 -0
- package/lib/hosted/node/scanners/scanner-theia.js.map +1 -1
- package/lib/main/browser/authentication-main.js +1 -1
- package/lib/main/browser/authentication-main.js.map +1 -1
- package/lib/main/browser/commands.js +1 -1
- package/lib/main/browser/commands.js.map +1 -1
- package/lib/main/browser/debug/debug-main.d.ts.map +1 -1
- package/lib/main/browser/debug/debug-main.js +1 -0
- package/lib/main/browser/debug/debug-main.js.map +1 -1
- package/lib/main/browser/dialogs-main.d.ts.map +1 -1
- package/lib/main/browser/dialogs-main.js +2 -1
- package/lib/main/browser/dialogs-main.js.map +1 -1
- package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts +2 -2
- package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts.map +1 -1
- package/lib/main/browser/menus/plugin-menu-command-adapter.js +6 -2
- package/lib/main/browser/menus/plugin-menu-command-adapter.js.map +1 -1
- package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts +2 -2
- package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts.map +1 -1
- package/lib/main/browser/menus/vscode-theia-menu-mappings.js +6 -0
- package/lib/main/browser/menus/vscode-theia-menu-mappings.js.map +1 -1
- package/lib/main/browser/plugin-contribution-handler.d.ts +6 -0
- package/lib/main/browser/plugin-contribution-handler.d.ts.map +1 -1
- package/lib/main/browser/plugin-contribution-handler.js +35 -0
- package/lib/main/browser/plugin-contribution-handler.js.map +1 -1
- package/lib/main/browser/plugin-ext-frontend-module.d.ts.map +1 -1
- package/lib/main/browser/plugin-ext-frontend-module.js +8 -3
- package/lib/main/browser/plugin-ext-frontend-module.js.map +1 -1
- package/lib/main/browser/plugin-terminal-registry.d.ts +5 -0
- package/lib/main/browser/plugin-terminal-registry.d.ts.map +1 -0
- package/lib/main/browser/plugin-terminal-registry.js +35 -0
- package/lib/main/browser/plugin-terminal-registry.js.map +1 -0
- package/lib/main/browser/scm-main.d.ts +1 -0
- package/lib/main/browser/scm-main.d.ts.map +1 -1
- package/lib/main/browser/scm-main.js +7 -0
- package/lib/main/browser/scm-main.js.map +1 -1
- package/lib/main/browser/terminal-main.d.ts +10 -4
- package/lib/main/browser/terminal-main.d.ts.map +1 -1
- package/lib/main/browser/terminal-main.js +51 -25
- package/lib/main/browser/terminal-main.js.map +1 -1
- package/lib/main/browser/view/dnd-file-content-store.d.ts +8 -0
- package/lib/main/browser/view/dnd-file-content-store.d.ts.map +1 -0
- package/lib/main/browser/view/dnd-file-content-store.js +52 -0
- package/lib/main/browser/view/dnd-file-content-store.js.map +1 -0
- package/lib/main/browser/view/plugin-view-registry.d.ts.map +1 -1
- package/lib/main/browser/view/plugin-view-registry.js +1 -1
- package/lib/main/browser/view/plugin-view-registry.js.map +1 -1
- package/lib/main/browser/view/tree-view-decorator-service.d.ts +2 -4
- package/lib/main/browser/view/tree-view-decorator-service.d.ts.map +1 -1
- package/lib/main/browser/view/tree-view-decorator-service.js +1 -2
- package/lib/main/browser/view/tree-view-decorator-service.js.map +1 -1
- package/lib/main/browser/view/tree-view-widget.d.ts +25 -9
- package/lib/main/browser/view/tree-view-widget.d.ts.map +1 -1
- package/lib/main/browser/view/tree-view-widget.js +184 -38
- package/lib/main/browser/view/tree-view-widget.js.map +1 -1
- package/lib/main/browser/view/tree-views-main.d.ts +5 -2
- package/lib/main/browser/view/tree-views-main.d.ts.map +1 -1
- package/lib/main/browser/view/tree-views-main.js +16 -2
- package/lib/main/browser/view/tree-views-main.js.map +1 -1
- package/lib/main/browser/webview/webview.d.ts +1 -1
- package/lib/main/browser/webview/webview.d.ts.map +1 -1
- package/lib/main/browser/webview/webview.js +7 -2
- package/lib/main/browser/webview/webview.js.map +1 -1
- package/lib/main/node/handlers/plugin-theia-directory-handler.d.ts +1 -1
- package/lib/main/node/handlers/plugin-theia-directory-handler.d.ts.map +1 -1
- package/lib/plugin/debug/debug-ext.d.ts +3 -0
- package/lib/plugin/debug/debug-ext.d.ts.map +1 -1
- package/lib/plugin/debug/debug-ext.js +10 -0
- package/lib/plugin/debug/debug-ext.js.map +1 -1
- package/lib/plugin/languages/code-action.d.ts.map +1 -1
- package/lib/plugin/languages/code-action.js +8 -8
- package/lib/plugin/languages/code-action.js.map +1 -1
- package/lib/plugin/plugin-context.d.ts.map +1 -1
- package/lib/plugin/plugin-context.js +8 -0
- package/lib/plugin/plugin-context.js.map +1 -1
- package/lib/plugin/plugin-manager.d.ts.map +1 -1
- package/lib/plugin/plugin-manager.js +1 -0
- package/lib/plugin/plugin-manager.js.map +1 -1
- package/lib/plugin/preference-registry.d.ts.map +1 -1
- package/lib/plugin/preference-registry.js +4 -2
- package/lib/plugin/preference-registry.js.map +1 -1
- package/lib/plugin/quick-open.d.ts +3 -0
- package/lib/plugin/quick-open.d.ts.map +1 -1
- package/lib/plugin/quick-open.js +7 -0
- package/lib/plugin/quick-open.js.map +1 -1
- package/lib/plugin/scm.d.ts +3 -0
- package/lib/plugin/scm.d.ts.map +1 -1
- package/lib/plugin/scm.js +7 -0
- package/lib/plugin/scm.js.map +1 -1
- package/lib/plugin/tabs.js +2 -2
- package/lib/plugin/tabs.js.map +1 -1
- package/lib/plugin/terminal-ext.d.ts +9 -1
- package/lib/plugin/terminal-ext.d.ts.map +1 -1
- package/lib/plugin/terminal-ext.js +63 -7
- package/lib/plugin/terminal-ext.js.map +1 -1
- package/lib/plugin/tree/tree-views.d.ts +13 -7
- package/lib/plugin/tree/tree-views.d.ts.map +1 -1
- package/lib/plugin/tree/tree-views.js +93 -24
- package/lib/plugin/tree/tree-views.js.map +1 -1
- package/lib/plugin/type-converters.d.ts +4 -0
- package/lib/plugin/type-converters.d.ts.map +1 -1
- package/lib/plugin/type-converters.js +48 -46
- package/lib/plugin/type-converters.js.map +1 -1
- package/lib/plugin/type-converters.spec.js +19 -0
- package/lib/plugin/type-converters.spec.js.map +1 -1
- package/lib/plugin/types-impl.d.ts +61 -6
- package/lib/plugin/types-impl.d.ts.map +1 -1
- package/lib/plugin/types-impl.js +117 -17
- package/lib/plugin/types-impl.js.map +1 -1
- package/package.json +26 -26
- package/src/common/plugin-api-rpc.ts +36 -18
- package/src/common/plugin-protocol.ts +18 -0
- package/src/common/rpc-protocol.ts +2 -3
- package/src/common/types.ts +4 -4
- package/src/hosted/browser/hosted-plugin.ts +4 -0
- package/src/hosted/node/hosted-plugin-localization-service.ts +3 -3
- package/src/hosted/node/plugin-host.ts +1 -2
- package/src/hosted/node/scanners/scanner-theia.ts +15 -1
- package/src/main/browser/authentication-main.ts +1 -1
- package/src/main/browser/commands.ts +1 -1
- package/src/main/browser/debug/debug-main.ts +1 -0
- package/src/main/browser/dialogs-main.ts +2 -1
- package/src/main/browser/menus/plugin-menu-command-adapter.ts +7 -4
- package/src/main/browser/menus/vscode-theia-menu-mappings.ts +6 -0
- package/src/main/browser/plugin-contribution-handler.ts +35 -0
- package/src/main/browser/plugin-ext-frontend-module.ts +10 -4
- package/src/main/browser/plugin-terminal-registry.ts +27 -0
- package/src/main/browser/scm-main.ts +10 -0
- package/src/main/browser/terminal-main.ts +55 -25
- package/src/main/browser/view/dnd-file-content-store.ts +42 -0
- package/src/main/browser/view/plugin-view-registry.ts +4 -1
- package/src/main/browser/view/tree-view-decorator-service.ts +4 -5
- package/src/main/browser/view/tree-view-widget.tsx +189 -35
- package/src/main/browser/view/tree-views-main.ts +20 -4
- package/src/main/browser/webview/pre/main.js +112 -111
- package/src/main/browser/webview/webview.ts +7 -3
- package/src/plugin/debug/debug-ext.ts +12 -0
- package/src/plugin/languages/code-action.ts +8 -8
- package/src/plugin/plugin-context.ts +16 -3
- package/src/plugin/plugin-manager.ts +1 -0
- package/src/plugin/preference-registry.ts +4 -2
- package/src/plugin/quick-open.ts +10 -0
- package/src/plugin/scm.ts +11 -0
- package/src/plugin/tabs.ts +2 -2
- package/src/plugin/terminal-ext.ts +68 -8
- package/src/plugin/tree/tree-views.ts +98 -31
- package/src/plugin/type-converters.spec.ts +20 -0
- package/src/plugin/type-converters.ts +51 -50
- package/src/plugin/types-impl.ts +143 -21
|
@@ -14,9 +14,8 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
import { URI } from '@theia/core/shared/vscode-uri';
|
|
18
17
|
import { injectable, inject, postConstruct } from '@theia/core/shared/inversify';
|
|
19
|
-
import { TreeViewsExt, TreeViewItemCollapsibleState, TreeViewItem,
|
|
18
|
+
import { TreeViewsExt, TreeViewItemCollapsibleState, TreeViewItem, TreeViewItemReference, ThemeIcon, DataTransferFileDTO } from '../../../common/plugin-api-rpc';
|
|
20
19
|
import { Command } from '../../../common/plugin-api-rpc-model';
|
|
21
20
|
import {
|
|
22
21
|
TreeNode,
|
|
@@ -32,7 +31,8 @@ import {
|
|
|
32
31
|
TreeViewWelcomeWidget,
|
|
33
32
|
TooltipAttributes,
|
|
34
33
|
TreeSelection,
|
|
35
|
-
HoverService
|
|
34
|
+
HoverService,
|
|
35
|
+
ApplicationShell
|
|
36
36
|
} from '@theia/core/lib/browser';
|
|
37
37
|
import { MenuPath, MenuModelRegistry, ActionMenuNode } from '@theia/core/lib/common/menu';
|
|
38
38
|
import * as React from '@theia/core/shared/react';
|
|
@@ -41,7 +41,7 @@ import { ACTION_ITEM, Widget } from '@theia/core/lib/browser/widgets/widget';
|
|
|
41
41
|
import { Emitter, Event } from '@theia/core/lib/common/event';
|
|
42
42
|
import { MessageService } from '@theia/core/lib/common/message-service';
|
|
43
43
|
import { View } from '../../../common/plugin-protocol';
|
|
44
|
-
import
|
|
44
|
+
import { URI } from '@theia/core/lib/common/uri';
|
|
45
45
|
import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
|
|
46
46
|
import { MarkdownString } from '@theia/core/lib/common/markdown-rendering';
|
|
47
47
|
import { LabelParser } from '@theia/core/lib/browser/label-parser';
|
|
@@ -52,6 +52,7 @@ import { WidgetDecoration } from '@theia/core/lib/browser/widget-decoration';
|
|
|
52
52
|
import { CancellationTokenSource, CancellationToken } from '@theia/core/lib/common';
|
|
53
53
|
import { mixin } from '../../../common/types';
|
|
54
54
|
import { Deferred } from '@theia/core/lib/common/promise-util';
|
|
55
|
+
import { DnDFileContentStore } from './dnd-file-content-store';
|
|
55
56
|
|
|
56
57
|
export const TREE_NODE_HYPERLINK = 'theia-TreeNodeHyperlink';
|
|
57
58
|
export const VIEW_ITEM_CONTEXT_MENU: MenuPath = ['view-item-context-menu'];
|
|
@@ -161,8 +162,11 @@ export namespace CompositeTreeViewNode {
|
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
@injectable()
|
|
164
|
-
export class
|
|
165
|
+
export class TreeViewWidgetOptions {
|
|
165
166
|
id: string;
|
|
167
|
+
multiSelect: boolean | undefined;
|
|
168
|
+
dragMimeTypes: string[] | undefined;
|
|
169
|
+
dropMimeTypes: string[] | undefined;
|
|
166
170
|
}
|
|
167
171
|
|
|
168
172
|
@injectable()
|
|
@@ -171,8 +175,8 @@ export class PluginTree extends TreeImpl {
|
|
|
171
175
|
@inject(PluginSharedStyle)
|
|
172
176
|
protected readonly sharedStyle: PluginSharedStyle;
|
|
173
177
|
|
|
174
|
-
@inject(
|
|
175
|
-
protected readonly
|
|
178
|
+
@inject(TreeViewWidgetOptions)
|
|
179
|
+
protected readonly options: TreeViewWidgetOptions;
|
|
176
180
|
|
|
177
181
|
@inject(MessageService)
|
|
178
182
|
protected readonly notification: MessageService;
|
|
@@ -188,7 +192,7 @@ export class PluginTree extends TreeImpl {
|
|
|
188
192
|
set proxy(proxy: TreeViewsExt | undefined) {
|
|
189
193
|
this._proxy = proxy;
|
|
190
194
|
if (proxy) {
|
|
191
|
-
this._hasTreeItemResolve = proxy.$hasResolveTreeItem(this.
|
|
195
|
+
this._hasTreeItemResolve = proxy.$hasResolveTreeItem(this.options.id);
|
|
192
196
|
} else {
|
|
193
197
|
this._hasTreeItemResolve = Promise.resolve(false);
|
|
194
198
|
}
|
|
@@ -220,7 +224,7 @@ export class PluginTree extends TreeImpl {
|
|
|
220
224
|
|
|
221
225
|
protected async fetchChildren(proxy: TreeViewsExt, parent: CompositeTreeNode): Promise<TreeViewItem[]> {
|
|
222
226
|
try {
|
|
223
|
-
const children = await proxy.$getChildren(this.
|
|
227
|
+
const children = await proxy.$getChildren(this.options.id, parent.id);
|
|
224
228
|
const oldEmpty = this._isEmpty;
|
|
225
229
|
this._isEmpty = !parent.id && (!children || children.length === 0);
|
|
226
230
|
if (oldEmpty !== this._isEmpty) {
|
|
@@ -229,8 +233,8 @@ export class PluginTree extends TreeImpl {
|
|
|
229
233
|
return children || [];
|
|
230
234
|
} catch (e) {
|
|
231
235
|
if (e) {
|
|
232
|
-
console.error(`Failed to fetch children for '${this.
|
|
233
|
-
const label = this._viewInfo ? this._viewInfo.name : this.
|
|
236
|
+
console.error(`Failed to fetch children for '${this.options.id}'`, e);
|
|
237
|
+
const label = this._viewInfo ? this._viewInfo.name : this.options.id;
|
|
234
238
|
this.notification.error(`${label}: ${e.message}`);
|
|
235
239
|
}
|
|
236
240
|
return [];
|
|
@@ -288,7 +292,7 @@ export class PluginTree extends TreeImpl {
|
|
|
288
292
|
children: [],
|
|
289
293
|
command: item.command
|
|
290
294
|
}, update);
|
|
291
|
-
return new ResolvableCompositeTreeViewNode(compositeNode, async (token: CancellationToken) => this._proxy?.$resolveTreeItem(this.
|
|
295
|
+
return new ResolvableCompositeTreeViewNode(compositeNode, async (token: CancellationToken) => this._proxy?.$resolveTreeItem(this.options.id, item.id, token));
|
|
292
296
|
}
|
|
293
297
|
|
|
294
298
|
// Node is a leaf
|
|
@@ -304,13 +308,13 @@ export class PluginTree extends TreeImpl {
|
|
|
304
308
|
selected: false,
|
|
305
309
|
command: item.command,
|
|
306
310
|
}, update);
|
|
307
|
-
return new ResolvableTreeViewNode(treeNode, async (token: CancellationToken) => this._proxy?.$resolveTreeItem(this.
|
|
311
|
+
return new ResolvableTreeViewNode(treeNode, async (token: CancellationToken) => this._proxy?.$resolveTreeItem(this.options.id, item.id, token));
|
|
308
312
|
}
|
|
309
313
|
|
|
310
314
|
protected createTreeNodeUpdate(item: TreeViewItem): Partial<TreeViewNode> {
|
|
311
315
|
const decorationData = this.toDecorationData(item);
|
|
312
316
|
const icon = this.toIconClass(item);
|
|
313
|
-
const resourceUri = item.resourceUri && URI.
|
|
317
|
+
const resourceUri = item.resourceUri && URI.fromComponents(item.resourceUri).toString();
|
|
314
318
|
const themeIcon = item.themeIcon ? item.themeIcon : item.collapsibleState !== TreeViewItemCollapsibleState.None ? { id: 'folder' } : undefined;
|
|
315
319
|
return {
|
|
316
320
|
name: item.label,
|
|
@@ -393,14 +397,17 @@ export class TreeViewWidget extends TreeViewWelcomeWidget {
|
|
|
393
397
|
|
|
394
398
|
protected _contextSelection = false;
|
|
395
399
|
|
|
400
|
+
@inject(ApplicationShell)
|
|
401
|
+
protected readonly applicationShell: ApplicationShell;
|
|
402
|
+
|
|
396
403
|
@inject(MenuModelRegistry)
|
|
397
404
|
protected readonly menus: MenuModelRegistry;
|
|
398
405
|
|
|
399
406
|
@inject(ContextKeyService)
|
|
400
407
|
protected readonly contextKeys: ContextKeyService;
|
|
401
408
|
|
|
402
|
-
@inject(
|
|
403
|
-
readonly
|
|
409
|
+
@inject(TreeViewWidgetOptions)
|
|
410
|
+
readonly options: TreeViewWidgetOptions;
|
|
404
411
|
|
|
405
412
|
@inject(PluginTreeModel)
|
|
406
413
|
override readonly model: PluginTreeModel;
|
|
@@ -417,16 +424,23 @@ export class TreeViewWidget extends TreeViewWelcomeWidget {
|
|
|
417
424
|
@inject(ColorRegistry)
|
|
418
425
|
protected readonly colorRegistry: ColorRegistry;
|
|
419
426
|
|
|
427
|
+
@inject(DnDFileContentStore)
|
|
428
|
+
protected readonly dndFileContentStore: DnDFileContentStore;
|
|
429
|
+
|
|
430
|
+
protected treeDragType: string;
|
|
431
|
+
protected readonly expansionTimeouts: Map<string, number> = new Map();
|
|
432
|
+
|
|
420
433
|
@postConstruct()
|
|
421
434
|
protected override init(): void {
|
|
422
435
|
super.init();
|
|
423
|
-
this.id = this.
|
|
436
|
+
this.id = this.options.id;
|
|
424
437
|
this.addClass('theia-tree-view');
|
|
425
438
|
this.node.style.height = '100%';
|
|
426
439
|
this.model.onDidChangeWelcomeState(this.update, this);
|
|
427
440
|
this.toDispose.push(this.model.onDidChangeWelcomeState(this.update, this));
|
|
428
441
|
this.toDispose.push(this.onDidChangeVisibilityEmitter);
|
|
429
442
|
this.toDispose.push(this.contextKeyService.onDidChange(() => this.update()));
|
|
443
|
+
this.treeDragType = `application/vnd.code.tree.${this.id.toLowerCase()}`;
|
|
430
444
|
}
|
|
431
445
|
|
|
432
446
|
protected override renderIcon(node: TreeNode, props: NodeProps): React.ReactNode {
|
|
@@ -498,7 +512,7 @@ export class TreeViewWidget extends TreeViewWelcomeWidget {
|
|
|
498
512
|
});
|
|
499
513
|
} else {
|
|
500
514
|
const title = node.tooltip ||
|
|
501
|
-
(node.resourceUri && this.labelProvider.getLongName(new
|
|
515
|
+
(node.resourceUri && this.labelProvider.getLongName(new URI(node.resourceUri)))
|
|
502
516
|
|| this.toNodeName(node);
|
|
503
517
|
event.currentTarget.title = title;
|
|
504
518
|
}
|
|
@@ -518,7 +532,7 @@ export class TreeViewWidget extends TreeViewWelcomeWidget {
|
|
|
518
532
|
};
|
|
519
533
|
} else {
|
|
520
534
|
const title = node.tooltip ||
|
|
521
|
-
(node.resourceUri && this.labelProvider.getLongName(new
|
|
535
|
+
(node.resourceUri && this.labelProvider.getLongName(new URI(node.resourceUri)))
|
|
522
536
|
|| this.toNodeName(node);
|
|
523
537
|
|
|
524
538
|
attrs = {
|
|
@@ -546,41 +560,181 @@ export class TreeViewWidget extends TreeViewWelcomeWidget {
|
|
|
546
560
|
return <div {...attrs}>{...children}</div>;
|
|
547
561
|
}
|
|
548
562
|
|
|
549
|
-
protected override
|
|
550
|
-
|
|
563
|
+
protected override createNodeAttributes(node: TreeViewNode, props: NodeProps): React.Attributes & React.HTMLAttributes<HTMLElement> {
|
|
564
|
+
const attrs = super.createNodeAttributes(node, props);
|
|
565
|
+
|
|
566
|
+
if (this.options.dragMimeTypes) {
|
|
567
|
+
attrs.onDragStart = event => this.handleDragStartEvent(node, event);
|
|
568
|
+
attrs.onDragEnd = event => this.handleDragEnd(node, event);
|
|
569
|
+
attrs.draggable = true;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (this.options.dropMimeTypes) {
|
|
573
|
+
attrs.onDrop = event => this.handleDropEvent(node, event);
|
|
574
|
+
attrs.onDragEnter = event => this.handleDragEnter(node, event);
|
|
575
|
+
attrs.onDragLeave = event => this.handleDragLeave(node, event);
|
|
576
|
+
attrs.onDragOver = event => this.handleDragOver(event);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
return attrs;
|
|
580
|
+
}
|
|
581
|
+
handleDragLeave(node: TreeViewNode, event: React.DragEvent<HTMLElement>): void {
|
|
582
|
+
const timeout = this.expansionTimeouts.get(node.id);
|
|
583
|
+
if (typeof timeout !== 'undefined') {
|
|
584
|
+
console.debug(`dragleave ${node.id} canceling timeout`);
|
|
585
|
+
clearTimeout(timeout);
|
|
586
|
+
this.expansionTimeouts.delete(node.id);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
handleDragEnter(node: TreeViewNode, event: React.DragEvent<HTMLElement>): void {
|
|
590
|
+
console.debug(`dragenter ${node.id}`);
|
|
591
|
+
if (ExpandableTreeNode.is(node)) {
|
|
592
|
+
console.debug(`dragenter ${node.id} starting timeout`);
|
|
593
|
+
this.expansionTimeouts.set(node.id, window.setTimeout(() => {
|
|
594
|
+
console.debug(`dragenter ${node.id} timeout reached`);
|
|
595
|
+
this.model.expandNode(node);
|
|
596
|
+
}, 500));
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
protected override createContainerAttributes(): React.HTMLAttributes<HTMLElement> {
|
|
601
|
+
const attrs = super.createContainerAttributes();
|
|
602
|
+
if (this.options.dropMimeTypes) {
|
|
603
|
+
attrs.onDrop = event => this.handleDropEvent(undefined, event);
|
|
604
|
+
attrs.onDragOver = event => this.handleDragOver(event);
|
|
605
|
+
}
|
|
606
|
+
return attrs;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
protected handleDragStartEvent(node: TreeViewNode, event: React.DragEvent<HTMLElement>): void {
|
|
610
|
+
event.dataTransfer!.setData(this.treeDragType, '');
|
|
611
|
+
let selectedNodes: TreeViewNode[] = [];
|
|
612
|
+
if (this.model.selectedNodes.find(selected => TreeNode.equals(selected, node))) {
|
|
613
|
+
selectedNodes = this.model.selectedNodes.filter(TreeViewNode.is);
|
|
614
|
+
} else {
|
|
615
|
+
selectedNodes = [node];
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
this.options.dragMimeTypes!.forEach(type => {
|
|
619
|
+
if (type === 'text/uri-list') {
|
|
620
|
+
ApplicationShell.setDraggedEditorUris(event.dataTransfer, selectedNodes.filter(n => n.resourceUri).map(n => new URI(n.resourceUri)));
|
|
621
|
+
} else {
|
|
622
|
+
event.dataTransfer.setData(type, '');
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
this.model.proxy!.$dragStarted(this.options.id, selectedNodes.map(selected => selected.id), CancellationToken.None).then(maybeUris => {
|
|
627
|
+
if (maybeUris) {
|
|
628
|
+
this.applicationShell.addAdditionalDraggedEditorUris(maybeUris.map(URI.fromComponents));
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
handleDragEnd(node: TreeViewNode, event: React.DragEvent<HTMLElement>): void {
|
|
634
|
+
this.applicationShell.clearAdditionalDraggedEditorUris();
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
handleDragOver(event: React.DragEvent<HTMLElement>): void {
|
|
638
|
+
if (event.dataTransfer) {
|
|
639
|
+
const canDrop = event.dataTransfer.types.some(type => this.options.dropMimeTypes!.includes(type)) ||
|
|
640
|
+
event.dataTransfer.types.includes(this.treeDragType) ||
|
|
641
|
+
this.options.dropMimeTypes!.includes('files') && event.dataTransfer.files.length > 0;
|
|
642
|
+
if (canDrop) {
|
|
643
|
+
event.preventDefault();
|
|
644
|
+
event.dataTransfer.dropEffect = 'move';
|
|
645
|
+
} else {
|
|
646
|
+
event.dataTransfer.dropEffect = 'none';
|
|
647
|
+
}
|
|
648
|
+
event.stopPropagation();
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
protected handleDropEvent(node: TreeViewNode | undefined, event: React.DragEvent<HTMLElement>): void {
|
|
653
|
+
if (event.dataTransfer) {
|
|
654
|
+
const items: [string, string | DataTransferFileDTO][] = [];
|
|
655
|
+
let files: string[] = [];
|
|
656
|
+
try {
|
|
657
|
+
for (let i = 0; i < event.dataTransfer.items.length; i++) {
|
|
658
|
+
const transferItem = event.dataTransfer.items[i];
|
|
659
|
+
if (transferItem.type !== this.treeDragType) {
|
|
660
|
+
// do not pass the artificial drag data to the extension
|
|
661
|
+
const f = event.dataTransfer.items[i].getAsFile();
|
|
662
|
+
if (f) {
|
|
663
|
+
const fileId = this.dndFileContentStore.addFile(f);
|
|
664
|
+
files.push(fileId);
|
|
665
|
+
const uri = f.path ? {
|
|
666
|
+
scheme: 'file',
|
|
667
|
+
path: f.path,
|
|
668
|
+
authority: '',
|
|
669
|
+
query: '',
|
|
670
|
+
fragment: ''
|
|
671
|
+
} : undefined;
|
|
672
|
+
items.push([transferItem.type, new DataTransferFileDTO(f.name, fileId, uri)]);
|
|
673
|
+
} else {
|
|
674
|
+
const textData = event.dataTransfer.getData(transferItem.type);
|
|
675
|
+
if (textData) {
|
|
676
|
+
items.push([transferItem.type, textData]);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
if (items.length > 0 || event.dataTransfer.types.includes(this.treeDragType)) {
|
|
682
|
+
event.preventDefault();
|
|
683
|
+
event.stopPropagation();
|
|
684
|
+
this.model.proxy?.$drop(this.id, node?.id, items, CancellationToken.None).finally(() => {
|
|
685
|
+
for (const file of files) {
|
|
686
|
+
this.dndFileContentStore.removeFile(file);
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
files = [];
|
|
690
|
+
}
|
|
691
|
+
} catch (e) {
|
|
692
|
+
for (const file of files) {
|
|
693
|
+
this.dndFileContentStore.removeFile(file);
|
|
694
|
+
}
|
|
695
|
+
throw e;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
protected override renderTailDecorations(treeViewNode: TreeViewNode, props: NodeProps): React.ReactNode {
|
|
701
|
+
return this.contextKeys.with({ view: this.id, viewItem: treeViewNode.contextValue }, () => {
|
|
551
702
|
const menu = this.menus.getMenu(VIEW_ITEM_INLINE_MENU);
|
|
552
|
-
const
|
|
703
|
+
const args = this.toContextMenuArgs(treeViewNode);
|
|
553
704
|
const inlineCommands = menu.children.filter((item): item is ActionMenuNode => item instanceof ActionMenuNode);
|
|
554
|
-
const tailDecorations = super.renderTailDecorations(
|
|
705
|
+
const tailDecorations = super.renderTailDecorations(treeViewNode, props);
|
|
555
706
|
return <React.Fragment>
|
|
556
707
|
{inlineCommands.length > 0 && <div className={TREE_NODE_SEGMENT_CLASS + ' flex'}>
|
|
557
|
-
{inlineCommands.map((item, index) => this.renderInlineCommand(item, index, this.focusService.hasFocus(
|
|
708
|
+
{inlineCommands.map((item, index) => this.renderInlineCommand(item, index, this.focusService.hasFocus(treeViewNode), args))}
|
|
558
709
|
</div>}
|
|
559
710
|
{tailDecorations !== undefined && <div className={TREE_NODE_SEGMENT_CLASS + ' flex'}>{tailDecorations}</div>}
|
|
560
711
|
</React.Fragment>;
|
|
561
712
|
});
|
|
562
713
|
}
|
|
563
714
|
|
|
564
|
-
|
|
565
|
-
return {
|
|
715
|
+
toTreeViewItemReference(treeNode: TreeNode): TreeViewItemReference {
|
|
716
|
+
return { viewId: this.id, itemId: treeNode.id };
|
|
566
717
|
}
|
|
567
718
|
|
|
568
719
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
569
|
-
protected renderInlineCommand(
|
|
570
|
-
|
|
571
|
-
if (!icon || !this.commands.isVisible(node.command, arg) || !node.when || !this.contextKeys.match(node.when)) {
|
|
720
|
+
protected renderInlineCommand(actionMenuNode: ActionMenuNode, index: number, tabbable: boolean, args: any[]): React.ReactNode {
|
|
721
|
+
if (!actionMenuNode.icon || !this.commands.isVisible(actionMenuNode.command, ...args) || !actionMenuNode.when || !this.contextKeys.match(actionMenuNode.when)) {
|
|
572
722
|
return false;
|
|
573
723
|
}
|
|
574
|
-
const className = [TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS, icon, ACTION_ITEM, 'theia-tree-view-inline-action'].join(' ');
|
|
724
|
+
const className = [TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS, actionMenuNode.icon, ACTION_ITEM, 'theia-tree-view-inline-action'].join(' ');
|
|
575
725
|
const tabIndex = tabbable ? 0 : undefined;
|
|
576
|
-
return <div key={index} className={className} title={
|
|
726
|
+
return <div key={index} className={className} title={actionMenuNode.label} tabIndex={tabIndex} onClick={e => {
|
|
577
727
|
e.stopPropagation();
|
|
578
|
-
this.commands.executeCommand(
|
|
728
|
+
this.commands.executeCommand(actionMenuNode.command, ...args);
|
|
579
729
|
}} />;
|
|
580
730
|
}
|
|
581
731
|
|
|
582
|
-
protected override toContextMenuArgs(
|
|
583
|
-
|
|
732
|
+
protected override toContextMenuArgs(target: SelectableTreeNode): [TreeViewItemReference, TreeViewItemReference[]] | [TreeViewItemReference] {
|
|
733
|
+
if (this.options.multiSelect) {
|
|
734
|
+
return [this.toTreeViewItemReference(target), this.model.selectedNodes.map(node => this.toTreeViewItemReference(node))];
|
|
735
|
+
} else {
|
|
736
|
+
return [this.toTreeViewItemReference(target)];
|
|
737
|
+
}
|
|
584
738
|
}
|
|
585
739
|
|
|
586
740
|
override setFlag(flag: Widget.Flag): void {
|
|
@@ -688,7 +842,7 @@ export class TreeViewWidget extends TreeViewWelcomeWidget {
|
|
|
688
842
|
const args = this.toContextMenuArgs(node);
|
|
689
843
|
const contextKeyService = this.contextKeyService.createOverlay([
|
|
690
844
|
['viewItem', (TreeViewNode.is(node) && node.contextValue) || undefined],
|
|
691
|
-
['view', this.
|
|
845
|
+
['view', this.options.id]
|
|
692
846
|
]);
|
|
693
847
|
setTimeout(() => this.contextMenuRenderer.render({
|
|
694
848
|
menuPath: contextMenuPath,
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import { interfaces } from '@theia/core/shared/inversify';
|
|
18
|
-
import { MAIN_RPC_CONTEXT, TreeViewsMain, TreeViewsExt, TreeViewRevealOptions } from '../../../common/plugin-api-rpc';
|
|
18
|
+
import { MAIN_RPC_CONTEXT, TreeViewsMain, TreeViewsExt, TreeViewRevealOptions, RegisterTreeDataProviderOptions } from '../../../common/plugin-api-rpc';
|
|
19
19
|
import { RPCProtocol } from '../../../common/rpc-protocol';
|
|
20
20
|
import { PluginViewRegistry, PLUGIN_VIEW_DATA_FACTORY_ID } from './plugin-view-registry';
|
|
21
21
|
import {
|
|
@@ -26,8 +26,10 @@ import {
|
|
|
26
26
|
} from '@theia/core/lib/browser';
|
|
27
27
|
import { ViewContextKeyService } from './view-context-key-service';
|
|
28
28
|
import { Disposable, DisposableCollection } from '@theia/core';
|
|
29
|
-
import { TreeViewWidget, TreeViewNode, PluginTreeModel } from './tree-view-widget';
|
|
29
|
+
import { TreeViewWidget, TreeViewNode, PluginTreeModel, TreeViewWidgetOptions } from './tree-view-widget';
|
|
30
30
|
import { PluginViewWidget } from './plugin-view-widget';
|
|
31
|
+
import { BinaryBuffer } from '@theia/core/lib/common/buffer';
|
|
32
|
+
import { DnDFileContentStore } from './dnd-file-content-store';
|
|
31
33
|
|
|
32
34
|
export class TreeViewsMainImpl implements TreeViewsMain, Disposable {
|
|
33
35
|
|
|
@@ -35,6 +37,7 @@ export class TreeViewsMainImpl implements TreeViewsMain, Disposable {
|
|
|
35
37
|
private readonly viewRegistry: PluginViewRegistry;
|
|
36
38
|
private readonly contextKeys: ViewContextKeyService;
|
|
37
39
|
private readonly widgetManager: WidgetManager;
|
|
40
|
+
private readonly fileContentStore: DnDFileContentStore;
|
|
38
41
|
|
|
39
42
|
private readonly treeViewProviders = new Map<string, Disposable>();
|
|
40
43
|
|
|
@@ -48,15 +51,22 @@ export class TreeViewsMainImpl implements TreeViewsMain, Disposable {
|
|
|
48
51
|
|
|
49
52
|
this.contextKeys = this.container.get(ViewContextKeyService);
|
|
50
53
|
this.widgetManager = this.container.get(WidgetManager);
|
|
54
|
+
this.fileContentStore = this.container.get(DnDFileContentStore);
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
dispose(): void {
|
|
54
58
|
this.toDispose.dispose();
|
|
55
59
|
}
|
|
56
60
|
|
|
57
|
-
async $registerTreeDataProvider(treeViewId: string): Promise<void> {
|
|
61
|
+
async $registerTreeDataProvider(treeViewId: string, $options: RegisterTreeDataProviderOptions): Promise<void> {
|
|
58
62
|
this.treeViewProviders.set(treeViewId, this.viewRegistry.registerViewDataProvider(treeViewId, async ({ state, viewInfo }) => {
|
|
59
|
-
const
|
|
63
|
+
const options: TreeViewWidgetOptions = {
|
|
64
|
+
id: treeViewId,
|
|
65
|
+
multiSelect: $options.canSelectMany,
|
|
66
|
+
dragMimeTypes: $options.dragMimeTypes,
|
|
67
|
+
dropMimeTypes: $options.dropMimeTypes
|
|
68
|
+
};
|
|
69
|
+
const widget = await this.widgetManager.getOrCreateWidget<TreeViewWidget>(PLUGIN_VIEW_DATA_FACTORY_ID, options);
|
|
60
70
|
widget.model.viewInfo = viewInfo;
|
|
61
71
|
if (state) {
|
|
62
72
|
widget.restoreState(state);
|
|
@@ -94,6 +104,12 @@ export class TreeViewsMainImpl implements TreeViewsMain, Disposable {
|
|
|
94
104
|
}
|
|
95
105
|
}
|
|
96
106
|
|
|
107
|
+
async $readDroppedFile(contentId: string): Promise<BinaryBuffer> {
|
|
108
|
+
const file = this.fileContentStore.getFile(contentId);
|
|
109
|
+
const buffer = await file.arrayBuffer();
|
|
110
|
+
return BinaryBuffer.wrap(new Uint8Array(buffer));
|
|
111
|
+
}
|
|
112
|
+
|
|
97
113
|
async $refresh(treeViewId: string): Promise<void> {
|
|
98
114
|
const viewPanel = await this.viewRegistry.getView(treeViewId);
|
|
99
115
|
const widget = viewPanel && viewPanel.widgets[0];
|