import { ExecutionPathProps , ExecutionPathStatus } from 'pytea/service/executionPaths' ; import { commands , Event , EventEmitter , ExtensionContext , ProviderResult , TreeDataProvider , TreeItem , TreeView , Uri , window , } from 'vscode' ; import { PyteaCommands } from './commands' ; interface PyteaTreeProvider { refresh ( props ? ) : void ; } type NumId = { id : number ; } ; const idCache = { } ; function getId ( id ) { if ( id in idCache ) return idCache [ id ] ; const newId = { id } ; idCache [ id ] = newId ; return newId ; } export class PathSelectionProvider implements TreeDataProvider < NumId > { private _onDidChangeTreeData : EventEmitter < any > = new EventEmitter < any > ( ) ; readonly onDidChangeTreeData : Event < any > = this . _onDidChangeTreeData . event ; constructor ( private pathProps ) { } public refresh ( pathProps ) { this . pathProps = pathProps ; console . log ( `refresh with ${ pathProps . length }` ) ; this . _onDidChangeTreeData . fire ( undefined ) ; } public getTreeItem ( pathId ) { return { label : this . _label ( pathId . id ) , command : { command : 'pytea.selectPath' , arguments : [ pathId . id ] , title : 'Select Specific Execution Path' , } , } ; } public getChildren ( element ? ) { if ( element !== undefined ) return [ ] ; return this . pathProps . map ( ( _ , i ) => { return getId ( i ) ; } ) ; } private _label ( pathId ) { if ( pathId < 0 || this . pathProps . length <= pathId ) return `Unknown Id ${ pathId }` ; const path = this . pathProps [ pathId ] ; switch ( path . status ) { case ExecutionPathStatus . Success : return `🟢 Success path ${ pathId + 1 }` ; case ExecutionPathStatus . Stopped : return `🟡 Stopped path ${ pathId + 1 }` ; case ExecutionPathStatus . Failed : return `🔴 Failed path ${ pathId + 1 }` ; } } } export class VariableDataProvider implements TreeDataProvider < NumId > , PyteaTreeProvider { private _onDidChangeTreeData : EventEmitter < any > = new EventEmitter < any > ( ) ; readonly onDidChangeTreeData : Event < any > = this . _onDidChangeTreeData . event ; constructor ( private props ? ) { } public refresh ( props ? ) { this . props = props ; this . _onDidChangeTreeData . fire ( undefined ) ; } public getTreeItem ( element ) { return { label : `var ${ element }` , } ; } public getChildren ( element ? ) { return undefined ; } } export class CallStackProvider implements TreeDataProvider < NumId > , PyteaTreeProvider { private _onDidChangeTreeData : EventEmitter < any > = new EventEmitter < any > ( ) ; readonly onDidChangeTreeData : Event < any > = this . _onDidChangeTreeData . event ; constructor ( private props ? ) { } public refresh ( props ? ) { this . props = props ; this . _onDidChangeTreeData . fire ( undefined ) ; } public getTreeItem ( element ) { return { command : { command : 'pytea.selectPath' , arguments : [ element ] , title : 'Select Specific Execution Path' , } , } ; } public getChildren ( element ? ) { return undefined ; } } const enum CtrType { Hard , Path , Soft } export class ConstraintDataProvider implements TreeDataProvider < NumId > , PyteaTreeProvider { private _onDidChangeTreeData : EventEmitter < any > = new EventEmitter < any > ( ) ; readonly onDidChangeTreeData : Event < any > = this . _onDidChangeTreeData . event ; private _ctrIdList : number [ ] ; constructor ( private type , private props ? ) { this . _ctrIdList = [ ] ; } public refresh ( props ? ) { this . props = props ; if ( props ) { switch ( this . type ) { case CtrType . Hard : this . _ctrIdList = props . hardCtr ; break ; case CtrType . Path : this . _ctrIdList = props . pathCtr ; break ; case CtrType . Soft : this . _ctrIdList = props . softCtr ; break ; } } else { this . _ctrIdList = [ ] ; } this . _onDidChangeTreeData . fire ( undefined ) ; } public getTreeItem ( nid ) { const ctrId = this . _ctrIdList [ nid . id ] ; const ctr = this . props ?. ctrPool [ ctrId ] ; if ( ! ctr ) { return { } ; } let resourceUri ; return { resourceUri , label : ctr [ 0 ] , command : { command : 'pytea.gotoConstraint' , arguments : [ ctrId ] , title : 'Go To The Generation Point Of The Constraint' , } , } ; } public getChildren ( nid ? ) { if ( nid !== undefined ) return undefined ; return this . _ctrIdList . map ( ( _ , i ) => { return getId ( i ) ; } ) ; } } export interface PathManagerCallback { selectPath ? : ( pathId : number ) => void ; } export class PathManager { private _pathTree : TreeView < NumId > ; private _varTree : TreeView < NumId > ; private _stackTree : TreeView < NumId > ; private _hardCtrTree : TreeView < NumId > ; private _pathCtrTree : TreeView < NumId > ; private _softCtrTree : TreeView < NumId > ; private _pathProps : ExecutionPathProps [ ] ; private _mainProvider : PathSelectionProvider ; private _providers : PyteaTreeProvider [ ] ; constructor ( context , callback ) { this . _pathProps = [ ] ; this . _mainProvider = new PathSelectionProvider ( this . _pathProps ) ; const providers = [ new VariableDataProvider ( ) , new CallStackProvider ( ) , new ConstraintDataProvider ( CtrType . Soft ) , new ConstraintDataProvider ( CtrType . Path ) , new ConstraintDataProvider ( CtrType . Hard ) , ] ; this . _pathTree = window . createTreeView ( 'executionPaths' , { treeDataProvider : this . _mainProvider , canSelectMany : false , } ) ; this . _varTree = window . createTreeView ( 'variables' , { treeDataProvider : providers [ 0 ] , showCollapseAll : true , canSelectMany : false , } ) ; this . _stackTree = window . createTreeView ( 'callStack' , { treeDataProvider : providers [ 1 ] } ) ; this . _softCtrTree = window . createTreeView ( 'softConstraints' , { treeDataProvider : providers [ 2 ] } ) ; this . _pathCtrTree = window . createTreeView ( 'pathConstraints' , { treeDataProvider : providers [ 3 ] } ) ; this . _hardCtrTree = window . createTreeView ( 'hardConstraints' , { treeDataProvider : providers [ 4 ] } ) ; this . _providers = providers ; context . subscriptions . push ( this . _pathTree ) ; context . subscriptions . push ( this . _varTree ) ; context . subscriptions . push ( this . _stackTree ) ; context . subscriptions . push ( this . _softCtrTree ) ; context . subscriptions . push ( this . _pathCtrTree ) ; context . subscriptions . push ( this . _hardCtrTree ) ; commands . registerCommand ( PyteaCommands . selectPath , ( pathId ) => { if ( callback . selectPath ) callback . selectPath ( pathId ) ; if ( pathId < 0 || pathId >= this . _pathProps . length ) { console . log ( `selected ${ pathId }` ) ; this . _providers . forEach ( ( p ) => p . refresh ( this . _pathProps [ pathId ] ) ) ; } } ) ; } applyPathProps ( results ) { this . _pathProps = results ; this . _mainProvider . refresh ( results ) ; let mainPath ; if ( results . length > 0 ) { mainPath = results [ 0 ] ; } this . _providers . forEach ( ( p ) => p . refresh ( mainPath ) ) ; } }