@@ -10,14 +10,15 @@ import { Logger } from '../services/logging';
1010import { GNULinter , GNUModernLinter , IntelLinter , LFortranLinter , NAGLinter } from '../lib/linters' ;
1111import {
1212 EXTENSION_ID ,
13- FortranDocumentSelector ,
1413 resolveVariables ,
1514 promptForMissingTool ,
1615 isFreeForm ,
1716 spawnAsPromise ,
17+ isFortran ,
18+ shellTask ,
1819} from '../lib/tools' ;
1920import { arraysEqual } from '../lib/helper' ;
20- import { RescanLint } from './commands' ;
21+ import { BuildDebug , BuildRun , RescanLint } from './commands' ;
2122import { GlobPaths } from '../lib/glob-paths' ;
2223
2324export class LinterSettings {
@@ -164,7 +165,24 @@ export class FortranLintingProvider {
164165 public async activate ( subscriptions : vscode . Disposable [ ] ) {
165166 // Register Linter commands
166167 subscriptions . push ( vscode . commands . registerCommand ( RescanLint , this . rescanLinter , this ) ) ;
167-
168+ subscriptions . push (
169+ vscode . commands . registerTextEditorCommand (
170+ BuildRun ,
171+ async ( textEditor : vscode . TextEditor , edit : vscode . TextEditorEdit , ...args : any [ ] ) => {
172+ await this . buildAndRun ( textEditor ) ;
173+ } ,
174+ this
175+ )
176+ ) ;
177+ subscriptions . push (
178+ vscode . commands . registerTextEditorCommand (
179+ BuildDebug ,
180+ async ( textEditor : vscode . TextEditor , edit : vscode . TextEditorEdit , ...args : any [ ] ) => {
181+ await this . buildAndDebug ( textEditor ) ;
182+ } ,
183+ this
184+ )
185+ ) ;
168186 vscode . workspace . onDidOpenTextDocument ( this . doLint , this , subscriptions ) ;
169187 vscode . workspace . onDidCloseTextDocument (
170188 textDocument => {
@@ -194,12 +212,7 @@ export class FortranLintingProvider {
194212 // Only lint if a compiler is specified
195213 if ( ! this . settings . enabled ) return ;
196214 // Only lint Fortran (free, fixed) format files
197- if (
198- ! FortranDocumentSelector ( ) . some ( e => e . scheme === textDocument . uri . scheme ) ||
199- ! FortranDocumentSelector ( ) . some ( e => e . language === textDocument . languageId )
200- ) {
201- return ;
202- }
215+ if ( ! isFortran ( textDocument ) ) return ;
203216
204217 this . linter = this . getLinter ( this . settings . compiler ) ;
205218 const command = this . getLinterExecutable ( ) ;
@@ -252,6 +265,45 @@ export class FortranLintingProvider {
252265 }
253266 }
254267
268+ private async buildAndRun ( textEditor : vscode . TextEditor ) {
269+ return this . buildAndDebug ( textEditor , false ) ;
270+ }
271+
272+ /**
273+ * Compile and run the current file using the provided linter options.
274+ * It has the ability to launch a Debug session or just run the executable.
275+ * @param textEditor a text editor instance
276+ * @param debug performing a debug build or not
277+ */
278+ private async buildAndDebug ( textEditor : vscode . TextEditor , debug = true ) : Promise < void > {
279+ const textDocument = textEditor . document ;
280+ this . linter = this . getLinter ( this . settings . compiler ) ;
281+ const command = this . getLinterExecutable ( ) ;
282+ let argList = [ ...this . constructArgumentList ( textDocument ) ] ;
283+ // Remove mandatory linter args, used for mock compilation
284+ argList = argList . filter ( arg => ! this . linter . args . includes ( arg ) ) ;
285+ if ( debug ) argList . push ( '-g' ) ; // add debug symbols flag, same for all compilers
286+ try {
287+ await shellTask ( command , argList , 'Build Fortran file' ) ;
288+ const folder : vscode . WorkspaceFolder = vscode . workspace . getWorkspaceFolder (
289+ textEditor . document . uri
290+ ) ;
291+ const selectedConfig : vscode . DebugConfiguration = {
292+ name : `${ debug ? 'Debug' : 'Run' } Fortran file` ,
293+ // This relies on the C/C++ debug adapters
294+ type : process . platform === 'win32' ? 'cppvsdbg' : 'cppdbg' ,
295+ request : 'launch' ,
296+ program : `${ textDocument . fileName } .o` ,
297+ cwd : folder . uri . fsPath ,
298+ } ;
299+ await vscode . debug . startDebugging ( folder , selectedConfig , { noDebug : debug } ) ;
300+ return ;
301+ } catch ( err ) {
302+ this . logger . error ( `[build] Compiling ${ textDocument . fileName } failed:` , err ) ;
303+ console . error ( `ERROR: ${ err } ` ) ;
304+ }
305+ }
306+
255307 private getLinter ( compiler : string ) : GNULinter | GNUModernLinter | IntelLinter | NAGLinter {
256308 switch ( compiler ) {
257309 case 'gfortran' :
@@ -276,8 +328,8 @@ export class FortranLintingProvider {
276328 this . logger . debug ( `[lint] glob paths:` , this . pathCache . get ( opt ) . globs ) ;
277329 this . logger . debug ( `[lint] resolved paths:` , this . pathCache . get ( opt ) . paths ) ;
278330
279- const extensionIndex = textDocument . fileName . lastIndexOf ( '.' ) ;
280- const fileNameWithoutExtension = textDocument . fileName . substring ( 0 , extensionIndex ) ;
331+ // const extensionIndex = textDocument.fileName.lastIndexOf('.');
332+ // const fileNameWithoutExtension = textDocument.fileName.substring(0, extensionIndex);
281333 const fortranSource : string [ ] = this . settings . fyppEnabled
282334 ? [ '-xf95' , isFreeForm ( textDocument ) ? '-ffree-form' : '-ffixed-form' , '-' ]
283335 : [ textDocument . fileName ] ;
@@ -286,7 +338,7 @@ export class FortranLintingProvider {
286338 ...args ,
287339 ...this . getIncludeParams ( includePaths ) , // include paths
288340 '-o' ,
289- `${ fileNameWithoutExtension } .mod ` ,
341+ `${ textDocument . fileName } .o ` ,
290342 ...fortranSource ,
291343 ] ;
292344
0 commit comments