diff --git a/library/Registry.md b/library/Registry.md deleted file mode 100644 index 7440e4379e..0000000000 --- a/library/Registry.md +++ /dev/null @@ -1,22 +0,0 @@ -# Q# Library Registry - -This document is a list of notable Q# library projects. If you have a library that you would like to add to this list, please open a pull request. If you have a Q# project that you'd like to share as a library, please see the [documentation on how to do this](https://learn.microsoft.com/en-us/azure/quantum/how-to-work-with-qsharp-projects?tabs=tabid-qsharp%2Ctabid-qsharp-run#configuring-q-projects-as-external-dependencies). - -## Unstable - -[link](https://github.com/microsoft/qsharp/tree/main/library/unstable) - -A general staging ground for some useful APIs that have not yet been stabilized into the standard library. - -## Signed - -[link](https://github.com/microsoft/qsharp/tree/main/library/signed) - -Defines types and functions to work with signed qubit-based integers. - -## FixedPoint - -[link](https://github.com/microsoft/qsharp/tree/main/library/fixed_point) - -Types and functions for fixed-point arithmetic with qubits. - diff --git a/library/fixed_point/qsharp.json b/library/fixed_point/qsharp.json index 976c27aa25..ce625648fa 100644 --- a/library/fixed_point/qsharp.json +++ b/library/fixed_point/qsharp.json @@ -24,4 +24,4 @@ "src/Tests.qs", "src/Types.qs" ] -} +} \ No newline at end of file diff --git a/vscode/src/createProject.ts b/vscode/src/createProject.ts index 2d6f59e48f..4c253c5e64 100644 --- a/vscode/src/createProject.ts +++ b/vscode/src/createProject.ts @@ -5,6 +5,7 @@ import * as vscode from "vscode"; import { log, samples } from "qsharp-lang"; import { EventType, sendTelemetryEvent } from "./telemetry"; import { qsharpExtensionId } from "./common"; +import registryJson from "./registry.json"; export async function initProjectCreator(context: vscode.ExtensionContext) { context.subscriptions.push( @@ -182,18 +183,6 @@ export async function initProjectCreator(context: vscode.ExtensionContext) { type Dependency = LocalProjectRef | GitHubProjectRef; - // TODO: Replace with a list of legitimate known Q# projects on GitHub - const githubProjects: { [name: string]: GitHubProjectRef } = { - // Add a template to the end of the list users can use to easily add their own - "": { - github: { - owner: "", - repo: "", - ref: "", - }, - }, - }; - // Given two directory paths, return the relative path from the first to the second function getRelativeDirPath(from: string, to: string): string { // Ensure we have something @@ -265,93 +254,175 @@ export async function initProjectCreator(context: vscode.ExtensionContext) { return; } - // Find all the other Q# projects in the workspace - const projectFiles = ( - await vscode.workspace.findFiles("**/qsharp.json") - ).filter((file) => file.toString() !== qsharpJsonUri.toString()); - - const projectChoices: Array<{ name: string; ref: Dependency }> = []; - - projectFiles.forEach((file) => { - const dirName = file.path.slice(0, -"/qsharp.json".length); - const relPath = getRelativeDirPath(qsharpJsonDir.path, dirName); - projectChoices.push({ - name: dirName.slice(dirName.lastIndexOf("/") + 1), - ref: { - path: relPath, - }, - }); - }); - - Object.keys(githubProjects).forEach((name) => { - projectChoices.push({ - name: name, - ref: githubProjects[name], - }); - }); - - // Convert any spaces, dashes, dots, tildes, or quotes in project names - // to underscores. (Leave more 'exotic' non-identifier patterns to the user to fix) - // - // Note: At some point we may want to detect/avoid duplicate names, e.g. if the user already - // references a project via 'foo', and they add a reference to a 'foo' on GitHub or in another dir. - projectChoices.forEach( - (val, idx, arr) => - (arr[idx].name = val.name.replace(/[- "'.~]/g, "_")), + // ask the user if they want to import from github, or locally on their computer + const importChoice = await vscode.window.showQuickPick( + ["Import from GitHub", "Import from local directory"], + { placeHolder: "Pick a source to import from" }, ); - const folderIcon = new vscode.ThemeIcon("folder"); - const githubIcon = new vscode.ThemeIcon("github"); - - // Ask the user to pick a project to add as a reference - const projectChoice = await vscode.window.showQuickPick( - projectChoices.map((choice) => { - if ("github" in choice.ref) { - return { - label: choice.name, - detail: `github://${choice.ref.github.owner}/${choice.ref.github.repo}#${choice.ref.github.ref}`, - iconPath: githubIcon, - ref: choice.ref, - }; - } else { - return { - label: choice.name, - detail: choice.ref.path, - iconPath: folderIcon, - ref: choice.ref, - }; - } - }), - { placeHolder: "Pick a project to add as a reference" }, - ); - - if (!projectChoice) { - log.info("User cancelled project choice"); + if (!importChoice) { + log.info("User cancelled import choice"); return; } - log.info("User picked project: ", projectChoice); - - if (!manifestObj["dependencies"]) manifestObj["dependencies"] = {}; - manifestObj["dependencies"][projectChoice.label] = projectChoice.ref; - - // Apply the edits to the qsharp.json - const edit = new vscode.WorkspaceEdit(); - edit.replace( - qsharpJsonUri, - new vscode.Range(0, 0, qsharpJsonDoc.lineCount, 0), - JSON.stringify(manifestObj, null, 2), - ); - if (!(await vscode.workspace.applyEdit(edit))) { - vscode.window.showErrorMessage( - "Unable to update the qsharp.json file. Check the file is writable", + if (importChoice === "Import from GitHub") { + await importExternalPackage( + qsharpJsonDoc, + qsharpJsonUri, + manifestObj, + ); + } else { + await importLocalPackage( + qsharpJsonDoc, + qsharpJsonDir, + qsharpJsonUri, + manifestObj, ); - return; } - - // Bring the qsharp.json to the front for the user to save - await vscode.window.showTextDocument(qsharpJsonDoc); }, ), ); + async function importLocalPackage( + qsharpJsonDoc: vscode.TextDocument, + qsharpJsonDir: vscode.Uri, + qsharpJsonUri: vscode.Uri, + manifestObj: any, + ) { + // Find all the other Q# projects in the workspace + const projectFiles = ( + await vscode.workspace.findFiles("**/qsharp.json") + ).filter((file) => file.toString() !== qsharpJsonUri.toString()); + + const projectChoices: Array<{ name: string; ref: LocalProjectRef }> = []; + + projectFiles.forEach((file) => { + const dirName = file.path.slice(0, -"/qsharp.json".length); + const relPath = getRelativeDirPath(qsharpJsonDir.path, dirName); + projectChoices.push({ + name: dirName.slice(dirName.lastIndexOf("/") + 1), + ref: { + path: relPath, + }, + }); + }); + + // Convert any spaces, dashes, dots, tildes, or quotes in project names + // to underscores. (Leave more 'exotic' non-identifier patterns to the user to fix) + // + // Note: At some point we may want to detect/avoid duplicate names, e.g. if the user already + // references a project via 'foo', and they add a reference to a 'foo' on GitHub or in another dir. + projectChoices.forEach( + (val, idx, arr) => (arr[idx].name = val.name.replace(/[- "'.~]/g, "_")), + ); + + const folderIcon = new vscode.ThemeIcon("folder"); + + // Ask the user to pick a project to add as a reference + const projectChoice = await vscode.window.showQuickPick( + projectChoices.map((choice) => ({ + label: choice.name, + detail: choice.ref.path, + iconPath: folderIcon, + ref: choice.ref, + })), + { placeHolder: "Pick a project to add as a reference" }, + ); + + if (!projectChoice) { + log.info("User cancelled project choice"); + return; + } + + await updateManifestAndSave( + qsharpJsonDoc, + qsharpJsonUri, + manifestObj, + projectChoice.label, + projectChoice.ref, + ); + } + + async function importExternalPackage( + qsharpJsonDoc: vscode.TextDocument, + qsharpJsonUri: vscode.Uri, + manifestObj: any, + ) { + // ask the user to pick a package to import + const packageChoice = await vscode.window.showQuickPick( + registryJson.knownPackages.map( + (pkg: { name: string; description: string; dependency: object }) => ({ + label: pkg.name, + description: pkg.description, + }), + ), + { placeHolder: "Pick a package to import" }, + ); + + if (!packageChoice) { + log.info("User cancelled package choice"); + return; + } + + const chosenPackage = registryJson.knownPackages.find( + (pkg: { name: string; description: string; dependency: object }) => + pkg.name === packageChoice.label, + )!; + + const versionChoice = await vscode.window.showQuickPick( + chosenPackage.dependency.github.refs.map(({ ref, notes }) => ({ + label: ref, + description: notes, + })), + { placeHolder: "Pick a version to import" }, + ); + + if (!versionChoice) { + log.info("User cancelled version choice"); + return; + } + + const dependencyRef = { + github: { + ref: versionChoice.label, + ...chosenPackage.dependency.github, + refs: undefined, + }, + }; + + await updateManifestAndSave( + qsharpJsonDoc, + qsharpJsonUri, + manifestObj, + packageChoice.label, + dependencyRef, + ); + } + + async function updateManifestAndSave( + qsharpJsonDoc: vscode.TextDocument, + qsharpJsonUri: vscode.Uri, + manifestObj: any, + label: string, + ref: Dependency, + ) { + if (!manifestObj["dependencies"]) manifestObj["dependencies"] = {}; + manifestObj["dependencies"][label] = ref; + + // Apply the edits to the qsharp.json + const edit = new vscode.WorkspaceEdit(); + edit.replace( + qsharpJsonUri, + new vscode.Range(0, 0, qsharpJsonDoc.lineCount, 0), + JSON.stringify(manifestObj, null, 2), + ); + if (!(await vscode.workspace.applyEdit(edit))) { + vscode.window.showErrorMessage( + "Unable to update the qsharp.json file. Check the file is writable", + ); + return; + } + + // Bring the qsharp.json to the front for the user to save + await vscode.window.showTextDocument(qsharpJsonDoc); + } } diff --git a/vscode/src/registry.json b/vscode/src/registry.json new file mode 100644 index 0000000000..3d00fa1708 --- /dev/null +++ b/vscode/src/registry.json @@ -0,0 +1,64 @@ +{ + "knownPackages": [ + { + "name": "Signed", + "description": "Defines types and functions to work with signed qubit-based integers.", + "dependency": { + "github": { + "owner": "Microsoft", + "repo": "qsharp", + "refs": [ + { "ref": "546b053", "notes": "latest stable" }, + { "ref": "main", "notes": "nightly, unstable" } + ], + "path": "library/signed" + } + } + }, + { + "name": "FixedPoint", + "description": "Types and functions for fixed-point arithmetic with qubits.", + "dependency": { + "github": { + "owner": "Microsoft", + "repo": "qsharp", + "refs": [ + { "ref": "546b053", "notes": "latest stable" }, + { "ref": "main", "notes": "nightly, unstable" } + ], + "path": "library/signed" + } + } + }, + { + "name": "Rotations", + "description": "Defines types and functions to work with rotations.", + "dependency": { + "github": { + "owner": "Microsoft", + "repo": "qsharp", + "refs": [ + { "ref": "546b053", "notes": "latest stable" }, + { "ref": "main", "notes": "nightly, unstable" } + ], + "path": "library/rotations" + } + } + }, + { + "name": "Qtest", + "description": "Utilities for writing and running Q# tests.", + "dependency": { + "github": { + "owner": "Microsoft", + "repo": "qsharp", + "refs": [ + { "ref": "546b053", "notes": "latest stable" }, + { "ref": "main", "notes": "nightly, unstable" } + ], + "path": "library/qtest" + } + } + } + ] +}