1
1
import * as vscode from 'vscode' ;
2
2
import * as path from 'path' ;
3
3
import * as fs from 'fs' ;
4
+ import * as os from 'os' ;
4
5
import * as toml from 'toml' ;
5
6
import { getAllRazDirectories } from './utils/workspace' ;
6
7
@@ -42,9 +43,9 @@ export class RazOverrideTreeProvider implements vscode.TreeDataProvider<Override
42
43
if ( ! element ) {
43
44
// Root level - show all projects with .raz directories
44
45
return Promise . resolve ( this . getRazProjects ( ) ) ;
45
- } else if ( element . contextValue === 'razProject' ) {
46
+ } else if ( element . contextValue === 'razProject' || element . contextValue === 'razGlobalProject' ) {
46
47
// For projects, show overrides
47
- return Promise . resolve ( this . getProjectChildren ( element . filePath ! ) ) ;
48
+ return Promise . resolve ( this . getProjectChildren ( element . filePath ! , element . contextValue === 'razGlobalProject' ) ) ;
48
49
} else if ( element . contextValue === 'razOverride' ) {
49
50
// Show override details as children
50
51
return Promise . resolve ( this . getOverrideDetails ( element ) ) ;
@@ -59,6 +60,55 @@ export class RazOverrideTreeProvider implements vscode.TreeDataProvider<Override
59
60
const items : OverrideItem [ ] = [ ] ;
60
61
const workspaceRoots = new Set < string > ( ) ;
61
62
63
+ // Add global overrides section first
64
+ const globalRazPath = path . join ( os . homedir ( ) , '.raz' ) ;
65
+ const globalOverridePath = path . join ( globalRazPath , 'overrides.toml' ) ;
66
+
67
+ if ( fs . existsSync ( globalOverridePath ) ) {
68
+ // For global overrides, the overrides.toml is directly in .raz folder
69
+ let globalOverrideCount = 0 ;
70
+ try {
71
+ const content = fs . readFileSync ( globalOverridePath , 'utf8' ) ;
72
+ const data = toml . parse ( content ) ;
73
+
74
+ if ( data . overrides ) {
75
+ // Filter global overrides to only those relevant to current workspace
76
+ const workspaceFolders = vscode . workspace . workspaceFolders ;
77
+ const workspacePaths = workspaceFolders ? workspaceFolders . map ( folder => folder . uri . fsPath ) : [ ] ;
78
+
79
+ let relevantCount = 0 ;
80
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
81
+ for ( const [ , override ] of Object . entries ( data . overrides as Record < string , any > ) ) {
82
+ if ( override && override . metadata && override . metadata . file_path ) {
83
+ const filePath = override . metadata . file_path ;
84
+ // Check if this file is within any workspace folder
85
+ const isRelevant = workspacePaths . some ( workspacePath =>
86
+ filePath . startsWith ( workspacePath )
87
+ ) ;
88
+ if ( isRelevant ) {
89
+ relevantCount ++ ;
90
+ }
91
+ }
92
+ }
93
+ globalOverrideCount = relevantCount ;
94
+ }
95
+ } catch ( error ) {
96
+ console . error ( 'Error counting global overrides:' , error ) ;
97
+ }
98
+
99
+ if ( globalOverrideCount > 0 ) {
100
+ const globalItem = new OverrideItem (
101
+ `Standalone (${ globalOverrideCount } override${ globalOverrideCount !== 1 ? 's' : '' } )` ,
102
+ vscode . TreeItemCollapsibleState . Collapsed ,
103
+ 'razGlobalProject' ,
104
+ globalRazPath
105
+ ) ;
106
+ globalItem . iconPath = new vscode . ThemeIcon ( 'globe' ) ;
107
+ globalItem . tooltip = `${ globalRazPath } \n${ globalOverrideCount } standalone override${ globalOverrideCount !== 1 ? 's' : '' } ` ;
108
+ items . push ( globalItem ) ;
109
+ }
110
+ }
111
+
62
112
// First pass: identify all workspace roots
63
113
for ( const dir of razDirs ) {
64
114
const cargoTomlPath = path . join ( dir , 'Cargo.toml' ) ;
@@ -80,6 +130,11 @@ export class RazOverrideTreeProvider implements vscode.TreeDataProvider<Override
80
130
continue ;
81
131
}
82
132
133
+ // Skip the global .raz directory (home directory) since we handle it separately as "Standalone"
134
+ if ( dir === os . homedir ( ) ) {
135
+ continue ;
136
+ }
137
+
83
138
// Skip if this directory is inside a workspace (will be handled by workspace)
84
139
let isInsideWorkspace = false ;
85
140
for ( const wsRoot of workspaceRoots ) {
@@ -166,13 +221,17 @@ export class RazOverrideTreeProvider implements vscode.TreeDataProvider<Override
166
221
return items ;
167
222
}
168
223
169
- private getProjectChildren ( projectPath : string ) : OverrideItem [ ] {
224
+ private getProjectChildren ( projectPath : string , isGlobal = false ) : OverrideItem [ ] {
170
225
// Simply get the overrides for this project
171
- return this . getProjectOverrides ( projectPath ) ;
226
+ return this . getProjectOverrides ( projectPath , isGlobal ) ;
172
227
}
173
228
174
- private getProjectOverrides ( projectPath : string ) : OverrideItem [ ] {
175
- const overridePath = path . join ( projectPath , '.raz' , 'overrides.toml' ) ;
229
+ private getProjectOverrides ( projectPath : string , isGlobal = false ) : OverrideItem [ ] {
230
+ // For global overrides, the path is different
231
+ const overridePath = isGlobal
232
+ ? path . join ( projectPath , 'overrides.toml' )
233
+ : path . join ( projectPath , '.raz' , 'overrides.toml' ) ;
234
+
176
235
if ( ! fs . existsSync ( overridePath ) ) {
177
236
return [ ] ;
178
237
}
@@ -183,9 +242,68 @@ export class RazOverrideTreeProvider implements vscode.TreeDataProvider<Override
183
242
const items : OverrideItem [ ] = [ ] ;
184
243
185
244
if ( data . overrides ) {
186
- for ( const [ , override ] of Object . entries ( data . overrides as Record < string , OverrideEntry > ) ) {
245
+ // Get workspace paths for filtering
246
+ const workspaceFolders = vscode . workspace . workspaceFolders ;
247
+ const workspacePaths = workspaceFolders ? workspaceFolders . map ( folder => folder . uri . fsPath ) : [ ] ;
248
+
249
+ // For global overrides, each key is the override ID and contains the full override object
250
+ for ( const [ overrideKey , override ] of Object . entries ( data . overrides as Record < string , OverrideEntry > ) ) {
251
+ if ( ! override || typeof override !== 'object' ) {
252
+ continue ;
253
+ }
254
+
255
+ // For global overrides, only show those relevant to current workspace
256
+ if ( isGlobal && override . metadata && override . metadata . file_path ) {
257
+ const filePath = override . metadata . file_path ;
258
+ const isRelevant = workspacePaths . some ( workspacePath =>
259
+ filePath . startsWith ( workspacePath )
260
+ ) ;
261
+ if ( ! isRelevant ) {
262
+ continue ;
263
+ }
264
+ }
265
+
187
266
const metadata = override . metadata ;
188
- const functionName = metadata . function_name || 'unknown' ;
267
+
268
+ // Try to extract a better function name
269
+ let functionName = metadata . function_name ;
270
+
271
+ if ( ! functionName || functionName === 'unknown' ) {
272
+ // Try to extract from the override key
273
+ const keyParts = overrideKey . split ( ':' ) ;
274
+ if ( keyParts . length >= 2 ) {
275
+ const lastPart = keyParts [ keyParts . length - 1 ] ;
276
+ // Check if it looks like a function name (not just a line number)
277
+ if ( lastPart && ! lastPart . startsWith ( 'L' ) && ! / ^ \d + $ / . test ( lastPart ) ) {
278
+ functionName = lastPart ;
279
+ } else if ( keyParts . length >= 3 ) {
280
+ // Maybe it's file:line:function format
281
+ const potentialFunction = keyParts [ keyParts . length - 2 ] ;
282
+ if ( potentialFunction && ! potentialFunction . startsWith ( 'L' ) && ! / ^ \d + $ / . test ( potentialFunction ) ) {
283
+ functionName = potentialFunction ;
284
+ }
285
+ }
286
+ }
287
+
288
+ // If still no good name, check if it's a doctest or test
289
+ if ( ! functionName || functionName === 'unknown' ) {
290
+ const overrideConfigKey = override . override_config ?. key || '' ;
291
+ const isTestRelated = overrideKey . includes ( 'doctest' ) ||
292
+ overrideConfigKey === 'test' ||
293
+ overrideConfigKey . includes ( 'test' ) ||
294
+ overrideKey . includes ( ':L' ) ; // Line-based overrides are often doctests
295
+
296
+ if ( isTestRelated ) {
297
+ // Try to extract from file path for doctests
298
+ const filePath = metadata . file_path || '' ;
299
+ const fileName = filePath . split ( '/' ) . pop ( ) ?. replace ( '.rs' , '' ) || 'doctest' ;
300
+ functionName = `${ fileName } _doctest` ;
301
+ } else {
302
+ functionName = 'unknown' ;
303
+ }
304
+ }
305
+ }
306
+
189
307
const line = metadata . original_line || 0 ;
190
308
191
309
// Create main override item with just function name
@@ -251,6 +369,7 @@ export class RazOverrideTreeProvider implements vscode.TreeDataProvider<Override
251
369
}
252
370
}
253
371
372
+ console . log ( `Returning ${ items . length } items for ${ isGlobal ? 'global' : 'project' } overrides` ) ;
254
373
return items . sort ( ( a , b ) => a . label . localeCompare ( b . label ) ) ;
255
374
} catch ( error ) {
256
375
console . error ( 'Failed to parse overrides:' , error ) ;
0 commit comments