diff --git a/.github/media/platformio-toggle-multienv-tasks.gif b/.github/media/platformio-toggle-multienv-tasks.gif new file mode 100644 index 00000000..fc71425c Binary files /dev/null and b/.github/media/platformio-toggle-multienv-tasks.gif differ diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bcb9846..01a0f70d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Release Notes +## 3.3.0 (2023-07-10) + +* Enhanced the user experience in the "Project Tasks" explorer by displaying tasks specific to the selected environment by default +* Introduced a new option that allows seamless switching between multi-environment project tasks +* Expanded the functionality of the "Actvity Bar > PlatformIO IDE > Quick Access" menu by including a new item called [Serial & UDP Plotter](https://marketplace.visualstudio.com/items?itemName=alexnesnes.teleplot) +* Updated the PlatformIO Core Installer Script to version [1.2.0](https://github.com/platformio/platformio-core-installer/releases/tag/v1.2.0) + +![Toggle between Multi Environment Project Tasks](https://raw.githubusercontent.com/platformio/platformio-vscode-ide/develop/.github/media/platformio-toggle-multienv-tasks.gif) + ## 3.2.0 (2023-06-09) * Introducing a powerful linting feature that highlights syntactical and stylistic issues in the ["platformio.ini"](https://docs.platformio.org/en/latest/projectconf/index.html) configuration file (issue [#3723](https://github.com/platformio/platformio-vscode-ide/issues/3723)) diff --git a/package.json b/package.json index ce472e8c..3917c149 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "platformio-ide", - "version": "3.2.0", + "version": "3.3.0", "publisher": "platformio", "engines": { "vscode": "^1.65.0" @@ -142,40 +142,47 @@ "icon": "$(plug)", "enablement": "pioProjectReady" }, + { + "command": "platformio-ide.toggleMultiEnvProjectTasks", + "title": "Toggle between Multi Environment Project Tasks", + "category": "PlatformIO", + "icon": "$(layers)", + "enablement": "pioProjectTasksReady" + }, { "command": "platformio-ide.refreshProjectTasks", "title": "Refresh Project Tasks", "category": "PlatformIO", "icon": "$(refresh)", - "enablement": "pioProjectReady" + "enablement": "pioProjectTasksReady" }, { "command": "platformio-ide.build", "title": "Build", "category": "PlatformIO", "icon": "$(check)", - "enablement": "pioProjectReady" + "enablement": "pioProjectTasksReady" }, { "command": "platformio-ide.upload", "title": "Upload", "category": "PlatformIO", "icon": "$(arrow-right)", - "enablement": "pioProjectReady" + "enablement": "pioProjectTasksReady" }, { "command": "platformio-ide.uploadAndMonitor", "title": "Upload and Monitor", "category": "PlatformIO", "icon": "$(arrow-right)", - "enablement": "pioProjectReady" + "enablement": "pioProjectTasksReady" }, { "command": "platformio-ide.clean", "title": "Clean", "category": "PlatformIO", "icon": "$(trashcan)", - "enablement": "pioProjectReady" + "enablement": "pioProjectTasksReady" }, { "command": "platformio-ide.serialMonitor", @@ -189,13 +196,13 @@ "title": "Test", "category": "PlatformIO", "icon": "$(beaker)", - "enablement": "pioProjectReady" + "enablement": "pioProjectTasksReady" }, { "command": "platformio-ide.rebuildProjectIndex", "title": "Rebuild IntelliSense Index", "category": "PlatformIO", - "enablement": "pioProjectReady" + "enablement": "pioProjectTasksReady" }, { "command": "platformio-ide.startDebugging", @@ -444,12 +451,17 @@ "view/title": [ { "command": "platformio-ide.pickProjectEnv", - "when": "pioMultiEnvProject && view == platformio-ide.projectTasks", + "when": "pioProjectTasksReady && pioMultiEnvProject && view == platformio-ide.projectTasks", + "group": "navigation" + }, + { + "command": "platformio-ide.toggleMultiEnvProjectTasks", + "when": "pioProjectTasksReady && view == platformio-ide.projectTasks", "group": "navigation" }, { "command": "platformio-ide.refreshProjectTasks", - "when": "pioProjectReady && view == platformio-ide.projectTasks", + "when": "pioProjectTasksReady && view == platformio-ide.projectTasks", "group": "navigation" }, { @@ -887,18 +899,18 @@ }, "dependencies": { "fs-plus": "~3.1.1", - "platformio-node-helpers": "~11.0.1", + "platformio-node-helpers": "~11.1.0", "platformio-vscode-debug": "~1.4.1" }, "devDependencies": { "@types/node": "~14", "@types/vscode": "~1.65.0", "@vscode/vsce": "~2.19.0", - "eslint": "~8.42.0", + "eslint": "~8.44.0", "eslint-import-resolver-webpack": "~0.13.2", "eslint-plugin-import": "~2.27.5", "prettier": "~2.8.8", - "webpack": "~5.85.1", + "webpack": "~5.88.1", "webpack-cli": "~5.1.4" }, "extensionDependencies": [ diff --git a/src/project/config.js b/src/project/config.js index 09628efa..3a97599b 100644 --- a/src/project/config.js +++ b/src/project/config.js @@ -349,63 +349,11 @@ ${option.description} return; } const script = ` -import configparser -import glob import json -from platformio import fs -from platformio.project import exception from platformio.public import ProjectConfig - -# remove this code for PIO Core 6.1.8+ -class TmpProjectConfig(ProjectConfig): - def read(self, path, parse_extra=True): - if path in self._parsed: - return - self._parsed.append(path) - try: - self._parser.read(path, "utf-8") - except configparser.Error as exc: - raise exception.InvalidProjectConfError(path, str(exc)) from exc - if not parse_extra: - return - # load extra configs - for pattern in self.get("platformio", "extra_configs", []): - if pattern.startswith("~"): - pattern = fs.expanduser(pattern) - for item in glob.glob(pattern, recursive=True): - self.read(item) - - -errors = [] -warnings = [] - -try: - config = TmpProjectConfig() - config.validate(silent=True) - warnings = config.warnings - config.as_tuple() -except Exception as exc: - if exc.__cause__: - exc = exc.__cause__ - item = {"type": exc.__class__.__name__, "message": str(exc)} - for attr in ("lineno", "source"): - if hasattr(exc, attr): - item[attr] = getattr(exc, attr) - errors.append(item) - if item["type"] == "ParsingError" and hasattr(exc, "errors"): - for lineno, line in getattr(exc, "errors"): - errors.append( - { - "type": item["type"], - "message": f"Parsing error: {line}", - "lineno": lineno, - "source": item["source"] - } - ) - -print(json.dumps(dict(errors=errors, warnings=warnings))) +print(json.dumps(ProjectConfig.lint())) `; this.diagnosticCollection.clear(); const projectDir = path.dirname(uri.fsPath); diff --git a/src/project/manager.js b/src/project/manager.js index b9953eae..5e33ca02 100644 --- a/src/project/manager.js +++ b/src/project/manager.js @@ -112,6 +112,9 @@ export default class ProjectManager { vscode.commands.registerCommand('platformio-ide.refreshProjectTasks', () => this._taskManager.refresh({ force: true }) ), + vscode.commands.registerCommand('platformio-ide.toggleMultiEnvProjectTasks', () => + this._taskManager.toggleMultiEnvExplorer() + ), vscode.commands.registerCommand('platformio-ide._runProjectTask', (task) => this._taskManager.runTask(task) ), @@ -192,15 +195,19 @@ export default class ProjectManager { // validate configuration file const configUri = vscode.Uri.file(path.join(projectDir, 'platformio.ini')); - const isConfigValid = await this._configProvider.lintConfig(configUri); - if (!isConfigValid) { - vscode.window.showErrorMessage( - 'The project configuration process has encountered an error due to ' + - "a problem with the 'platformio.ini' file. " + - 'Please review the file and fix the issues.' - ); - vscode.window.showTextDocument(configUri); - return; + try { + const isConfigValid = await this._configProvider.lintConfig(configUri); + if (!isConfigValid) { + vscode.window.showErrorMessage( + 'The project configuration process has encountered an error due to ' + + "a problem with the 'platformio.ini' file. " + + 'Please review the file and fix the issues.' + ); + vscode.window.showTextDocument(configUri); + return; + } + } catch (err) { + console.error(err); } if ('env' in options) { diff --git a/src/project/task-tree.js b/src/project/task-tree.js index 20416879..65dd8108 100644 --- a/src/project/task-tree.js +++ b/src/project/task-tree.js @@ -11,12 +11,35 @@ import * as vscode from 'vscode'; export default class ProjectTasksTreeProvider { static DEFAULT_ENV_NAME = 'Default'; - constructor(id, envs, tasks, selectedEnv = undefined) { + constructor(id, envs, tasks, selectedEnv = undefined, multiEnvExplorer = false) { this.id = id; this.envs = envs; this.tasks = tasks; this.selectedEnv = selectedEnv; this.multiEnvProject = this.envs.length > 1; + this.multiEnvExplorer = multiEnvExplorer; + } + + getEnvTasks(env = undefined, group = undefined) { + const cmpGroup = (task) => { + if (!group) { + return true; + } + return task.group === group; + }; + const result = this.tasks.filter((task) => cmpGroup(task) && task.coreEnv === env); + // merge default/env-independent tasks + if (env) { + result.push( + ...this.tasks.filter( + (task) => + cmpGroup(task) && + env !== ProjectTasksTreeProvider.DEFAULT_ENV_NAME && + !task.multienv + ) + ); + } + return result; } getTreeItem(item) { @@ -40,9 +63,11 @@ export default class ProjectTasksTreeProvider { getChildren(element) { if (element && element.group) { - return this.getEnvGroupChildren(element.env, element.group); + return this.getEnvTasks(element.env, element.group); } else if (element) { return this.getEnvChildren(element.env); + } else if (this.selectedEnv && !this.multiEnvExplorer) { + return this.getEnvChildren(this.selectedEnv); } return this.getRootChildren(); } @@ -64,12 +89,8 @@ export default class ProjectTasksTreeProvider { return result; } - getEnvGroupChildren(env, group) { - return this.tasks.filter((task) => task.coreEnv === env && task.group === group); - } - getEnvChildren(env) { - const envTasks = this.tasks.filter((task) => task.coreEnv === env); + const envTasks = this.getEnvTasks(env); if (!envTasks.length) { return [new vscode.TreeItem('Loading...')]; } diff --git a/src/project/tasks.js b/src/project/tasks.js index 4033cc1c..78b77efb 100644 --- a/src/project/tasks.js +++ b/src/project/tasks.js @@ -25,6 +25,7 @@ export default class ProjectTaskManager { this.subscriptions = []; this._sid = Math.random(); + this._multienvTaskExplorer = false; this._refreshTimeout = undefined; this._startedTask = undefined; this._tasksToRestore = []; @@ -38,6 +39,11 @@ export default class ProjectTaskManager { disposeSubscriptions(this.subscriptions); } + toggleMultiEnvExplorer() { + this._multienvTaskExplorer = !this._multienvTaskExplorer; + this.refresh({ force: true }); + } + requestRefresh() { if (this._refreshTimeout) { clearTimeout(this._refreshTimeout); @@ -67,7 +73,8 @@ export default class ProjectTaskManager { this._sid, projectEnvs, projectTasks, - this.projectObserver.getSelectedEnv() + this.projectObserver.getSelectedEnv(), + this._multienvTaskExplorer ), showCollapseAll: true, }); @@ -95,6 +102,7 @@ export default class ProjectTaskManager { this.registerTaskBasedCommands(projectTasks); this.registerPortSwitcher(); + vscode.commands.executeCommand('setContext', 'pioProjectTasksReady', true); vscode.commands.executeCommand( 'setContext', 'pioMultiEnvProject', diff --git a/src/views/quick-access-tree.js b/src/views/quick-access-tree.js index ff9fa91f..6ca4036e 100644 --- a/src/views/quick-access-tree.js +++ b/src/views/quick-access-tree.js @@ -62,6 +62,11 @@ export default class QuickAccessTreeProvider { undefined, vscode.TreeItemCollapsibleState.Expanded, [ + new QuickItem( + 'Serial & UDP Plotter', + 'workbench.extensions.action.showExtensionsWithIds', + [['alexnesnes.teleplot']] + ), new QuickItem('PlatformIO Core CLI', 'platformio-ide.openPIOCoreCLI'), new QuickItem('Clone Git Project', 'git.clone'), new QuickItem('New Terminal', 'platformio-ide.newTerminal'),