Skip to content

Commit ff2620c

Browse files
pedro-ricardokrvajal
authored andcommitted
Intrinsics case auto-complete. (#83)
* Add new configuration option for intrinsics case auto-complete. * Refactor code * Fix README spelling mistakes
1 parent 104ef08 commit ff2620c

File tree

5 files changed

+175
-102
lines changed

5 files changed

+175
-102
lines changed

README.md

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66
[![Installs](https://vsmarketplacebadge.apphb.com/installs/krvajalm.linter-gfortran.svg)](https://marketplace.visualstudio.com/items?itemName=krvajalm.linter-gfortran)
77
[![GitHub release](https://img.shields.io/github/release/krvajal/vscode-fortran-support.svg)](https://GitHub.com/krvajal/vscode-fortran-support/releases/)
88

9-
> This extension provides support for the Fortran programming language. It includes syntax highlighting, code snippets and a linting based on gfortran. You can download the Visual Estudio Code editor from [here](https://code.visualstudio.com/download).
9+
> This extension provides support for the Fortran programming language. It includes syntax highlighting, code snippets and a linting based on `gfortran`. You can download the Visual Studio Code editor from [here](https://code.visualstudio.com/download).
1010
1111
## Features
1212

13-
* Syntax highlighting
14-
* Code Snippets
15-
* Documentation on hover for intrisic functions
16-
* Code linting based on `gfortran` to show errors swiggles in your code
17-
* Code autocompletion (beta)
18-
* Symbols provider
13+
- Syntax highlighting
14+
- Code Snippets
15+
- Documentation on hover for intrinsic functions
16+
- Code linting based on `gfortran` to show errors wiggles in your code
17+
- Code autocompletion (beta)
18+
- Symbols provider
1919

2020
![symbol_nav](./doc/symbol_nav.png)
2121

@@ -58,17 +58,25 @@ You can configure what kind of symbols will appear in the symbol list by using
5858

5959
The available options are
6060

61-
* "function"
62-
* "subroutine"
63-
* "variable"
64-
* "module" (not supported yet)
65-
* "program" (not supported yet)
61+
- "function"
62+
- "subroutine"
63+
- "variable"
64+
- "module" (not supported yet)
65+
- "program" (not supported yet)
6666

6767
and by default only functions and subroutines are shown
6868

69+
You can also configure the case for fortran intrinsics auto-complete by using
70+
71+
```
72+
{
73+
"fortran.preferredCase": "lowercase" | "uppercase"
74+
}
75+
```
76+
6977
## Snippets
7078

71-
This is a list of some of the snippets included, if you like to include some additionals snippets please let me know and I will add them.
79+
This is a list of some of the snippets included, if you like to include additional snippets please let me know and I will add them.
7280

7381
#### Program skeleton
7482

@@ -78,7 +86,7 @@ This is a list of some of the snippets included, if you like to include some add
7886

7987
![module snippet](https://media.giphy.com/media/3ohzdUNRuio5FfyF1u/giphy.gif)
8088

81-
## Error swiggles
89+
## Error wiggles
8290

8391
To trigger code validations you must save the file first.
8492

@@ -88,13 +96,13 @@ For the linter to work you need to have `gfortran` on your path, or wherever you
8896

8997
## Issues
9098

91-
Please report any issues and feature request on the github repo [here](https://github.com/krvajalmiguelangel/vscode-fortran-support/issues/new)
99+
Please report any issues and feature request on the GitHub repo [here](https://github.com/krvajalmiguelangel/vscode-fortran-support/issues/new)
92100

93101
## Notice
94102

95103
The syntax highlight support was imported from [TextMate bundle](https://github.com/textmate/fortran.tmbundle)
96104

97-
The idea of using gfortran cames from this awesome [fortran plugin](https://github.com/315234/SublimeFortran) for Sublime Text.
105+
The idea of using `gfortran` comes from this awesome [fortran plugin](https://github.com/315234/SublimeFortran) for Sublime Text.
98106

99107
## LICENSE
100108

package.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,15 @@
128128
"subroutine"
129129
],
130130
"description": "Specify what kind of symbols should be shown by the symbols' provider"
131+
},
132+
"fortran.preferredCase": {
133+
"type": "string",
134+
"default": "lowercase",
135+
"enum": [
136+
"lowercase",
137+
"uppercase"
138+
],
139+
"description": "Scpecify the word case to use when suggesting autocomplete options (One of 'lowercase' or 'upercase')"
131140
}
132141
}
133142
}

src/extension.ts

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,34 @@
11
// src/extension.ts
2-
import * as vscode from "vscode";
2+
import * as vscode from 'vscode'
33

4-
import FortranLintingProvider from "./features/linter-provider";
5-
import FortranHoverProvider from "./features/hover-provider";
6-
import { FortranCompletionProvider } from "./features/completion-provider";
7-
import { FortranDocumentSymbolProvider } from "./features/document-symbol-provider";
8-
import { LANGUAGE_ID } from './lib/helper';
4+
import FortranLintingProvider from './features/linter-provider'
5+
import FortranHoverProvider from './features/hover-provider'
6+
import { FortranCompletionProvider } from './features/completion-provider'
7+
import { FortranDocumentSymbolProvider } from './features/document-symbol-provider'
8+
import { LANGUAGE_ID } from './lib/helper'
99

10-
const FORTRAN_FREE_FORM_ID = { language: LANGUAGE_ID, scheme: "file" };
10+
const FORTRAN_FREE_FORM_ID = { language: LANGUAGE_ID, scheme: 'file' }
1111

1212
export function activate(context: vscode.ExtensionContext) {
13-
let hoverProvider = new FortranHoverProvider();
14-
let completionProvider = new FortranCompletionProvider();
15-
let symbolProvider = new FortranDocumentSymbolProvider();
13+
let hoverProvider = new FortranHoverProvider()
14+
let completionProvider = new FortranCompletionProvider()
15+
let symbolProvider = new FortranDocumentSymbolProvider()
16+
const extensionConfig = vscode.workspace.getConfiguration('LANGUAGE_ID')
1617

17-
if (vscode.workspace.getConfiguration("fortran").get("linterEnabled", true)) {
18-
let linter = new FortranLintingProvider();
19-
linter.activate(context.subscriptions);
20-
vscode.languages.registerCodeActionsProvider(FORTRAN_FREE_FORM_ID, linter);
18+
if (extensionConfig.get('linterEnabled', true)) {
19+
let linter = new FortranLintingProvider()
20+
linter.activate(context.subscriptions)
21+
vscode.languages.registerCodeActionsProvider(FORTRAN_FREE_FORM_ID, linter)
2122
}
2223

2324
vscode.languages.registerCompletionItemProvider(
2425
FORTRAN_FREE_FORM_ID,
2526
completionProvider
26-
);
27-
vscode.languages.registerHoverProvider(FORTRAN_FREE_FORM_ID, hoverProvider);
27+
)
28+
vscode.languages.registerHoverProvider(FORTRAN_FREE_FORM_ID, hoverProvider)
29+
2830
vscode.languages.registerDocumentSymbolProvider(
2931
FORTRAN_FREE_FORM_ID,
3032
symbolProvider
31-
);
33+
)
3234
}

src/features/completion-provider.ts

Lines changed: 121 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,36 @@
1-
import { CancellationToken, TextDocument, Position, Hover } from "vscode";
2-
import * as fs from "fs";
3-
import * as vscode from "vscode";
4-
import {
5-
isPositionInString,
6-
intrinsics,
7-
FORTRAN_KEYWORDS
8-
} from "../lib/helper";
9-
import { getDeclaredFunctions } from "../lib/functions";
1+
import { CancellationToken, TextDocument, Position, Hover } from 'vscode'
2+
import * as fs from 'fs'
3+
import * as vscode from 'vscode'
4+
import { isPositionInString, intrinsics, FORTRAN_KEYWORDS } from '../lib/helper'
5+
import { getDeclaredFunctions } from '../lib/functions'
6+
import { EXTENSION_ID } from '../lib/helper'
7+
8+
class CaseCoverter {
9+
preferredCase: string
10+
static LOWER = 'lowercase'
11+
static UPPER = 'uppercase'
12+
13+
constructor(preferredCase: string = CaseCoverter.LOWER) {
14+
this.preferredCase = preferredCase
15+
}
16+
17+
convert(word: string): string {
18+
if (this.preferredCase == CaseCoverter.LOWER) {
19+
return this.toLower(word)
20+
} else if (this.preferredCase == CaseCoverter.UPPER) {
21+
return this.toUpper(word)
22+
}
23+
24+
throw new Error(`the provided case ${this.preferredCase} is not supported`)
25+
}
26+
27+
toLower(word: string) {
28+
return word.toLowerCase()
29+
}
30+
toUpper(word: string) {
31+
return word.toUpperCase()
32+
}
33+
}
1034

1135
export class FortranCompletionProvider
1236
implements vscode.CompletionItemProvider {
@@ -19,87 +43,115 @@ export class FortranCompletionProvider
1943
document,
2044
position,
2145
token,
22-
vscode.workspace.getConfiguration("go")
23-
);
46+
vscode.workspace.getConfiguration(EXTENSION_ID)
47+
)
2448
}
49+
2550
public provideCompletionItemsInternal(
2651
document: vscode.TextDocument,
2752
position: vscode.Position,
2853
token: vscode.CancellationToken,
2954
config: vscode.WorkspaceConfiguration
3055
): Thenable<vscode.CompletionItem[]> {
3156
return new Promise<vscode.CompletionItem[]>((resolve, reject) => {
32-
let filename = document.fileName;
33-
let lineText = document.lineAt(position.line).text;
34-
let lineTillCurrentPosition = lineText.substr(0, position.character);
57+
let lineText = document.lineAt(position.line).text
58+
let lineTillCurrentPosition = lineText.substr(0, position.character)
3559
// nothing to complete
3660
if (lineText.match(/^\s*\/\//)) {
37-
return resolve([]);
61+
return resolve([])
3862
}
3963

40-
let inString = isPositionInString(document, position);
64+
let inString = isPositionInString(document, position)
4165
if (!inString && lineTillCurrentPosition.endsWith('"')) {
4266
// completing a string
43-
return resolve([]);
67+
return resolve([])
4468
}
4569

46-
// get current word
47-
let wordAtPosition = document.getWordRangeAtPosition(position);
48-
let currentWord = "";
49-
if (
50-
wordAtPosition &&
51-
wordAtPosition.start.character < position.character
52-
) {
53-
let word = document.getText(wordAtPosition);
54-
currentWord = word.substr(
55-
0,
56-
position.character - wordAtPosition.start.character
57-
);
58-
}
70+
let currentWord = this.getCurrentWord(document, position)
5971

6072
if (currentWord.match(/^\d+$/)) {
6173
// starts with a number
62-
return resolve([]);
74+
return resolve([])
6375
}
6476

65-
let suggestions = [];
66-
67-
if (currentWord.length > 0) {
68-
intrinsics.forEach(intrinsic => {
69-
if (intrinsic.startsWith(currentWord.toUpperCase())) {
70-
suggestions.push(
71-
new vscode.CompletionItem(
72-
intrinsic,
73-
vscode.CompletionItemKind.Method
74-
)
75-
);
76-
}
77-
});
78-
79-
// add keyword suggestions
80-
FORTRAN_KEYWORDS.forEach(keyword => {
81-
if (keyword.startsWith(currentWord.toUpperCase())) {
82-
suggestions.push(
83-
new vscode.CompletionItem(
84-
keyword.toLowerCase(),
85-
vscode.CompletionItemKind.Keyword
86-
)
87-
);
88-
}
89-
});
77+
const caseConverter = new CaseCoverter(config.get('preferredCase'))
78+
79+
if (currentWord.length === 0) {
80+
resolve([])
9081
}
91-
const functions = getDeclaredFunctions(document);
92-
// check for available functions
93-
functions.filter(fun => fun.name.startsWith(currentWord)).forEach(fun => {
94-
suggestions.push(
95-
new vscode.CompletionItem(
96-
fun.name,
97-
vscode.CompletionItemKind.Function
98-
)
99-
);
100-
});
101-
102-
return resolve(suggestions);
103-
});
82+
83+
const intrinsicSuggestions = this.getIntrinsicSuggestions(
84+
currentWord,
85+
caseConverter
86+
)
87+
88+
// add keyword suggestions
89+
const keywordSuggestions = this.getKeywordSuggestions(currentWord)
90+
91+
const functionSuggestions = this.getFunctionSuggestions(
92+
document,
93+
currentWord
94+
)
95+
96+
return resolve([
97+
...intrinsicSuggestions,
98+
...keywordSuggestions,
99+
...functionSuggestions,
100+
])
101+
})
102+
}
103+
104+
private getIntrinsicSuggestions(
105+
currentWord: string,
106+
caseConverter: CaseCoverter
107+
): vscode.CompletionItem[] {
108+
return intrinsics
109+
.filter(i => i.startsWith(currentWord.toUpperCase()))
110+
.map((intrinsic: string) => {
111+
return new vscode.CompletionItem(
112+
caseConverter.convert(intrinsic),
113+
vscode.CompletionItemKind.Method
114+
)
115+
})
116+
}
117+
118+
private getKeywordSuggestions(currentWord: string): vscode.CompletionItem[] {
119+
return FORTRAN_KEYWORDS.filter(keyword =>
120+
keyword.startsWith(currentWord.toUpperCase())
121+
).map(keyword => {
122+
return new vscode.CompletionItem(
123+
keyword.toLowerCase(),
124+
vscode.CompletionItemKind.Keyword
125+
)
126+
})
127+
}
128+
129+
private getFunctionSuggestions(
130+
document: TextDocument,
131+
currentWord: string
132+
): vscode.CompletionItem[] {
133+
const functions = getDeclaredFunctions(document)
134+
// check for available functions
135+
return functions
136+
.filter(fun => fun.name.startsWith(currentWord))
137+
.map(fun => {
138+
return new vscode.CompletionItem(
139+
`${fun.name}(`,
140+
vscode.CompletionItemKind.Function
141+
)
142+
})
143+
}
144+
145+
private getCurrentWord(document: TextDocument, position: Position): string {
146+
let wordAtPosition = document.getWordRangeAtPosition(position)
147+
let currentWord = ''
148+
if (wordAtPosition && wordAtPosition.start.character < position.character) {
149+
let word = document.getText(wordAtPosition)
150+
currentWord = word.substr(
151+
0,
152+
position.character - wordAtPosition.start.character
153+
)
154+
}
155+
return currentWord
104156
}
105157
}

src/lib/helper.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import * as vscode from 'vscode'
55
// on the package.json otherwise the extension won't
66
// work at all
77
export const LANGUAGE_ID = 'FortranFreeForm'
8+
export const EXTENSION_ID = 'fortran'
9+
810

911
export const intrinsics = [
1012
'ABORT',

0 commit comments

Comments
 (0)