@@ -23,6 +23,12 @@ import { Resources } from "../extension/resources";
2323
2424/** A tree item representing a workspace folder. */
2525export class BazelWorkspaceFolderTreeItem implements IBazelTreeItem {
26+ /**
27+ * Stores all BazelPackageTreeItems in sorted order (by path length and in descending order).
28+ * This is used to find the most specific match for a given file path.
29+ */
30+ private sortedPackageTreeItems : BazelPackageTreeItem [ ] = [ ] ;
31+
2632 /**
2733 * Initializes a new tree item with the given workspace folder.
2834 *
@@ -31,7 +37,9 @@ export class BazelWorkspaceFolderTreeItem implements IBazelTreeItem {
3137 constructor (
3238 private readonly resources : Resources ,
3339 private readonly workspaceInfo : BazelWorkspaceInfo ,
34- ) { }
40+ ) {
41+ void this . getDirectoryItems ( ) ; // Initialize the tree items
42+ }
3543
3644 public mightHaveChildren ( ) : boolean {
3745 return true ;
@@ -41,6 +49,10 @@ export class BazelWorkspaceFolderTreeItem implements IBazelTreeItem {
4149 return this . getDirectoryItems ( ) ;
4250 }
4351
52+ public getParent ( ) : vscode . ProviderResult < IBazelTreeItem > {
53+ return undefined ;
54+ }
55+
4456 public getLabel ( ) : string {
4557 return this . workspaceInfo . workspaceFolder . name ;
4658 }
@@ -61,6 +73,31 @@ export class BazelWorkspaceFolderTreeItem implements IBazelTreeItem {
6173 return "workspaceFolder" ;
6274 }
6375
76+ public getWorkspaceInfo ( ) : BazelWorkspaceInfo {
77+ return this . workspaceInfo ;
78+ }
79+
80+ public getPackagePath ( ) : string {
81+ return "" ;
82+ }
83+
84+ /**
85+ * Finds the package that contains the given relative file path.
86+ * Uses the presorted list of package items for efficient lookups.
87+ * Find the first package that is a prefix of the relative path
88+ *
89+ * @param relativeFilePath The filepath relative to the workspace folder.
90+ * @returns The package tree item that contains the given relative file path,
91+ * or undefined if no such package exists.
92+ */
93+ public getClosestPackageTreeItem (
94+ relativeFilePath : string ,
95+ ) : BazelPackageTreeItem | undefined {
96+ return this . sortedPackageTreeItems . find ( ( pkg ) =>
97+ relativeFilePath . startsWith ( pkg . getPackagePath ( ) ) ,
98+ ) ;
99+ }
100+
64101 /**
65102 * Recursively creates the tree items that represent packages found in a Bazel
66103 * query.
@@ -73,16 +110,15 @@ export class BazelWorkspaceFolderTreeItem implements IBazelTreeItem {
73110 * common prefixes should be searched.
74111 * @param treeItems An array into which the tree items created at this level
75112 * in the tree will be pushed.
76- * @param parentPackagePath The parent package path of the items being created
77- * by this call, which is used to trim the package prefix from labels in
78- * the tree items.
113+ * @param parent The parent tree item of the items being created by this call,
114+ * which is used to trim the package prefix from labels in the tree items.
79115 */
80116 private buildPackageTree (
81117 packagePaths : string [ ] ,
82118 startIndex : number ,
83119 endIndex : number ,
84120 treeItems : BazelPackageTreeItem [ ] ,
85- parentPackagePath : string ,
121+ parent : IBazelTreeItem ,
86122 ) {
87123 // We can assume that the caller has sorted the packages, so we scan them to
88124 // find groupings into which we should traverse more deeply. For example, if
@@ -128,16 +164,16 @@ export class BazelWorkspaceFolderTreeItem implements IBazelTreeItem {
128164 const item = new BazelPackageTreeItem (
129165 this . resources ,
130166 this . workspaceInfo ,
167+ parent ,
131168 packagePath ,
132- parentPackagePath ,
133169 ) ;
134170 treeItems . push ( item ) ;
135171 this . buildPackageTree (
136172 packagePaths ,
137173 groupStart + 1 ,
138174 groupEnd ,
139175 item . directSubpackages ,
140- packagePath ,
176+ item ,
141177 ) ;
142178
143179 // Move our index to start looking for more groups in the next iteration
@@ -175,7 +211,7 @@ export class BazelWorkspaceFolderTreeItem implements IBazelTreeItem {
175211 0 ,
176212 packagePaths . length ,
177213 topLevelItems ,
178- "" ,
214+ this ,
179215 ) ;
180216
181217 // Now collect any targets in the directory also (this can fail since
@@ -191,10 +227,37 @@ export class BazelWorkspaceFolderTreeItem implements IBazelTreeItem {
191227 return new BazelTargetTreeItem (
192228 this . resources ,
193229 this . workspaceInfo ,
230+ this as unknown as IBazelTreeItem ,
194231 target ,
195232 ) ;
196233 } ) ;
197234
235+ // Cache all packages after building the tree
236+ this . collectAndSortPackageTreeItems ( topLevelItems ) ;
237+
198238 return Promise . resolve ( ( topLevelItems as IBazelTreeItem [ ] ) . concat ( targets ) ) ;
199239 }
240+
241+ /**
242+ * Collect, sort and store packages for later lookup
243+ */
244+ private collectAndSortPackageTreeItems ( items : BazelPackageTreeItem [ ] ) : void {
245+ this . sortedPackageTreeItems = [ ] ;
246+ this . collectAllPackageTreeItems ( items ) ;
247+ this . sortedPackageTreeItems . sort (
248+ ( a , b ) => b . getPackagePath ( ) . length - a . getPackagePath ( ) . length ,
249+ ) ;
250+ }
251+
252+ /**
253+ * Recursively collect all children of type BazelPackageTreeItem
254+ */
255+ private collectAllPackageTreeItems ( items : BazelPackageTreeItem [ ] ) : void {
256+ for ( const item of items ) {
257+ this . sortedPackageTreeItems . push ( item ) ;
258+ if ( item . directSubpackages ) {
259+ this . collectAllPackageTreeItems ( item . directSubpackages ) ;
260+ }
261+ }
262+ }
200263}
0 commit comments