import * as fse from "fs-extra" ; import * as _ from "lodash" ; import * as path from "path" ; import { commands , Disposable , ExtensionContext , QuickPickItem , TextEditor , TreeView , TreeViewExpansionEvent , TreeViewSelectionChangeEvent , TreeViewVisibilityChangeEvent , Uri , window , } from "vscode" ; import { instrumentOperationAsVsCodeCommand , sendInfo } from "vscode-extension-telemetry-wrapper" ; import { Commands } from "../commands" ; import { deleteFiles } from "../explorerCommands/delete" ; import { newJavaClass , newPackage } from "../explorerCommands/new" ; import { renameFile } from "../explorerCommands/rename" ; import { getCmdNode } from "../explorerCommands/utility" ; import { Jdtls } from "../java/jdtls" ; import { INodeData } from "../java/nodeData" ; import { Settings } from "../settings" ; import { EventCounter , Utility } from "../utility" ; import { DataNode } from "./dataNode" ; import { DependencyDataProvider } from "./dependencyDataProvider" ; import { ExplorerNode } from "./explorerNode" ; import { explorerNodeCache } from "./nodeCache/explorerNodeCache" ; export class DependencyExplorer implements Disposable { public static getInstance ( context ) { if ( ! this . _instance ) { this . _instance = new DependencyExplorer ( context ) ; } return this . _instance ; } private static _instance : DependencyExplorer ; private _dependencyViewer : TreeView < ExplorerNode > ; private _dataProvider : DependencyDataProvider ; constructor ( public readonly context ) { this . _dataProvider = new DependencyDataProvider ( context ) ; this . _dependencyViewer = window . createTreeView ( "javaProjectExplorer" , { treeDataProvider : this . _dataProvider , showCollapseAll : true } ) ; context . subscriptions . push ( window . onDidChangeActiveTextEditor ( ( textEditor ) => { if ( this . _dependencyViewer . visible && textEditor ?. document ) { const uri = textEditor . document . uri ; this . reveal ( uri ) ; } } ) , this . _dependencyViewer . onDidChangeVisibility ( ( e ) => { if ( e . visible ) { sendInfo ( "" , { projectManagerVisible : 1 } ) ; if ( window . activeTextEditor ) { this . reveal ( window . activeTextEditor . document . uri ) ; } } } ) , this . _dataProvider . onDidChangeTreeData ( ( ) => { if ( this . _dependencyViewer . visible && window . activeTextEditor ) { this . reveal ( window . activeTextEditor . document . uri ) ; } } ) , instrumentOperationAsVsCodeCommand ( Commands . VIEW_PACKAGE_REVEAL_IN_PROJECT_EXPLORER , async ( uri ) => { await commands . executeCommand ( Commands . JAVA_PROJECT_EXPLORER_FOCUS ) ; let fsPath = uri . fsPath ; const fileName = path . basename ( fsPath ) ; if ( /(.*\.gradle)|(.*\.gradle\.kts)|(pom\.xml)$/ . test ( fileName ) ) { fsPath = path . dirname ( fsPath ) ; } uri = Uri . file ( fsPath ) ; if ( ( await fse . stat ( fsPath ) ) . isFile ( ) ) { await commands . executeCommand ( Commands . VSCODE_OPEN , uri , { preserveFocus : true } ) ; } this . reveal ( uri , false ) ; } ) ) ; context . subscriptions . push ( this . _dependencyViewer . onDidChangeSelection ( ( _e ) => { EventCounter . increase ( "didChangeSelection" ) ; } ) , this . _dependencyViewer . onDidCollapseElement ( ( _e ) => { EventCounter . increase ( "didCollapseElement" ) ; } ) , this . _dependencyViewer . onDidExpandElement ( ( _e ) => { EventCounter . increase ( "didExpandElement" ) ; } ) ) ; context . subscriptions . push ( instrumentOperationAsVsCodeCommand ( Commands . VIEW_PACKAGE_NEW_JAVA_CLASS , async ( node ? ) => { newJavaClass ( node ) ; } ) , instrumentOperationAsVsCodeCommand ( Commands . VIEW_PACKAGE_NEW_JAVA_PACKAGE , async ( node ? ) => { let cmdNode = getCmdNode ( this . _dependencyViewer . selection , node ) ; if ( ! cmdNode ) { cmdNode = await this . promptForProjectNode ( ) ; } newPackage ( cmdNode ) ; } ) , instrumentOperationAsVsCodeCommand ( Commands . VIEW_PACKAGE_REVEAL_FILE_OS , ( node ? ) => { const cmdNode = getCmdNode ( this . _dependencyViewer . selection , node ) ; if ( cmdNode ?. uri ) { commands . executeCommand ( "revealFileInOS" , Uri . parse ( cmdNode . uri ) ) ; } } ) , instrumentOperationAsVsCodeCommand ( Commands . VIEW_PACKAGE_COPY_FILE_PATH , ( node ? ) => { const cmdNode = getCmdNode ( this . _dependencyViewer . selection , node ) ; if ( cmdNode ?. uri ) { commands . executeCommand ( "copyFilePath" , Uri . parse ( cmdNode . uri ) ) ; } } ) , instrumentOperationAsVsCodeCommand ( Commands . VIEW_PACKAGE_COPY_RELATIVE_FILE_PATH , ( node ? ) => { const cmdNode = getCmdNode ( this . _dependencyViewer . selection , node ) ; if ( cmdNode ?. uri ) { commands . executeCommand ( "copyRelativeFilePath" , Uri . parse ( cmdNode . uri ) ) ; } } ) , instrumentOperationAsVsCodeCommand ( Commands . VIEW_PACKAGE_RENAME_FILE , ( node ? ) => { renameFile ( getCmdNode ( this . _dependencyViewer . selection , node ) ) ; } ) , instrumentOperationAsVsCodeCommand ( Commands . VIEW_PACKAGE_MOVE_FILE_TO_TRASH , ( node ? ) => { deleteFiles ( getCmdNode ( this . _dependencyViewer . selection , node ) ) ; } ) ) ; } public dispose ( ) { if ( this . _dependencyViewer ) { this . _dependencyViewer . dispose ( ) ; } } public async reveal ( uri , needCheckSyncSetting = true ) { if ( needCheckSyncSetting && ! Settings . syncWithFolderExplorer ( ) ) { return ; } if ( ! await Utility . isRevealable ( uri ) ) { return ; } let node = explorerNodeCache . getDataNode ( uri ) ; if ( ! node ) { const paths = await Jdtls . resolvePath ( uri . toString ( ) ) ; if ( ! _ . isEmpty ( paths ) ) { node = await this . _dataProvider . revealPaths ( paths ) ; } } if ( ! node ) { return ; } await this . _dependencyViewer . reveal ( node ) ; } public get dataProvider ( ) : DependencyDataProvider { return this . _dataProvider ; } private async promptForProjectNode ( ) { const projects = await this . _dataProvider . getRootProjects ( ) ; if ( projects . length === 0 ) { window . showInformationMessage ( "There is no Java projects in current workspace." ) ; return undefined ; } else if ( projects . length === 1 ) { return projects [ 0 ] as DataNode ; } else { const options = projects . map ( ( p ) => { return { label : p . name , node : p , } ; } ) ; const choice = await window . showQuickPick ( options , { placeHolder : "Choose a project" , ignoreFocusOut : true , } ) ; return choice ?. node as DataNode ; } } } interface IProjectPickItem extends QuickPickItem { node : ExplorerNode ; }