Skip to content

Commit 7d743a0

Browse files
committed
Fix zephyr project creation UI
Signed-off-by: paulober <[email protected]>
1 parent 4d10bf7 commit 7d743a0

File tree

3 files changed

+257
-92
lines changed

3 files changed

+257
-92
lines changed

src/utils/cmakeUtil.mts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { exec } from "child_process";
1+
import { exec, execFile } from "child_process";
22
import { workspace, type Uri, window, ProgressLocation } from "vscode";
33
import { showRequirementsNotMetErrorMessage } from "./requirementsUtil.mjs";
44
import { dirname, join, resolve } from "path";
@@ -541,3 +541,52 @@ export function cmakeGetPicoVar(
541541

542542
return match[1];
543543
}
544+
545+
/**
546+
* Get the version string of a CMake executable.
547+
* Works for both stable releases (e.g. "3.31.5")
548+
* and prereleases like "3.31.0-rc4".
549+
*
550+
* @param cmakePath Path to the cmake executable (absolute or in PATH).
551+
* @returns Promise that resolves to the version string (e.g. "3.31.5" or "3.31.0-rc4"),
552+
* or undefined if not found/parse failed.
553+
*/
554+
export async function getCmakeVersion(
555+
cmakePath: string
556+
): Promise<string | undefined> {
557+
return new Promise(resolve => {
558+
execFile(cmakePath, ["--version"], { windowsHide: true }, (err, stdout) => {
559+
if (err) {
560+
console.error(`Failed to run cmake at ${cmakePath}: ${err.message}`);
561+
resolve(undefined);
562+
563+
return;
564+
}
565+
566+
const firstLine = stdout.split(/\r?\n/)[0].trim();
567+
// Expected: "cmake version 3.31.5" or "cmake version 3.31.0-rc4"
568+
const prefix = "cmake version ";
569+
if (firstLine.toLowerCase().startsWith(prefix)) {
570+
const version = firstLine.substring(prefix.length).trim();
571+
resolve(version);
572+
} else {
573+
console.error(`Unexpected cmake --version output: ${firstLine}`);
574+
resolve(undefined);
575+
}
576+
});
577+
});
578+
}
579+
580+
/**
581+
* Get the version string of the system-installed CMake (in PATH).
582+
* @returns Promise that resolves to a version string (e.g. "3.31.5")
583+
* or undefined if cmake not available.
584+
*/
585+
export async function getSystemCmakeVersion(): Promise<string | undefined> {
586+
const cmakePath = await which("cmake", { nothrow: true });
587+
if (!cmakePath) {
588+
return undefined;
589+
}
590+
591+
return getCmakeVersion(cmakePath);
592+
}

src/webview/newZephyrProjectPanel.mts

Lines changed: 78 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import {
2121
getProjectFolderDialogOptions,
2222
getWebviewOptions,
2323
} from "./newProjectPanel.mjs";
24-
import which from "which";
2524
import { existsSync } from "fs";
2625
import { join, dirname } from "path";
2726
import { PythonExtension } from "@vscode/python-extension";
@@ -31,6 +30,7 @@ import { setupZephyr } from "../utils/setupZephyr.mjs";
3130
import type { VersionBundle } from "../utils/versionBundles.mjs";
3231
import type VersionBundlesLoader from "../utils/versionBundles.mjs";
3332
import { getCmakeReleases } from "../utils/githubREST.mjs";
33+
import { getSystemCmakeVersion } from "../utils/cmakeUtil.mjs";
3434

3535
enum BoardType {
3636
pico = "pico",
@@ -144,6 +144,7 @@ export class NewZephyrProjectPanel {
144144
private _pythonExtensionApi?: PythonExtension;
145145
private _versionBundlesLoader?: VersionBundlesLoader;
146146
private _versionBundle: VersionBundle | undefined;
147+
private _systemCmakeVersion: string | undefined;
147148

148149
// Create settings.json file with correct subsitution for tools such as
149150
// CMake, Ninja, Python, etc
@@ -500,17 +501,12 @@ export class NewZephyrProjectPanel {
500501
return;
501502
}
502503

503-
if (
504-
this._versionBundle === undefined &&
505-
// if no versionBundle then all version options the could be dependent on it must be custom (=> independent of versionBundle)
506-
data.cmakeMode === 0
507-
// (data.ninjaMode === 0 || data.cmakeMode === 0)
508-
) {
504+
if (this._versionBundle === undefined && data.cmakeMode === 0) {
509505
progress.report({
510506
message: "Failed",
511507
increment: 100,
512508
});
513-
void window.showErrorMessage("Failed to find selected SDK version.");
509+
void window.showErrorMessage("Unknown cmake version selected.");
514510

515511
return;
516512
}
@@ -751,8 +747,7 @@ export class NewZephyrProjectPanel {
751747
// (await which("python3", { nothrow: true })) !== null ||
752748
// (await which("python", { nothrow: true })) !== null;
753749

754-
const isCmakeSystemAvailable =
755-
(await which("cmake", { nothrow: true })) !== null;
750+
this._systemCmakeVersion = await getSystemCmakeVersion();
756751

757752
// Restrict the webview to only load specific scripts
758753
const nonce = getNonce();
@@ -970,8 +965,8 @@ export class NewZephyrProjectPanel {
970965
</ul>
971966
</div>
972967
973-
<div class="grid gap-6 grid-cols-3 mt-10">
974-
<div id="section-console" class="snap-start col-span-2">
968+
<div class="grid gap-6 grid-cols-2 mt-10">
969+
<div id="section-console" class="snap-start">
975970
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-8">Stdio support:</h3>
976971
<div class="flex items-stretch space-x-4">
977972
<div class="flex items-center px-4 py-2 border border-gray-200 rounded dark:border-gray-700">
@@ -985,45 +980,84 @@ export class NewZephyrProjectPanel {
985980
</div>
986981
</div>
987982
988-
<div id="selection-cmake-version" class="snap-end">
989-
<label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">CMake Version:</label>
990-
${
991-
this._versionBundle !== undefined
992-
? `<div class="flex items-center mb-2">
993-
<input type="radio" id="cmake-radio-default-version" name="cmake-version-radio" value="0" class="mr-1 text-blue-500 requires-version-bundle">
994-
<label for="cmake-radio-default-version" class="text-gray-900 dark:text-white">Default version</label>
995-
</div>`
996-
: ""
997-
}
998-
999-
${
1000-
isCmakeSystemAvailable
1001-
? `<div class="flex items-center mb-2">
1002-
<input type="radio" id="cmake-radio-system-version" name="cmake-version-radio" value="1" class="mr-1 text-blue-500">
1003-
<label for="cmake-radio-system-version" class="text-gray-900 dark:text-white">Use system version</label>
1004-
</div>`
1005-
: ""
1006-
}
1007-
1008-
<div class="flex items-center mb-2">
1009-
<input type="radio" id="cmake-radio-latest-version" name="cmake-version-radio" value="4" class="mr-1 text-blue-500">
1010-
<label for="cmake-radio-latest-version" class="text-gray-900 dark:text-white">Latest version</label>
983+
<!-- CMake Version -->
984+
<fieldset id="cmake-fieldset" class="snap-end">
985+
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-8">
986+
CMake Version:
987+
</h3>
988+
989+
<div class="flex items-center gap-3 flex-wrap">
990+
<!-- Primary mode selector -->
991+
<select id="cmake-mode"
992+
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg
993+
focus:ring-blue-500 focus:border-blue-500 p-2.5
994+
dark:bg-gray-700 dark:border-gray-600 dark:text-white">
995+
${
996+
this._versionBundle !== undefined
997+
? `<option value="default">Default bundle</option>`
998+
: ""
999+
}
1000+
${
1001+
this._systemCmakeVersion !== undefined
1002+
? `<option value="system">Use system version</option>`
1003+
: ""
1004+
}
1005+
<option value="latest">Latest</option>
1006+
<option value="select">Select</option>
1007+
<option value="custom">Custom path</option>
1008+
</select>
1009+
1010+
<!-- Secondary areas; one shown at a time -->
1011+
1012+
<!-- Shown for "system" (optional) -->
1013+
<div id="cmake-secondary-system" class="hidden text-sm text-gray-600 dark:text-gray-300">
1014+
System: <span id="cmake-system-label">${
1015+
this._systemCmakeVersion
1016+
}</span>
1017+
</div>
1018+
1019+
<!-- Shown for "latest" -->
1020+
<div id="cmake-secondary-latest" class="hidden text-sm text-gray-600 dark:text-gray-300">
1021+
Latest: <span id="cmake-latest-label">${
1022+
cmakeReleases.length > 0 ? cmakeReleases[0] : "unknown"
1023+
}</span>
10111024
</div>
10121025
1013-
<div class="flex items-center mb-2">
1014-
<input type="radio" id="cmake-radio-select-version" name="cmake-version-radio" value="2" class="mr-1 text-blue-500">
1015-
<label for="cmake-radio-select-version" class="text-gray-900 dark:text-white">Select version:</label>
1016-
<select id="sel-cmake" class="ml-2 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
1026+
<!-- Shown for "select" -->
1027+
<div id="cmake-secondary-select" class="hidden">
1028+
<label for="sel-cmake" class="sr-only">Select CMake version</label>
1029+
<select id="sel-cmake" data-input data-required="true"
1030+
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg
1031+
focus:ring-blue-500 focus:border-blue-500 p-2.5 w-44
1032+
dark:bg-gray-700 dark:border-gray-600 dark:text-white">
10171033
${cmakesHtml}
10181034
</select>
10191035
</div>
10201036
1021-
<div class="flex items-center mb-2">
1022-
<input type="radio" id="cmake-radio-path-executable" name="cmake-version-radio" value="3" class="mr-1 text-blue-500">
1023-
<label for="cmake-radio-path-executable" class="text-gray-900 dark:text-white">Path to executable:</label>
1024-
<input type="file" id="cmake-path-executable" multiple="false" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 ms-2">
1037+
<!-- Shown for "custom" -->
1038+
<div id="cmake-secondary-custom" class="hidden">
1039+
<!-- The actual file input is visually hidden, the label is the clickable box -->
1040+
<input
1041+
type="file"
1042+
id="cmake-path-executable"
1043+
data-input
1044+
data-required="true"
1045+
class="sr-only"
1046+
/>
1047+
1048+
<!-- Match the select's look & width; make the whole thing clickable -->
1049+
<label
1050+
for="cmake-path-executable"
1051+
id="cmake-filebox"
1052+
class="inline-flex items-center gap-2 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus-within:ring-2 focus-within:ring-blue-500 focus-within:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white px-3 py-2.5 w-44" role="button" tabindex="0">
1053+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-folder2-open" viewBox="0 0 16 16">
1054+
<path d="M1 3.5A1.5 1.5 0 0 1 2.5 2h2.764c.958 0 1.76.56 2.311 1.184C7.985 3.648 8.48 4 9 4h4.5A1.5 1.5 0 0 1 15 5.5v.64c.57.265.94.876.856 1.546l-.64 5.124A2.5 2.5 0 0 1 12.733 15H3.266a2.5 2.5 0 0 1-2.481-2.19l-.64-5.124A1.5 1.5 0 0 1 1 6.14zM2 6h12v-.5a.5.5 0 0 0-.5-.5H9c-.964 0-1.71-.629-2.174-1.154C6.374 3.334 5.82 3 5.264 3H2.5a.5.5 0 0 0-.5.5zm-.367 1a.5.5 0 0 0-.496.562l.64 5.124A1.5 1.5 0 0 0 3.266 14h9.468a1.5 1.5 0 0 0 1.489-1.314l.64-5.124A.5.5 0 0 0 14.367 7z"/>
1055+
</svg>
1056+
<span id="cmake-file-label" class="truncate select-none">No file selected</span>
1057+
</label>
10251058
</div>
1026-
</div>
1059+
</div>
1060+
</fieldset>
10271061
</div>
10281062
10291063
<div class="bottom-3 mt-8 mb-12 w-full flex justify-end">

0 commit comments

Comments
 (0)