Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

show a warning if the minimum_zig_version of the project is unsatisfied #266

Merged
merged 1 commit into from
Dec 20, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 97 additions & 19 deletions src/zigSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,47 @@ async function selectVersionAndInstall(context: vscode.ExtensionContext) {
}
}

interface BuildZigZonMetadata {
/** The `build.zig.zon` document. */
document: vscode.TextDocument;
minimumZigVersion: semver.SemVer;
/** `.minimum_zig_version = "<start>0.13.0<end>"` */
minimumZigVersionSourceRange: vscode.Range;
}

/**
* Look for a `build.zig.zon` in the current workspace and return the `minimum_zig_version` in it.
*/
async function parseBuildZigZon(): Promise<BuildZigZonMetadata | null> {
let workspace: vscode.WorkspaceFolder | null = null;
// Supporting multiple workspaces is significantly more complex so we just look for the first workspace.
if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
workspace = vscode.workspace.workspaceFolders[0];
}
if (!workspace) return null;

const manifestUri = vscode.Uri.joinPath(workspace.uri, "build.zig.zon");

const manifest = await vscode.workspace.openTextDocument(manifestUri);
// Not perfect, but good enough
const regex = /\n\s*\.minimum_zig_version\s=\s\"(.*)\"/;
const matches = regex.exec(manifest.getText());
if (!matches) return null;

const versionString = matches[1];
const version = semver.parse(versionString);
if (!version) return null;

const startPosition = manifest.positionAt(matches.index + matches[0].length - versionString.length - 1);
const endPosition = startPosition.translate(0, versionString.length);

return {
document: manifest,
minimumZigVersion: version,
minimumZigVersionSourceRange: new vscode.Range(startPosition, endPosition),
};
}

/** The order of these enums defines the default order in which these sources are executed. */
enum WantedZigVersionSource {
workspaceState = "workspace-state",
Expand Down Expand Up @@ -305,15 +346,9 @@ async function getWantedZigVersion(
}
break;
case WantedZigVersionSource.workspaceBuildZigZon:
if (workspace) {
const manifest = await vscode.workspace.fs.readFile(
vscode.Uri.joinPath(workspace.uri, "build.zig.zon"),
);
// Not perfect, but good enough
const matches = /\n\s*\.minimum_zig_version\s=\s\"(.*)\"/.exec(manifest.toString());
if (matches) {
result = semver.parse(matches[1]);
}
const metadata = await parseBuildZigZon();
if (metadata?.minimumZigVersion) {
result = metadata.minimumZigVersion;
}
break;
case WantedZigVersionSource.zigVersionConfigOption:
Expand Down Expand Up @@ -397,6 +432,56 @@ function updateZigEnvironmentVariableCollection(context: vscode.ExtensionContext
}
}

/**
* Should be called when one of the following events happen:
* - The Zig executable has been modified
* - A workspace configuration file has been modified (e.g. `.zigversion`, `build.zig.zon`)
*/
async function updateStatus(context: vscode.ExtensionContext): Promise<void> {
const zigVersion = zigProvider.getZigVersion();
const zigPath = zigProvider.getZigPath();

updateStatusItem(statusItem, zigVersion);
updateLanguageStatusItem(languageStatusItem, zigVersion);
updateZigEnvironmentVariableCollection(context, zigPath);

// Try to check whether the Zig version satifies the `minimum_zig_version` in `build.zig.zon`

if (!zigVersion || !zigPath) return;
const buildZigZonMetadata = await parseBuildZigZon();
if (!buildZigZonMetadata) return;
if (semver.gte(zigVersion, buildZigZonMetadata.minimumZigVersion)) return;

statusItem.backgroundColor = new vscode.ThemeColor("statusBarItem.warningBackground");

void vscode.window
.showWarningMessage(
`Your Zig version '${zigVersion.toString()}' does not satify the minimum Zig version '${buildZigZonMetadata.minimumZigVersion.toString()}' of your project.`,
"update Zig",
"open build.zig.zon",
)
.then(async (response) => {
switch (response) {
case undefined:
break;
case "update Zig": {
await context.workspaceState.update("zig-version", undefined);
// This will source the desired Zig version with `getWantedZigVersion` which may not satisfy the minimum Zig version.
// This could happen for example when the a `.zigversion` specifies `0.12.0` but `minimum_zig_version` is `0.13.0`.
// The extension would install `0.12.0` and then complain again.
await installZig(context);
break;
}
case "open build.zig.zon": {
void vscode.window.showTextDocument(buildZigZonMetadata.document, {
selection: buildZigZonMetadata.minimumZigVersionSourceRange,
});
break;
}
}
});
}

export async function setupZig(context: vscode.ExtensionContext) {
{
// This check can be removed once enough time has passed so that most users switched to the new value
Expand Down Expand Up @@ -456,9 +541,7 @@ export async function setupZig(context: vscode.ExtensionContext) {
if (!vscode.workspace.getConfiguration("zig").get<string>("path")) {
await installZig(context);
} else {
updateStatusItem(statusItem, zigProvider.getZigVersion());
updateLanguageStatusItem(languageStatusItem, zigProvider.getZigVersion());
updateZigEnvironmentVariableCollection(context, zigProvider.getZigPath());
await updateStatus(context);
}
};

Expand All @@ -485,13 +568,8 @@ export async function setupZig(context: vscode.ExtensionContext) {
}
}),
vscode.window.onDidChangeActiveTextEditor(onDidChangeActiveTextEditor),
zigProvider.onChange.event((result) => {
const { exe, version } = result ?? { exe: null, version: null };

updateStatusItem(statusItem, version);
updateLanguageStatusItem(languageStatusItem, version);

updateZigEnvironmentVariableCollection(context, exe);
zigProvider.onChange.event(() => {
void updateStatus(context);
}),
watcher1.onDidCreate(refreshZigInstallation),
watcher1.onDidChange(refreshZigInstallation),
Expand Down
Loading