11import * as path from 'path' ;
22import * as vscode from 'vscode' ;
33import { TreeItem , TaskTreeItem , NamespaceTreeItem , WorkspaceTreeItem } from '../elements/treeItem.js' ;
4- import { Taskfile , Task , TaskMapping } from '../models/taskfile .js' ;
4+ import { Namespace , Task } from '../models/models .js' ;
55
66const namespaceSeparator = ':' ;
77
88export class TaskTreeDataProvider implements vscode . TreeDataProvider < TreeItem > {
99 private _onDidChangeTreeData : vscode . EventEmitter < TaskTreeItem | undefined > = new vscode . EventEmitter < TaskTreeItem | undefined > ( ) ;
1010 readonly onDidChangeTreeData : vscode . Event < TaskTreeItem | undefined > = this . _onDidChangeTreeData . event ;
11- private _taskfiles ?: Taskfile [ ] ;
12- private _treeViewMap : TaskMapping = { } ;
11+ private _namespaces ?: Namespace [ ] ;
12+ private _nesting : boolean = false ;
1313
14- constructor (
15- private nestingEnabled : boolean = false
16- ) { }
17-
18- setTreeNesting ( enabled : boolean ) {
19- this . nestingEnabled = enabled ;
14+ refresh ( namespaces ?: Namespace [ ] , nesting ?: boolean ) : void {
15+ if ( namespaces ) {
16+ this . _namespaces = namespaces ;
17+ }
18+ this . _nesting = nesting ?? this . _nesting ;
19+ this . _onDidChangeTreeData . fire ( undefined ) ;
2020 }
2121
2222 getTreeItem ( element : TreeItem ) : vscode . TreeItem {
2323 return element ;
2424 }
2525
2626 getChildren ( parent ?: TreeItem ) : Thenable < TreeItem [ ] > {
27- var treeItems : TreeItem [ ] = [ ] ;
28-
2927 // If there are no workspace folders, return an empty array
3028 if ( vscode . workspace . workspaceFolders === undefined || vscode . workspace . workspaceFolders . length === 0 ) {
3129 return Promise . resolve ( [ ] ) ;
@@ -38,51 +36,56 @@ export class TaskTreeDataProvider implements vscode.TreeDataProvider<TreeItem> {
3836 return Promise . resolve ( workspaces ) ;
3937 }
4038
41- // If there are no taskfiles , return an empty array
42- if ( ! this . _taskfiles || this . _taskfiles . length === 0 ) {
39+ // If there are no namespaces , return an empty array
40+ if ( ! this . _namespaces || this . _namespaces . length === 0 ) {
4341 return Promise . resolve ( [ ] ) ;
4442 }
4543
46- var tasks : Task [ ] | undefined ;
47- var parentNamespace = "" ;
48- var namespaceMap = this . _treeViewMap ;
49- var workspace = "" ;
50-
5144 // If there is no parent and exactly one workspace folder or if the parent is a workspace
5245 if ( ! parent && vscode . workspace . workspaceFolders . length === 1 ) {
53- tasks = this . _taskfiles [ 0 ] . tasks ;
54- workspace = this . _taskfiles [ 0 ] . workspace ?? "" ;
46+ return Promise . resolve ( this . createTreeItems (
47+ this . _namespaces [ 0 ] . workspace ?? "" ,
48+ this . _namespaces [ 0 ] . namespaces ,
49+ this . _namespaces [ 0 ] . tasks
50+ ) ) ;
5551 }
5652
57- // If there is a parent and it is a workspace
58- if ( parent instanceof WorkspaceTreeItem ) {
59- tasks = parent . tasks ;
60- workspace = parent . workspace ;
53+ // If there is a parent and it is a workspace or namespace
54+ if ( parent instanceof WorkspaceTreeItem || parent instanceof NamespaceTreeItem ) {
55+ return Promise . resolve ( this . createTreeItems (
56+ parent . workspace ,
57+ parent . namespace . namespaces ,
58+ parent . namespace . tasks
59+ ) ) ;
6160 }
6261
63- // If there is a parent and it is a namespace
64- if ( parent instanceof NamespaceTreeItem ) {
65- tasks = parent . tasks ;
66- parentNamespace = parent . label ;
67- namespaceMap = parent . namespaceMap ;
68- workspace = parent . workspace ;
69- }
62+ return Promise . resolve ( [ ] ) ;
63+ }
7064
65+ createTreeItems (
66+ workspace : string ,
67+ namespaces : Map < string , Namespace > ,
68+ tasks : Task [ ]
69+ ) : TreeItem [ ] {
70+ var treeItems : TreeItem [ ] = [ ] ;
7171
72- if ( tasks === undefined ) {
73- return Promise . resolve ( [ ] ) ;
72+ // Add each namespace to the tree
73+ if ( namespaces ) {
74+ for ( const [ key , namespace ] of Object . entries ( namespaces ) ) {
75+ treeItems = treeItems . concat ( new NamespaceTreeItem (
76+ key ,
77+ workspace ,
78+ namespace ,
79+ vscode . TreeItemCollapsibleState . Collapsed
80+ ) ) ;
81+ }
7482 }
7583
76- let namespaceTreeItems = new Map < string , NamespaceTreeItem > ( ) ;
77- let taskTreeItems : TaskTreeItem [ ] = [ ] ;
78- tasks . forEach ( task => {
79- let taskName = task . name . split ( ":" ) . pop ( ) ?? task . name ;
80- let namespacePath = trimParentNamespace ( task . name , parentNamespace ) ;
81- let namespaceName = getNamespaceName ( namespacePath ) ;
82-
83- if ( taskName in namespaceMap ) {
84- let item = new TaskTreeItem (
85- task . name . split ( namespaceSeparator ) . pop ( ) ?? task . name ,
84+ // Add each task to the tree
85+ if ( tasks ) {
86+ for ( const task of tasks ) {
87+ treeItems = treeItems . concat ( new TaskTreeItem (
88+ this . _nesting ? task . name . split ( namespaceSeparator ) . pop ( ) ?? task . name : task . name ,
8689 workspace ,
8790 task ,
8891 vscode . TreeItemCollapsibleState . None ,
@@ -91,119 +94,25 @@ export class TaskTreeDataProvider implements vscode.TreeDataProvider<TreeItem> {
9194 title : 'Go to Definition' ,
9295 arguments : [ task , true ]
9396 }
94- ) ;
95- taskTreeItems = taskTreeItems . concat ( item ) ;
96- }
97-
98- if ( namespaceName in namespaceMap && namespaceMap [ namespaceName ] !== null ) {
99- let namespaceTreeItem = namespaceTreeItems . get ( namespaceName ) ;
100-
101- if ( namespaceTreeItem === undefined ) {
102- namespaceTreeItem = new NamespaceTreeItem (
103- namespaceName ,
104- workspace ,
105- namespaceMap [ namespaceName ] ,
106- [ ] ,
107- vscode . TreeItemCollapsibleState . Collapsed
108- ) ;
109- }
110- namespaceTreeItem . tasks . push ( task ) ;
111- namespaceTreeItems . set ( namespaceName , namespaceTreeItem ) ;
97+ ) ) ;
11298 }
99+ }
113100
114- } ) ;
115-
116- // Add the namespace and tasks to the tree
117- namespaceTreeItems . forEach ( namespace => {
118- treeItems = treeItems . concat ( namespace ) ;
119- } ) ;
120- treeItems = treeItems . concat ( taskTreeItems ) ;
121-
122- return Promise . resolve ( treeItems ) ;
101+ return treeItems ;
123102 }
124103
125104 getWorkspaces ( ) : WorkspaceTreeItem [ ] {
126105 let workspaceTreeItems : WorkspaceTreeItem [ ] = [ ] ;
127- this . _taskfiles ?. forEach ( taskfile => {
128- let dir = path . dirname ( taskfile . location ) ;
106+ this . _namespaces ?. forEach ( namespace => {
107+ let dir = path . dirname ( namespace . location ) ;
129108 let workspaceTreeItem = new WorkspaceTreeItem (
130109 path . basename ( dir ) ,
131110 dir ,
132- taskfile . tasks ,
111+ namespace ,
133112 vscode . TreeItemCollapsibleState . Expanded
134113 ) ;
135114 workspaceTreeItems = workspaceTreeItems . concat ( workspaceTreeItem ) ;
136115 } ) ;
137116 return workspaceTreeItems ;
138117 }
139-
140- refresh ( taskfiles ?: Taskfile [ ] ) : void {
141- if ( taskfiles ) {
142- this . _taskfiles = taskfiles ;
143- this . _treeViewMap = { } ;
144-
145- // loop over all of the tasks in all of the task files and map their names into a set
146- const taskNames = Array . from ( new Set (
147- taskfiles . flatMap ( taskfile =>
148- taskfile . tasks . flatMap ( task => task . name )
149- )
150- // and sort desc so we know that the namespace reduction sets child objects correctly.
151- ) ) . sort ( ( a , b ) => ( a > b ? - 1 : 1 ) ) ;
152-
153- taskNames . reduce ( ( acc : any , key : string ) => {
154- const parts = key . split ( ':' ) ;
155- let currentLevel = acc ;
156-
157- parts . forEach ( ( part , index ) => {
158- if ( part === "" ) {
159- return ;
160- } ;
161-
162- if ( ! ( part in currentLevel ) ) {
163- currentLevel [ part ] = { } ;
164- if ( index === parts . length - 1 ) {
165- currentLevel [ part ] = null ;
166- }
167- }
168-
169- currentLevel = currentLevel [ part ] as TaskMapping ;
170- } ) ;
171-
172- return acc ;
173- } , this . _treeViewMap ) ;
174- }
175- this . _onDidChangeTreeData . fire ( undefined ) ;
176- }
177- }
178-
179- function getFullNamespacePath ( task : Task ) : string {
180- // If the task has no namespace, return undefined
181- if ( ! task . name . includes ( namespaceSeparator ) ) {
182- return "" ;
183- }
184- // Return the task's namespace by removing the last element
185- return task . name . substring ( 0 , task . name . lastIndexOf ( namespaceSeparator ) ) ;
186- }
187-
188- function trimParentNamespace ( namespace : string , parentNamespace : string ) : string {
189- if ( parentNamespace === "" ) {
190- return namespace ;
191- }
192-
193- const index = namespace . indexOf ( parentNamespace + namespaceSeparator ) ;
194-
195- if ( index === - 1 ) {
196- return namespace ;
197- }
198-
199- return namespace . substring ( index + parentNamespace . length + 1 ) ;
200- }
201-
202- function getNamespaceName ( namespacePath : string ) : string {
203- // If the namespace has no separator, return the namespace
204- if ( ! namespacePath . includes ( namespaceSeparator ) ) {
205- return namespacePath ;
206- }
207- // Return the first element of the namespace
208- return namespacePath . substring ( 0 , namespacePath . indexOf ( namespaceSeparator ) ) ;
209118}
0 commit comments