Initial version of .NET Solution Launcher

Startup project and solution configuration (Debug|x64, Test|x64, ...) in
the status bar, with build and debug tasks that pass both configuration
and platform. Made for DotRush, whose build never passes -p:Platform and
whose status item shows the configuration but not the project.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0169iPWwKHZoBTNN9qwXiwqk
This commit is contained in:
max
2026-09-08 13:10:55 +02:00
co-authored by Claude Fable 5.1
commit e2ba32a647
21 changed files with 3279 additions and 0 deletions
+85
View File
@@ -0,0 +1,85 @@
import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
import { SolutionModel } from './model';
import { taskLabel } from './tasks';
export const LAUNCH_NAME = '.NET Solution: Debug startup project';
function launchSettings() {
return vscode.workspace.getConfiguration('dotnetSolution');
}
/**
* A complete launch configuration for the startup project under the active configuration.
*
* `program` is the apphost .exe when the project makes one, because vsdbg wants an
* executable. Projects without an apphost run through the dotnet host instead. The
* debugger options DotRush normally fills in (justMyCode, symbol servers, console) are
* left out so its own provider still adds them.
*/
export async function buildLaunchConfiguration(
model: SolutionModel, options: { noDebug?: boolean; preLaunchTask?: string }): Promise<vscode.DebugConfiguration> {
const active = model.active;
if (!active) {
throw new Error('No startup project selected.');
}
const target = await model.resolveTarget();
const settings = launchSettings();
const userArgs = settings.get<string[]>('launch.args', []);
const cwd = settings.get<string>('launch.cwd', '') || target.targetDir.replace(/[\\/]+$/, '');
const console = settings.get<string>('launch.console', 'internalConsole');
const program = target.executablePath ?? 'dotnet';
const args = target.executablePath ? userArgs : [target.targetPath, ...userArgs];
return {
name: `${active.project.info.name} (${active.solutionConfiguration.configuration}|${active.solutionPlatform})`,
type: settings.get<string>('debugType', 'coreclr'),
request: 'launch',
program,
args,
cwd,
env: settings.get<Record<string, string>>('launch.env', {}),
console,
noDebug: options.noDebug ?? false,
preLaunchTask: options.preLaunchTask,
// DotRush looks for Properties/launchSettings.json next to *its* startup project;
// this one is synced, so that still works. Point it explicitly anyway.
launchSettingsFilePath: launchSettingsPath(active.project.info.fsPath),
};
}
function launchSettingsPath(projectPath: string): string | undefined {
const candidate = path.join(path.dirname(projectPath), 'Properties', 'launchSettings.json');
return fs.existsSync(candidate) ? candidate : undefined;
}
/** The static entry written to launch.json: values come back through `${command:…}` at launch time. */
export function launchJsonEntry(): Record<string, unknown> {
return {
name: LAUNCH_NAME,
type: launchSettings().get<string>('debugType', 'coreclr'),
request: 'launch',
program: '${command:dotnetSolution.activeProgram}',
args: [],
cwd: '${command:dotnetSolution.activeTargetDir}',
preLaunchTask: taskLabel('build'),
};
}
/**
* Offers the dynamic "debug the startup project" entry in the Run and Debug dropdown,
* and fills in `program` for launch.json entries that use this extension's variables
* but omitted them.
*/
export class SolutionDebugConfigurationProvider implements vscode.DebugConfigurationProvider {
constructor(private readonly model: SolutionModel) { }
async provideDebugConfigurations(): Promise<vscode.DebugConfiguration[]> {
if (!this.model.active) {
return [];
}
return [launchJsonEntry() as vscode.DebugConfiguration];
}
}