Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace config generation with automatic run of the current file #770

Merged
merged 1 commit into from
Dec 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1034,9 +1034,9 @@ function launchMetals(
);
treeViews = startTreeView(client, outputChannel, context, viewIds);
context.subscriptions.concat(treeViews.disposables);
scalaDebugger
.initialize(outputChannel)
.forEach((disposable) => context.subscriptions.push(disposable));
scalaDebugger.initialize(outputChannel).forEach((disposable) => {
context.subscriptions.push(disposable);
});
client.onNotification(DecorationTypeDidChange.type, (options) => {
decorationType = window.createTextEditorDecorationType(options);
});
Expand Down
187 changes: 33 additions & 154 deletions src/scalaDebugger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,23 @@ import {
ProviderResult,
WorkspaceFolder,
DebugAdapterDescriptor,
DebugConfigurationProviderTriggerKind,
} from "vscode";
import { ServerCommands } from "metals-languageclient";
import {
DebugDiscoveryParams,
RunType,
ServerCommands,
} from "metals-languageclient";

const configurationType = "scala";
const launchRequestType = "launch";
const attachRequestType = "attach";

export function initialize(outputChannel: vscode.OutputChannel): Disposable[] {
outputChannel.appendLine("Initializing Scala Debugger");
return [
vscode.debug.registerDebugConfigurationProvider(
configurationType,
new ScalaConfigProvider()
new ScalaMainConfigProvider(),
DebugConfigurationProviderTriggerKind.Initial
),
vscode.debug.registerDebugAdapterDescriptorFactory(
configurationType,
Expand Down Expand Up @@ -58,164 +62,39 @@ export async function start(
});
}

class ScalaConfigProvider implements vscode.DebugConfigurationProvider {
provideDebugConfigurations(): ProviderResult<DebugConfiguration[]> {
const mainClassPick = "Main Class";
const testClassPick = "Test Suite";
const attachPick = "Attach to JVM";

return vscode.window
.showQuickPick([mainClassPick, testClassPick, attachPick], {
placeHolder:
"Pick the kind of the class to debug (Press 'Escape' to create 'launch.json' with no initial configuration)",
})
.then((result) => {
switch (result) {
case mainClassPick:
return this.provideDebugMainClassConfiguration().then((config) => [
config,
]);
case testClassPick:
return this.provideDebugTestClassConfiguration().then((config) => [
config,
]);
case attachPick:
return this.provideDebugAttachConfiguration().then((config) => [
config,
]);
default:
return [];
}
})
.then(
(result) => result,
() => []
);
}

class ScalaMainConfigProvider implements vscode.DebugConfigurationProvider {
resolveDebugConfiguration(
_folder: WorkspaceFolder | undefined,
debugConfiguration: DebugConfiguration
): ProviderResult<DebugConfiguration> {
if (debugConfiguration.type === undefined) {
return null;
}
return debugConfiguration;
}

private provideDebugMainClassConfiguration(): Thenable<DebugConfiguration> {
return this.askForOptionalBuildTarget().then((buildTarget) =>
this.askForClassName().then((className) =>
this.askForConfigurationName(className).then((name) => {
const result: DebugConfiguration = {
type: configurationType,
name: name,
request: launchRequestType,
mainClass: className,
buildTarget: buildTarget,
args: [],
};
return result;
})
)
);
}
let editor = vscode.window.activeTextEditor;
// debugConfiguration.type is undefined if there are no configurations
// we are running whatever is in the file
if (debugConfiguration.type === undefined && editor) {
const args: DebugDiscoveryParams = {
path: editor.document.uri.toString(true),
runType: RunType.RunOrTestFile,
};
return vscode.commands
.executeCommand<DebugSession>(ServerCommands.DebugAdapterStart, args)
.then((response) => {
if (response === undefined) {
return;
}

private provideDebugTestClassConfiguration(): Thenable<DebugConfiguration> {
return this.askForOptionalBuildTarget().then((buildTarget) =>
this.askForClassName().then((className) =>
this.askForConfigurationName(className).then((name) => {
const result: DebugConfiguration = {
type: configurationType,
name: name,
request: launchRequestType,
testClass: className,
buildTarget: buildTarget,
};
return result;
})
)
);
}
const port = debugServerFromUri(response.uri).port;

provideDebugAttachConfiguration(): Thenable<DebugConfiguration> {
return this.askForHostName().then((hostName) =>
this.askForPort().then((port) =>
this.askForBuildTarget().then((buildTarget) => {
const result: DebugConfiguration = {
const configuration: vscode.DebugConfiguration = {
type: configurationType,
name: `Attach to ${hostName}:${port} - ${buildTarget}`,
request: attachRequestType,
hostName: hostName,
port: port,
buildTarget: buildTarget,
name: response.name,
noDebug: false,
request: "launch",
debugServer: port, // note: MUST be a number. vscode magic - automatically connects to the server
};
return result;
})
)
);
}

private askForOptionalBuildTarget(): Thenable<string | undefined> {
return vscode.window
.showInputBox({
prompt: "Enter the name of the build target",
placeHolder: "Optional, you can leave it empty",
})
.then((buildTarget) => {
if (buildTarget === undefined) {
return Promise.reject();
} else if (buildTarget === "") {
return undefined;
} else {
return buildTarget;
}
});
}

private askForHostName(): Thenable<string> {
return vscode.window
.showInputBox({
prompt: "Enter host name of the debuggee JVM",
placeHolder: "localhost",
})
.then((hostName) => hostName ?? Promise.reject());
}

private askForPort(): Thenable<number> {
return vscode.window
.showInputBox({
prompt: "Enter port to attach to",
placeHolder: "5005",
})
.then((port) => port ?? Promise.reject())
.then((port) => parseInt(port));
}

private askForBuildTarget(): Thenable<string> {
return vscode.window
.showInputBox({
prompt: "Enter the name of the build target",
})
.then((buildTarget) => buildTarget ?? Promise.reject());
}

private askForClassName(): Thenable<string> {
return vscode.window
.showInputBox({
prompt: "Enter the name of the class to debug",
placeHolder: "<package>.<Class>",
})
.then((name) => name ?? Promise.reject());
}

private askForConfigurationName(className: string): Thenable<string> {
return vscode.window
.showInputBox({
prompt: "Enter the name of the configuration",
value: `Debug ${className}`,
})
.then((name) => name ?? Promise.reject());
commands.executeCommand("workbench.panel.repl.view.focus");
return configuration;
});
} else return debugConfiguration;
}
}

Expand Down