@@ -9,6 +9,7 @@ import { getOrAskForProgram } from './debugConfigProvider';
99import { adaExtState , mainOutputChannel } from './extension' ;
1010import { getProjectFileRelPath } from './helpers' ;
1111import { CustomTaskDefinition , getEnclosingSymbol } from './taskProviders' ;
12+ import { LanguageClient } from 'vscode-languageclient/node' ;
1213
1314export function registerCommands ( context : vscode . ExtensionContext , clients : ExtensionState ) {
1415 context . subscriptions . push ( vscode . commands . registerCommand ( 'ada.otherFile' , otherFileHandler ) ) ;
@@ -45,6 +46,24 @@ export function registerCommands(context: vscode.ExtensionContext, clients: Exte
4546 return p ;
4647 } )
4748 ) ;
49+
50+ context . subscriptions . push (
51+ vscode . commands . registerCommand (
52+ 'ada.addMissingDirsToWorkspace' ,
53+ async (
54+ // eslint-disable-next-line @typescript-eslint/no-inferrable-types
55+ displayPopupWhenMissing : boolean = false ,
56+ // eslint-disable-next-line @typescript-eslint/no-inferrable-types
57+ displayPopupOnSuccess : boolean = true
58+ ) => {
59+ await checkSrcDirectories (
60+ clients . adaClient ,
61+ displayPopupWhenMissing ,
62+ displayPopupOnSuccess
63+ ) ;
64+ }
65+ )
66+ ) ;
4867}
4968/**
5069 * Add a subprogram box above the subprogram enclosing the cursor's position, if any.
@@ -335,3 +354,110 @@ const otherFileHandler = () => {
335354 ] ,
336355 } ) ;
337356} ;
357+
358+ /**
359+ *
360+ * Check if we need to add some source directories to the workspace (e.g: when imported
361+ * projects' source directories are not placed under the root project's directory).
362+ * Do nothing if the user did not setup any workspace file.
363+ *
364+ * @param alsClient - the running ALS client
365+ * @param displayPopupWhenMissing - whether or not we should display a yes/no popup
366+ * when missing directories
367+ * @param displayPopupOnSuccess - whether or not we should display a popup to notify
368+ * the user that there is no missing directory
369+ */
370+ export async function checkSrcDirectories (
371+ alsClient : LanguageClient ,
372+ displayPopupWhenMissing = true ,
373+ displayPopupOnSuccess = true
374+ ) {
375+ type ALSSourceDirDescription = {
376+ name : string ;
377+ uri : string ;
378+ } ;
379+
380+ const foldersInSettings = vscode . workspace . getConfiguration ( ) . get ( 'folders' ) ;
381+
382+ // Don't propose any popup if we multi-root workspace folders are already set
383+ // explicitly in the workspace's settings.
384+ if ( foldersInSettings === undefined ) {
385+ const sourceDirs : ALSSourceDirDescription [ ] = ( await alsClient . sendRequest (
386+ ExecuteCommandRequest . type ,
387+ {
388+ command : 'als-source-dirs' ,
389+ }
390+ ) ) as ALSSourceDirDescription [ ] ;
391+
392+ const isSubdirectory = ( dir : string , parent : string ) => {
393+ // Use lower-case on Windows since drives can be specified in VS Code
394+ // either with lower or upper case characters.
395+ if ( process . platform == 'win32' ) {
396+ dir = dir . toLowerCase ( ) ;
397+ parent = parent . toLowerCase ( ) ;
398+ }
399+
400+ return dir . startsWith ( parent + '/' ) ;
401+ } ;
402+
403+ const workspaceFolders = vscode . workspace . workspaceFolders ?? [ ] ;
404+ const workspaceDirsToAdd : { uri : vscode . Uri ; name ?: string | undefined } [ ] = [ ] ;
405+
406+ for ( const source_dir of sourceDirs ) {
407+ const sourceDirURI = vscode . Uri . parse ( source_dir . uri ) ;
408+ const sourceDirPath = sourceDirURI . path ;
409+
410+ // If the source directory is not under one of the workspace folders and
411+ // if it's not already present in the workspace's folders, push
412+ // this source directory to the workspace folders to add later.
413+ if (
414+ ! workspaceFolders . some (
415+ ( workspaceFolder ) =>
416+ workspaceFolder . uri . path == sourceDirPath ||
417+ isSubdirectory ( sourceDirPath , workspaceFolder . uri . path )
418+ )
419+ ) {
420+ workspaceDirsToAdd . push ( {
421+ name : source_dir . name ,
422+ uri : sourceDirURI ,
423+ } ) ;
424+ }
425+ }
426+
427+ // If there are some source directories missing in the workspace, ask the user
428+ // to add them in his workspace.
429+ if ( workspaceDirsToAdd . length > 0 ) {
430+ let doAdd = true ;
431+
432+ if ( displayPopupWhenMissing ) {
433+ await vscode . window
434+ . showInformationMessage (
435+ 'Some project source directories are not \
436+ listed in your workspace: do you want to add them?' ,
437+ 'Yes' ,
438+ 'No'
439+ )
440+ . then ( ( answer ) => {
441+ if ( answer !== 'Yes' ) {
442+ doAdd = false ;
443+ }
444+ } ) ;
445+ }
446+
447+ if ( doAdd ) {
448+ vscode . workspace . updateWorkspaceFolders (
449+ vscode . workspace . workspaceFolders
450+ ? vscode . workspace . workspaceFolders . length
451+ : 0 ,
452+ null ,
453+ ...workspaceDirsToAdd
454+ ) ;
455+ }
456+ } else if ( displayPopupOnSuccess ) {
457+ void vscode . window . showInformationMessage (
458+ "All the project's source directories are already \
459+ available in the current workspace."
460+ ) ;
461+ }
462+ }
463+ }
0 commit comments