Skip to content

Commit

Permalink
Select created new files and folders in the navigator
Browse files Browse the repository at this point in the history
Signed-off-by: Igor Vinokur <ivinokur@redhat.com>
  • Loading branch information
vinokurig committed May 7, 2020
1 parent 3d17ad2 commit 05a2da6
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 9 deletions.
6 changes: 6 additions & 0 deletions packages/core/src/browser/tree/tree-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,15 @@ export class TreeModelImpl implements TreeModel, SelectionProvider<ReadonlyArray
@inject(TreeSearch) protected readonly treeSearch: TreeSearch;

protected readonly onChangedEmitter = new Emitter<void>();
protected readonly onNodesAddedEmitter = new Emitter<TreeNode[]>();
protected readonly onOpenNodeEmitter = new Emitter<TreeNode>();
protected readonly toDispose = new DisposableCollection();

@postConstruct()
protected init(): void {
this.toDispose.push(this.tree);
this.toDispose.push(this.tree.onChanged(() => this.fireChanged()));
this.toDispose.push(this.tree.onNodesAdded(nodes => this.onNodesAddedEmitter.fire(nodes)));

this.toDispose.push(this.selectionService);

Expand Down Expand Up @@ -199,6 +201,10 @@ export class TreeModelImpl implements TreeModel, SelectionProvider<ReadonlyArray
return this.onChangedEmitter.event;
}

get onNodesAdded(): Event<TreeNode[]> {
return this.onNodesAddedEmitter.event;
}

get onOpenNode(): Event<TreeNode> {
return this.onOpenNodeEmitter.event;
}
Expand Down
20 changes: 20 additions & 0 deletions packages/core/src/browser/tree/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ export interface Tree extends Disposable {
* Emit when the tree is changed.
*/
readonly onChanged: Event<void>;

/**
* Emit when new nodes are added to the tree.
*/
readonly onNodesAdded: Event<TreeNode[]>;
/**
* Return a node for the given identifier or undefined if such does not exist.
*/
Expand Down Expand Up @@ -233,6 +238,7 @@ export class TreeImpl implements Tree {

protected _root: TreeNode | undefined;
protected readonly onChangedEmitter = new Emitter<void>();
protected readonly onNodesAddedEmitter = new Emitter<TreeNode[]>();
protected readonly onNodeRefreshedEmitter = new Emitter<CompositeTreeNode & WaitUntilEvent>();
protected readonly toDispose = new DisposableCollection();

Expand All @@ -247,6 +253,7 @@ export class TreeImpl implements Tree {
this.toDispose.push(this.onChangedEmitter);
this.toDispose.push(this.onNodeRefreshedEmitter);
this.toDispose.push(this.onDidChangeBusyEmitter);
this.toDispose.push(this.onNodesAddedEmitter);
}

dispose(): void {
Expand All @@ -269,6 +276,10 @@ export class TreeImpl implements Tree {
return this.onChangedEmitter.event;
}

get onNodesAdded(): Event<TreeNode[]> {
return this.onNodesAddedEmitter.event;
}

protected fireChanged(): void {
this.onChangedEmitter.fire(undefined);
}
Expand Down Expand Up @@ -314,6 +325,12 @@ export class TreeImpl implements Tree {
}

protected async setChildren(parent: CompositeTreeNode, children: TreeNode[]): Promise<CompositeTreeNode | undefined> {
const newNodes: TreeNode[] = [];
children.forEach(newNode => {
if (!parent.children.find(node => node.id === newNode.id)) {
newNodes.push(newNode);
}
});
const root = this.getRootNode(parent);
if (this.nodes[root.id] && this.nodes[root.id] !== root) {
console.error(`Child node '${parent.id}' does not belong to this '${root.id}' tree.`);
Expand All @@ -323,6 +340,9 @@ export class TreeImpl implements Tree {
parent.children = children;
this.addNode(parent);
await this.fireNodeRefreshed(parent);
if (newNodes.length > 0) {
this.onNodesAddedEmitter.fire(newNodes);
}
return parent;
}

Expand Down
63 changes: 54 additions & 9 deletions packages/navigator/src/browser/navigator-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,49 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { injectable, inject, postConstruct } from 'inversify';
import { inject, injectable, postConstruct } from 'inversify';
import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
import {
Navigatable, SelectableTreeNode, Widget, KeybindingRegistry, CommonCommands,
OpenerService, FrontendApplicationContribution, FrontendApplication, CompositeTreeNode, PreferenceScope
CommonCommands,
CompositeTreeNode, ExpandableTreeNode,
FrontendApplication,
FrontendApplicationContribution,
KeybindingRegistry,
Navigatable,
OpenerService,
PreferenceScope,
PreferenceService,
SelectableTreeNode,
SHELL_TABBAR_CONTEXT_MENU,
Widget
} from '@theia/core/lib/browser';
import { FileDownloadCommands } from '@theia/filesystem/lib/browser/download/file-download-command-contribution';
import { CommandRegistry, MenuModelRegistry, MenuPath, isOSX, Command, DisposableCollection, Mutable } from '@theia/core/lib/common';
import { SHELL_TABBAR_CONTEXT_MENU } from '@theia/core/lib/browser';
import { WorkspaceCommands, WorkspaceService, WorkspacePreferences } from '@theia/workspace/lib/browser';
import { FILE_NAVIGATOR_ID, FileNavigatorWidget, EXPLORER_VIEW_CONTAINER_ID } from './navigator-widget';
import {
Command,
CommandRegistry,
DisposableCollection,
isOSX,
MenuModelRegistry,
MenuPath,
Mutable
} from '@theia/core/lib/common';
import { WorkspaceCommands, WorkspacePreferences, WorkspaceService } from '@theia/workspace/lib/browser';
import { EXPLORER_VIEW_CONTAINER_ID, FILE_NAVIGATOR_ID, FileNavigatorWidget } from './navigator-widget';
import { FileNavigatorPreferences } from './navigator-preferences';
import { NavigatorKeybindingContexts } from './navigator-keybinding-context';
import { FileNavigatorFilter } from './navigator-filter';
import { WorkspaceNode } from './navigator-tree';
import { NavigatorContextKeyService } from './navigator-context-key-service';
import { TabBarToolbarContribution, TabBarToolbarRegistry, TabBarToolbarItem } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
import {
TabBarToolbarContribution,
TabBarToolbarItem,
TabBarToolbarRegistry
} from '@theia/core/lib/browser/shell/tab-bar-toolbar';
import { FileSystemCommands } from '@theia/filesystem/lib/browser/filesystem-frontend-contribution';
import { NavigatorDiff, NavigatorDiffCommands } from './navigator-diff';
import { UriSelection } from '@theia/core/lib/common/selection';
import { PreferenceService } from '@theia/core/lib/browser';
import { FileChangeType, FileSystemWatcher } from '@theia/filesystem/lib/browser';
import { DirNode } from '@theia/filesystem/lib/browser/file-tree/file-tree';

export namespace FileNavigatorCommands {
export const REVEAL_IN_NAVIGATOR: Command = {
Expand Down Expand Up @@ -129,6 +151,9 @@ export class FileNavigatorContribution extends AbstractViewContribution<FileNavi
@inject(PreferenceService)
protected readonly preferenceService: PreferenceService;

@inject(FileSystemWatcher)
protected readonly watcher: FileSystemWatcher;

constructor(
@inject(FileNavigatorPreferences) protected readonly fileNavigatorPreferences: FileNavigatorPreferences,
@inject(OpenerService) protected readonly openerService: OpenerService,
Expand Down Expand Up @@ -161,6 +186,26 @@ export class FileNavigatorContribution extends AbstractViewContribution<FileNavi
};
updateFocusContextKeys();
this.shell.activeChanged.connect(updateFocusContextKeys);
const widget = await this.widget;
const model = widget.model;
model.onNodesAdded(async nodes => {
// Select created new file or folder.
const node = nodes[0];
if (nodes.length === 1 && SelectableTreeNode.is(node)
&& (this.fileNavigatorPreferences['explorer.autoReveal'] ? true : DirNode.is(node))) {
model.selectNode(node);
}
});
this.watcher.onFilesChanged(changes => {
// Expand the parent of the created new file or folder.
const change = changes[0];
if (changes.length === 1 && change.type === FileChangeType.ADDED) {
const node = model.getNodesByUri(change.uri.parent).next().value;
if (ExpandableTreeNode.is(node) && !node.expanded) {
model.expandNode(node);
}
}
});
}

async onStart(app: FrontendApplication): Promise<void> {
Expand Down

0 comments on commit 05a2da6

Please sign in to comment.