Skip to content

Commit 5f1a6ed

Browse files
Add a terminal provider to detect the Java stacktrace printed in terminal (#890)
1 parent 0755aa2 commit 5f1a6ed

File tree

6 files changed

+74
-5
lines changed

6 files changed

+74
-5
lines changed

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"debugger"
1515
],
1616
"engines": {
17-
"vscode": "^1.47.3"
17+
"vscode": "^1.49.0"
1818
},
1919
"license": "SEE LICENSE IN LICENSE.txt",
2020
"repository": {
@@ -745,7 +745,7 @@
745745
"@types/lodash": "^4.14.137",
746746
"@types/mocha": "^5.2.7",
747747
"@types/node": "^8.10.51",
748-
"@types/vscode": "1.47.0",
748+
"@types/vscode": "1.49.0",
749749
"cross-env": "^5.2.0",
750750
"gulp": "^4.0.2",
751751
"gulp-tslint": "^8.1.4",

src/commands.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ export const JAVA_FETCH_PLATFORM_SETTINGS = "vscode.java.fetchPlatformSettings";
4242

4343
export const JAVA_RESOLVE_CLASSFILTERS = "vscode.java.resolveClassFilters";
4444

45+
export const JAVA_RESOLVE_SOURCE_URI = "vscode.java.resolveSourceUri";
46+
4547
export function executeJavaLanguageServerCommand(...rest) {
4648
return executeJavaExtensionCommand(JAVA_EXECUTE_WORKSPACE_COMMAND, ...rest);
4749
}

src/extension.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { IMainClassOption, IMainMethod, resolveMainClass, resolveMainMethod } fr
1818
import { logger, Type } from "./logger";
1919
import { mainClassPicker } from "./mainClassPicker";
2020
import { pickJavaProcess } from "./processPicker";
21+
import { JavaTerminalLinkProvder } from "./terminalLinkProvider";
2122
import { initializeThreadOperations } from "./threadOperations";
2223
import * as utility from "./utility";
2324

@@ -34,6 +35,7 @@ function initializeExtension(operationId: string, context: vscode.ExtensionConte
3435

3536
registerDebugEventListener(context);
3637
context.subscriptions.push(logger);
38+
context.subscriptions.push(vscode.window.registerTerminalLinkProvider(new JavaTerminalLinkProvder()));
3739
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider("java", new JavaDebugConfigurationProvider()));
3840
context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory("java", new JavaDebugAdapterDescriptorFactory()));
3941
context.subscriptions.push(instrumentOperationAsVsCodeCommand("JavaDebug.SpecifyProgramArgs", async () => {

src/languageServerPlugin.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,7 @@ export function fetchPlatformSettings(): any {
112112
export async function resolveClassFilters(patterns: string[]): Promise<string[]> {
113113
return <string[]> await commands.executeJavaLanguageServerCommand(commands.JAVA_RESOLVE_CLASSFILTERS, ...patterns);
114114
}
115+
116+
export async function resolveSourceUri(line: string): Promise<string> {
117+
return <string> await commands.executeJavaLanguageServerCommand(commands.JAVA_RESOLVE_SOURCE_URI, line);
118+
}

src/terminalLinkProvider.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
import { CancellationToken, commands, Position, ProviderResult, Range, TerminalLink, TerminalLinkContext,
5+
TerminalLinkProvider, Uri, window } from "vscode";
6+
import { resolveSourceUri } from "./languageServerPlugin";
7+
8+
export class JavaTerminalLinkProvder implements TerminalLinkProvider<IJavaTerminalLink> {
9+
/**
10+
* Provide terminal links for the given context. Note that this can be called multiple times
11+
* even before previous calls resolve, make sure to not share global objects (eg. `RegExp`)
12+
* that could have problems when asynchronous usage may overlap.
13+
* @param context Information about what links are being provided for.
14+
* @param token A cancellation token.
15+
* @return A list of terminal links for the given line.
16+
*/
17+
public provideTerminalLinks(context: TerminalLinkContext, token: CancellationToken): ProviderResult<IJavaTerminalLink[]> {
18+
if (context.terminal.name !== "Java Debug Console" && context.terminal.name !== "Java Process Console") {
19+
return [];
20+
}
21+
22+
const regex = new RegExp("(\\sat\\s+)([\\w$\\.]+\\/)?(([\\w$]+\\.)+[<\\w$>]+)\\(([\\w-$]+\\.java:\\d+)\\)");
23+
const result: RegExpExecArray = regex.exec(context.line);
24+
if (result && result.length) {
25+
const stackTrace = `${result[2] || ""}${result[3]}(${result[5]})`;
26+
const sourceLineNumber = Number(result[5].split(":")[1]);
27+
return [{
28+
startIndex: result.index + result[1].length,
29+
length: stackTrace.length,
30+
methodName: result[3],
31+
stackTrace,
32+
lineNumber: sourceLineNumber,
33+
}];
34+
}
35+
}
36+
37+
/**
38+
* Handle an activated terminal link.
39+
*/
40+
public async handleTerminalLink(link: IJavaTerminalLink): Promise<void> {
41+
const uri = await resolveSourceUri(link.stackTrace);
42+
if (uri) {
43+
const lineNumber = Math.max(link.lineNumber - 1, 0);
44+
window.showTextDocument(Uri.parse(uri), {
45+
preserveFocus: true,
46+
selection: new Range(new Position(lineNumber, 0), new Position(lineNumber, 0)),
47+
});
48+
} else {
49+
// If no source is found, then open the searching symbols quickpick box.
50+
const fullyQualifiedName = link.methodName.substring(0, link.methodName.lastIndexOf("."));
51+
const className = fullyQualifiedName.substring(fullyQualifiedName.lastIndexOf(".") + 1);
52+
commands.executeCommand("workbench.action.quickOpen", "#" + className);
53+
}
54+
}
55+
}
56+
57+
interface IJavaTerminalLink extends TerminalLink {
58+
methodName: string;
59+
stackTrace: string;
60+
lineNumber: number;
61+
}

0 commit comments

Comments
 (0)