Skip to content

Commit

Permalink
Project Panel
Browse files Browse the repository at this point in the history
Convert the dependencies panel in to the new project panel. This rolls
the dependencies up in to its own top level item in the tree, and places
it along side Targets, Tasks, Commands and Snippets.

Tasks, Commands and Snippets can be run directly from the panel, and
update their icon to show their running status.

Clicking a test target will run all the tests in the target.
  • Loading branch information
plemarquand committed Feb 12, 2025
1 parent 4fa67ac commit e8cd031
Show file tree
Hide file tree
Showing 26 changed files with 1,138 additions and 498 deletions.
44 changes: 44 additions & 0 deletions assets/test/targets/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// swift-tools-version: 5.6
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "targets",
products: [
.library(
name: "LibraryTarget",
targets: ["LibraryTarget"]
),
.executable(
name: "ExecutableTarget",
targets: ["ExecutableTarget"]
),
.plugin(
name: "PluginTarget",
targets: ["PluginTarget"]
),
],
dependencies: [
.package(url: "https://github.com/swiftlang/swift-markdown.git", branch: "main"),
.package(path: "../defaultPackage"),
],
targets: [
.target(
name: "LibraryTarget"
),
.executableTarget(
name: "ExecutableTarget"
),
.plugin(
name: "PluginTarget",
capability: .command(
intent: .custom(verb: "testing", description: "A plugin for testing plugins")
)
),
.testTarget(
name: "TargetsTests",
dependencies: ["LibraryTarget"]
),
]
)
9 changes: 9 additions & 0 deletions assets/test/targets/Plugins/PluginTarget/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import PackagePlugin
import Foundation

@main
struct MyCommandPlugin: CommandPlugin {
func performCommand(context: PluginContext, arguments: [String]) throws {
print("Plugin Target Hello World")
}
}
1 change: 1 addition & 0 deletions assets/test/targets/Snippets/AnotherSnippet.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("Another Snippet Hello World")
1 change: 1 addition & 0 deletions assets/test/targets/Snippets/Snippet.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("Snippet Hello World")
Empty file.
1 change: 1 addition & 0 deletions assets/test/targets/Sources/ExecutableTarget/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("Executable Target Hello World!")
6 changes: 6 additions & 0 deletions assets/test/targets/Sources/LibraryTarget/Targets.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// The Swift Programming Language
// https://docs.swift.org/swift-book

func foo() {
print("foo")
}
4 changes: 4 additions & 0 deletions assets/test/targets/Tests/TargetsTests/TargetsTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Testing

@Test func example() async throws {
}
29 changes: 17 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,11 @@
"command": "swift.runAllTestsParallel",
"title": "Run All Tests in Parallel",
"category": "Test"
},
{
"command": "swift.runAllTests",
"title": "Run All Tests",
"category": "Test"
}
],
"configuration": [
Expand Down Expand Up @@ -917,50 +922,50 @@
"view/title": [
{
"command": "swift.updateDependencies",
"when": "view == packageDependencies",
"when": "view == projectPanel",
"group": "navigation@1"
},
{
"command": "swift.resolveDependencies",
"when": "view == packageDependencies",
"when": "view == projectPanel",
"group": "navigation@2"
},
{
"command": "swift.resetPackage",
"when": "view == packageDependencies",
"when": "view == projectPanel",
"group": "navigation@3"
},
{
"command": "swift.flatDependenciesList",
"when": "view == packageDependencies && !swift.flatDependenciesList",
"when": "view == projectPanel && !swift.flatDependenciesList",
"group": "navigation@4"
},
{
"command": "swift.nestedDependenciesList",
"when": "view == packageDependencies && swift.flatDependenciesList",
"when": "view == projectPanel && swift.flatDependenciesList",
"group": "navigation@5"
}
],
"view/item/context": [
{
"command": "swift.useLocalDependency",
"when": "view == packageDependencies && viewItem == remote"
"when": "view == projectPanel && viewItem == remote"
},
{
"command": "swift.uneditDependency",
"when": "view == packageDependencies && viewItem == editing"
"when": "view == projectPanel && viewItem == editing"
},
{
"command": "swift.openInWorkspace",
"when": "view == packageDependencies && viewItem == editing"
"when": "view == projectPanel && viewItem == editing"
},
{
"command": "swift.openInWorkspace",
"when": "view == packageDependencies && viewItem == local"
"when": "view == projectPanel && viewItem == local"
},
{
"command": "swift.openExternal",
"when": "view == packageDependencies && viewItem != local"
"when": "view == projectPanel && (viewItem == 'editing' || viewItem == 'remote')"
}
]
},
Expand Down Expand Up @@ -1157,8 +1162,8 @@
"views": {
"explorer": [
{
"id": "packageDependencies",
"name": "Package Dependencies",
"id": "projectPanel",
"name": "Swift Project",
"icon": "$(archive)",
"when": "swift.hasPackage"
}
Expand Down
2 changes: 1 addition & 1 deletion src/SwiftPackage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface Target {
c99name: string;
path: string;
sources: string[];
type: "executable" | "test" | "library" | "snippet";
type: "executable" | "test" | "library" | "snippet" | "plugin";
}

/** Swift Package Manager dependency */
Expand Down
47 changes: 32 additions & 15 deletions src/SwiftSnippets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,29 +48,44 @@ export function setSnippetContextKey(ctx: WorkspaceContext) {
* If current file is a Swift Snippet run it
* @param ctx Workspace Context
*/
export async function runSnippet(ctx: WorkspaceContext): Promise<boolean | undefined> {
return await debugSnippetWithOptions(ctx, { noDebug: true });
export async function runSnippet(
ctx: WorkspaceContext,
snippet?: string
): Promise<boolean | undefined> {
return await debugSnippetWithOptions(ctx, { noDebug: true }, snippet);
}

/**
* If current file is a Swift Snippet run it in the debugger
* @param ctx Workspace Context
*/
export async function debugSnippet(ctx: WorkspaceContext): Promise<boolean | undefined> {
return await debugSnippetWithOptions(ctx, {});
export async function debugSnippet(
ctx: WorkspaceContext,
snippet?: string
): Promise<boolean | undefined> {
return await debugSnippetWithOptions(ctx, {}, snippet);
}

export async function debugSnippetWithOptions(
ctx: WorkspaceContext,
options: vscode.DebugSessionOptions
options: vscode.DebugSessionOptions,
snippet?: string
): Promise<boolean | undefined> {
// create build task
let snippetName: string;
if (snippet) {
snippetName = snippet;
} else if (ctx.currentDocument) {
snippetName = path.basename(ctx.currentDocument.fsPath, ".swift");
} else {
return false;
}

const folderContext = ctx.currentFolder;
if (!ctx.currentDocument || !folderContext) {
return;
if (!folderContext) {
return false;
}

// create build task
const snippetName = path.basename(ctx.currentDocument.fsPath, ".swift");
const snippetBuildTask = createSwiftTask(
["build", "--product", snippetName],
`Build ${snippetName}`,
Expand All @@ -84,26 +99,28 @@ export async function debugSnippetWithOptions(
},
ctx.toolchain
);

const snippetDebugConfig = createSnippetConfiguration(snippetName, folderContext);
try {
ctx.buildStarted(snippetName, snippetDebugConfig, options);

// queue build task and when it is complete run executable in the debugger
return await folderContext.taskQueue
.queueOperation(new TaskOperation(snippetBuildTask))
.then(result => {
if (result === 0) {
const snippetDebugConfig = createSnippetConfiguration(
snippetName,
folderContext
);
return debugLaunchConfig(
folderContext.workspaceFolder,
snippetDebugConfig,
options
);
}
})
.then(result => {
ctx.buildFinished(snippetName, snippetDebugConfig, options);
return result;
});
} catch {
// ignore error if task failed to run
return;
return false;
}
}
9 changes: 4 additions & 5 deletions src/TestExplorer/TestRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,8 @@ export class TestRunner {
* @returns When complete
*/
async runHandler() {
this.workspaceContext.testsStarted(this.folderContext, this.testKind);

const runState = new TestRunnerTestRunState(this.testRun);

const cancellationDisposable = this.testRun.token.onCancellationRequested(() => {
Expand All @@ -551,6 +553,8 @@ export class TestRunner {

cancellationDisposable.dispose();
await this.testRun.end();

this.workspaceContext.testsFinished(this.folderContext, this.testKind);
}

/** Run test session without attaching to a debugger */
Expand Down Expand Up @@ -971,11 +975,6 @@ export class TestRunner {
);
}

// show test results pane
vscode.commands.executeCommand(
"testing.showMostRecentOutput"
);

const terminateSession =
vscode.debug.onDidTerminateDebugSession(() => {
this.workspaceContext.outputChannel.logDiagnostic(
Expand Down
51 changes: 51 additions & 0 deletions src/WorkspaceContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { SwiftToolchain } from "./toolchain/toolchain";
import { DiagnosticsManager } from "./DiagnosticsManager";
import { DocumentationManager } from "./documentation/DocumentationManager";
import { DocCDocumentationRequest, ReIndexProjectRequest } from "./sourcekit-lsp/extensions";
import { TestKind } from "./TestExplorer/TestKind";

/**
* Context for whole workspace. Holds array of contexts for each workspace folder
Expand All @@ -55,6 +56,17 @@ export class WorkspaceContext implements vscode.Disposable {
private lastFocusUri: vscode.Uri | undefined;
private initialisationFinished = false;

private readonly testStartEmitter = new vscode.EventEmitter<TestEvent>();
private readonly testFinishEmitter = new vscode.EventEmitter<TestEvent>();

public onDidStartTests = this.testStartEmitter.event;
public onDidFinishTests = this.testFinishEmitter.event;

private readonly buildStartEmitter = new vscode.EventEmitter<BuildEvent>();
private readonly buildFinishEmitter = new vscode.EventEmitter<BuildEvent>();
public onDidStartBuild = this.buildStartEmitter.event;
public onDidFinishBuild = this.buildFinishEmitter.event;

private constructor(
extensionContext: vscode.ExtensionContext,
public tempFolder: TemporaryFolder,
Expand Down Expand Up @@ -338,6 +350,30 @@ export class WorkspaceContext implements vscode.Disposable {
await this.fireEvent(folderContext, FolderOperation.focus);
}

public testsFinished(folder: FolderContext, kind: TestKind) {
this.testFinishEmitter.fire({ kind, folder });
}

public testsStarted(folder: FolderContext, kind: TestKind) {
this.testStartEmitter.fire({ kind, folder });
}

public buildStarted(
targetName: string,
launchConfig: vscode.DebugConfiguration,
options: vscode.DebugSessionOptions
) {
this.buildStartEmitter.fire({ targetName, launchConfig, options });
}

public buildFinished(
targetName: string,
launchConfig: vscode.DebugConfiguration,
options: vscode.DebugSessionOptions
) {
this.buildFinishEmitter.fire({ targetName, launchConfig, options });
}

/**
* catch workspace folder changes and add or remove folders based on those changes
* @param event workspace folder event
Expand Down Expand Up @@ -666,6 +702,19 @@ export class WorkspaceContext implements vscode.Disposable {
private swiftFileObservers = new Set<(listener: SwiftFileEvent) => unknown>();
}

/** Test events for test run begin/end */
interface TestEvent {
kind: TestKind;
folder: FolderContext;
}

/** Build events for build + run start/stop */
interface BuildEvent {
targetName: string;
launchConfig: vscode.DebugConfiguration;
options: vscode.DebugSessionOptions;
}

/** Workspace Folder Operation types */
export enum FolderOperation {
// Package folder has been added
Expand All @@ -684,6 +733,8 @@ export enum FolderOperation {
workspaceStateUpdated = "workspaceStateUpdated",
// .build/workspace-state.json has been updated
packageViewUpdated = "packageViewUpdated",
// Package plugins list has been updated
pluginsUpdated = "pluginsUpdated",
}

/** Workspace Folder Event */
Expand Down
Loading

0 comments on commit e8cd031

Please sign in to comment.