Skip to content

Commit 41ef467

Browse files
committed
Use terminal link providers also as document link providers for 'vscode-test-data' scheme
See microsoft/vscode#157500 (comment). Fixes #4089.
1 parent 119acb3 commit 41ef467

8 files changed

Lines changed: 76 additions & 119 deletions

File tree

‎src/extension/extension.ts‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ import { PubGlobal } from "./pub/global";
101101
import { StatusBarVersionTracker } from "./sdk/status_bar_version_tracker";
102102
import { checkForStandardDartSdkUpdates } from "./sdk/update_check";
103103
import { SdkUtils } from "./sdk/utils";
104-
import { DartFileUriTerminalLinkProvider } from "./terminal/file_uri_link_provider";
105-
import { DartPackageUriTerminalLinkProvider } from "./terminal/package_uri_link_provider";
104+
import { DartFileUriLinkProvider } from "./terminal/file_uri_link_provider";
105+
import { DartPackageUriLinkProvider } from "./terminal/package_uri_link_provider";
106106
import { VsCodeTestController } from "./test/vs_test_controller";
107107
import { handleNewProjects, showUserPrompts } from "./user_prompts";
108108
import * as util from "./utils";
@@ -649,9 +649,16 @@ export async function activate(context: vs.ExtensionContext, isRestart: boolean
649649
context.subscriptions.push(new LspEditCommands(lspAnalyzer));
650650
}
651651

652-
if (vs.window.registerTerminalLinkProvider) { // Temporary workaround for GitPod/Theia not having this.
653-
context.subscriptions.push(vs.window.registerTerminalLinkProvider(new DartPackageUriTerminalLinkProvider(logger, workspaceContext)));
654-
context.subscriptions.push(vs.window.registerTerminalLinkProvider(new DartFileUriTerminalLinkProvider()));
652+
const packageLinkProvider = new DartPackageUriLinkProvider(logger, workspaceContext);
653+
const fileLinkProvider = new DartFileUriLinkProvider();
654+
if (vs.window.registerTerminalLinkProvider) { // Workaround for GitPod/Theia not having this.
655+
context.subscriptions.push(vs.window.registerTerminalLinkProvider(packageLinkProvider));
656+
context.subscriptions.push(vs.window.registerTerminalLinkProvider(fileLinkProvider));
657+
}
658+
659+
if (vs.languages.registerDocumentLinkProvider) {
660+
vs.languages.registerDocumentLinkProvider({ scheme: "vscode-test-data" }, packageLinkProvider);
661+
vs.languages.registerDocumentLinkProvider({ scheme: "vscode-test-data" }, fileLinkProvider);
655662
}
656663

657664
// Register our view providers.
Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
11
import * as vs from "vscode";
22
import { fsPath } from "../../shared/utils/fs";
3-
import { DartFileUriTerminalLink, findFileUriLinks } from "../../shared/vscode/terminal_link_provider_utils";
3+
import { DartFileUriLink, findFileUriLinks, formatLineColFragment } from "../../shared/vscode/terminal_link_provider_utils";
44

55

6-
export class DartFileUriTerminalLinkProvider implements vs.TerminalLinkProvider<DartFileUriTerminalLink> {
7-
public async provideTerminalLinks(context: vs.TerminalLinkContext, token: vs.CancellationToken): Promise<DartFileUriTerminalLink[]> {
8-
return findFileUriLinks(context.line);
6+
export class DartFileUriLinkProvider implements vs.TerminalLinkProvider<DartFileUriLink>, vs.DocumentLinkProvider<vs.DocumentLink> {
7+
public async provideTerminalLinks(context: vs.TerminalLinkContext, token: vs.CancellationToken): Promise<DartFileUriLink[]> {
8+
return this.getLinks(context.line);
99
}
1010

11-
public handleTerminalLink(link: DartFileUriTerminalLink): vs.ProviderResult<void> {
11+
private getLinks(content: string) {
12+
return findFileUriLinks(content);
13+
}
14+
15+
public handleTerminalLink(link: DartFileUriLink): vs.ProviderResult<void> {
1216
const filePath = fsPath(link.uri);
1317
vs.commands.executeCommand("_dart.jumpToLineColInUri", vs.Uri.file(filePath), link.line, link.col);
1418
}
19+
20+
public async provideDocumentLinks(document: vs.TextDocument, token: vs.CancellationToken): Promise<vs.DocumentLink[]> {
21+
const links = await this.getLinks(document.getText());
22+
23+
return links.map((link) => {
24+
const range = new vs.Range(document.positionAt(link.startIndex), document.positionAt(link.startIndex + link.length));
25+
return new vs.DocumentLink(range, link.uri.with({ fragment: formatLineColFragment(link) }));
26+
});
27+
}
1528
}
29+
30+

‎src/extension/terminal/package_uri_link_provider.ts‎

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import * as vs from "vscode";
22
import { Logger } from "../../shared/interfaces";
33
import { PackageMap } from "../../shared/pub/package_map";
4-
import { DartPackageUriTerminalLink, findPackageUriLinks } from "../../shared/vscode/terminal_link_provider_utils";
4+
import { notUndefined } from "../../shared/utils";
5+
import { DartPackageUriLink, findPackageUriLinks, formatLineColFragment } from "../../shared/vscode/terminal_link_provider_utils";
56
import { getAllProjectFolders } from "../../shared/vscode/utils";
67
import { WorkspaceContext } from "../../shared/workspace";
78
import { config } from "../config";
89
import { getExcludedFolders } from "../utils";
910

1011

11-
export class DartPackageUriTerminalLinkProvider implements vs.TerminalLinkProvider<DartPackageUriTerminalLink> {
12+
export class DartPackageUriLinkProvider implements vs.TerminalLinkProvider<DartPackageUriLink>, vs.DocumentLinkProvider<vs.DocumentLink> {
1213
packageMaps: { [key: string]: PackageMap } | undefined;
1314
packageMapDiscovery: Promise<void> | undefined;
1415

@@ -49,14 +50,18 @@ export class DartPackageUriTerminalLinkProvider implements vs.TerminalLinkProvid
4950
return undefined;
5051
}
5152

52-
public async provideTerminalLinks(context: vs.TerminalLinkContext, token: vs.CancellationToken): Promise<DartPackageUriTerminalLink[]> {
53+
public provideTerminalLinks(context: vs.TerminalLinkContext, token: vs.CancellationToken): Promise<DartPackageUriLink[]> {
54+
return this.getLinks(context.line);
55+
}
56+
57+
private async getLinks(content: string) {
5358
if (!this.packageMaps)
5459
await this.discoverPackageMaps();
5560

56-
return findPackageUriLinks(context.line, (name) => this.isKnownPackage(name));
61+
return findPackageUriLinks(content, (name) => this.isKnownPackage(name));
5762
}
5863

59-
public handleTerminalLink(link: DartPackageUriTerminalLink): vs.ProviderResult<void> {
64+
public handleTerminalLink(link: DartPackageUriLink): vs.ProviderResult<void> {
6065
const filePath = this.resolvePackageUri(link.uri);
6166
if (!filePath) {
6267
vs.window.showErrorMessage(`Unable to find root for package ${link.packageName}`);
@@ -65,4 +70,17 @@ export class DartPackageUriTerminalLinkProvider implements vs.TerminalLinkProvid
6570

6671
vs.commands.executeCommand("_dart.jumpToLineColInUri", vs.Uri.file(filePath), link.line, link.col);
6772
}
73+
74+
public async provideDocumentLinks(document: vs.TextDocument, token: vs.CancellationToken): Promise<vs.DocumentLink[]> {
75+
const links = await this.getLinks(document.getText());
76+
77+
return links.map((link) => {
78+
const range = new vs.Range(document.positionAt(link.startIndex), document.positionAt(link.startIndex + link.length));
79+
const filePath = this.resolvePackageUri(link.uri);
80+
if (!filePath)
81+
return undefined;
82+
return new vs.DocumentLink(range, vs.Uri.file(filePath).with({ fragment: formatLineColFragment(link) }));
83+
}).filter(notUndefined);
84+
}
85+
6886
}

‎src/extension/test/vs_test_controller.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { GroupNode, SuiteData, SuiteNode, TestEventListener, TestModel, TestNode
66
import { ErrorNotification, PrintNotification } from "../../shared/test_protocol";
77
import { disposeAll, notUndefined } from "../../shared/utils";
88
import { fsPath } from "../../shared/utils/fs";
9-
import { rewriteUrisForTestOutput } from "../../shared/utils/test";
109
import { config } from "../config";
1110
import { TestDiscoverer } from "../lsp/test_discoverer";
1211
import { formatForTerminal } from "../utils/vscode/terminals";
@@ -321,7 +320,7 @@ export class VsCodeTestController implements TestEventListener, IAmDisposable {
321320
public appendTestOutputLines(run: vs.TestRun, item: vs.TestItem, message: string) {
322321
if (message.trim() === "")
323322
return;
324-
run.appendOutput(`${formatForTerminal(rewriteUrisForTestOutput(message))}\r\n`, undefined, item);
323+
run.appendOutput(`${formatForTerminal(message)}\r\n`, undefined, item);
325324
}
326325

327326
public testDone(sessionID: string, node: TestNode, result: "skipped" | "success" | "failure" | "error" | undefined): void {

‎src/shared/utils/test.ts‎

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,3 @@ export function extractTestNameFromOutline(elementName: string): string | undefi
118118

119119
return elementName;
120120
}
121-
122-
/// Rewrites file:/// URIs that use the format `file.dart:1:2` so that VS Code will
123-
/// handle them correctly when Ctrl+Clicked.
124-
///
125-
/// https://github.com/Dart-Code/Dart-Code/issues/4089
126-
/// https://github.com/microsoft/vscode/issues/150702
127-
/// https://github.com/microsoft/vscode/issues/157500
128-
export function rewriteUrisForTestOutput(message: string): string {
129-
const uriColonRegex = new RegExp("((?:file:\\/\\/|package:).*?\\.dart):(\\d+):(\\d+)", "g");
130-
const uriSpaceLine = new RegExp("((?:file:\\/\\/|package:).*?\\.dart) line (\\d+)", "g");
131-
return message
132-
.replace(uriColonRegex, "$1#$2,$3")
133-
.replace(uriSpaceLine, "$1#$2");
134-
}

‎src/shared/vscode/terminal_link_provider_utils.ts‎

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import * as vs from "vscode";
22

3-
const fileUriPattern = new RegExp("(?<uri>file:\\/{3}\\S+[\\/]\\S+\\.dart)(?:[: ](?<line>\\d+):(?<col>\\d+))?", "mg");
4-
const packageUriPattern = new RegExp("(?<uri>package:\\S+[\\/]\\S+\\.dart)(?:[: ](?<line>\\d+):(?<col>\\d+))?", "mg");
3+
const fileUriPattern = new RegExp("(?<uri>file:\\/{3}\\S+[\\/]\\S+\\.dart)(?:(?:[: ]| line )(?<line>\\d+)(?::(?<col>\\d+))?)?", "mg");
4+
const packageUriPattern = new RegExp("(?<uri>package:\\S+[\\/]\\S+\\.dart)(?:(?:[: ]| line )(?<line>\\d+)(?::(?<col>\\d+))?)?", "mg");
55

6-
export async function findPackageUriLinks(line: string, isKnownPackage: (packageName: string) => boolean): Promise<DartPackageUriTerminalLink[]> {
7-
const results: DartPackageUriTerminalLink[] = [];
6+
export async function findPackageUriLinks(content: string, isKnownPackage: (packageName: string) => boolean): Promise<DartPackageUriLink[]> {
7+
const results: DartPackageUriLink[] = [];
88
packageUriPattern.lastIndex = -1;
99
let result: RegExpExecArray | null;
1010
// tslint:disable-next-line: no-conditional-assignment
11-
while ((result = packageUriPattern.exec(line)) && result.groups) {
11+
while ((result = packageUriPattern.exec(content)) && result.groups) {
1212
let uri: vs.Uri | undefined;
1313
try {
1414
uri = vs.Uri.parse(result.groups.uri, true);
@@ -40,8 +40,8 @@ export async function findPackageUriLinks(line: string, isKnownPackage: (package
4040
return results;
4141
}
4242

43-
export async function findFileUriLinks(line: string): Promise<DartFileUriTerminalLink[]> {
44-
const results: DartFileUriTerminalLink[] = [];
43+
export async function findFileUriLinks(line: string): Promise<DartFileUriLink[]> {
44+
const results: DartFileUriLink[] = [];
4545
fileUriPattern.lastIndex = -1;
4646
let result: RegExpExecArray | null;
4747
// tslint:disable-next-line: no-conditional-assignment
@@ -73,8 +73,16 @@ export async function findFileUriLinks(line: string): Promise<DartFileUriTermina
7373
return results;
7474
}
7575

76+
export function formatLineColFragment(link: { line: number | undefined, col: number | undefined }) {
77+
if (link.line !== undefined && link.col !== undefined)
78+
return `${link.line},${link.col}`;
79+
else if (!link.line !== undefined)
80+
return `${link.line}`;
81+
else
82+
return "";
83+
}
7684

77-
export interface DartFileUriTerminalLink extends vs.TerminalLink {
85+
export interface DartFileUriLink {
7886
startIndex: number;
7987
length: number;
8088
tooltip: string;
@@ -84,7 +92,7 @@ export interface DartFileUriTerminalLink extends vs.TerminalLink {
8492
}
8593

8694

87-
export interface DartPackageUriTerminalLink extends vs.TerminalLink {
95+
export interface DartPackageUriLink {
8896
startIndex: number;
8997
length: number;
9098
tooltip: string;

‎src/test/dart/providers/terminal_link_providers.test.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ describe("DartFileUriTerminalLinkProvider", () => {
1414
await expectLink("file:///foo/bar.dart", "/foo/bar.dart");
1515
await expectLink("file:///foo/bar.dart:5:8", "/foo/bar.dart", 5, 8);
1616
await expectLink("file:///foo/bar.dart 5:8", "/foo/bar.dart", 5, 8);
17+
await expectLink("file:///foo/bar.dart line 5", "/foo/bar.dart", 5);
1718
await expectLink("aaa file:///foo/bar.dart:5:8 bbb", "/foo/bar.dart", 5, 8);
1819
});
1920

@@ -23,6 +24,7 @@ describe("DartFileUriTerminalLinkProvider", () => {
2324
await expectLink("file:///C:/foo/bar.dart", "C:\\foo\\bar.dart");
2425
await expectLink("file:///C:/foo/bar.dart:5:8", "C:\\foo\\bar.dart", 5, 8);
2526
await expectLink("file:///C:/foo/bar.dart 5:8", "C:\\foo\\bar.dart", 5, 8);
27+
await expectLink("file:///C:/foo/bar.dart line 5", "C:\\foo\\bar.dart", 5);
2628
await expectLink("aaa file:///C:/foo/bar.dart:5:8 bbb", "C:\\foo\\bar.dart", 5, 8);
2729
});
2830

@@ -32,6 +34,7 @@ describe("DartFileUriTerminalLinkProvider", () => {
3234
await expectLink("file:///c:/foo/bar.dart", "C:\\foo\\bar.dart");
3335
await expectLink("file:///c:/foo/bar.dart:5:8", "C:\\foo\\bar.dart", 5, 8);
3436
await expectLink("file:///c:/foo/bar.dart 5:8", "C:\\foo\\bar.dart", 5, 8);
37+
await expectLink("file:///c:/foo/bar.dart line 5", "C:\\foo\\bar.dart", 5);
3538
await expectLink("aaa file:///c:/foo/bar.dart:5:8 bbb", "C:\\foo\\bar.dart", 5, 8);
3639
});
3740

‎src/test/dart/utils/test.test.ts‎

Lines changed: 0 additions & 79 deletions
This file was deleted.

0 commit comments

Comments
 (0)