@@ -258,6 +258,47 @@ async function selectVersionAndInstall(context: vscode.ExtensionContext) {
258
258
}
259
259
}
260
260
261
+ interface BuildZigZonMetadata {
262
+ /** The `build.zig.zon` document. */
263
+ document : vscode . TextDocument ;
264
+ minimumZigVersion : semver . SemVer ;
265
+ /** `.minimum_zig_version = "<start>0.13.0<end>"` */
266
+ minimumZigVersionSourceRange : vscode . Range ;
267
+ }
268
+
269
+ /**
270
+ * Look for a `build.zig.zon` in the current workspace and return the `minimum_zig_version` in it.
271
+ */
272
+ async function parseBuildZigZon ( ) : Promise < BuildZigZonMetadata | null > {
273
+ let workspace : vscode . WorkspaceFolder | null = null ;
274
+ // Supporting multiple workspaces is significantly more complex so we just look for the first workspace.
275
+ if ( vscode . workspace . workspaceFolders && vscode . workspace . workspaceFolders . length > 0 ) {
276
+ workspace = vscode . workspace . workspaceFolders [ 0 ] ;
277
+ }
278
+ if ( ! workspace ) return null ;
279
+
280
+ const manifestUri = vscode . Uri . joinPath ( workspace . uri , "build.zig.zon" ) ;
281
+
282
+ const manifest = await vscode . workspace . openTextDocument ( manifestUri ) ;
283
+ // Not perfect, but good enough
284
+ const regex = / \n \s * \. m i n i m u m _ z i g _ v e r s i o n \s = \s \" ( .* ) \" / ;
285
+ const matches = regex . exec ( manifest . getText ( ) ) ;
286
+ if ( ! matches ) return null ;
287
+
288
+ const versionString = matches [ 1 ] ;
289
+ const version = semver . parse ( versionString ) ;
290
+ if ( ! version ) return null ;
291
+
292
+ const startPosition = manifest . positionAt ( matches . index + matches [ 0 ] . length - versionString . length - 1 ) ;
293
+ const endPosition = startPosition . translate ( 0 , versionString . length ) ;
294
+
295
+ return {
296
+ document : manifest ,
297
+ minimumZigVersion : version ,
298
+ minimumZigVersionSourceRange : new vscode . Range ( startPosition , endPosition ) ,
299
+ } ;
300
+ }
301
+
261
302
/** The order of these enums defines the default order in which these sources are executed. */
262
303
enum WantedZigVersionSource {
263
304
workspaceState = "workspace-state" ,
@@ -305,15 +346,9 @@ async function getWantedZigVersion(
305
346
}
306
347
break ;
307
348
case WantedZigVersionSource . workspaceBuildZigZon :
308
- if ( workspace ) {
309
- const manifest = await vscode . workspace . fs . readFile (
310
- vscode . Uri . joinPath ( workspace . uri , "build.zig.zon" ) ,
311
- ) ;
312
- // Not perfect, but good enough
313
- const matches = / \n \s * \. m i n i m u m _ z i g _ v e r s i o n \s = \s \" ( .* ) \" / . exec ( manifest . toString ( ) ) ;
314
- if ( matches ) {
315
- result = semver . parse ( matches [ 1 ] ) ;
316
- }
349
+ const metadata = await parseBuildZigZon ( ) ;
350
+ if ( metadata ?. minimumZigVersion ) {
351
+ result = metadata . minimumZigVersion ;
317
352
}
318
353
break ;
319
354
case WantedZigVersionSource . zigVersionConfigOption :
@@ -397,6 +432,56 @@ function updateZigEnvironmentVariableCollection(context: vscode.ExtensionContext
397
432
}
398
433
}
399
434
435
+ /**
436
+ * Should be called when one of the following events happen:
437
+ * - The Zig executable has been modified
438
+ * - A workspace configuration file has been modified (e.g. `.zigversion`, `build.zig.zon`)
439
+ */
440
+ async function updateStatus ( context : vscode . ExtensionContext ) : Promise < void > {
441
+ const zigVersion = zigProvider . getZigVersion ( ) ;
442
+ const zigPath = zigProvider . getZigPath ( ) ;
443
+
444
+ updateStatusItem ( statusItem , zigVersion ) ;
445
+ updateLanguageStatusItem ( languageStatusItem , zigVersion ) ;
446
+ updateZigEnvironmentVariableCollection ( context , zigPath ) ;
447
+
448
+ // Try to check whether the Zig version satifies the `minimum_zig_version` in `build.zig.zon`
449
+
450
+ if ( ! zigVersion || ! zigPath ) return ;
451
+ const buildZigZonMetadata = await parseBuildZigZon ( ) ;
452
+ if ( ! buildZigZonMetadata ) return ;
453
+ if ( semver . gte ( zigVersion , buildZigZonMetadata . minimumZigVersion ) ) return ;
454
+
455
+ statusItem . backgroundColor = new vscode . ThemeColor ( "statusBarItem.warningBackground" ) ;
456
+
457
+ void vscode . window
458
+ . showWarningMessage (
459
+ `Your Zig version '${ zigVersion . toString ( ) } ' does not satify the minimum Zig version '${ buildZigZonMetadata . minimumZigVersion . toString ( ) } ' of your project.` ,
460
+ "update Zig" ,
461
+ "open build.zig.zon" ,
462
+ )
463
+ . then ( async ( response ) => {
464
+ switch ( response ) {
465
+ case undefined :
466
+ break ;
467
+ case "update Zig" : {
468
+ await context . workspaceState . update ( "zig-version" , undefined ) ;
469
+ // This will source the desired Zig version with `getWantedZigVersion` which not satisfy the minimum Zig version.
470
+ // This could happen for example when the a `.zigversion` specifies `0.12.0` but `minimum_zig_version` is `0.13.0`.
471
+ // The extension would install `0.12.0` and then complain again.
472
+ await installZig ( context ) ;
473
+ break ;
474
+ }
475
+ case "open build.zig.zon" : {
476
+ void vscode . window . showTextDocument ( buildZigZonMetadata . document , {
477
+ selection : buildZigZonMetadata . minimumZigVersionSourceRange ,
478
+ } ) ;
479
+ break ;
480
+ }
481
+ }
482
+ } ) ;
483
+ }
484
+
400
485
export async function setupZig ( context : vscode . ExtensionContext ) {
401
486
{
402
487
// This check can be removed once enough time has passed so that most users switched to the new value
@@ -456,9 +541,7 @@ export async function setupZig(context: vscode.ExtensionContext) {
456
541
if ( ! vscode . workspace . getConfiguration ( "zig" ) . get < string > ( "path" ) ) {
457
542
await installZig ( context ) ;
458
543
} else {
459
- updateStatusItem ( statusItem , zigProvider . getZigVersion ( ) ) ;
460
- updateLanguageStatusItem ( languageStatusItem , zigProvider . getZigVersion ( ) ) ;
461
- updateZigEnvironmentVariableCollection ( context , zigProvider . getZigPath ( ) ) ;
544
+ await updateStatus ( context ) ;
462
545
}
463
546
} ;
464
547
@@ -485,13 +568,8 @@ export async function setupZig(context: vscode.ExtensionContext) {
485
568
}
486
569
} ) ,
487
570
vscode . window . onDidChangeActiveTextEditor ( onDidChangeActiveTextEditor ) ,
488
- zigProvider . onChange . event ( ( result ) => {
489
- const { exe, version } = result ?? { exe : null , version : null } ;
490
-
491
- updateStatusItem ( statusItem , version ) ;
492
- updateLanguageStatusItem ( languageStatusItem , version ) ;
493
-
494
- updateZigEnvironmentVariableCollection ( context , exe ) ;
571
+ zigProvider . onChange . event ( ( ) => {
572
+ void updateStatus ( context ) ;
495
573
} ) ,
496
574
watcher1 . onDidCreate ( refreshZigInstallation ) ,
497
575
watcher1 . onDidChange ( refreshZigInstallation ) ,
0 commit comments