From a9aed52fd7ea27c6567aff04b5a620555b74c91a Mon Sep 17 00:00:00 2001 From: Luke Elliott Date: Thu, 16 Nov 2023 19:38:46 +0000 Subject: [PATCH] Added configure/build/clean context menus where appropriate to meson project view. Build icons from vscode-cmake-tools. --- package.json | 68 +++++++++++++++++++++++++++++++++- res/build-icon-dark.svg | 8 ++++ res/build-icon-light.svg | 8 ++++ src/extension.ts | 18 ++++++++- src/tasks.ts | 2 +- src/treeview/nodes/base.ts | 5 +++ src/treeview/nodes/targets.ts | 8 +++- src/treeview/nodes/toplevel.ts | 12 +++++- 8 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 res/build-icon-dark.svg create mode 100644 res/build-icon-light.svg diff --git a/package.json b/package.json index ffe1154c..7265c622 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,11 @@ }, { "command": "mesonbuild.build", - "title": "Meson: Build" + "title": "Meson: Build", + "icon": { + "dark": "res/build-icon-dark.svg", + "light": "res/build-icon-light.svg" + } }, { "command": "mesonbuild.test", @@ -88,6 +92,26 @@ "command": "mesonbuild.restartLanguageServer", "title": "Meson: Restart Language Server" }, + { + "command": "mesonbuild.node.reconfigure", + "title": "Reconfigure", + "icon": { + "dark": "res/meson_32.svg", + "light": "res/meson_32.svg" + } + }, + { + "command": "mesonbuild.node.build", + "title": "Build", + "icon": { + "dark": "res/build-icon-dark.svg", + "light": "res/build-icon-light.svg" + } + }, + { + "command": "mesonbuild.node.clean", + "title": "Clean" + }, { "command": "mesonbuild.node.runAll", "title": "Run all", @@ -398,11 +422,41 @@ }, "menus": { "view/item/context": [ + { + "command": "mesonbuild.node.reconfigure", + "when": "view == meson-project && viewItem == meson-projectroot", + "group": "build@0" + }, + { + "command": "mesonbuild.node.build", + "when": "view == meson-project && viewItem == meson-projectroot", + "group": "inline" + }, + { + "command": "mesonbuild.node.build", + "when": "view == meson-project && viewItem == meson-projectroot", + "group": "build@1" + }, + { + "command": "mesonbuild.node.clean", + "when": "view == meson-project && viewItem == meson-projectroot", + "group": "build@2" + }, { "command": "mesonbuild.openBuildFile", "when": "view == meson-project && viewItem == meson-target", "group": "inline" }, + { + "command": "mesonbuild.openBuildFile", + "when": "view == meson-project && viewItem == meson-target", + "group": "build" + }, + { + "command": "mesonbuild.node.build", + "when": "view == meson-project && viewItem == meson-target", + "group": "build" + }, { "command": "mesonbuild.node.runAll", "when": "view == meson-project && viewItem == meson-test-root", @@ -436,6 +490,18 @@ "command": "mesonbuild.openBuildFile", "when": "false" }, + { + "command": "mesonbuild.node.reconfigure", + "when": "false" + }, + { + "command": "mesonbuild.node.build", + "when": "false" + }, + { + "command": "mesonbuild.node.clean", + "when": "false" + }, { "command": "mesonbuild.node.run", "when": "false" diff --git a/res/build-icon-dark.svg b/res/build-icon-dark.svg new file mode 100644 index 00000000..2cd8a0c9 --- /dev/null +++ b/res/build-icon-dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/res/build-icon-light.svg b/res/build-icon-light.svg new file mode 100644 index 00000000..79a8a633 --- /dev/null +++ b/res/build-icon-light.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/extension.ts b/src/extension.ts index 11e0d4ef..8388cc24 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -21,7 +21,7 @@ import { activateFormatters } from "./formatters"; import { SettingsKey, TaskQuickPickItem } from "./types"; import { createLanguageServerClient } from "./lsp/common"; import { dirname, relative } from "path"; -import { IRunnableNode } from "./treeview/nodes/base"; +import { IBuildableNode, IRunnableNode } from "./treeview/nodes/base"; export let extensionPath: string; export let workspaceState: vscode.Memento; @@ -202,6 +202,22 @@ export async function activate(ctx: vscode.ExtensionContext) { }), ); + ctx.subscriptions.push( + vscode.commands.registerCommand("mesonbuild.node.reconfigure", async () => { + runFirstTask("reconfigure"); + }), + ); + + ctx.subscriptions.push( + vscode.commands.registerCommand("mesonbuild.node.build", async (node: IBuildableNode) => node.build()), + ); + + ctx.subscriptions.push( + vscode.commands.registerCommand("mesonbuild.node.clean", async () => { + runFirstTask("clean"); + }), + ); + // Two commands just to have different icons. ctx.subscriptions.push( vscode.commands.registerCommand("mesonbuild.node.runAll", async (node: IRunnableNode) => node.run()), diff --git a/src/tasks.ts b/src/tasks.ts index 506fcf79..fdf57b38 100644 --- a/src/tasks.ts +++ b/src/tasks.ts @@ -68,7 +68,7 @@ function createReconfigureTask(buildDir: string, sourceDir: string) { export async function getMesonTasks(buildDir: string, sourceDir: string) { try { const defaultBuildTask = new vscode.Task( - { type: "meson", mode: "build" }, + { type: "meson", mode: "build", target: pseudoAllTarget }, "Build all targets", "Meson", new vscode.ShellExecution(extensionConfiguration("mesonPath"), ["compile", "-C", buildDir]), diff --git a/src/treeview/nodes/base.ts b/src/treeview/nodes/base.ts index 29bd40b7..ae0b6ec1 100644 --- a/src/treeview/nodes/base.ts +++ b/src/treeview/nodes/base.ts @@ -32,6 +32,11 @@ export abstract class BaseDirectoryNode extends BaseNode { abstract buildFileTree(fpaths: T[]): FolderMap | Thenable>; } +// A node in the meson tree view that can be built. +export interface IBuildableNode { + build(): Thenable; +} + // A node in the meson tree view that can be run. export interface IRunnableNode { run(): Thenable; diff --git a/src/treeview/nodes/targets.ts b/src/treeview/nodes/targets.ts index d61eea57..20965906 100644 --- a/src/treeview/nodes/targets.ts +++ b/src/treeview/nodes/targets.ts @@ -5,7 +5,7 @@ import { BaseNode } from "../basenode"; import { Target, Targets } from "../../types"; import { TargetSourcesRootNode, TargetGeneratedSourcesRootNode } from "./sources"; import { extensionRelative, getTargetName } from "../../utils"; -import { BaseDirectoryNode } from "./base"; +import { BaseDirectoryNode, IBuildableNode } from "./base"; export class TargetDirectoryNode extends BaseDirectoryNode { constructor(parentId: string, folder: string, targets: Targets) { @@ -72,7 +72,7 @@ export class TargetDirectoryNode extends BaseDirectoryNode { } } -export class TargetNode extends BaseNode { +export class TargetNode extends BaseNode implements IBuildableNode { constructor( parentId: string, private readonly target: Target, @@ -123,6 +123,10 @@ export class TargetNode extends BaseNode { return item; } + async build() { + return vscode.commands.executeCommand("mesonbuild.build", await getTargetName(this.target)); + } + private getIconPath() { switch (this.target.type) { case "executable": diff --git a/src/treeview/nodes/toplevel.ts b/src/treeview/nodes/toplevel.ts index 4290b0b2..6264a56d 100644 --- a/src/treeview/nodes/toplevel.ts +++ b/src/treeview/nodes/toplevel.ts @@ -1,13 +1,14 @@ import * as vscode from "vscode"; import { BaseNode } from "../basenode"; -import { ProjectInfo, Subproject, Targets, Tests } from "../../types"; +import { ProjectInfo, Subproject, Targets, Tests, pseudoAllTarget } from "../../types"; import { extensionRelative } from "../../utils"; import { TargetDirectoryNode } from "./targets"; import { getMesonBenchmarks, getMesonTargets, getMesonTests } from "../../introspection"; import { TestRootNode } from "./tests"; +import { IBuildableNode } from "./base"; -export class ProjectNode extends BaseNode { +export class ProjectNode extends BaseNode implements IBuildableNode { constructor( private readonly project: ProjectInfo, projectDir: string, @@ -26,6 +27,9 @@ export class ProjectNode extends BaseNode { item.iconPath = extensionRelative("res/meson_32.svg"); item.collapsibleState = vscode.TreeItemCollapsibleState.Expanded; + // To key in to "when": "view == meson-project && viewItem == test" in package.json. + item.contextValue = "meson-projectroot"; + return item; } @@ -60,6 +64,10 @@ export class ProjectNode extends BaseNode { return children; } + + build(): Thenable { + return vscode.commands.executeCommand("mesonbuild.build", pseudoAllTarget); + } } class SubprojectsRootNode extends BaseNode {