Skip to content

Commit d8e48b9

Browse files
committed
feat: add interpolation for config options
1 parent c21998f commit d8e48b9

File tree

6 files changed

+406
-62
lines changed

6 files changed

+406
-62
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@
191191
"istanbul": "^0.4.5",
192192
"lint-staged": "^7.3.0",
193193
"mocha": "^2.3.3",
194+
"prettier": "^2.3.1",
194195
"remap-istanbul": "^0.8.4",
195196
"tslint": "^4.0.2",
196197
"typescript": "^3.5.1",

src/extension.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,27 @@ import { FORTRAN_FREE_FORM_ID, EXTENSION_ID } from './lib/helper'
1010
import { FortranLangServer, checkForLangServer } from './lang-server'
1111
import { LoggingService } from './services/logging-service'
1212
import * as pkg from '../package.json'
13+
import { Config } from './services/config'
1314

14-
export function activate(context: vscode.ExtensionContext) {
15+
export async function activate(context: vscode.ExtensionContext) {
1516
const loggingService = new LoggingService()
16-
const extensionConfig = vscode.workspace.getConfiguration(EXTENSION_ID)
1717

18+
const extensionConfig = new Config(
19+
vscode.workspace.getConfiguration(EXTENSION_ID),
20+
loggingService
21+
)
1822
loggingService.logInfo(`Extension Name: ${pkg.displayName}`)
1923
loggingService.logInfo(`Extension Version: ${pkg.version}`)
2024

21-
if (extensionConfig.get('linterEnabled', true)) {
22-
let linter = new FortranLintingProvider(loggingService)
25+
if (await extensionConfig.get('linterEnabled', true)) {
26+
let linter = new FortranLintingProvider(loggingService, extensionConfig)
2327
linter.activate(context.subscriptions)
2428
vscode.languages.registerCodeActionsProvider(FORTRAN_FREE_FORM_ID, linter)
2529
} else {
2630
loggingService.logInfo('Linter is not enabled')
2731
}
2832

29-
if (extensionConfig.get('provideCompletion', true)) {
33+
if (await extensionConfig.get('provideCompletion', true)) {
3034
let completionProvider = new FortranCompletionProvider(loggingService)
3135
vscode.languages.registerCompletionItemProvider(
3236
FORTRAN_FREE_FORM_ID,
@@ -36,14 +40,14 @@ export function activate(context: vscode.ExtensionContext) {
3640
loggingService.logInfo('Completion Provider is not enabled')
3741
}
3842

39-
if (extensionConfig.get('provideHover', true)) {
43+
if (await extensionConfig.get('provideHover', true)) {
4044
let hoverProvider = new FortranHoverProvider(loggingService)
4145
vscode.languages.registerHoverProvider(FORTRAN_FREE_FORM_ID, hoverProvider)
4246
} else {
4347
loggingService.logInfo('Hover Provider is not enabled')
4448
}
4549

46-
if (extensionConfig.get('provideSymbols', true)) {
50+
if (await extensionConfig.get('provideSymbols', true)) {
4751
let symbolProvider = new FortranDocumentSymbolProvider()
4852
vscode.languages.registerDocumentSymbolProvider(
4953
FORTRAN_FREE_FORM_ID,

src/features/linter-provider.ts

Lines changed: 87 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,23 @@ import { getIncludeParams, LANGUAGE_ID } from '../lib/helper'
66

77
import * as vscode from 'vscode'
88
import { LoggingService } from '../services/logging-service'
9+
import { Config } from '../services/config'
10+
import { EnvironmentVariables } from '../services/utils'
11+
12+
const ERROR_REGEX: RegExp =
13+
/^([a-zA-Z]:\\)*([^:]*):([0-9]+):([0-9]+):\s+(.*)\s+.*?\s+(Error|Warning|Fatal Error):\s(.*)$/gm
14+
15+
const knownModNames = ['mpi']
916

1017
export default class FortranLintingProvider {
11-
constructor(private loggingService: LoggingService) {}
18+
constructor(
19+
private loggingService: LoggingService,
20+
private _config: Config
21+
) {}
1222

1323
private diagnosticCollection: vscode.DiagnosticCollection
1424

15-
private doModernFortranLint(textDocument: vscode.TextDocument) {
16-
const errorRegex: RegExp =
17-
/^([a-zA-Z]:\\)*([^:]*):([0-9]+):([0-9]+):\s+(.*)\s+.*?\s+(Error|Warning|Fatal Error):\s(.*)$/gm
18-
25+
private async doModernFortranLint(textDocument: vscode.TextDocument) {
1926
if (
2027
textDocument.languageId !== LANGUAGE_ID ||
2128
textDocument.uri.scheme !== 'file'
@@ -24,9 +31,9 @@ export default class FortranLintingProvider {
2431
}
2532

2633
let decoded = ''
27-
let diagnostics: vscode.Diagnostic[] = []
28-
let command = this.getGfortranPath()
29-
let argList = this.constructArgumentList(textDocument)
34+
35+
let command = await this.getGfortranPath()
36+
let argList = await this.constructArgumentList(textDocument)
3037

3138
let filePath = path.parse(textDocument.fileName).dir
3239

@@ -37,70 +44,82 @@ export default class FortranLintingProvider {
3744
*
3845
* see also: https://gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
3946
*/
40-
const env = process.env
41-
env.LC_ALL = 'C'
47+
const env: EnvironmentVariables = { ...process.env, LC_ALL: 'C' }
4248
if (process.platform === 'win32') {
4349
// Windows needs to know the path of other tools
4450
if (!env.Path.includes(path.dirname(command))) {
4551
env.Path = `${path.dirname(command)}${path.delimiter}${env.Path}`
4652
}
4753
}
48-
let childProcess = cp.spawn(command, argList, { cwd: filePath, env: env })
54+
this.loggingService.logInfo(
55+
`executing linter command ${command} ${argList.join(' ')}`
56+
)
57+
let gfortran = cp.spawn(command, argList, { cwd: filePath, env })
4958

50-
if (childProcess.pid) {
51-
childProcess.stdout.on('data', (data: Buffer) => {
59+
if (gfortran && gfortran.pid) {
60+
gfortran!.stdout!.on('data', (data: Buffer) => {
5261
decoded += data
5362
})
54-
childProcess.stderr.on('data', (data) => {
63+
gfortran!.stderr!.on('data', (data) => {
5564
decoded += data
5665
})
57-
childProcess.stderr.on('end', () => {
58-
let matchesArray: string[]
59-
while ((matchesArray = errorRegex.exec(decoded)) !== null) {
60-
let elements: string[] = matchesArray.slice(1) // get captured expressions
61-
let startLine = parseInt(elements[2])
62-
let startColumn = parseInt(elements[3])
63-
let type = elements[5] // error or warning
64-
let severity =
65-
type.toLowerCase() === 'warning'
66-
? vscode.DiagnosticSeverity.Warning
67-
: vscode.DiagnosticSeverity.Error
68-
let message = elements[6]
69-
let range = new vscode.Range(
70-
new vscode.Position(startLine - 1, startColumn),
71-
new vscode.Position(startLine - 1, startColumn)
72-
)
73-
let diagnostic = new vscode.Diagnostic(range, message, severity)
74-
diagnostics.push(diagnostic)
75-
}
76-
77-
this.diagnosticCollection.set(textDocument.uri, diagnostics)
66+
gfortran!.stderr.on('end', () => {
67+
this.reportErrors(decoded, textDocument)
7868
})
79-
childProcess.stdout.on('close', (code) => {
69+
gfortran.stdout.on('close', (code) => {
8070
console.log(`child process exited with code ${code}`)
8171
})
8272
} else {
83-
childProcess.on('error', (err: any) => {
73+
gfortran.on('error', (err: any) => {
8474
if (err.code === 'ENOENT') {
8575
vscode.window.showErrorMessage(
86-
"gfortran can't found on path, update your settings with a proper path or disable the linter."
76+
"gfortran executable can't be found at the provided path, update your settings with a proper path or disable the linter."
8777
)
8878
}
8979
})
9080
}
9181
}
9282

93-
private constructArgumentList(textDocument: vscode.TextDocument): string[] {
94-
let options = vscode.workspace.rootPath
95-
? { cwd: vscode.workspace.rootPath }
96-
: undefined
83+
reportErrors(errors: string, textDocument: vscode.TextDocument) {
84+
let diagnostics: vscode.Diagnostic[] = []
85+
let matchesArray: string[]
86+
while ((matchesArray = ERROR_REGEX.exec(errors)) !== null) {
87+
let elements: string[] = matchesArray.slice(1) // get captured expressions
88+
let startLine = parseInt(elements[2])
89+
let startColumn = parseInt(elements[3])
90+
let type = elements[5] // error or warning
91+
let severity =
92+
type.toLowerCase() === 'warning'
93+
? vscode.DiagnosticSeverity.Warning
94+
: vscode.DiagnosticSeverity.Error
95+
let message = elements[6]
96+
const [isModError, modName] = isModuleMissingErrorMessage(message)
97+
// skip error from known mod names
98+
if (isModError && knownModNames.includes(modName)) {
99+
continue
100+
}
101+
let range = new vscode.Range(
102+
new vscode.Position(startLine - 1, startColumn),
103+
new vscode.Position(startLine - 1, startColumn)
104+
)
105+
106+
let diagnostic = new vscode.Diagnostic(range, message, severity)
107+
diagnostics.push(diagnostic)
108+
}
109+
110+
this.diagnosticCollection.set(textDocument.uri, diagnostics)
111+
}
112+
113+
private async constructArgumentList(
114+
textDocument: vscode.TextDocument
115+
): Promise<string[]> {
97116
let args = [
98117
'-fsyntax-only',
99118
'-cpp',
100119
'-fdiagnostics-show-option',
101-
...this.getLinterExtraArgs(),
120+
...(await this.getLinterExtraArgs()),
102121
]
103-
let includePaths = this.getIncludePaths()
122+
let includePaths = await this.getIncludePaths()
104123

105124
let extensionIndex = textDocument.fileName.lastIndexOf('.')
106125
let fileNameWithoutExtension = textDocument.fileName.substring(
@@ -164,21 +183,34 @@ export default class FortranLintingProvider {
164183
this.command.dispose()
165184
}
166185

167-
private getIncludePaths(): string[] {
168-
let config = vscode.workspace.getConfiguration('fortran')
169-
let includePaths: string[] = config.get('includePaths', [])
170-
186+
private async getIncludePaths(): Promise<string[]> {
187+
let includePaths: string[] = await this._config.get('includePaths', [])
188+
this.loggingService.logInfo(`using include paths "${includePaths}"`)
171189
return includePaths
172190
}
173-
private getGfortranPath(): string {
174-
let config = vscode.workspace.getConfiguration('fortran')
175-
const gfortranPath = config.get('gfortranExecutable', 'gfortran')
176-
this.loggingService.logInfo(`using gfortran executable: ${gfortranPath}`)
191+
192+
private async getGfortranPath(): Promise<string> {
193+
const gfortranPath = await this._config.get(
194+
'gfortranExecutable',
195+
'gfortran'
196+
)
197+
this.loggingService.logInfo(`using gfortran executable: "${gfortranPath}"`)
177198
return gfortranPath
178199
}
179200

180-
private getLinterExtraArgs(): string[] {
181-
let config = vscode.workspace.getConfiguration('fortran')
182-
return config.get('linterExtraArgs', ['-Wall'])
201+
private getLinterExtraArgs(): Promise<string[]> {
202+
return this._config.get('linterExtraArgs', ['-Wall'])
203+
}
204+
}
205+
206+
function isModuleMissingErrorMessage(
207+
message: string
208+
): [boolean, string | null] {
209+
const result = /^Cannot open module file '(\w+).mod' for reading/.exec(
210+
message
211+
)
212+
if (result) {
213+
return [true, result[1]]
183214
}
215+
return [false, null]
184216
}

0 commit comments

Comments
 (0)