Improve remote sketchbook explorer (#459)

* Refactor remote sketchbook explorer
* sketches sorting
This commit is contained in:
Francesco Stasi
2021-07-22 14:34:10 +02:00
committed by GitHub
parent 4da5d573e4
commit d790266cc8
16 changed files with 592 additions and 613 deletions

View File

@@ -34,7 +34,7 @@ export class SketchbookTreeModel extends FileTreeModel {
protected readonly arduinoPreferences: ArduinoPreferences;
@inject(CommandRegistry)
protected readonly commandRegistry: CommandRegistry;
public readonly commandRegistry: CommandRegistry;
@inject(ConfigService)
protected readonly configService: ConfigService;
@@ -162,34 +162,24 @@ export class SketchbookTreeModel extends FileTreeModel {
protected async createRoot(): Promise<TreeNode | undefined> {
const config = await this.configService.getConfiguration();
const stat = await this.fileService.resolve(new URI(config.sketchDirUri));
const rootFileStats = await this.fileService.resolve(
new URI(config.sketchDirUri)
);
if (this.workspaceService.opened) {
const isMulti = stat ? !stat.isDirectory : false;
const workspaceNode = isMulti
? this.createMultipleRootNode()
: WorkspaceNode.createRoot();
workspaceNode.children.push(
await this.tree.createWorkspaceRoot(stat, workspaceNode)
);
if (this.workspaceService.opened && rootFileStats.children) {
// filter out libraries and hardware
return workspaceNode;
if (this.workspaceService.opened) {
const workspaceNode = WorkspaceNode.createRoot();
workspaceNode.children.push(
await this.tree.createWorkspaceRoot(rootFileStats, workspaceNode)
);
return workspaceNode;
}
}
}
/**
* Create multiple root node used to display
* the multiple root workspace name.
*
* @returns `WorkspaceNode`
*/
protected createMultipleRootNode(): WorkspaceNode {
const workspace = this.workspaceService.workspace;
let name = workspace ? workspace.resource.path.name : 'untitled';
name += ' (Workspace)';
return WorkspaceNode.createRoot(name);
}
/**
* Move the given source file or directory to the given target directory.
*/

View File

@@ -1,22 +1,17 @@
import { inject, injectable } from 'inversify';
import { LabelProvider } from '@theia/core/lib/browser/label-provider';
import { Command } from '@theia/core/lib/common/command';
import { CompositeTreeNode, TreeNode } from '@theia/core/lib/browser/tree';
import { DirNode, FileStatNode } from '@theia/filesystem/lib/browser/file-tree';
import { SketchesService } from '../../../common/protocol';
import { FileStat } from '@theia/filesystem/lib/common/files';
import { SketchbookCommands } from './sketchbook-commands';
import {
FileNavigatorTree,
WorkspaceNode,
WorkspaceRootNode,
} from '@theia/navigator/lib/browser/navigator-tree';
import { ArduinoPreferences } from '../../arduino-preferences';
@injectable()
export class SketchbookTree extends FileNavigatorTree {
@inject(LabelProvider)
protected readonly labelProvider: LabelProvider;
@inject(SketchesService)
protected readonly sketchesService: SketchesService;
@@ -27,61 +22,71 @@ export class SketchbookTree extends FileNavigatorTree {
const showAllFiles =
this.arduinoPreferences['arduino.sketchbook.showAllFiles'];
const children = (
await Promise.all(
(
await super.resolveChildren(parent)
).map((node) => this.maybeDecorateNode(node, showAllFiles))
)
).filter((node) => {
// filter out hidden nodes
if (DirNode.is(node) || FileStatNode.is(node)) {
return node.fileStat.name.indexOf('.') !== 0;
const children = (await super.resolveChildren(parent)).filter((child) => {
// strip libraries and hardware directories
if (
DirNode.is(child) &&
['libraries', 'hardware'].includes(child.fileStat.name) &&
WorkspaceRootNode.is(child.parent)
) {
return false;
}
// strip files if only directories are admitted
if (!DirNode.is(child) && !showAllFiles) {
return false;
}
// strip hidden files
if (FileStatNode.is(child) && child.fileStat.name.indexOf('.') === 0) {
return false;
}
return true;
});
// filter out hardware and libraries
if (WorkspaceNode.is(parent.parent)) {
return children
.filter(DirNode.is)
.filter(
(node) =>
['libraries', 'hardware'].indexOf(
this.labelProvider.getName(node)
) === -1
);
if (children.length === 0) {
delete (parent as any).expanded;
}
// return the Arduino directory containing all user sketches
if (WorkspaceNode.is(parent)) {
return children;
}
return children;
// return this.filter.filter(super.resolveChildren(parent));
return await Promise.all(
children.map(
async (childNode) => await this.decorateNode(childNode, showAllFiles)
)
);
}
protected async maybeDecorateNode(
protected async isSketchNode(node: DirNode): Promise<boolean> {
const sketch = await this.sketchesService.maybeLoadSketch(
node.uri.toString()
);
return !!sketch;
}
/**
* Add commands available for the given node
* @param node
* @returns
*/
protected async augmentSketchNode(node: DirNode): Promise<void> {
Object.assign(node, {
type: 'sketch',
commands: [SketchbookCommands.OPEN_SKETCHBOOK_CONTEXT_MENU],
});
}
protected async decorateNode(
node: TreeNode,
showAllFiles: boolean
): Promise<TreeNode> {
if (DirNode.is(node)) {
const sketch = await this.sketchesService.maybeLoadSketch(
node.uri.toString()
);
if (sketch) {
Object.assign(node, {
type: 'sketch',
commands: [SketchbookCommands.OPEN_SKETCHBOOK_CONTEXT_MENU],
});
if (!showAllFiles) {
delete (node as any).expanded;
node.children = [];
} else {
node.expanded = false;
}
return node;
if (DirNode.is(node) && (await this.isSketchNode(node))) {
await this.augmentSketchNode(node);
if (!showAllFiles) {
delete (node as any).expanded;
(node as any).children = [];
} else {
(node as any).expanded = false;
}
}
return node;
@@ -89,25 +94,6 @@ export class SketchbookTree extends FileNavigatorTree {
}
export namespace SketchbookTree {
export interface RootNode extends DirNode {
readonly showAllFiles: boolean;
}
export namespace RootNode {
export function is(node: TreeNode & Partial<RootNode>): node is RootNode {
return typeof node.showAllFiles === 'boolean';
}
export function create(
fileStat: FileStat,
showAllFiles: boolean
): RootNode {
return Object.assign(DirNode.createRoot(fileStat), {
showAllFiles,
visible: false,
});
}
}
export interface SketchDirNode extends DirNode {
readonly type: 'sketch';
readonly commands?: Command[];

View File

@@ -100,10 +100,7 @@ export class SketchbookWidgetContribution
registry.registerCommand(SketchbookCommands.OPEN_NEW_WINDOW, {
execute: async (arg) => {
const underlying = await this.fileService.toUnderlyingResource(
arg.node.uri
);
return this.workspaceService.open(underlying);
return this.workspaceService.open(arg.node.uri);
},
isEnabled: (arg) =>
!!arg && 'node' in arg && SketchbookTree.SketchDirNode.is(arg.node),
@@ -214,7 +211,8 @@ export class SketchbookWidgetContribution
if (Navigatable.is(widget)) {
const resourceUri = widget.getResourceUri();
if (resourceUri) {
const { model } = (await this.widget).getTreeWidget();
const treeWidget = (await this.widget).getTreeWidget();
const { model } = treeWidget;
const node = await model.revealFile(resourceUri);
if (SelectableTreeNode.is(node)) {
model.selectNode(node);