Skip to content

Commit 1a5f458

Browse files
committed
show a warning if the minimum_zig_version of the project is unsatisfied
fixes #245
1 parent 9f65aef commit 1a5f458

File tree

1 file changed

+97
-19
lines changed

1 file changed

+97
-19
lines changed

src/zigSetup.ts

+97-19
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,47 @@ async function selectVersionAndInstall(context: vscode.ExtensionContext) {
258258
}
259259
}
260260

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*\.minimum_zig_version\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+
261302
/** The order of these enums defines the default order in which these sources are executed. */
262303
enum WantedZigVersionSource {
263304
workspaceState = "workspace-state",
@@ -305,15 +346,9 @@ async function getWantedZigVersion(
305346
}
306347
break;
307348
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*\.minimum_zig_version\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;
317352
}
318353
break;
319354
case WantedZigVersionSource.zigVersionConfigOption:
@@ -397,6 +432,56 @@ function updateZigEnvironmentVariableCollection(context: vscode.ExtensionContext
397432
}
398433
}
399434

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+
400485
export async function setupZig(context: vscode.ExtensionContext) {
401486
{
402487
// 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) {
456541
if (!vscode.workspace.getConfiguration("zig").get<string>("path")) {
457542
await installZig(context);
458543
} else {
459-
updateStatusItem(statusItem, zigProvider.getZigVersion());
460-
updateLanguageStatusItem(languageStatusItem, zigProvider.getZigVersion());
461-
updateZigEnvironmentVariableCollection(context, zigProvider.getZigPath());
544+
await updateStatus(context);
462545
}
463546
};
464547

@@ -485,13 +568,8 @@ export async function setupZig(context: vscode.ExtensionContext) {
485568
}
486569
}),
487570
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);
495573
}),
496574
watcher1.onDidCreate(refreshZigInstallation),
497575
watcher1.onDidChange(refreshZigInstallation),

0 commit comments

Comments
 (0)