diff --git a/vscode/src/azure/commands.ts b/vscode/src/azure/commands.ts index 5fe1cd8ad5..6775e9573c 100644 --- a/vscode/src/azure/commands.ts +++ b/vscode/src/azure/commands.ts @@ -23,8 +23,9 @@ import { getQirForActiveWindow } from "../qirGeneration"; import { supportsAdaptive, targetSupportQir } from "./providerProperties"; import { startRefreshCycle } from "./treeRefresher"; import { getTokenForWorkspace } from "./auth"; +import { qsharpExtensionId } from "../common"; -const workspacesSecret = "qsharp-vscode.workspaces"; +const workspacesSecret = `${qsharpExtensionId}.workspaces`; export async function initAzureWorkspaces(context: vscode.ExtensionContext) { const workspaceTreeProvider = new WorkspaceTreeProvider(); @@ -81,17 +82,17 @@ export async function initAzureWorkspaces(context: vscode.ExtensionContext) { await vscode.commands.executeCommand( "setContext", - "qsharp-vscode.treeItemSupportsQir", + `${qsharpExtensionId}.treeItemSupportsQir`, supportsQir, ); await vscode.commands.executeCommand( "setContext", - "qsharp-vscode.treeItemSupportsDownload", + `${qsharpExtensionId}.treeItemSupportsDownload`, supportsDownload, ); await vscode.commands.executeCommand( "setContext", - "qsharp-vscode.treeItemIsWorkspace", + `${qsharpExtensionId}.treeItemIsWorkspace`, isWorkspace, ); }), @@ -99,7 +100,7 @@ export async function initAzureWorkspaces(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand( - "qsharp-vscode.targetSubmit", + `${qsharpExtensionId}.targetSubmit`, async (arg: WorkspaceTreeItem) => { // Could be run via the treeItem icon or the menu command. const treeItem = arg || currentTreeItem; @@ -156,17 +157,20 @@ export async function initAzureWorkspaces(context: vscode.ExtensionContext) { ); context.subscriptions.push( - vscode.commands.registerCommand("qsharp-vscode.workspacesRefresh", () => { - // The user manually triggered a refresh. Start a cycle for each workspace - const workspaceIds = workspaceTreeProvider.getWorkspaceIds(); - - workspaceIds.forEach((id) => { - const workspace = workspaceTreeProvider.getWorkspace(id); - if (workspace) { - startRefreshCycle(workspaceTreeProvider, workspace); - } - }); - }), + vscode.commands.registerCommand( + `${qsharpExtensionId}.workspacesRefresh`, + () => { + // The user manually triggered a refresh. Start a cycle for each workspace + const workspaceIds = workspaceTreeProvider.getWorkspaceIds(); + + workspaceIds.forEach((id) => { + const workspace = workspaceTreeProvider.getWorkspace(id); + if (workspace) { + startRefreshCycle(workspaceTreeProvider, workspace); + } + }); + }, + ), ); async function saveWorkspaceList() { @@ -196,20 +200,23 @@ export async function initAzureWorkspaces(context: vscode.ExtensionContext) { } context.subscriptions.push( - vscode.commands.registerCommand("qsharp-vscode.workspacesAdd", async () => { - const workspace = await queryWorkspaces(); - if (workspace) { - workspaceTreeProvider.updateWorkspace(workspace); - await saveWorkspaceList(); - // Just kick off the refresh loop, no need to await - startRefreshCycle(workspaceTreeProvider, workspace); - } - }), + vscode.commands.registerCommand( + `${qsharpExtensionId}.workspacesAdd`, + async () => { + const workspace = await queryWorkspaces(); + if (workspace) { + workspaceTreeProvider.updateWorkspace(workspace); + await saveWorkspaceList(); + // Just kick off the refresh loop, no need to await + startRefreshCycle(workspaceTreeProvider, workspace); + } + }, + ), ); context.subscriptions.push( vscode.commands.registerCommand( - "qsharp-vscode.workspacesRemove", + `${qsharpExtensionId}.workspacesRemove`, async (arg: WorkspaceTreeItem) => { // Could be run via the treeItem icon or the menu command. const treeItem = arg || currentTreeItem; @@ -224,7 +231,7 @@ export async function initAzureWorkspaces(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand( - "qsharp-vscode.downloadResults", + `${qsharpExtensionId}.downloadResults`, async (arg: WorkspaceTreeItem) => { // Could be run via the treeItem icon or the menu command. const treeItem = arg || currentTreeItem; @@ -273,7 +280,7 @@ export async function initAzureWorkspaces(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand( - "qsharp-vscode.workspacePythonCode", + `${qsharpExtensionId}.workspacePythonCode`, async (arg: WorkspaceTreeItem) => { // Could be run via the treeItem icon or the menu command. const treeItem = arg || currentTreeItem; @@ -300,7 +307,7 @@ export async function initAzureWorkspaces(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand( - "qsharp-vscode.workspaceOpenPortal", + `${qsharpExtensionId}.workspaceOpenPortal`, async (arg: WorkspaceTreeItem) => { // Could be run via the treeItem icon or the menu command. const treeItem = arg || currentTreeItem; diff --git a/vscode/src/createProject.ts b/vscode/src/createProject.ts index 6bf478cf54..2d6f59e48f 100644 --- a/vscode/src/createProject.ts +++ b/vscode/src/createProject.ts @@ -4,11 +4,12 @@ import * as vscode from "vscode"; import { log, samples } from "qsharp-lang"; import { EventType, sendTelemetryEvent } from "./telemetry"; +import { qsharpExtensionId } from "./common"; export async function initProjectCreator(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand( - "qsharp-vscode.createProject", + `${qsharpExtensionId}.createProject`, async (folderUri: vscode.Uri | undefined) => { sendTelemetryEvent(EventType.CreateProject, {}, {}); @@ -66,7 +67,7 @@ export async function initProjectCreator(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand( - "qsharp-vscode.populateFilesList", + `${qsharpExtensionId}.populateFilesList`, async (qsharpJsonUri: vscode.Uri | undefined) => { // If called from the content menu qsharpJsonUri will be the full qsharp.json uri // If called from the command palette is will be undefined, so use the active editor @@ -228,7 +229,7 @@ export async function initProjectCreator(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand( - "qsharp-vscode.addProjectReference", + `${qsharpExtensionId}.addProjectReference`, async (qsharpJsonUri: vscode.Uri | undefined) => { // If called from the content menu qsharpJsonUri will be the full qsharp.json uri // If called from the command palette is will be undefined, so use the active editor diff --git a/vscode/src/diagnostics.ts b/vscode/src/diagnostics.ts index e0fd154c86..2b08e0cbf9 100644 --- a/vscode/src/diagnostics.ts +++ b/vscode/src/diagnostics.ts @@ -3,7 +3,11 @@ import { IQSharpError, log, qsharpLibraryUriScheme } from "qsharp-lang"; import * as vscode from "vscode"; -import { qsharpLanguageId, toVsCodeDiagnostic } from "./common.js"; +import { + qsharpExtensionId, + qsharpLanguageId, + toVsCodeDiagnostic, +} from "./common.js"; /** * Initialize diagnostics for `qsharp.json` files and failures @@ -84,7 +88,7 @@ function startCommandDiagnostics(): vscode.Disposable[] { vscode.languages.createDiagnosticCollection(qsharpLanguageId); const dismissCommand = vscode.commands.registerCommand( - "qsharp-vscode.dismissCommandDiagnostics", + `${qsharpExtensionId}.dismissCommandDiagnostics`, clearCommandDiagnostics, ); @@ -102,7 +106,7 @@ function startCommandDiagnostics(): vscode.Disposable[] { ); action.diagnostics = commandErrors; action.command = { - command: "qsharp-vscode.dismissCommandDiagnostics", + command: `${qsharpExtensionId}.dismissCommandDiagnostics`, title: "Dismiss errors for the last run Q# command", }; action.isPreferred = true; diff --git a/vscode/src/memfs.ts b/vscode/src/memfs.ts index f5ac8570fc..387e55ac07 100644 --- a/vscode/src/memfs.ts +++ b/vscode/src/memfs.ts @@ -3,6 +3,7 @@ import { log, samples } from "qsharp-lang"; import * as vscode from "vscode"; +import { qsharpExtensionId } from "./common"; export const scheme = "qsharp-vfs"; @@ -69,7 +70,7 @@ export async function initFileSystem(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand( - "qsharp-vscode.openPlayground", + `${qsharpExtensionId}.openPlayground`, async () => { await vscode.commands.executeCommand( "vscode.openFolder", @@ -80,47 +81,52 @@ export async function initFileSystem(context: vscode.ExtensionContext) { ); context.subscriptions.push( - vscode.commands.registerCommand("qsharp-vscode.webOpener", async (uri) => { - log.debug(`webOpener called with URI ${uri}`); - - // Open the README if the user has navigated to the playground - if (typeof uri === "string" && uri.endsWith("/playground/")) { - // Nice to have: First check if the readme is already open from a prior visit - await vscode.commands.executeCommand( - "markdown.showPreview", - playgroundRootUri.with({ path: "/README.md" }), - ); - return; - } + vscode.commands.registerCommand( + `${qsharpExtensionId}.webOpener`, + async (uri) => { + log.debug(`webOpener called with URI ${uri}`); + + // Open the README if the user has navigated to the playground + if (typeof uri === "string" && uri.endsWith("/playground/")) { + // Nice to have: First check if the readme is already open from a prior visit + await vscode.commands.executeCommand( + "markdown.showPreview", + playgroundRootUri.with({ path: "/README.md" }), + ); + return; + } - // Example: https://vscode.dev/quantum?code=H4sIAAAAAAAAEz2Ouw6CQBRE%2B%2F2KITbQSI%2BNhRYWhkc0FoTiBm5kE9kld3c1xPDvEjSe8mQmM2mKS68dWtsxXuTgehLu8NQEwrU6RZFShgZ2I7WM81QGMj4Mhdi70IC3UljYH42XqbDa%2BDhZjR1ZyGtrcCZt4gQZKnbh4etmKeFHusznhzzDTbRnTDYIys33Tc%2FC239S2AcxqJvdqmY1qw8FRbBxvAAAAA%3D%3D - let linkedCode: string | undefined; - if (typeof uri === "string") { - const uriObj = vscode.Uri.parse(uri); - log.debug("uri query component: " + uriObj.query); - - // The query appears to be URIDecoded already, which is causing issues with URLSearchParams, so extract with a regex for now. - const code = uriObj.query.match(/code=([^&]*)/)?.[1]; - - if (code) { - log.debug("code from query: " + code); - try { - linkedCode = await compressedBase64ToCode(code); - const codeFile = vscode.Uri.parse(`${scheme}:/code.qs`); - - const encoder = new TextEncoder(); - vfs.writeFile(codeFile, encoder.encode(linkedCode), { - create: true, - overwrite: true, - }); - await vscode.commands.executeCommand("vscode.open", codeFile); - await vscode.commands.executeCommand("qsharp-vscode.showHelp"); - } catch (err) { - log.warn("Unable to decode the code in the URL. ", err); + // Example: https://vscode.dev/quantum?code=H4sIAAAAAAAAEz2Ouw6CQBRE%2B%2F2KITbQSI%2BNhRYWhkc0FoTiBm5kE9kld3c1xPDvEjSe8mQmM2mKS68dWtsxXuTgehLu8NQEwrU6RZFShgZ2I7WM81QGMj4Mhdi70IC3UljYH42XqbDa%2BDhZjR1ZyGtrcCZt4gQZKnbh4etmKeFHusznhzzDTbRnTDYIys33Tc%2FC239S2AcxqJvdqmY1qw8FRbBxvAAAAA%3D%3D + let linkedCode: string | undefined; + if (typeof uri === "string") { + const uriObj = vscode.Uri.parse(uri); + log.debug("uri query component: " + uriObj.query); + + // The query appears to be URIDecoded already, which is causing issues with URLSearchParams, so extract with a regex for now. + const code = uriObj.query.match(/code=([^&]*)/)?.[1]; + + if (code) { + log.debug("code from query: " + code); + try { + linkedCode = await compressedBase64ToCode(code); + const codeFile = vscode.Uri.parse(`${scheme}:/code.qs`); + + const encoder = new TextEncoder(); + vfs.writeFile(codeFile, encoder.encode(linkedCode), { + create: true, + overwrite: true, + }); + await vscode.commands.executeCommand("vscode.open", codeFile); + await vscode.commands.executeCommand( + `${qsharpExtensionId}.showHelp`, + ); + } catch (err) { + log.warn("Unable to decode the code in the URL. ", err); + } } } - } - }), + }, + ), ); } diff --git a/vscode/src/notebook.ts b/vscode/src/notebook.ts index 5e53cb54bd..6ee82e827e 100644 --- a/vscode/src/notebook.ts +++ b/vscode/src/notebook.ts @@ -5,7 +5,7 @@ import { log } from "qsharp-lang"; import * as vscode from "vscode"; import { WorkspaceTreeProvider } from "./azure/treeView.js"; import { getPythonCodeForWorkspace } from "./azure/workspaceActions.js"; -import { qsharpLanguageId } from "./common.js"; +import { qsharpExtensionId, qsharpLanguageId } from "./common.js"; import { notebookTemplate } from "./notebookTemplate.js"; const qsharpCellMagic = "%%qsharp"; @@ -130,7 +130,7 @@ export function registerCreateNotebookCommand( ) { context.subscriptions.push( vscode.commands.registerCommand( - "qsharp-vscode.createNotebook", + `${qsharpExtensionId}.createNotebook`, async () => { // Update the workspace connection info in the notebook if workspaces are already connected to const tree = WorkspaceTreeProvider.instance; diff --git a/vscode/src/qirGeneration.ts b/vscode/src/qirGeneration.ts index 5539b0c9a9..23c4619203 100644 --- a/vscode/src/qirGeneration.ts +++ b/vscode/src/qirGeneration.ts @@ -8,6 +8,7 @@ import { invokeAndReportCommandDiagnostics } from "./diagnostics"; import { getActiveProgram } from "./programConfig"; import { EventType, sendTelemetryEvent } from "./telemetry"; import { getRandomGuid } from "./utils"; +import { qsharpExtensionId } from "./common"; const generateQirTimeoutMs = 120000; @@ -142,7 +143,7 @@ export function initCodegen(context: vscode.ExtensionContext) { ).toString(); context.subscriptions.push( - vscode.commands.registerCommand("qsharp-vscode.getQir", async () => { + vscode.commands.registerCommand(`${qsharpExtensionId}.getQir`, async () => { try { const qir = await getQirForActiveWindow(); const qirDoc = await vscode.workspace.openTextDocument({ diff --git a/vscode/src/statusbar.ts b/vscode/src/statusbar.ts index ecd7f9eb99..cb19a9062e 100644 --- a/vscode/src/statusbar.ts +++ b/vscode/src/statusbar.ts @@ -3,7 +3,7 @@ import { log, TargetProfile } from "qsharp-lang"; import * as vscode from "vscode"; -import { isQsharpDocument } from "./common"; +import { isQsharpDocument, qsharpExtensionId } from "./common"; import { getTarget, getTargetFriendlyName, setTarget } from "./config"; import { getActiveQSharpDocumentUri } from "./programConfig"; @@ -18,7 +18,7 @@ export function activateTargetProfileStatusBarItem(): vscode.Disposable[] { ); disposables.push(statusBarItem); - statusBarItem.command = "qsharp-vscode.setTargetProfile"; + statusBarItem.command = `${qsharpExtensionId}.setTargetProfile`; disposables.push( vscode.window.onDidChangeActiveTextEditor((editor) => { @@ -75,7 +75,7 @@ export function activateTargetProfileStatusBarItem(): vscode.Disposable[] { function registerTargetProfileCommand() { return vscode.commands.registerCommand( - "qsharp-vscode.setTargetProfile", + `${qsharpExtensionId}.setTargetProfile`, async () => { const target = await vscode.window.showQuickPick( targetProfiles.map((profile) => ({ diff --git a/vscode/src/webviewPanel.ts b/vscode/src/webviewPanel.ts index 7344a6c6c6..8373a15190 100644 --- a/vscode/src/webviewPanel.ts +++ b/vscode/src/webviewPanel.ts @@ -25,6 +25,7 @@ import { getActiveProgram } from "./programConfig"; import { EventType, sendTelemetryEvent } from "./telemetry"; import { getRandomGuid } from "./utils"; import { getPauliNoiseModel } from "./config"; +import { qsharpExtensionId } from "./common"; const QSharpWebViewType = "qsharp-webview"; const compilerRunTimeoutMs = 1000 * 60 * 5; // 5 minutes @@ -43,7 +44,7 @@ export function registerWebViewCommands(context: ExtensionContext) { ).toString(); context.subscriptions.push( - commands.registerCommand("qsharp-vscode.showRe", async () => { + commands.registerCommand(`${qsharpExtensionId}.showRe`, async () => { clearCommandDiagnostics(); const associationId = getRandomGuid(); sendTelemetryEvent( @@ -271,7 +272,7 @@ export function registerWebViewCommands(context: ExtensionContext) { ); context.subscriptions.push( - commands.registerCommand("qsharp-vscode.showHelp", async () => { + commands.registerCommand(`${qsharpExtensionId}.showHelp`, async () => { const message = { command: "help", }; @@ -280,7 +281,7 @@ export function registerWebViewCommands(context: ExtensionContext) { ); context.subscriptions.push( - commands.registerCommand("qsharp-vscode.showHistogram", async () => { + commands.registerCommand(`${qsharpExtensionId}.showHistogram`, async () => { clearCommandDiagnostics(); const associationId = getRandomGuid(); @@ -372,7 +373,7 @@ export function registerWebViewCommands(context: ExtensionContext) { context.subscriptions.push( commands.registerCommand( - "qsharp-vscode.showCircuit", + `${qsharpExtensionId}.showCircuit`, async (operation?: IOperationInfo) => { await showCircuitCommand(context.extensionUri, operation); }, @@ -380,9 +381,12 @@ export function registerWebViewCommands(context: ExtensionContext) { ); context.subscriptions.push( - commands.registerCommand("qsharp-vscode.showDocumentation", async () => { - await showDocumentationCommand(context.extensionUri); - }), + commands.registerCommand( + `${qsharpExtensionId}.showDocumentation`, + async () => { + await showDocumentationCommand(context.extensionUri); + }, + ), ); } diff --git a/vscode/test/suites/debugger/debugger.test.ts b/vscode/test/suites/debugger/debugger.test.ts index 90447ef074..8ba06cd821 100644 --- a/vscode/test/suites/debugger/debugger.test.ts +++ b/vscode/test/suites/debugger/debugger.test.ts @@ -5,6 +5,7 @@ import * as vscode from "vscode"; import { assert } from "chai"; import { activateExtension, waitForCondition } from "../extensionUtils"; import { DebugProtocol } from "@vscode/debugprotocol"; +import { qsharpExtensionId } from "../../../src/common"; /** * Set to true to log Debug Adapter Protocol messages to the console. @@ -47,7 +48,9 @@ suite("Q# Debugger Tests", function suite() { await vscode.window.showTextDocument(fooUri); // launch debugger - await vscode.commands.executeCommand("qsharp-vscode.debugEditorContents"); + await vscode.commands.executeCommand( + `${qsharpExtensionId}.debugEditorContents`, + ); await waitUntilPaused([ {