Add a terminal provider to detect the Java stacktrace printed in terminal (#890)

This commit is contained in:
Jinbo Wang 2020-10-12 13:51:55 +08:00 committed by GitHub
parent 0755aa2172
commit 5f1a6edc5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 5 deletions

6
package-lock.json generated
View File

@ -49,9 +49,9 @@
"dev": true
},
"@types/vscode": {
"version": "1.47.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.47.0.tgz",
"integrity": "sha512-nJA37ykkz9FYA0ZOQUSc3OZnhuzEW2vUhUEo4MiduUo82jGwwcLfyvmgd/Q7b0WrZAAceojGhZybg319L24bTA==",
"version": "1.49.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.49.0.tgz",
"integrity": "sha512-wfNQmLmm1VdMBr6iuNdprWmC1YdrgZ9dQzadv+l2eSjJlElOdJw8OTm4RU4oGTBcfvG6RZI2jOcppkdSS18mZw==",
"dev": true
},
"@webassemblyjs/ast": {

View File

@ -14,7 +14,7 @@
"debugger"
],
"engines": {
"vscode": "^1.47.3"
"vscode": "^1.49.0"
},
"license": "SEE LICENSE IN LICENSE.txt",
"repository": {
@ -745,7 +745,7 @@
"@types/lodash": "^4.14.137",
"@types/mocha": "^5.2.7",
"@types/node": "^8.10.51",
"@types/vscode": "1.47.0",
"@types/vscode": "1.49.0",
"cross-env": "^5.2.0",
"gulp": "^4.0.2",
"gulp-tslint": "^8.1.4",

View File

@ -42,6 +42,8 @@ export const JAVA_FETCH_PLATFORM_SETTINGS = "vscode.java.fetchPlatformSettings";
export const JAVA_RESOLVE_CLASSFILTERS = "vscode.java.resolveClassFilters";
export const JAVA_RESOLVE_SOURCE_URI = "vscode.java.resolveSourceUri";
export function executeJavaLanguageServerCommand(...rest) {
return executeJavaExtensionCommand(JAVA_EXECUTE_WORKSPACE_COMMAND, ...rest);
}

View File

@ -18,6 +18,7 @@ import { IMainClassOption, IMainMethod, resolveMainClass, resolveMainMethod } fr
import { logger, Type } from "./logger";
import { mainClassPicker } from "./mainClassPicker";
import { pickJavaProcess } from "./processPicker";
import { JavaTerminalLinkProvder } from "./terminalLinkProvider";
import { initializeThreadOperations } from "./threadOperations";
import * as utility from "./utility";
@ -34,6 +35,7 @@ function initializeExtension(operationId: string, context: vscode.ExtensionConte
registerDebugEventListener(context);
context.subscriptions.push(logger);
context.subscriptions.push(vscode.window.registerTerminalLinkProvider(new JavaTerminalLinkProvder()));
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider("java", new JavaDebugConfigurationProvider()));
context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory("java", new JavaDebugAdapterDescriptorFactory()));
context.subscriptions.push(instrumentOperationAsVsCodeCommand("JavaDebug.SpecifyProgramArgs", async () => {

View File

@ -112,3 +112,7 @@ export function fetchPlatformSettings(): any {
export async function resolveClassFilters(patterns: string[]): Promise<string[]> {
return <string[]> await commands.executeJavaLanguageServerCommand(commands.JAVA_RESOLVE_CLASSFILTERS, ...patterns);
}
export async function resolveSourceUri(line: string): Promise<string> {
return <string> await commands.executeJavaLanguageServerCommand(commands.JAVA_RESOLVE_SOURCE_URI, line);
}

View File

@ -0,0 +1,61 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { CancellationToken, commands, Position, ProviderResult, Range, TerminalLink, TerminalLinkContext,
TerminalLinkProvider, Uri, window } from "vscode";
import { resolveSourceUri } from "./languageServerPlugin";
export class JavaTerminalLinkProvder implements TerminalLinkProvider<IJavaTerminalLink> {
/**
* Provide terminal links for the given context. Note that this can be called multiple times
* even before previous calls resolve, make sure to not share global objects (eg. `RegExp`)
* that could have problems when asynchronous usage may overlap.
* @param context Information about what links are being provided for.
* @param token A cancellation token.
* @return A list of terminal links for the given line.
*/
public provideTerminalLinks(context: TerminalLinkContext, token: CancellationToken): ProviderResult<IJavaTerminalLink[]> {
if (context.terminal.name !== "Java Debug Console" && context.terminal.name !== "Java Process Console") {
return [];
}
const regex = new RegExp("(\\sat\\s+)([\\w$\\.]+\\/)?(([\\w$]+\\.)+[<\\w$>]+)\\(([\\w-$]+\\.java:\\d+)\\)");
const result: RegExpExecArray = regex.exec(context.line);
if (result && result.length) {
const stackTrace = `${result[2] || ""}${result[3]}(${result[5]})`;
const sourceLineNumber = Number(result[5].split(":")[1]);
return [{
startIndex: result.index + result[1].length,
length: stackTrace.length,
methodName: result[3],
stackTrace,
lineNumber: sourceLineNumber,
}];
}
}
/**
* Handle an activated terminal link.
*/
public async handleTerminalLink(link: IJavaTerminalLink): Promise<void> {
const uri = await resolveSourceUri(link.stackTrace);
if (uri) {
const lineNumber = Math.max(link.lineNumber - 1, 0);
window.showTextDocument(Uri.parse(uri), {
preserveFocus: true,
selection: new Range(new Position(lineNumber, 0), new Position(lineNumber, 0)),
});
} else {
// If no source is found, then open the searching symbols quickpick box.
const fullyQualifiedName = link.methodName.substring(0, link.methodName.lastIndexOf("."));
const className = fullyQualifiedName.substring(fullyQualifiedName.lastIndexOf(".") + 1);
commands.executeCommand("workbench.action.quickOpen", "#" + className);
}
}
}
interface IJavaTerminalLink extends TerminalLink {
methodName: string;
stackTrace: string;
lineNumber: number;
}