Skip to content

Commit 9d88a75

Browse files
committed
feat(linter): add options for linter control
Added 3 commands for: - Running the initialisation process for the linter - Cleaning the linter produced files e.g. .mod - Cleaning all diagnostics produced by the linter Added the settings to: - Run the initialisation of the linter upon extension activation - Added the experimental setting of discarding the full project-wide diagnostics produced by the initialisation process Edited the descriptions of 2 existing settings Added additional extension activation events on commands
1 parent a680d2e commit 9d88a75

File tree

5 files changed

+138
-24
lines changed

5 files changed

+138
-24
lines changed

CHANGELOG.md

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

1010
### Added
1111

12+
- Added new settings for disabling Linter initialization and display of initialization Diagnostics
13+
`fortran.linter.initialize` and `fortran.experimental.keepInitDiagnostics`
14+
- Added commands for Initializing, Cleaning build artefacts and Clearing the Diagnostics from the Linter
1215
- Added support for storing build artefacts in a separate cache directory
1316
([#614](https://github.com/fortran-lang/vscode-fortran-support/issues/614))
1417
- Added a naive initialization for Fortran source files present in the workspace.
@@ -43,6 +46,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
4346

4447
### Changed
4548

49+
- Changed the activation events of the extension to include the `onCommand` for all register commands
4650
- Changed glob resolution module to `glob` from `fast-glob` due to bug #43
4751
([#681](https://github.com/fortran-lang/vscode-fortran-support/issues/681))
4852
- Changed how Python packages are installed for unittesting for performance

package.json

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,15 @@
5252
},
5353
"activationEvents": [
5454
"onLanguage:FortranFreeForm",
55-
"onLanguage:FortranFixedForm"
55+
"onLanguage:FortranFixedForm",
56+
"onCommand:fortran.analysis.restartLanguageServer",
57+
"onCommand:fortran.analysis.rescanLinter",
58+
"onCommand:fortran.analysis.cleanLinterDiagnostics",
59+
"onCommand:fortran.analysis.cleanLinterFiles",
60+
"onCommand:fortran.analysis.initLinter",
61+
"onCommand:fortran.analysis.showWhatsNew",
62+
"onCommand:fortran.build.run",
63+
"onCommand:fortran.build.debug"
5664
],
5765
"main": "./dist/extension.js",
5866
"extensionDependencies": [
@@ -231,6 +239,12 @@
231239
"markdownDescription": "Compiler used for linting support.",
232240
"order": 0
233241
},
242+
"fortran.linter.initialize": {
243+
"type": "boolean",
244+
"default": true,
245+
"markdownDescription": "Attempt to initialize the linter by mock-compiling all files in the workspace.",
246+
"order": 5
247+
},
234248
"fortran.linter.compilerPath": {
235249
"type": "string",
236250
"default": "",
@@ -257,7 +271,7 @@
257271
"fortran.linter.modOutput": {
258272
"type": "string",
259273
"default": "",
260-
"markdownDescription": "Global output directory for .mod files generated due to linting `-J<linter.modOutput>`. Can resolve internal variables with `~`, `${workspaceFolder}`, `${env}`, `${config}`, `${file}`, `${fileDirname}`, `${fileBasenameNoExtension}`.",
274+
"markdownDescription": "Output directory for .mod files generated due to linting `-J<linter.modOutput>`. By default this is an internal VS Code path unique to each workspace. Can resolve internal variables with `~`, `${workspaceFolder}`, `${env}`, `${config}`, `${file}`, `${fileDirname}`, `${fileBasenameNoExtension}`.",
261275
"order": 40
262276
},
263277
"fortran.linter.fypp.enabled": {
@@ -307,7 +321,7 @@
307321
"std",
308322
"gfortran5"
309323
],
310-
"markdownDescription": "ine numbering marker format, currently std`, `cpp` and `gfortran5` are supported, where `std` emits `#line` pragmas similar to standard tools, 'cpp' produces line directives as emitted by GNU cpp, and `gfortran5` cpp line directives with a workaround for a bug introduced in GFortran 5. Default: `cpp`.",
324+
"markdownDescription": "Line numbering marker format, currently std`, `cpp` and `gfortran5` are supported, where `std` emits `#line` pragmas similar to standard tools, 'cpp' produces line directives as emitted by GNU cpp, and `gfortran5` cpp line directives with a workaround for a bug introduced in GFortran 5. Default: `cpp`.",
311325
"order": 120
312326
},
313327
"fortran.linter.fypp.extraArgs": {
@@ -526,6 +540,19 @@
526540
}
527541
}
528542
},
543+
{
544+
"id": "experimental",
545+
"title": "Experimental",
546+
"order": 500,
547+
"properties": {
548+
"fortran.experimental.keepInitDiagnostics": {
549+
"type": "boolean",
550+
"default": true,
551+
"markdownDescription": "Keep (and show) all diagnostics generated from the initialization of the Linter, not just from opened files.",
552+
"order": 0
553+
}
554+
}
555+
},
529556
{
530557
"id": "deprecated",
531558
"title": "Deprecated Options",
@@ -581,7 +608,22 @@
581608
{
582609
"category": "Fortran",
583610
"command": "fortran.analysis.rescanLinter",
584-
"title": "Rescan Linter paths"
611+
"title": "Rescan Linter Include paths"
612+
},
613+
{
614+
"category": "Fortran",
615+
"command": "fortran.analysis.initLinter",
616+
"title": "Initialize Fortran Linter"
617+
},
618+
{
619+
"category": "Fortran",
620+
"command": "fortran.analysis.cleanLinterFiles",
621+
"title": "Clean Linter generated files"
622+
},
623+
{
624+
"category": "Fortran",
625+
"command": "fortran.analysis.cleanLinterDiagnostics",
626+
"title": "Clean All Linter Diagnostics"
585627
},
586628
{
587629
"category": "Fortran",
@@ -615,6 +657,24 @@
615657
"title": "Rescan Linter paths",
616658
"when": "!virtualWorkspace && shellExecutionSupported"
617659
},
660+
{
661+
"category": "Fortran",
662+
"command": "fortran.analysis.initLinter",
663+
"title": "Initialize Fortran Linter",
664+
"when": "!virtualWorkspace && shellExecutionSupported"
665+
},
666+
{
667+
"category": "Fortran",
668+
"command": "fortran.analysis.cleanLinterFiles",
669+
"title": "Clean Linter generated files",
670+
"when": "!virtualWorkspace && shellExecutionSupported"
671+
},
672+
{
673+
"category": "Fortran",
674+
"command": "fortran.analysis.cleanLinterDiagnostics",
675+
"title": "Clean All Linter Diagnostics",
676+
"when": "!virtualWorkspace && shellExecutionSupported"
677+
},
618678
{
619679
"category": "Fortran",
620680
"command": "fortran.analysis.showWhatsNew",

src/extension.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ export async function activate(context: vscode.ExtensionContext) {
4747
})
4848
);
4949
// Linter is always activated but will only lint if compiler !== Disabled
50-
const linter = new FortranLintingProvider(logger, context.storageUri.fsPath);
50+
const linterCache = path.join(context.storageUri.fsPath);
51+
const linter = new FortranLintingProvider(logger, linterCache);
5152
linter.activate(context);
5253
vscode.languages.registerCodeActionsProvider(FortranDocumentSelector(), linter);
5354

src/features/commands.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
export const RestartLS = 'fortran.analysis.restartLanguageServer';
66
export const RescanLint = 'fortran.analysis.rescanLinter';
7+
export const CleanLintDiagnostics = 'fortran.analysis.cleanLinterDiagnostics';
8+
export const CleanLintFiles = 'fortran.analysis.cleanLinterFiles';
9+
export const InitLint = 'fortran.analysis.initLinter';
710
export const WhatsNew = 'fortran.analysis.showWhatsNew';
811
export const BuildRun = 'fortran.build.run';
912
export const BuildDebug = 'fortran.build.debug';

src/features/linter-provider.ts

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as cp from 'child_process';
66
import which from 'which';
77
import * as semver from 'semver';
88
import * as vscode from 'vscode';
9+
import { glob } from 'glob';
910

1011
import * as pkg from '../../package.json';
1112
import { Logger } from '../services/logging';
@@ -20,7 +21,14 @@ import {
2021
shellTask,
2122
} from '../lib/tools';
2223
import { arraysEqual } from '../lib/helper';
23-
import { BuildDebug, BuildRun, RescanLint } from './commands';
24+
import {
25+
BuildDebug,
26+
BuildRun,
27+
InitLint,
28+
CleanLintFiles,
29+
RescanLint,
30+
CleanLintDiagnostics,
31+
} from './commands';
2432
import { GlobPaths } from '../lib/glob-paths';
2533

2634
const GNU = new GNULinter();
@@ -52,6 +60,12 @@ export class LinterSettings {
5260
const compiler = this.config.get<string>('linter.compiler');
5361
return compiler;
5462
}
63+
public get initialize() {
64+
return this.config.get<boolean>('linter.initialize');
65+
}
66+
public get keepInitDiagnostics() {
67+
return this.config.get<boolean>('experimental.keepInitDiagnostics');
68+
}
5569
public get compilerPath(): string {
5670
return this.config.get<string>('linter.compilerPath');
5771
}
@@ -148,7 +162,7 @@ export class LinterSettings {
148162
}
149163

150164
export class FortranLintingProvider {
151-
constructor(private logger: Logger = new Logger(), private storageUI: string = '') {
165+
constructor(private logger: Logger = new Logger(), private storageUI: string = undefined) {
152166
// Register the Linter provider
153167
this.fortranDiagnostics = vscode.languages.createDiagnosticCollection('Fortran');
154168
this.settings = new LinterSettings(this.logger);
@@ -158,6 +172,7 @@ export class FortranLintingProvider {
158172
private pathCache = new Map<string, GlobPaths>();
159173
private settings: LinterSettings;
160174
private linter: GNULinter | GNUModernLinter | IntelLinter | NAGLinter;
175+
private disposables: vscode.Disposable[];
161176

162177
public provideCodeActions(
163178
document: vscode.TextDocument,
@@ -173,6 +188,17 @@ export class FortranLintingProvider {
173188
context.subscriptions.push(
174189
vscode.commands.registerCommand(RescanLint, this.rescanLinter, this)
175190
);
191+
context.subscriptions.push(vscode.commands.registerCommand(InitLint, this.initialize, this));
192+
context.subscriptions.push(vscode.commands.registerCommand(CleanLintFiles, this.clean, this));
193+
context.subscriptions.push(
194+
vscode.commands.registerCommand(
195+
CleanLintDiagnostics,
196+
() => {
197+
this.fortranDiagnostics.clear();
198+
},
199+
this
200+
)
201+
);
176202
context.subscriptions.push(
177203
vscode.commands.registerTextEditorCommand(
178204
BuildRun,
@@ -192,38 +218,39 @@ export class FortranLintingProvider {
192218
)
193219
);
194220

195-
// Run the linter on every FreeForm and FixedForm Fortran file detected
196-
// in the workspace. Run this before registering the linter as an
197-
// Open event handler to prevent from Diagnostics being served for the whole
198-
// workspace
199-
await this.initialize();
200-
201-
vscode.workspace.onDidOpenTextDocument(this.doLint, this, context.subscriptions);
221+
vscode.workspace.onDidOpenTextDocument(this.doLint, this, this.disposables);
202222
vscode.workspace.onDidCloseTextDocument(
203-
textDocument => {
204-
this.fortranDiagnostics.delete(textDocument.uri);
223+
doc => {
224+
this.fortranDiagnostics.delete(doc.uri);
205225
},
206-
null,
207-
context.subscriptions
226+
this,
227+
this.disposables
208228
);
209229

210-
vscode.workspace.onDidSaveTextDocument(this.doLint, this);
211-
212-
// Run gfortran in all open fortran files
230+
vscode.workspace.onDidSaveTextDocument(this.doLint, this, this.disposables);
231+
// Run the linter for all open documents i.e. docs loaded in memory
213232
vscode.workspace.textDocuments.forEach(this.doLint, this);
214233

215234
// Update settings on Configuration change
216235
vscode.workspace.onDidChangeConfiguration(e => {
217236
this.settings.update(e);
218-
});
237+
}, this.disposables);
238+
239+
if (this.settings.initialize) this.initialize();
219240
}
220241

221242
public dispose(): void {
222243
this.fortranDiagnostics.clear();
223244
this.fortranDiagnostics.dispose();
245+
this.disposables.forEach(d => d.dispose());
224246
}
225247

226-
private async doLint(document: vscode.TextDocument) {
248+
/**
249+
* Lint a document using the specified linter options
250+
* @param document TextDocument to lint
251+
* @returns An array of vscode.Diagnostic[]
252+
*/
253+
private async doLint(document: vscode.TextDocument): Promise<vscode.Diagnostic[]> | undefined {
227254
// Only lint if a compiler is specified
228255
if (!this.settings.enabled) return;
229256
// Only lint Fortran (free, fixed) format files
@@ -239,6 +266,9 @@ export class FortranLintingProvider {
239266
return diagnostics;
240267
}
241268

269+
/**
270+
* Scan the workspace for Fortran files and lint them
271+
*/
242272
private async initialize() {
243273
const files = await this.getFiles();
244274
const opts = {
@@ -258,12 +288,16 @@ export class FortranLintingProvider {
258288
message: `file ${i}/${files.length}`,
259289
});
260290
try {
261-
this.doBuild(await vscode.workspace.openTextDocument(file));
291+
const doc = await vscode.workspace.openTextDocument(file);
292+
this.doLint(doc);
262293
} catch (error) {
263294
continue;
264295
}
265296
}
266297
});
298+
// Clear the diagnostics from the Problems console. FYI The textdocuments
299+
// are still open in memory
300+
if (!this.settings.keepInitDiagnostics) this.fortranDiagnostics.clear();
267301
}
268302

269303
private async getFiles() {
@@ -290,6 +324,18 @@ export class FortranLintingProvider {
290324
return deps;
291325
}
292326

327+
/**
328+
* Clean any build artifacts produced by the linter e.g. .mod, .smod files
329+
*/
330+
private async clean() {
331+
if (!this.storageUI) return;
332+
const cacheDir = this.storageUI;
333+
const files = glob.sync(cacheDir + '/**/*.{mod,smod,o}');
334+
files.forEach(file => {
335+
fs.promises.rm(file);
336+
});
337+
}
338+
293339
private async doBuild(document: vscode.TextDocument): Promise<string> | undefined {
294340
this.linter = this.getLinter(this.settings.compiler);
295341
const command = this.settings.compilerExe;

0 commit comments

Comments
 (0)