diff --git a/package.json b/package.json index 3ea35b3d3..8f37b48fb 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,16 @@ } ], "commands": [ + { + "command": "swift.browsePackageIndex", + "title": "Browse Package Index...", + "category": "Swift" + }, + { + "command": "swift.addPackageDependency", + "title": "Add Package Dependency...", + "category": "Swift" + }, { "command": "swift.createNewProject", "title": "Create New Project...", @@ -536,6 +546,14 @@ "command": "swift.createNewProject", "when": "!swift.isActivated || swift.createNewProjectAvailable" }, + { + "command": "swift.browsePackageIndex", + "when": "swift.hasPackage && swift.addPackageRefactoringAvailable" + }, + { + "command": "swift.addPackageDependency", + "when": "swift.hasPackage && swift.addPackageRefactoringAvailable" + }, { "command": "swift.updateDependencies", "when": "swift.hasPackage" @@ -1163,4 +1181,4 @@ "vscode-languageclient": "^9.0.1", "xml2js": "^0.6.2" } -} \ No newline at end of file +} diff --git a/src/WorkspaceContext.ts b/src/WorkspaceContext.ts index 5b7da0946..a3053caf6 100644 --- a/src/WorkspaceContext.ts +++ b/src/WorkspaceContext.ts @@ -76,6 +76,9 @@ export class WorkspaceContext implements vscode.Disposable { contextKeys.createNewProjectAvailable = toolchain.swiftVersion.isGreaterThanOrEqual( new Version(5, 8, 0) ); + contextKeys.addPackageRefactoringAvailable = toolchain.swiftVersion.isGreaterThanOrEqual( + new Version(6, 0, 0) + ); const onChangeConfig = vscode.workspace.onDidChangeConfiguration(async event => { // on toolchain config change, reload window diff --git a/src/commands.ts b/src/commands.ts index a32424282..8bb82dd01 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -248,6 +248,147 @@ export async function createNewProject(ctx: WorkspaceContext): Promise { } } +/** + * Prompts the user to input project details and then executes `swift package init` + * to create the project. + */ +export async function browsePackageIndex(ctx: WorkspaceContext): Promise { + // The context key `swift.addPackageRefactoringAvailable` only works if the extension has been + // activated. As such, we also have to allow this command to run when no workspace is + // active. Show an error to the user if the command is unavailable. + if (!ctx.toolchain.swiftVersion.isGreaterThanOrEqual(new Version(6, 0, 0))) { + vscode.window.showErrorMessage( + "Browsing the package index is only available starting in swift version 6.0.0." + ); + return; + } + + const panel = vscode.window.createWebviewPanel( + "swiftPackageIndex", + "Swift Package Index", + vscode.ViewColumn.One, + { + retainContextWhenHidden: true, + enableScripts: true, + } + ); + + panel.webview.onDidReceiveMessage( + message => { + switch (message.command) { + case "addSwiftPackage": + addPackageDependency(ctx, message.url, message.version); + return; + default: + // Log message + vscode.window.showErrorMessage(`An error occurred when adding packages`); + return; + } + }, + undefined, + ctx.subscriptions + ); + + panel.webview.html = ` + + + + `; +} + +export async function addPackageDependency( + ctx: WorkspaceContext, + url?: string, + version?: string +): Promise { + // The context key `swift.addPackageRefactoringAvailable` only works if the extension has been + // activated. As such, we also have to allow this command to run when no workspace is + // active. Show an error to the user if the command is unavailable. + if (!ctx.toolchain.swiftVersion.isGreaterThanOrEqual(new Version(6, 0, 0))) { + vscode.window.showErrorMessage( + "Adding a new swift package dependency is only available starting in swift version 6.0.0." + ); + return; + } + + if (!ctx.currentFolder) { + vscode.window.showErrorMessage("An error occurred when adding packages"); + return; + } + const folderContext = ctx.currentFolder; + + if (!url) { + url = await vscode.window.showInputBox({ + prompt: "Enter the URL for the package", + validateInput(value) { + if (value.trim() === "") { + return "URL cannot be empty."; + } + return undefined; + }, + }); + + if (!url) { + return; + } + } + + if (!version) { + version = await vscode.window.showInputBox({ + prompt: "Enter the version for the package", + validateInput(value) { + if (value.trim() === "") { + return "Version cannot be empty."; + } + return undefined; + }, + }); + + if (!version) { + return; + } + } + + const resolveTask = createSwiftTask( + ["package", "add-dependency", url, "--branch", version], + "Adding Package Dependency", + { + cwd: folderContext.folder, + scope: folderContext.workspaceFolder, + prefix: folderContext.name, + presentationOptions: { reveal: vscode.TaskRevealKind.Silent }, + }, + folderContext.workspaceContext.toolchain + ); + + await executeTaskWithUI(resolveTask, "Adding Package Dependency", folderContext); + + await openPackage(ctx); +} + /** * Run `swift package update` inside a folder * @param folderContext folder to run update inside @@ -840,6 +981,10 @@ function updateAfterError(result: boolean, folderContext: FolderContext) { export function register(ctx: WorkspaceContext) { ctx.subscriptions.push( vscode.commands.registerCommand("swift.createNewProject", () => createNewProject(ctx)), + vscode.commands.registerCommand("swift.browsePackageIndex", () => browsePackageIndex(ctx)), + vscode.commands.registerCommand("swift.addPackageDependency", (url, version) => + addPackageDependency(ctx, url, version) + ), vscode.commands.registerCommand("swift.resolveDependencies", () => resolveDependencies(ctx) ), diff --git a/src/contextKeys.ts b/src/contextKeys.ts index 6c221ba2c..736269cd8 100644 --- a/src/contextKeys.ts +++ b/src/contextKeys.ts @@ -80,6 +80,13 @@ const contextKeys = { set createNewProjectAvailable(value: boolean) { vscode.commands.executeCommand("setContext", "swift.createNewProjectAvailable", value); }, + + /** + * Whether the swift.addPackageRefactoringAvailable command is available. + */ + set addPackageRefactoringAvailable(value: boolean) { + vscode.commands.executeCommand("setContext", "swift.addPackageRefactoringAvailable", value); + }, }; export default contextKeys;