@@ -5,17 +5,36 @@ import { SymbolKind } from 'vscode';
55import { Disposable } from 'vscode-jsonrpc' ;
66import { ExecuteCommandRequest } from 'vscode-languageclient' ;
77import { ExtensionState } from './ExtensionState' ;
8- import { getOrAskForProgram } from './debugConfigProvider' ;
9- import { adaExtState , mainOutputChannel } from './extension' ;
10- import { getProjectFileRelPath } from './helpers' ;
8+ import { AdaConfig , getOrAskForProgram , initializeConfig } from './debugConfigProvider' ;
9+ import { adaExtState , logger , mainOutputChannel } from './extension' ;
10+ import { findAdaMain , getProjectFileRelPath } from './helpers' ;
1111import {
1212 CustomTaskDefinition ,
13+ findBuildAndRunTask ,
1314 getBuildAndRunTasks ,
1415 getConventionalTaskLabel ,
1516 getEnclosingSymbol ,
1617 isFromWorkspace ,
1718} from './taskProviders' ;
1819
20+ /**
21+ * Identifier for a hidden command used for building and running a project main.
22+ * The command accepts a parameter which is the URI of the main source file.
23+ * It is triggered by CodeLenses provided by the extension.
24+ *
25+ * @see {@link buildAndRunSpecifiedMain }
26+ */
27+ export const CMD_BUILD_AND_RUN_MAIN = 'ada.buildAndRunMain' ;
28+
29+ /**
30+ * Identifier for a hidden command used for building and debugging a project main.
31+ * The command accepts a parameter which is the URI of the main source file.
32+ * It is triggered by CodeLenses provided by the extension.
33+ *
34+ * @see {@link buildAndDebugSpecifiedMain }
35+ */
36+ export const CMD_BUILD_AND_DEBUG_MAIN = 'ada.buildAndDebugMain' ;
37+
1938export function registerCommands ( context : vscode . ExtensionContext , clients : ExtensionState ) {
2039 context . subscriptions . push ( vscode . commands . registerCommand ( 'ada.otherFile' , otherFileHandler ) ) ;
2140 context . subscriptions . push (
@@ -66,6 +85,17 @@ export function registerCommands(context: vscode.ExtensionContext, clients: Exte
6685 }
6786 )
6887 ) ;
88+
89+ /**
90+ * The following commands are not defined in package.json and hence not
91+ * exposed through the command palette but are called from CodeLenses.
92+ */
93+ context . subscriptions . push (
94+ vscode . commands . registerCommand ( CMD_BUILD_AND_RUN_MAIN , buildAndRunSpecifiedMain )
95+ ) ;
96+ context . subscriptions . push (
97+ vscode . commands . registerCommand ( CMD_BUILD_AND_DEBUG_MAIN , buildAndDebugSpecifiedMain )
98+ ) ;
6999}
70100/**
71101 * Add a subprogram box above the subprogram enclosing the cursor's position, if any.
@@ -439,3 +469,105 @@ export async function checkSrcDirectories(atStartup = false, displayYesNoPopup =
439469 }
440470 }
441471}
472+
473+ /*
474+ * This is a command handler that builds and runs the main given as parameter.
475+ * If the given URI does not match one of the project Mains an error is
476+ * displayed.
477+ *
478+ * @param main - a URI of a document
479+ */
480+ async function buildAndRunSpecifiedMain ( main : vscode . Uri ) : Promise < void > {
481+ const adaMain = await findAdaMain ( main . fsPath ) ;
482+ if ( adaMain ) {
483+ const task = await findBuildAndRunTask ( adaMain ) ;
484+ if ( task ) {
485+ lastUsedTaskInfo = { source : task . source , name : task . name } ;
486+ await vscode . tasks . executeTask ( task ) ;
487+ } else {
488+ void vscode . window . showErrorMessage (
489+ `Could not find the 'Build and Run' task for the project main ` +
490+ `${ adaMain . mainRelPath ( ) } ` ,
491+ { modal : true }
492+ ) ;
493+ }
494+ } else {
495+ void vscode . window . showErrorMessage (
496+ `The document ${ vscode . workspace . asRelativePath ( main ) } does not match ` +
497+ `any of the Mains of the project ${ await getProjectFileRelPath ( ) } ` ,
498+ { modal : true }
499+ ) ;
500+ }
501+ }
502+
503+ /**
504+ * This is a command handler that builds the main given as parameter and starts
505+ * a debug session on that main. If the given URI does not match one of the
506+ * project Mains an error is displayed.
507+ *
508+ * @param main - a URI of a document
509+ */
510+ async function buildAndDebugSpecifiedMain ( main : vscode . Uri ) : Promise < void > {
511+ function isMatchingConfig ( cfg : vscode . DebugConfiguration , configToMatch : AdaConfig ) : boolean {
512+ return cfg . type == configToMatch . type && cfg . name == configToMatch . name ;
513+ }
514+
515+ const wsFolder = vscode . workspace . getWorkspaceFolder ( main ) ;
516+ const adaMain = await findAdaMain ( main . fsPath ) ;
517+ if ( adaMain ) {
518+ /**
519+ * The vscode API doesn't provide a way to list both automatically
520+ * provided and User-defined debug configurations. So instead, we
521+ * inspect the launch.json data if it exists, and the dynamic configs
522+ * provided by the exctension. We look for a debug config that matches
523+ * the given main URI.
524+ */
525+ // Create a launch config for this main to help with matching
526+ const configToMatch = initializeConfig ( adaMain ) ;
527+ logger . debug ( 'Debug config to match:\n' + JSON . stringify ( configToMatch , null , 2 ) ) ;
528+
529+ let matchingConfig = undefined ;
530+
531+ {
532+ // Find matching config in the list of workspace-defined launch configs
533+ const configs : vscode . DebugConfiguration [ ] =
534+ vscode . workspace . getConfiguration ( 'launch' ) . get ( 'configurations' ) ?? [ ] ;
535+ logger . debug ( `Workspace debug configurations:\n${ JSON . stringify ( configs , null , 2 ) } ` ) ;
536+ matchingConfig = configs . find ( ( cfg ) => isMatchingConfig ( cfg , configToMatch ) ) ;
537+ }
538+
539+ if ( ! matchingConfig ) {
540+ logger . debug ( 'Could not find matching config in workspace configs.' ) ;
541+ // Look for a matching config among the configs dynamically provided by the extension
542+ const dynamicConfigs =
543+ await adaExtState . dynamicDebugConfigProvider . provideDebugConfigurations ( ) ;
544+ logger . debug (
545+ `Dynamic debug configurations:\n${ JSON . stringify ( dynamicConfigs , null , 2 ) } `
546+ ) ;
547+ matchingConfig = dynamicConfigs . find ( ( cfg ) => isMatchingConfig ( cfg , configToMatch ) ) ;
548+ }
549+
550+ if ( matchingConfig ) {
551+ logger . debug ( 'Found matching config: ' + JSON . stringify ( matchingConfig , null , 2 ) ) ;
552+ const success = await vscode . debug . startDebugging ( wsFolder , matchingConfig ) ;
553+ if ( ! success ) {
554+ void vscode . window . showErrorMessage (
555+ `Failed to start debug configuration: ${ matchingConfig . name } `
556+ ) ;
557+ }
558+ } else {
559+ logger . error ( 'Could not find matching config' ) ;
560+ void vscode . window . showErrorMessage (
561+ `Could not find a debug configuration for the project main ` +
562+ `${ adaMain . mainRelPath ( ) } ` ,
563+ { modal : true }
564+ ) ;
565+ }
566+ } else {
567+ void vscode . window . showErrorMessage (
568+ `The document ${ vscode . workspace . asRelativePath ( main ) } does not match ` +
569+ `any of the Mains of the project ${ await getProjectFileRelPath ( ) } ` ,
570+ { modal : true }
571+ ) ;
572+ }
573+ }
0 commit comments