Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { LibraryController } from "./controllers/libraryController";
import { ProjectController } from "./controllers/projectController";
import { init as initExpService } from "./ExperimentationService";
import { Settings } from "./settings";
import { syncHandler } from "./syncHandler";
import { DependencyExplorer } from "./views/dependencyExplorer";

export async function activate(context: ExtensionContext): Promise<any> {
Expand Down Expand Up @@ -58,6 +59,7 @@ async function activateExtension(_operationId: string, context: ExtensionContext
context.subscriptions.push(new LibraryController(context));
context.subscriptions.push(new DependencyExplorer(context));
context.subscriptions.push(contextManager);
context.subscriptions.push(syncHandler);
contextManager.setContextValue(Context.EXTENSION_ACTIVATED, true);

initExpService(context);
Expand Down
58 changes: 0 additions & 58 deletions src/fileWather.ts

This file was deleted.

11 changes: 4 additions & 7 deletions src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from "vscode";
import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper";
import { Commands } from "./commands";
import { SyncHandler } from "./fileWather";
import { syncHandler } from "./syncHandler";

export class Settings {

Expand All @@ -28,15 +28,12 @@ export class Settings {
|| (updatedConfig.syncWithFolderExplorer !== oldConfig.syncWithFolderExplorer
&& updatedConfig.syncWithFolderExplorer)) {
commands.executeCommand(Commands.VIEW_PACKAGE_REFRESH);
}
});
this.registerConfigurationListener((updatedConfig, oldConfig) => {
if (updatedConfig.autoRefresh !== oldConfig.autoRefresh) {
SyncHandler.updateFileWatcher(updatedConfig.autoRefresh);
} else if (updatedConfig.autoRefresh !== oldConfig.autoRefresh) {
syncHandler.updateFileWatcher(updatedConfig.autoRefresh);
}
});

SyncHandler.updateFileWatcher(Settings.autoRefresh());
syncHandler.updateFileWatcher(Settings.autoRefresh());

context.subscriptions.push({ dispose: () => { this._configurationListeners = []; } });

Expand Down
104 changes: 104 additions & 0 deletions src/syncHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

import * as path from "path";
import { commands, Disposable, FileSystemWatcher, Uri, workspace } from "vscode";
import { instrumentOperation } from "vscode-extension-telemetry-wrapper";
import { Commands } from "./commands";
import { Settings } from "./settings";
import { DataNode } from "./views/dataNode";
import { ExplorerNode } from "./views/explorerNode";
import { HierarchicalPackageRootNode } from "./views/hierarchicalPackageRootNode";
import { explorerNodeCache } from "./views/nodeCache/explorerNodeCache";
import { PackageRootNode } from "./views/packageRootNode";

const ENABLE_AUTO_REFRESH: string = "java.view.package.enableAutoRefresh";
const DISABLE_AUTO_REFRESH: string = "java.view.package.disableAutoRefresh";

class SyncHandler implements Disposable {

private disposables: Disposable[] = [];

public updateFileWatcher(autoRefresh: boolean): void {
if (autoRefresh) {
instrumentOperation(ENABLE_AUTO_REFRESH, () => this.enableAutoRefresh())();
} else {
instrumentOperation(DISABLE_AUTO_REFRESH, () => this.dispose())();
}
}

public dispose(): void {
for (const disposable of this.disposables) {
if (disposable) {
disposable.dispose();
}
}
this.disposables = [];
}

private async enableAutoRefresh() {
this.disposables.push(workspace.onDidChangeWorkspaceFolders(() => {
this.refresh();
}));

const fileSystemWatcher: FileSystemWatcher = workspace.createFileSystemWatcher("**/{*.java,src/**}");
this.setupWatchers(fileSystemWatcher);
this.disposables.push(fileSystemWatcher);
}

private setupWatchers(watcher: FileSystemWatcher): void {
this.disposables.push(watcher.onDidChange((uri: Uri) => {
if (path.extname(uri.fsPath) !== ".java" || !Settings.showMembers()) {
return;
}
const node: DataNode | undefined = explorerNodeCache.getDataNode(uri);
this.refresh(node);
}));

this.disposables.push(watcher.onDidCreate((uri: Uri) => {
this.refresh(this.getParentNodeInExplorer(uri));
}));

this.disposables.push(watcher.onDidDelete((uri: Uri) => {
this.refresh(this.getParentNodeInExplorer(uri));
}));

}

private getParentNodeInExplorer(uri: Uri): ExplorerNode {
let node: DataNode | undefined = explorerNodeCache.findBestMatchNodeByUri(uri);

if (!node) {
return undefined;
}

if (Settings.isHierarchicalView()) {
// TODO: has to get the hierarchical package root node due to the java side implementation
// because currently it will only get the types for a package node but no child packages.
while (!(node instanceof HierarchicalPackageRootNode)) {
node = <DataNode>node.getParent();
}
return node;
} else {
// in flat view
if (path.extname(uri.fsPath) === ".java" &&
Uri.parse(node.uri).fsPath === path.dirname(uri.fsPath)) {
// if the returned node is direct parent of the input uri, refresh it.
return node;
} else {
// the direct parent is not rendered in the explorer, the returned node
// is other package fragment, we need to refresh the package fragment root.
while (!(node instanceof PackageRootNode)) {
node = <DataNode>node.getParent();
}
return node;
}
}
}

private refresh(node?: ExplorerNode): void {
commands.executeCommand(Commands.VIEW_PACKAGE_REFRESH, /* debounce = */true, node);
}
}

export const syncHandler: SyncHandler = new SyncHandler();
34 changes: 19 additions & 15 deletions src/views/dependencyDataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,25 @@ import { Settings } from "../settings";
import { DataNode } from "./dataNode";
import { ExplorerNode } from "./explorerNode";
import { LightWeightNode } from "./lightWeightNode";
import { explorerNodeCache } from "./nodeCache/explorerNodeCache";
import { ProjectNode } from "./projectNode";
import { WorkspaceNode } from "./workspaceNode";

export class DependencyDataProvider implements TreeDataProvider<ExplorerNode> {

private _onDidChangeTreeData: EventEmitter<null> = new EventEmitter<null>();
private _onDidChangeTreeData: EventEmitter<ExplorerNode | null | undefined> = new EventEmitter<ExplorerNode | null | undefined>();

// tslint:disable-next-line:member-ordering
public onDidChangeTreeData: Event<null> = this._onDidChangeTreeData.event;
public onDidChangeTreeData: Event<ExplorerNode | null | undefined> = this._onDidChangeTreeData.event;

private _rootItems: ExplorerNode[] = null;
private _refreshDelayTrigger: (() => void) & _.Cancelable;
private _refreshDelayTrigger: ((element?: ExplorerNode) => void) & _.Cancelable;

constructor(public readonly context: ExtensionContext) {
context.subscriptions.push(commands.registerCommand(Commands.VIEW_PACKAGE_REFRESH, (debounce?: boolean) => this.refreshWithLog(debounce)));
context.subscriptions.push(commands.registerCommand(Commands.VIEW_PACKAGE_REFRESH, (debounce?: boolean, element?: ExplorerNode) =>
this.refreshWithLog(debounce, element)));
context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_EXPORT_JAR, (node: INodeData) => createJarFile(node)));
context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_REVEAL_FILE_OS, (node?: INodeData) =>
context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_REVEAL_FILE_OS, (node: INodeData) =>
commands.executeCommand("revealFileInOS", Uri.parse(node.uri))));
context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_COPY_FILE_PATH, (node: INodeData) =>
commands.executeCommand("copyFilePath", Uri.parse(node.uri))));
Expand All @@ -48,16 +50,16 @@ export class DependencyDataProvider implements TreeDataProvider<ExplorerNode> {
this.setRefreshDelay();
}

public refreshWithLog(debounce?: boolean) {
public refreshWithLog(debounce?: boolean, element?: ExplorerNode) {
if (Settings.autoRefresh()) {
this.refresh(debounce);
this.refresh(debounce, element);
} else {
instrumentOperation(Commands.VIEW_PACKAGE_REFRESH, () => this.refresh(debounce))();
instrumentOperation(Commands.VIEW_PACKAGE_REFRESH, () => this.refresh(debounce, element))();
}
}

public refresh(debounce = false) {
this._refreshDelayTrigger();
public refresh(debounce = false, element?: ExplorerNode) {
this._refreshDelayTrigger(element);
if (!debounce) { // Immediately refresh
this._refreshDelayTrigger.flush();
}
Expand All @@ -70,7 +72,7 @@ export class DependencyDataProvider implements TreeDataProvider<ExplorerNode> {
if (this._refreshDelayTrigger) {
this._refreshDelayTrigger.cancel();
}
this._refreshDelayTrigger = _.debounce(() => this.doRefresh(), wait);
this._refreshDelayTrigger = _.debounce(this.doRefresh, wait);
}

public openFile(uri: string) {
Expand Down Expand Up @@ -107,7 +109,9 @@ export class DependencyDataProvider implements TreeDataProvider<ExplorerNode> {
if (!this._rootItems || !element) {
return this.getRootNodes();
} else {
return element.getChildren();
const children: ExplorerNode[] = await element.getChildren();
explorerNodeCache.saveNodes(children);
return children;
}
}

Expand All @@ -123,9 +127,9 @@ export class DependencyDataProvider implements TreeDataProvider<ExplorerNode> {
return project ? project.revealPaths(paths) : null;
}

private doRefresh(): void {
this._rootItems = null;
this._onDidChangeTreeData.fire();
private doRefresh(element?: ExplorerNode): void {
explorerNodeCache.removeNodeChildren(element);
this._onDidChangeTreeData.fire(element);
}

private async getRootProjects(): Promise<ExplorerNode[]> {
Expand Down
13 changes: 9 additions & 4 deletions src/views/dependencyExplorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { isStandardServerReady } from "../extension";
import { Jdtls } from "../java/jdtls";
import { INodeData } from "../java/nodeData";
import { Settings } from "../settings";
import { DataNode } from "./dataNode";
import { DependencyDataProvider } from "./dependencyDataProvider";
import { ExplorerNode } from "./explorerNode";
import { explorerNodeCache } from "./nodeCache/explorerNodeCache";

export class DependencyExplorer implements Disposable {

Expand Down Expand Up @@ -55,11 +57,14 @@ export class DependencyExplorer implements Disposable {
return;
}

const paths: INodeData[] = await Jdtls.resolvePath(uri.toString());
if (!paths || paths.length === 0) {
return;
let node: DataNode | undefined = explorerNodeCache.getDataNode(uri);
if (!node) {
const paths: INodeData[] = await Jdtls.resolvePath(uri.toString());
if (!paths || paths.length === 0) {
return;
}
node = await this._dataProvider.revealPaths(paths);
}
const node = await this._dataProvider.revealPaths(paths);

if (this._dependencyViewer.visible) {
this._dependencyViewer.reveal(node);
Expand Down
9 changes: 6 additions & 3 deletions src/views/hierarchicalPackageNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ export class HierarchicalPackageNode extends PackageNode {

public getChildren(): ProviderResult<ExplorerNode[]> {
return this.loadData().then((res) => {
if (!!res) {
// Combine hierarchical children and normal package node children
res.forEach((node) => this.nodeData.children.push(node));
if (res) {
if (this.nodeData?.children) {
this.nodeData.children.push(...res);
} else {
this.nodeData.children = res;
}
}
return this.createChildNodeList();
});
Expand Down
Loading