diff --git a/i18n/en/package.i18n.json b/i18n/en/package.i18n.json index 033d2965a..1849012de 100644 --- a/i18n/en/package.i18n.json +++ b/i18n/en/package.i18n.json @@ -150,6 +150,7 @@ "espIdf.efuse.clearResults.title": "Clear eFuse Summary", "espIdf.jtag_flash.title": "Flash (with JTag)", "espIdf.selectFlashMethodAndFlash.title": "Select Flash Method", + "espIdf.selectCurrentIdfVersion.title": "Select Current ESP-IDF Version", "idf.flashType.description": "Device flash method, UART or JTag", "openocd.tcl.host.description": "Host for openocd tcl connection", "openocd.tcl.port.description": "Port for openocd tcl connection", diff --git a/i18n/es/package.i18n.json b/i18n/es/package.i18n.json index c8ab8c4e2..ba05a172c 100644 --- a/i18n/es/package.i18n.json +++ b/i18n/es/package.i18n.json @@ -150,6 +150,7 @@ "espIdf.efuse.clearResults.title": "Limpiar el resumen de eFuse", "espIdf.jtag_flash.title": "Flash (con JTag)", "espIdf.selectFlashMethodAndFlash.title": "Seleccione el método de programar", + "espIdf.selectCurrentIdfVersion.title": "Seleccione la versión ESP-IDF a usar", "idf.flashType.description": "Método de flash del dispositivo, UART o JTag", "openocd.tcl.host.description": "Anfitrión para conexión tcl openocd", "openocd.tcl.port.description": "Puerto para conexión tcl openocd", diff --git a/i18n/ru/package.i18n.json b/i18n/ru/package.i18n.json index 632b33221..aa8534e86 100644 --- a/i18n/ru/package.i18n.json +++ b/i18n/ru/package.i18n.json @@ -150,6 +150,7 @@ "espIdf.efuse.clearResults.title": "Очистить сводку eFuse", "espIdf.jtag_flash.title": "Прошить (через JTag)", "espIdf.selectFlashMethodAndFlash.title": "Выбрать метод прошивки", + "espIdf.selectCurrentIdfVersion.title": "Выберите текущую версию ESP-IDF", "idf.flashType.description": "Метод прошивки устройства, UART или JTag", "openocd.tcl.host.description": "Хост для подключения openocd tcl", "openocd.tcl.port.description": "Порт для подключения openocd tcl", diff --git a/i18n/zh-CN/package.i18n.json b/i18n/zh-CN/package.i18n.json index 2ddde3829..d7cdca971 100644 --- a/i18n/zh-CN/package.i18n.json +++ b/i18n/zh-CN/package.i18n.json @@ -150,6 +150,7 @@ "espIdf.efuse.clearResults.title": "清除 eFuse 摘要", "espIdf.jtag_flash.title": "JTag 烧录", "espIdf.selectFlashMethodAndFlash.title": "选择烧录方式烧录", + "espIdf.selectCurrentIdfVersion.title": "选择当前ESP-IDF版本", "idf.flashType.description": "设备烧录方式,UART 或 JTag", "openocd.tcl.host.description": "OpenOCD TCL 主机", "openocd.tcl.port.description": "OpenOCD TCL 端口", diff --git a/package.json b/package.json index 0e9033a34..847b6147a 100644 --- a/package.json +++ b/package.json @@ -1378,6 +1378,11 @@ "command": "espIdf.createSbom", "title": "%espIdf.createSbom.title%", "category": "ESP-IDF" + }, + { + "command": "espIdf.selectCurrentIdfVersion", + "title": "%espIdf.selectCurrentIdfVersion.title%", + "category": "ESP-IDF" } ], "breakpoints": [ diff --git a/package.nls.json b/package.nls.json index 6331723d0..cf066e15d 100644 --- a/package.nls.json +++ b/package.nls.json @@ -150,6 +150,7 @@ "espIdf.efuse.clearResults.title": "Clear eFuse Summary", "espIdf.jtag_flash.title": "Flash (with JTag)", "espIdf.selectFlashMethodAndFlash.title": "Select Flash Method", + "espIdf.selectCurrentIdfVersion.title": "Select Current ESP-IDF Version", "idf.flashType.description": "Device flash method, UART or JTag", "openocd.tcl.host.description": "Host for openocd tcl connection", "openocd.tcl.port.description": "Port for openocd tcl connection", diff --git a/schema.i18n.json b/schema.i18n.json index 16db54db0..e10e7571e 100644 --- a/schema.i18n.json +++ b/schema.i18n.json @@ -207,6 +207,7 @@ "espIdf.efuse.clearResults.title", "espIdf.jtag_flash.title", "espIdf.selectFlashMethodAndFlash.title", + "espIdf.selectCurrentIdfVersion.title", "idf.flashType.description", "openocd.tcl.host.description", "openocd.tcl.port.description", diff --git a/src/checkExtensionSettings.ts b/src/checkExtensionSettings.ts index fd940ca16..e39097115 100644 --- a/src/checkExtensionSettings.ts +++ b/src/checkExtensionSettings.ts @@ -26,7 +26,8 @@ import { useIdfSetupSettings } from "./setup/setupValidation/espIdfSetup"; export async function checkExtensionSettings( extensionPath: string, - workspace: vscode.Uri + workspace: vscode.Uri, + espIdfStatusBar: vscode.StatusBarItem ) { const showSetupWindow = readParameter("idf.showOnboardingOnInit") as boolean; if (!showSetupWindow) { @@ -62,6 +63,7 @@ export async function checkExtensionSettings( progress, workspace ); + setupArgs.espIdfStatusBar = espIdfStatusBar; if (setupArgs.existingIdfSetups && setupArgs.existingIdfSetups.length) { progress.report({ increment: 5, @@ -85,7 +87,8 @@ export async function checkExtensionSettings( await useIdfSetupSettings( selectedSetup.target, confTarget, - workspace + workspace, + espIdfStatusBar ); } else if ( typeof process.env.WEB_IDE === "undefined" && diff --git a/src/extension.ts b/src/extension.ts index 5a7fc5ed3..523de5f0a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -145,6 +145,7 @@ import { getFileList, getTestComponents } from "./espIdf/unitTest/utils"; import { saveDefSdkconfig } from "./espIdf/menuconfig/saveDefConfig"; import { createSBOM, installEspSBOM } from "./espBom"; import { getEspHomeKitSdk } from "./espHomekit/espHomekitDownload"; +import { getCurrentIdfSetup, selectIdfSetup } from "./versionSwitcher"; // Global variables shared by commands let workspaceRoot: vscode.Uri; @@ -276,7 +277,7 @@ export async function activate(context: vscode.ExtensionContext) { // Create a status bar item with current workspace // Status Bar Item with common commands - statusBarItems = createCmdsStatusBarItems(); + statusBarItems = await createCmdsStatusBarItems(); // Create Kconfig Language Server Client KconfigLangClient.startKconfigLangServer(context); @@ -804,6 +805,15 @@ export async function activate(context: vscode.ExtensionContext) { ); }); + registerIDFCommand("espIdf.selectCurrentIdfVersion", () => { + PreCheck.perform([webIdeCheck, openFolderCheck], async () => { + const currentIdfSetup = await selectIdfSetup( + workspaceRoot, + statusBarItems["currentIdfVersion"] + ); + }); + }); + registerIDFCommand("espIdf.customTask", async () => { try { const customTask = new CustomTask(workspaceRoot); @@ -1222,7 +1232,7 @@ export async function activate(context: vscode.ExtensionContext) { workspaceRoot ) as boolean; if (enableStatusBar) { - statusBarItems = createCmdsStatusBarItems(); + statusBarItems = await createCmdsStatusBarItems(); } else if (!enableStatusBar) { for (let statusItem in statusBarItems) { statusBarItems[statusItem].dispose(); @@ -1959,6 +1969,7 @@ export async function activate(context: vscode.ExtensionContext) { progress, workspaceRoot ); + setupArgs.espIdfStatusBar = statusBarItems["currentIdfVersion"]; SetupPanel.createOrShow(context, setupArgs); } catch (error) { Logger.errorNotify(error.message, error); @@ -3444,7 +3455,11 @@ export async function activate(context: vscode.ExtensionContext) { Logger.warn(`Failed to handle URI Open, ${uri.toString()}`); }, }); - await checkExtensionSettings(context.extensionPath, workspaceRoot); + await checkExtensionSettings( + context.extensionPath, + workspaceRoot, + statusBarItems["currentIdfVersion"] + ); } async function getFrameworksPickItems() { @@ -3603,7 +3618,7 @@ function registerTreeProvidersForIDFExplorer(context: vscode.ExtensionContext) { ); } -function createCmdsStatusBarItems() { +async function createCmdsStatusBarItems() { const enableStatusBar = idfConf.readParameter( "idf.enableStatusBar" ) as boolean; @@ -3625,8 +3640,16 @@ function createCmdsStatusBarItems() { workspaceRoot ); } + let currentIdfVersion = await getCurrentIdfSetup(workspaceRoot); const statusBarItems: { [key: string]: vscode.StatusBarItem } = {}; + statusBarItems["currentIdfVersion"] = createStatusBarItem( + "$(octoface) ESP-IDF v" + currentIdfVersion.version, + "ESP-IDF: Select current ESP-IDF version", + "espIdf.selectCurrentIdfVersion", + 102 + ); + statusBarItems["port"] = createStatusBarItem( "$(plug)" + port, "ESP-IDF: Select Port to Use (COM, tty, usbserial)", diff --git a/src/setup/SetupPanel.ts b/src/setup/SetupPanel.ts index 0c943d8e5..5fcea7d62 100644 --- a/src/setup/SetupPanel.ts +++ b/src/setup/SetupPanel.ts @@ -31,6 +31,7 @@ import { ExtensionContext, Progress, ProgressLocation, + StatusBarItem, Uri, ViewColumn, WebviewPanel, @@ -160,6 +161,7 @@ export class SetupPanel { message.saveScope, message.setupMode, context, + setupArgs.espIdfStatusBar, setupArgs.workspaceFolder, setupArgs.onReqPkgs ); @@ -182,6 +184,7 @@ export class SetupPanel { message.saveScope, setupArgs.workspaceFolder, context, + setupArgs.espIdfStatusBar, setupArgs.onReqPkgs ); } @@ -257,7 +260,8 @@ export class SetupPanel { setupArgs.gitPath, message.saveScope, context, - setupArgs.workspaceFolder + setupArgs.workspaceFolder, + setupArgs.espIdfStatusBar ); } break; @@ -300,7 +304,8 @@ export class SetupPanel { await useIdfSetupSettings( setupArgs.existingIdfSetups[message.selectedIdfSetup], message.saveScope, - setupArgs.workspaceFolder + setupArgs.workspaceFolder, + setupArgs.espIdfStatusBar ); this.panel.webview.postMessage({ command: "setIsInstalled", @@ -379,6 +384,7 @@ export class SetupPanel { saveScope: ConfigurationTarget, setupMode: SetupMode, context: ExtensionContext, + espIdfStatusBar: StatusBarItem, workspaceFolderUri: Uri, onReqPkgs?: string[] ) { @@ -455,6 +461,7 @@ export class SetupPanel { saveScope, setupMode, context, + espIdfStatusBar, workspaceFolderUri, idfGitPath, progress, @@ -531,6 +538,7 @@ export class SetupPanel { saveScope: ConfigurationTarget, workspaceFolderUri: Uri, context: ExtensionContext, + espIdfStatusBar: StatusBarItem, onReqPkgs?: string[] ) { const notificationMode = idfConf.readParameter( @@ -587,6 +595,7 @@ export class SetupPanel { saveScope, workspaceFolderUri, context, + espIdfStatusBar, progress, cancelToken, onReqPkgs @@ -607,7 +616,8 @@ export class SetupPanel { gitPath: string, saveScope: ConfigurationTarget, context: ExtensionContext, - workspaceFolderUri: Uri + workspaceFolderUri: Uri, + espIdfStatusBar: StatusBarItem ) { const notificationMode = idfConf.readParameter( "idf.notificationMode" @@ -644,7 +654,8 @@ export class SetupPanel { context, progress, cancelToken, - workspaceFolderUri + workspaceFolderUri, + espIdfStatusBar ); } catch (error) { this.setupErrHandler(error); diff --git a/src/setup/espIdfDownloadStep.ts b/src/setup/espIdfDownloadStep.ts index 74d7f3108..97f3fcacf 100644 --- a/src/setup/espIdfDownloadStep.ts +++ b/src/setup/espIdfDownloadStep.ts @@ -39,6 +39,7 @@ export async function expressInstall( saveScope: vscode.ConfigurationTarget, setupMode: SetupMode, context: vscode.ExtensionContext, + espIdfStatusBar: vscode.StatusBarItem, workspaceFolderUri: vscode.Uri, gitPath?: string, progress?: vscode.Progress<{ message: string; increment?: number }>, @@ -130,6 +131,7 @@ export async function expressInstall( saveScope, workspaceFolderUri, context, + espIdfStatusBar, progress, cancelToken, onReqPkgs diff --git a/src/setup/installPyReqs.ts b/src/setup/installPyReqs.ts index 3921cef7d..1e714a1fe 100644 --- a/src/setup/installPyReqs.ts +++ b/src/setup/installPyReqs.ts @@ -100,21 +100,6 @@ export async function installPyReqs( return; } -export async function installExtensionPyReqs( - idfToolsDir: string, - pythonBinPath: string, - espIdfPath: string -) { - const logTracker = new PyReqLog(sendPyReqLog); - await pythonManager.installExtensionPyReqs( - pythonBinPath, - espIdfPath, - idfToolsDir, - logTracker, - OutputChannel.init() - ); -} - export function sendPyReqLog(log: string) { SetupPanel.postMessage({ command: "updatePyReqsLog", diff --git a/src/setup/pyReqsInstallStep.ts b/src/setup/pyReqsInstallStep.ts index 5ccdd8a42..444a9cb4d 100644 --- a/src/setup/pyReqsInstallStep.ts +++ b/src/setup/pyReqsInstallStep.ts @@ -32,7 +32,8 @@ export async function createPyReqs( context: vscode.ExtensionContext, progress: vscode.Progress<{ message: string; increment?: number }>, cancelToken: vscode.CancellationToken, - workspaceFolderUri: vscode.Uri + workspaceFolderUri: vscode.Uri, + espIdfStatusBar: vscode.StatusBarItem ) { SetupPanel.postMessage({ command: "updatePyVEnvStatus", @@ -55,7 +56,8 @@ export async function createPyReqs( toolsPath, gitPath, saveScope, - workspaceFolderUri + workspaceFolderUri, + espIdfStatusBar ); let idfPathVersion = await getEspIdfFromCMake(idfPath); await addIdfPath(idfPath, virtualEnvPath, idfPathVersion, toolsPath, gitPath); diff --git a/src/setup/setupInit.ts b/src/setup/setupInit.ts index 652affa3e..beb4e94d3 100644 --- a/src/setup/setupInit.ts +++ b/src/setup/setupInit.ts @@ -12,14 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - ConfigurationTarget, - Progress, - Uri, - window, - workspace, - WorkspaceFolder, -} from "vscode"; +import { ConfigurationTarget, Progress, StatusBarItem, Uri } from "vscode"; import { IdfToolsManager } from "../idfToolsManager"; import * as utils from "../utils"; import { getEspIdfTags, getEspIdfVersions } from "./espIdfVersionList"; @@ -37,6 +30,7 @@ import { } from "./existingIdfSetups"; import { checkPyVenv } from "./setupValidation/pythonEnv"; import { packageJson } from "../utils"; +import { getCurrentIdfSetup } from "../versionSwitcher"; export interface ISetupInitArgs { espIdfPath: string; @@ -52,6 +46,7 @@ export interface ISetupInitArgs { pythonVersions: string[]; saveScope: number; workspaceFolder: Uri; + espIdfStatusBar: StatusBarItem; } export interface IPreviousInstallResult { @@ -318,7 +313,8 @@ export async function saveSettings( toolsPath: string, gitPath: string, saveScope: ConfigurationTarget, - workspaceFolderUri: Uri + workspaceFolderUri: Uri, + espIdfStatusBar: StatusBarItem ) { const confTarget = saveScope || @@ -363,6 +359,8 @@ export async function saveSettings( confTarget, workspaceFolder ); + let currentIdfVersion = await getCurrentIdfSetup(workspaceFolder); + espIdfStatusBar.text = "$(octoface) ESP-IDF v" + currentIdfVersion.version; await createIdfSetup(espIdfPath, toolsPath, pythonBinPath, gitPath); - window.showInformationMessage("ESP-IDF has been configured"); + Logger.infoNotify("ESP-IDF has been configured"); } diff --git a/src/setup/setupValidation/espIdfSetup.ts b/src/setup/setupValidation/espIdfSetup.ts index 386e91d20..db543a9e0 100644 --- a/src/setup/setupValidation/espIdfSetup.ts +++ b/src/setup/setupValidation/espIdfSetup.ts @@ -22,14 +22,14 @@ import { IdfToolsManager } from "../../idfToolsManager"; import { saveSettings } from "../setupInit"; import { pathExists } from "fs-extra"; import { Logger } from "../../logger/logger"; -import { installExtensionPyReqs } from "../installPyReqs"; import { checkPyVenv } from "./pythonEnv"; -import { ConfigurationTarget, Uri } from "vscode"; +import { ConfigurationTarget, StatusBarItem, Uri } from "vscode"; export async function useIdfSetupSettings( setupConf: IdfSetup, saveScope: ConfigurationTarget, - workspaceFolderUri: Uri + workspaceFolderUri: Uri, + espIdfStatusBar: StatusBarItem ) { const idfToolsManager = await IdfToolsManager.createIdfToolsManager( setupConf.idfPath @@ -42,11 +42,6 @@ export async function useIdfSetupSettings( const exportedVars = await idfToolsManager.exportVars( join(setupConf.toolsPath, "tools") ); - await installExtensionPyReqs( - setupConf.toolsPath, - setupConf.python, - setupConf.idfPath - ); await saveSettings( setupConf.idfPath, setupConf.python, @@ -55,7 +50,8 @@ export async function useIdfSetupSettings( setupConf.toolsPath, setupConf.gitPath, saveScope, - workspaceFolderUri + workspaceFolderUri, + espIdfStatusBar ); } diff --git a/src/setup/toolsDownloadStep.ts b/src/setup/toolsDownloadStep.ts index 639b7a882..0b05662c1 100644 --- a/src/setup/toolsDownloadStep.ts +++ b/src/setup/toolsDownloadStep.ts @@ -30,6 +30,7 @@ export async function downloadIdfTools( saveScope: vscode.ConfigurationTarget, workspaceFolderUri: vscode.Uri, context: vscode.ExtensionContext, + espIdfStatusBar: vscode.StatusBarItem, progress?: vscode.Progress<{ message: string; increment?: number }>, cancelToken?: vscode.CancellationToken, onReqPkgs?: string[], @@ -76,6 +77,7 @@ export async function downloadIdfTools( context, progress, cancelToken, - workspaceFolderUri + workspaceFolderUri, + espIdfStatusBar ); } diff --git a/src/versionSwitcher/index.ts b/src/versionSwitcher/index.ts new file mode 100644 index 000000000..2101e0f1d --- /dev/null +++ b/src/versionSwitcher/index.ts @@ -0,0 +1,85 @@ +/* + * Project: ESP-IDF VSCode Extension + * File Created: Thursday, 28th March 2024 7:18:49 pm + * Copyright 2024 Espressif Systems (Shanghai) CO LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ConfigurationTarget, StatusBarItem, Uri, window } from "vscode"; +import { getPreviousIdfSetups } from "../setup/existingIdfSetups"; +import { + checkIdfSetup, + useIdfSetupSettings, +} from "../setup/setupValidation/espIdfSetup"; +import { readParameter } from "../idfConfiguration"; +import { getIdfMd5sum } from "../setup/espIdfJson"; +import { getEspIdfFromCMake } from "../utils"; +import { IdfSetup } from "../views/setup/types"; + +export async function selectIdfSetup( + workspaceFolder: Uri, + espIdfStatusBar: StatusBarItem +) { + const idfSetups = await getPreviousIdfSetups(true); + if (idfSetups.length === 0) { + await window.showInformationMessage("No ESP-IDF Setups found"); + return; + } + const onlyValidIdfSetups = idfSetups.filter((i) => i.isValid); + const idfSetupOptions = onlyValidIdfSetups.map((idfSetup) => { + return { + label: `Version: v${idfSetup.version}`, + description: `IDF_PATH: ${idfSetup.idfPath}`, + detail: `IDF_TOOLS_PATH: ${idfSetup.toolsPath}`, + target: idfSetup, + }; + }); + const selectedIdfSetupOption = await window.showQuickPick(idfSetupOptions, { + placeHolder: "Select a ESP-IDF version to use", + }); + if (!selectedIdfSetupOption) { + return; + } + await useIdfSetupSettings( + selectedIdfSetupOption.target, + ConfigurationTarget.WorkspaceFolder, + workspaceFolder, + espIdfStatusBar + ); + return selectedIdfSetupOption.target; +} + +export async function getCurrentIdfSetup(workspaceFolder: Uri) { + const idfPath = readParameter("idf.espIdfPath", workspaceFolder); + const toolsPath = readParameter("idf.toolsPath", workspaceFolder) as string; + const gitPath = readParameter("idf.gitPath", workspaceFolder); + const pythonPath = readParameter( + "idf.pythonBinPath", + workspaceFolder + ) as string; + + const idfSetupId = getIdfMd5sum(idfPath); + const idfVersion = await getEspIdfFromCMake(idfPath); + const currentIdfSetup: IdfSetup = { + id: idfSetupId, + idfPath, + gitPath, + toolsPath, + python: pythonPath, + version: idfVersion, + isValid: false, + }; + currentIdfSetup.isValid = await checkIdfSetup(currentIdfSetup); + return currentIdfSetup; +}