Skip to content

Commit 6cf6e7d

Browse files
committed
Refactoring TS integration
1 parent 817278f commit 6cf6e7d

17 files changed

+274
-672
lines changed

vscode/package.json

+48-169
Large diffs are not rendered by default.

vscode/src/common.ts

+29-38
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the MIT License.
33

44
import { TextDocument, Uri, Range, Location } from "vscode";
5-
import { Utils } from "vscode-uri";
65
import {
76
getCompilerWorker,
87
ICompilerWorker,
@@ -17,65 +16,57 @@ export const qsharpLanguageId = "qsharp";
1716
export const qsharpCircuitLanguageId = "qsharpcircuit";
1817
export const openqasmLanguageId = "openqasm";
1918

20-
// Returns true for all Q# documents, including unsaved files, notebook cells, circuit files, etc.
21-
export function isQsharpDocument(document: TextDocument): boolean {
19+
// Returns true for all documents supported by the extension, including unsaved files, notebook cells, circuit files, qasm files, etc.
20+
// excludes text documents we don't want to add support for at all, such as git/pr/chat "virtual" document views
21+
export function isQdkDocument(document: TextDocument): boolean {
2222
return (
23-
(document.languageId === qsharpLanguageId &&
24-
(Utils.extname(document.uri) === ".qs" || document.isUntitled) &&
25-
document.uri.scheme !== "git" &&
26-
document.uri.scheme !== "pr" &&
27-
// The Copilot Chat window also creates documents with various schemes that start
28-
// with "chat", such as "chat-editing-text-model" and others.
29-
!document.uri.scheme.startsWith("chat")) ||
30-
isCircuitDocument(document)
23+
!isUnsupportedScheme(document.uri.scheme) &&
24+
isQdkSupportedLanguage(document)
3125
);
3226
}
3327

34-
// Returns true for all circuit documents
35-
export function isCircuitDocument(document: TextDocument): boolean {
28+
function isQdkSupportedLanguage(document: TextDocument): boolean {
3629
return (
37-
document.languageId === qsharpCircuitLanguageId &&
38-
(Utils.extname(document.uri) === ".qsc" || document.isUntitled) &&
39-
document.uri.scheme !== "git" &&
40-
document.uri.scheme !== "pr" &&
41-
// The Copilot Chat window also creates documents with various schemes that start
42-
// with "chat", such as "chat-editing-text-model" and others.
43-
!document.uri.scheme.startsWith("chat")
30+
document.languageId === qsharpLanguageId ||
31+
document.languageId === qsharpCircuitLanguageId ||
32+
document.languageId === openqasmLanguageId
4433
);
4534
}
4635

47-
// Returns true for only Q# notebook cell documents.
48-
export function isQsharpNotebookCell(document: TextDocument): boolean {
36+
function isUnsupportedScheme(scheme: string): boolean {
37+
return scheme === "git" || scheme === "pr" || scheme.startsWith("chat");
38+
}
39+
40+
// Returns true for all Q# documents, including unsaved files, notebook cells, circuit files, etc.
41+
export function isQsharpDocument(document: TextDocument): boolean {
4942
return (
50-
document.languageId === qsharpLanguageId &&
51-
document.uri.scheme === "vscode-notebook-cell"
43+
!isUnsupportedScheme(document.uri.scheme) &&
44+
document.languageId === qsharpLanguageId
5245
);
5346
}
5447

55-
// Returns true for only Q# notebook cell documents.
56-
export function isOpenQasmNotebookCell(document: TextDocument): boolean {
48+
// Returns true for all circuit documents
49+
export function isCircuitDocument(document: TextDocument): boolean {
5750
return (
58-
document.languageId === openqasmLanguageId &&
59-
document.uri.scheme === "vscode-notebook-cell"
51+
!isUnsupportedScheme(document.uri.scheme) &&
52+
document.languageId === qsharpCircuitLanguageId
6053
);
6154
}
6255

56+
export function isQdkNotebookCell(document: TextDocument): boolean {
57+
return isQdkDocument(document) && isNotebookCell(document);
58+
}
59+
6360
// Returns true for all OpenQASM documents, including unsaved files, notebook cells, etc.
6461
export function isOpenQasmDocument(document: TextDocument): boolean {
6562
return (
66-
document.languageId === openqasmLanguageId &&
67-
(hasOpenQasmExt(document.uri) || document.isUntitled) &&
68-
document.uri.scheme !== "git" &&
69-
document.uri.scheme !== "pr" &&
70-
// The Copilot Chat window also creates documents with various schemes that start
71-
// with "chat", such as "chat-editing-text-model" and others.
72-
!document.uri.scheme.startsWith("chat")
63+
!isUnsupportedScheme(document.uri.scheme) &&
64+
document.languageId === openqasmLanguageId
7365
);
7466
}
7567

76-
export function hasOpenQasmExt(uri: vscode.Uri): boolean {
77-
const ext = Utils.extname(uri);
78-
return ext === ".qasm" || ext === ".inc";
68+
export function isNotebookCell(document: TextDocument): boolean {
69+
return document.uri.scheme === "vscode-notebook-cell";
7970
}
8071

8172
export const qsharpExtensionId = "qsharp-vscode";

vscode/src/debugger/activate.ts

+22-188
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ import { qsharpExtensionId } from "../common";
99
import { clearCommandDiagnostics } from "../diagnostics";
1010
import {
1111
FullProgramConfigOrError,
12-
getActiveOpenQasmDocumentUri,
13-
getActiveQSharpDocumentUri,
14-
getOpenQasmProgramForDocument,
15-
getQSharpProgramForDocument,
12+
getActiveQdkDocumentUri,
13+
getProgramForDocument,
1614
} from "../programConfig";
1715
import { getRandomGuid } from "../utils";
1816
import { QscDebugSession } from "./session";
@@ -35,29 +33,15 @@ export async function activateDebugger(
3533

3634
const provider = new QsDebugConfigProvider();
3735
context.subscriptions.push(
38-
vscode.debug.registerDebugConfigurationProvider("qsharp", provider),
36+
vscode.debug.registerDebugConfigurationProvider("qdk", provider),
3937
);
4038

41-
const factory = new InlineDebugAdapterFactory((uri) =>
42-
getQSharpProgramForDocument(uri),
43-
);
39+
const factory = new InlineDebugAdapterFactory(async (uri) => {
40+
const file = await vscode.workspace.openTextDocument(uri);
41+
return getProgramForDocument(file);
42+
});
4443
context.subscriptions.push(
45-
vscode.debug.registerDebugAdapterDescriptorFactory("qsharp", factory),
46-
);
47-
48-
const qasm_provider = new OpenQasmDebugConfigProvider();
49-
context.subscriptions.push(
50-
vscode.debug.registerDebugConfigurationProvider("openqasm", qasm_provider),
51-
);
52-
53-
const qasm_factory = new InlineDebugAdapterFactory((uri) =>
54-
getOpenQasmProgramForDocument(uri),
55-
);
56-
context.subscriptions.push(
57-
vscode.debug.registerDebugAdapterDescriptorFactory(
58-
"openqasm",
59-
qasm_factory,
60-
),
44+
vscode.debug.registerDebugAdapterDescriptorFactory("qdk", factory),
6145
);
6246
}
6347

@@ -72,9 +56,9 @@ function registerCommands(context: vscode.ExtensionContext) {
7256
if (typeof expr !== "string") {
7357
expr = undefined;
7458
}
75-
startQSharpDebugging(
59+
startQdkDebugging(
7660
resource,
77-
{ name: "Run Q# File", stopOnEntry: false, entry: expr },
61+
{ name: "Run File", stopOnEntry: false, entry: expr },
7862
{ noDebug: true },
7963
);
8064
},
@@ -87,8 +71,8 @@ function registerCommands(context: vscode.ExtensionContext) {
8771
if (typeof expr !== "string") {
8872
expr = undefined;
8973
}
90-
startQSharpDebugging(resource, {
91-
name: "Debug Q# File",
74+
startQdkDebugging(resource, {
75+
name: "Debug File",
9276
stopOnEntry: true,
9377
entry: expr,
9478
});
@@ -97,7 +81,7 @@ function registerCommands(context: vscode.ExtensionContext) {
9781
vscode.commands.registerCommand(
9882
`${qsharpExtensionId}.runEditorContentsWithCircuit`,
9983
(resource: vscode.Uri) =>
100-
startQSharpDebugging(
84+
startQdkDebugging(
10185
resource,
10286
{
10387
name: "Run file and show circuit diagram",
@@ -109,97 +93,31 @@ function registerCommands(context: vscode.ExtensionContext) {
10993
),
11094
);
11195

112-
function startQSharpDebugging(
96+
function startQdkDebugging(
11397
resource: vscode.Uri | undefined,
11498
config: { name: string; [key: string]: any },
11599
options?: vscode.DebugSessionOptions,
116100
) {
117101
clearCommandDiagnostics();
118102

119-
if (vscode.debug.activeDebugSession?.type === "qsharp") {
103+
if (vscode.debug.activeDebugSession?.type === "qdk") {
120104
// Multiple debug sessions disallowed, to reduce confusion
121105
return;
122106
}
123107

124-
const targetResource = resource || getActiveQSharpDocumentUri();
125-
126-
if (targetResource) {
127-
config.programUri = targetResource.toString();
128-
129-
vscode.debug.startDebugging(
130-
undefined,
131-
{
132-
type: "qsharp",
133-
request: "launch",
134-
shots: 1,
135-
...config,
136-
},
137-
{
138-
// no need to save the file, in fact better not to, since it may cause the document uri to change
139-
suppressSaveBeforeStart: true,
140-
...options,
141-
},
142-
);
143-
}
144-
}
145-
146-
// Register commands for running and debugging OpenQASM files.
147-
context.subscriptions.push(
148-
vscode.commands.registerCommand(
149-
`${qsharpExtensionId}.openqasm.runEditorContents`,
150-
(resource: vscode.Uri) => {
151-
startOpenQasmDebugging(
152-
resource,
153-
{ name: "Run OpenQASM File", stopOnEntry: false },
154-
{ noDebug: true },
155-
);
156-
},
157-
),
158-
vscode.commands.registerCommand(
159-
`${qsharpExtensionId}.openqasm.debugEditorContents`,
160-
(resource: vscode.Uri) => {
161-
startOpenQasmDebugging(resource, {
162-
name: "Debug OpenQASM File",
163-
stopOnEntry: true,
164-
});
165-
},
166-
),
167-
vscode.commands.registerCommand(
168-
`${qsharpExtensionId}.openqasm.runEditorContentsWithCircuit`,
169-
(resource: vscode.Uri) =>
170-
startOpenQasmDebugging(
171-
resource,
172-
{
173-
name: "Run file and show circuit diagram",
174-
stopOnEntry: false,
175-
showCircuit: true,
176-
},
177-
{ noDebug: true },
178-
),
179-
),
180-
);
181-
182-
function startOpenQasmDebugging(
183-
resource: vscode.Uri | undefined,
184-
config: { name: string; [key: string]: any },
185-
options?: vscode.DebugSessionOptions,
186-
) {
187-
clearCommandDiagnostics();
188-
189-
if (vscode.debug.activeDebugSession?.type === "openqasm") {
190-
// Multiple debug sessions disallowed, to reduce confusion
108+
const targetResource = resource || getActiveQdkDocumentUri();
109+
if (!targetResource) {
110+
// No active document
191111
return;
192112
}
193113

194-
const targetResource = resource || getActiveOpenQasmDocumentUri();
195-
196114
if (targetResource) {
197115
config.programUri = targetResource.toString();
198116

199117
vscode.debug.startDebugging(
200118
undefined,
201119
{
202-
type: "openqasm",
120+
type: "qdk",
203121
request: "launch",
204122
shots: 1,
205123
...config,
@@ -245,9 +163,9 @@ class QsDebugConfigProvider implements vscode.DebugConfigurationProvider {
245163
.toString();
246164
} else {
247165
// if launch.json is missing or empty, try to launch the active Q# document
248-
const docUri = getActiveQSharpDocumentUri();
166+
const docUri = getActiveQdkDocumentUri();
249167
if (docUri) {
250-
config.type = "qsharp";
168+
config.type = "qdk";
251169
config.name = "Launch";
252170
config.request = "launch";
253171
config.programUri = docUri.toString();
@@ -283,7 +201,7 @@ class QsDebugConfigProvider implements vscode.DebugConfigurationProvider {
283201
_token?: vscode.CancellationToken | undefined,
284202
): vscode.ProviderResult<vscode.DebugConfiguration> {
285203
// apply defaults if not set
286-
config.type = config.type ?? "qsharp";
204+
config.type = "qdk";
287205
config.name = config.name ?? "Launch";
288206
config.request = config.request ?? "launch";
289207
config.shots = config.shots ?? 1;
@@ -300,90 +218,6 @@ class QsDebugConfigProvider implements vscode.DebugConfigurationProvider {
300218
}
301219
}
302220

303-
class OpenQasmDebugConfigProvider implements vscode.DebugConfigurationProvider {
304-
resolveDebugConfigurationWithSubstitutedVariables(
305-
folder: vscode.WorkspaceFolder | undefined,
306-
config: vscode.DebugConfiguration,
307-
_token?: vscode.CancellationToken | undefined,
308-
): vscode.ProviderResult<vscode.DebugConfiguration> {
309-
if (config.program && folder) {
310-
// A program is specified in launch.json.
311-
//
312-
// Variable substitution is a bit odd in VS Code. Variables such as
313-
// ${file} and ${workspaceFolder} are expanded to absolute filesystem
314-
// paths with platform-specific separators. To correctly convert them
315-
// back to a URI, we need to use the vscode.Uri.file constructor.
316-
//
317-
// However, this gives us the URI scheme file:// , which is not correct
318-
// when the workspace uses a virtual filesystem such as qsharp-vfs://
319-
// or vscode-test-web://. So now we also need the workspace folder URI
320-
// to use as the basis for our file URI.
321-
//
322-
// Examples of program paths that can come through variable substitution:
323-
// C:\foo\bar.qs
324-
// \foo\bar.qs
325-
// /foo/bar.qs
326-
const fileUri = vscode.Uri.file(config.program);
327-
config.programUri = folder.uri
328-
.with({
329-
path: fileUri.path,
330-
})
331-
.toString();
332-
} else {
333-
// if launch.json is missing or empty, try to launch the active Q# document
334-
const docUri = getActiveOpenQasmDocumentUri();
335-
if (docUri) {
336-
config.type = "openqasm";
337-
config.name = "Launch";
338-
config.request = "launch";
339-
config.programUri = docUri.toString();
340-
config.shots = 1;
341-
config.noDebug = "noDebug" in config ? config.noDebug : false;
342-
config.stopOnEntry = !config.noDebug;
343-
}
344-
}
345-
346-
log.trace(
347-
`resolveDebugConfigurationWithSubstitutedVariables config.program=${
348-
config.program
349-
} folder.uri=${folder?.uri.toString()} config.programUri=${
350-
config.programUri
351-
}`,
352-
);
353-
354-
if (!config.programUri) {
355-
// abort launch
356-
return vscode.window
357-
.showInformationMessage("Cannot find a OpenQASM program to debug")
358-
.then((_) => {
359-
return undefined;
360-
});
361-
}
362-
return config;
363-
}
364-
365-
resolveDebugConfiguration(
366-
folder: vscode.WorkspaceFolder | undefined,
367-
config: vscode.DebugConfiguration,
368-
_token?: vscode.CancellationToken | undefined,
369-
): vscode.ProviderResult<vscode.DebugConfiguration> {
370-
// apply defaults if not set
371-
config.type = config.type ?? "openqasm";
372-
config.name = config.name ?? "Launch";
373-
config.request = config.request ?? "launch";
374-
config.shots = config.shots ?? 1;
375-
config.trace = config.trace ?? false;
376-
// noDebug is set to true when the user runs the program without debugging.
377-
// otherwise it usually isn't set, but we default to false.
378-
config.noDebug = config.noDebug ?? false;
379-
// stopOnEntry is set to true when the user runs the program with debugging.
380-
// unless overridden.
381-
config.stopOnEntry = config.stopOnEntry ?? !config.noDebug;
382-
383-
return config;
384-
}
385-
}
386-
387221
class InlineDebugAdapterFactory
388222
implements vscode.DebugAdapterDescriptorFactory
389223
{

0 commit comments

Comments
 (0)