Skip to content

Commit 33a346b

Browse files
authored
Merge pull request #655 from fortran-lang/gnikit/issue646
feat: adding Run and Debug buttons for source files
2 parents 32acba4 + d858d87 commit 33a346b

File tree

4 files changed

+108
-12
lines changed

4 files changed

+108
-12
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Added
1111

12+
- Added Run and Debug buttons for single Fortran files based on linter settings
13+
([#646](https://github.com/fortran-lang/vscode-fortran-support/issues/646))
1214
- Added linter support for [LFortran](https://lfortran.org/)
1315
([#589](https://github.com/fortran-lang/vscode-fortran-support/issues/589))
1416
- Added coverage reporting using `c8`

package.json

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,18 @@
568568
"category": "Fortran",
569569
"command": "fortran.analysis.showWhatsNew",
570570
"title": "What's New"
571+
},
572+
{
573+
"category": "Fortran",
574+
"command": "fortran.build.run",
575+
"icon": "$(play)",
576+
"title": "Run Fortran File"
577+
},
578+
{
579+
"category": "Fortran",
580+
"command": "fortran.build.debug",
581+
"icon": "$(debug-alt)",
582+
"title": "Debug Fortran File"
571583
}
572584
],
573585
"menus": {
@@ -589,6 +601,34 @@
589601
"command": "fortran.analysis.showWhatsNew",
590602
"title": "What's New",
591603
"when": "!virtualWorkspace && shellExecutionSupported"
604+
},
605+
{
606+
"category": "Fortran",
607+
"command": "fortran.build.run",
608+
"icon": "$(play)",
609+
"title": "Run Fortran File",
610+
"when": "!virtualWorkspace && shellExecutionSupported"
611+
},
612+
{
613+
"category": "Fortran",
614+
"command": "fortran.build.debug",
615+
"icon": "$(debug-alt)",
616+
"title": "Debug Fortran file",
617+
"when": "!virtualWorkspace && shellExecutionSupported"
618+
}
619+
],
620+
"editor/title/run": [
621+
{
622+
"command": "fortran.build.run",
623+
"group": "navigation@0",
624+
"title": "Run Fortran File",
625+
"when": "resourceLangId =~ /Fortran/ && !isInDiffEditor && !virtualWorkspace && shellExecutionSupported"
626+
},
627+
{
628+
"command": "fortran.build.debug",
629+
"group": "navigation@1",
630+
"title": "Debug Fortran File",
631+
"when": "resourceLangId == fortran && !isInDiffEditor && !virtualWorkspace && shellExecutionSupported"
592632
}
593633
]
594634
}

src/features/commands.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@
55
export const RestartLS = 'fortran.analysis.restartLanguageServer';
66
export const RescanLint = 'fortran.analysis.rescanLinter';
77
export const WhatsNew = 'fortran.analysis.showWhatsNew';
8+
export const BuildRun = 'fortran.build.run';
9+
export const BuildDebug = 'fortran.build.debug';

src/features/linter-provider.ts

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ import { Logger } from '../services/logging';
1010
import { GNULinter, GNUModernLinter, IntelLinter, LFortranLinter, NAGLinter } from '../lib/linters';
1111
import {
1212
EXTENSION_ID,
13-
FortranDocumentSelector,
1413
resolveVariables,
1514
promptForMissingTool,
1615
isFreeForm,
1716
spawnAsPromise,
17+
isFortran,
18+
shellTask,
1819
} from '../lib/tools';
1920
import { arraysEqual } from '../lib/helper';
20-
import { RescanLint } from './commands';
21+
import { BuildDebug, BuildRun, RescanLint } from './commands';
2122
import { GlobPaths } from '../lib/glob-paths';
2223

2324
export 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

Comments
 (0)