Skip to content

Commit

Permalink
Paths are normalized for Uri parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
idavis committed Aug 15, 2023
1 parent ce5e721 commit 4f9bf97
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 52 deletions.
12 changes: 8 additions & 4 deletions vscode/src/common.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { DocumentFilter } from "vscode";
import { DocumentFilter, TextDocument, Uri } from "vscode";

export const qsharpLanguageId = "qsharp";
// Matches all Q# documents, including unsaved files, notebook cells, etc.
Expand All @@ -16,7 +16,11 @@ export const qsharpNotebookCellDocumentFilter: DocumentFilter = {
export const qsharpExtensionId = "qsharp-vscode";

export interface FileAccessor {
readFile(uri: string): Promise<Uint8Array>;
readFileAsString(uri: string): Promise<string>;
writeFile(uri: string, contents: Uint8Array): Promise<void>;
normalizePath(path: string): string;
resolvePathToUri(path: string): Uri;
openFile(path: string): Promise<TextDocument>;
openUri(uri: Uri): Promise<TextDocument>;
readFile(path: string): Promise<Uint8Array>;
readFileAsString(path: string): Promise<string>;
writeFile(path: string, contents: Uint8Array): Promise<void>;
}
27 changes: 21 additions & 6 deletions vscode/src/debugger/activate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,30 @@ class QsDebugConfigProvider implements vscode.DebugConfigurationProvider {
}

export const workspaceFileAccessor: FileAccessor = {
async readFile(uri: string): Promise<Uint8Array> {
return await vscode.workspace.fs.readFile(vscode.Uri.parse(uri));
normalizePath(path: string): string {
return path.replace(/\\/g, "/");
},
async readFileAsString(uri: string): Promise<string> {
const contents = await this.readFile(uri);
resolvePathToUri(path: string): vscode.Uri {
const normalizedPath = this.normalizePath(path);
return vscode.Uri.parse(normalizedPath, false);
},
async openFile(path: string): Promise<vscode.TextDocument> {
const uri: vscode.Uri = this.resolvePathToUri(path);
return await vscode.workspace.openTextDocument(uri);
},
async openUri(uri: vscode.Uri): Promise<vscode.TextDocument> {
return await vscode.workspace.openTextDocument(uri);
},
async readFile(path: string): Promise<Uint8Array> {
let uri: vscode.Uri = this.resolvePathToUri(path);
return await vscode.workspace.fs.readFile(uri);
},
async readFileAsString(path: string): Promise<string> {
const contents = await this.readFile(path);
return new TextDecoder().decode(contents);
},
async writeFile(uri: string, contents: Uint8Array) {
await vscode.workspace.fs.writeFile(vscode.Uri.parse(uri), contents);
async writeFile(path: string, contents: Uint8Array) {
await vscode.workspace.fs.writeFile(this.resolvePathToUri(path), contents);
},
};

Expand Down
92 changes: 50 additions & 42 deletions vscode/src/debugger/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class QscDebugSession extends LoggingDebugSession {
private breakpoints: Map<string, DebugProtocol.Breakpoint[]>;
private variableHandles = new Handles<"locals" | "quantum">();
private failed: boolean;
private program: string;
private program: vscode.Uri;
private eventTarget: QscEventTarget;
private supportsVariableType = false;

Expand All @@ -62,7 +62,7 @@ export class QscDebugSession extends LoggingDebugSession {
) {
super();

this.program = vscode.Uri.parse(this.config.program).path;
this.program = fileAccessor.resolvePathToUri(this.config.program);
this.failed = false;
this.eventTarget = createDebugConsoleEventTarget((message) => {
this.writeToStdOut(message);
Expand All @@ -75,17 +75,20 @@ export class QscDebugSession extends LoggingDebugSession {
}

public async init(): Promise<void> {
const programText = await this.fileAccessor.readFileAsString(
this.config.program
);
const programText = (
await this.fileAccessor.openUri(this.program)
).getText();

const loaded = await this.debugService.loadSource(
this.program,
this.program.toString(),
programText
);
if (loaded) {
const locations = await this.debugService.getBreakpoints(this.program);
const locations = await this.debugService.getBreakpoints(
this.program.toString()
);
log.trace(`init breakpointLocations: %O`, locations);
this.breakpointLocations.set(this.program, locations);
this.breakpointLocations.set(this.program.toString(), locations);
} else {
log.warn(`compilation failed.`);
this.failed = true;
Expand Down Expand Up @@ -299,7 +302,7 @@ export class QscDebugSession extends LoggingDebugSession {

private getBreakpointIds(): number[] {
const bps: number[] = [];
for (const bp of this.breakpoints.get(this.program) ?? []) {
for (const bp of this.breakpoints.get(this.program.toString()) ?? []) {
if (bp && bp.id) {
bps.push(bp.id);
}
Expand Down Expand Up @@ -364,19 +367,20 @@ export class QscDebugSession extends LoggingDebugSession {
breakpoints: [],
};

const fileUri = vscode.Uri.file(args.source.path ?? "");
const file = await this.fileAccessor
.openFile(args.source.path ?? "")
.catch((e) => {
log.error(`Failed to open file: ${e}`);
const fileUri = this.fileAccessor.resolvePathToUri(
args.source.path ?? ""
);
log.trace(
"breakpointLocationsRequest, target file: " + fileUri.toString()
);
});

const file = vscode.workspace.textDocuments.find(
(td) => td.uri.path === fileUri.path
);
if (!file) {
for (const td of vscode.workspace.textDocuments) {
log.trace("breakpointLocationsRequest: potential file" + td.uri.path);
}
log.trace("breakpointLocationsRequest: target file" + fileUri.path);
}
const targetLineNumber = this.convertClientLineToDebugger(args.line);
if (fileUri && file && targetLineNumber < file.lineCount) {
if (file && targetLineNumber < file.lineCount) {
// Map request start/end line/column to file offset for debugger
const line = file.lineAt(targetLineNumber);
const lineRange = line.range;
Expand Down Expand Up @@ -406,7 +410,7 @@ export class QscDebugSession extends LoggingDebugSession {
// where the rest of the statement is on the next line(s)
const bps =
this.breakpointLocations
.get(fileUri.path)
.get(file.uri.toString())
?.filter((bp) => startOffset <= bp.lo && bp.hi <= endOffset) ?? [];

log.trace(`breakpointLocationsRequest: candidates %O`, bps);
Expand Down Expand Up @@ -439,26 +443,24 @@ export class QscDebugSession extends LoggingDebugSession {
): Promise<void> {
log.trace(`setBreakPointsRequest: %O`, args);

const fileUri = vscode.Uri.file(args.source.path ?? "");

const file = vscode.workspace.textDocuments.find(
(td) => td.uri.path === fileUri.path
);
if (!file) {
for (const td of vscode.workspace.textDocuments) {
log.trace("setBreakPointsRequest: potential file" + td.uri.path);
}
log.trace("setBreakPointsRequest: target file" + fileUri.path);
}
const file = await this.fileAccessor
.openFile(args.source.path ?? "")
.catch((e) => {
log.error(`setBreakPointsRequest - Failed to open file: ${e}`);
const fileUri = this.fileAccessor.resolvePathToUri(
args.source.path ?? ""
);
log.trace("setBreakPointsRequest, target file: " + fileUri.toString());
});

if (fileUri && file) {
if (file) {
log.trace(`setBreakPointsRequest: looking`);
this.breakpoints.set(fileUri.path, []);
this.breakpoints.set(file.uri.toString(), []);
log.trace(
`setBreakPointsRequest: files in cache %O`,
this.breakpointLocations.keys()
);
const locations = this.breakpointLocations.get(fileUri.path) ?? [];
const locations = this.breakpointLocations.get(file.uri.toString()) ?? [];
log.trace(`setBreakPointsRequest: got locations %O`, locations);
// convert the request line/column to file offset for debugger
const bpOffsets: [lo: number, hi: number][] = (args.breakpoints ?? [])
Expand Down Expand Up @@ -513,7 +515,7 @@ export class QscDebugSession extends LoggingDebugSession {
}

// Update our breakpoint list for the given file
this.breakpoints.set(fileUri.path, bps);
this.breakpoints.set(file.uri.toString(), bps);

response.body = {
breakpoints: bps,
Expand Down Expand Up @@ -544,11 +546,17 @@ export class QscDebugSession extends LoggingDebugSession {
const mappedStackFrames = await Promise.all(
debuggerStackFrames
.map(async (f, id) => {
const fileUri = vscode.Uri.file(f.path);
log.trace(`frames: fileUri %O`, fileUri);
const file = vscode.workspace.textDocuments.find(
(td) => td.uri.path === fileUri.path
);
log.trace(`frames: path %O`, f.path);

const file = await this.fileAccessor
.openFile(f.path ?? "")
.catch((e) => {
log.error(`stackTraceRequest - Failed to open file: ${e}`);
const fileUri = this.fileAccessor.resolvePathToUri(f.path ?? "");
log.trace(
"stackTraceRequest, target file: " + fileUri.toString()
);
});
if (file) {
log.trace(`frames: file %O`, file);
const start_pos = file.positionAt(f.lo);
Expand Down Expand Up @@ -582,7 +590,7 @@ export class QscDebugSession extends LoggingDebugSession {
scheme: qsharpLibraryUriScheme,
path: f.path,
});
const file = await vscode.workspace.openTextDocument(uri);
const file = await this.fileAccessor.openUri(uri);
const start_pos = file.positionAt(f.lo);
const end_pos = file.positionAt(f.hi);
const source = new Source(
Expand Down

0 comments on commit 4f9bf97

Please sign in to comment.