Skip to content

Support for Formatting #256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 70 commits into from
Nov 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
1ed6c2f
Updated CHANGELOG for v2.2.2
gnikit Jun 30, 2021
10d0cd3
Incremented package version to 2.2.2
gnikit Jun 30, 2021
56f0072
Minor aesthetic improvements to CHANGELOG
gnikit Jun 30, 2021
04a317b
Adds OpenACC unit test
gnikit Jun 30, 2021
9aaadd1
Updated tasks and launch files
gnikit Jun 30, 2021
b7296b3
Fixes Remove unused packages #243
gnikit Jul 1, 2021
d448d10
Updated README badges
gnikit Jul 2, 2021
75a7ba4
Updated workflows to run on Ubuntu latest
gnikit Jul 2, 2021
4cd833b
Fix overzealous OpenMP regex.
gnikit Sep 16, 2021
24ba48c
Updating changelog.md
gnikit Sep 16, 2021
aa8ade4
New minor release
gnikit Sep 16, 2021
b64402a
Housekeeping
gnikit Sep 19, 2021
2b11a66
Added info to package.json
gnikit Oct 1, 2021
38caef9
Fixes in-house documentaiton hover
gnikit Oct 1, 2021
bc7a38d
Now the deocumentation displays correctly
gnikit Oct 1, 2021
d4b6cad
Formatting .json doc files with prettier
gnikit Oct 1, 2021
b6e840f
Updated README.md
gnikit Oct 1, 2021
f0e6af4
Adds VS marketplace automated release
gnikit Oct 2, 2021
83aa34f
Further improvements to the hover documentation
gnikit Oct 2, 2021
2adaa8d
further fixes for internal documentation
gnikit Oct 3, 2021
f1c2aa2
Adds autoclosing for strings
gnikit Oct 3, 2021
23e6437
Updates Fortran extensino and adds .pFUnit support
gnikit Oct 3, 2021
25eb5bb
Updates CHANGELOG.md
gnikit Oct 3, 2021
6537b38
Fixes preprocessor syntax highlighting
gnikit Oct 6, 2021
b5342a5
Preprocessor assignment i.e. = is not a thing
gnikit Oct 6, 2021
1086fe5
Preprocessor operator fixes
gnikit Oct 7, 2021
d214d53
Fixes Erroneous syntax highlighting, when argument is called "functio…
gnikit Oct 11, 2021
064bd20
Adds unittest for #207 and updates CHANGELOG
gnikit Oct 11, 2021
7f6706a
Adds syntax highlighting support for fypp
gnikit Oct 11, 2021
06af154
Add MIT license badge back to README
gnikit Oct 11, 2021
5bfbbe6
Adds names specific to individual scopes
gnikit Oct 11, 2021
a8f33f9
Fixes Erroneous syntax highlighting of if construct with tags #204
gnikit Oct 11, 2021
e9763d3
Updated CHANGELOG.md
gnikit Oct 11, 2021
5a6039d
Fixes STOP named_string #172
gnikit Oct 11, 2021
920ea64
Comments are correctly highlighted for type,...
gnikit Oct 12, 2021
801c7f3
Add syntax test for fixed form fortran
gnikit Oct 12, 2021
b221114
Switches to @types/vscode & @vscode/test-electron
gnikit Oct 15, 2021
3a35241
Updated changelog
gnikit Oct 15, 2021
595f10d
Updated yarn.lock
gnikit Oct 15, 2021
fd6c177
Increments version to 2.4.0
gnikit Oct 15, 2021
37cdec2
Updated tasks.json and launch.json
gnikit Oct 18, 2021
dd94666
Updated names of scopes to contain fortran
gnikit Oct 19, 2021
3d60be6
Fixes normal labeled construct end statements
gnikit Oct 19, 2021
f20856e
Adds error highlighting for else labeled
gnikit Oct 19, 2021
901bcb3
Upgraded package.json grammar update
gnikit Oct 19, 2021
caf2d46
Removes paths.ts which checks if binary is in PATH
gnikit Sep 21, 2021
d60ad88
Updates install tools.
gnikit Sep 21, 2021
8b72230
Adds formatting support
gnikit Sep 21, 2021
548ffd7
Installing `findent` through pip
gnikit Oct 1, 2021
3f426b2
Minor edit when installing a VSCode extension
gnikit Oct 1, 2021
0bc0f86
Renames `fortran_fixed-form` to `FortranFixedForm`
gnikit Oct 1, 2021
c186690
The extension would not activate for fixed form
gnikit Oct 1, 2021
17dce23
Linting now works with fixed form
gnikit Oct 1, 2021
4d2d08a
Added safeguard for fprettify and fixed Fortran
gnikit Oct 1, 2021
521dcd5
Updates README.md
gnikit Oct 1, 2021
4da11a2
Addresses review comments
gnikit Oct 14, 2021
202a962
Update to version 2.5.0
gnikit Oct 15, 2021
251fb79
Updates CHANGELOG after rebase
gnikit Oct 15, 2021
1041142
Merge branch 'master' into feature/formatting
gnikit Nov 9, 2021
264f7d2
Merge branch 'master' into feature/formatting
gnikit Nov 9, 2021
4586013
Merge branch 'master' into feature/formatting
gnikit Nov 9, 2021
5790bc4
Lint and format
gnikit Nov 10, 2021
cd132ca
Merge branch 'master' into feature/formatting
gnikit Nov 10, 2021
08e1832
Updates changelog
gnikit Nov 10, 2021
efacb05
Merge branch 'master' into feature/formatting
gnikit Nov 12, 2021
f2e7c21
Merge branch 'master' into feature/formatting
gnikit Nov 12, 2021
c14dae7
Merge branch 'master' into feature/formatting
gnikit Nov 12, 2021
d61c972
Merge branch 'master' into feature/formatting
gnikit Nov 16, 2021
ff7a2a1
Updates README by including formatting annimations
gnikit Nov 17, 2021
3dec046
Sets findent as the default formatter
gnikit Nov 17, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

## [2.5.0]

### Added

- Adds support for formatting with `findent` and `fprettify`
([#29](https://github.com/krvajal/vscode-fortran-support/issues/29))

## [2.4.3]

### Changed
Expand All @@ -22,13 +29,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
([#257](https://github.com/krvajal/vscode-fortran-support/issues/257))
- Linting is now operational for `FortranFixedForm`
([#258](https://github.com/krvajal/vscode-fortran-support/issues/258))
- Fixes dummy variable list erroneous syntax highlighting
([#264](https://github.com/krvajal/vscode-fortran-support/issues/264))

### Changed

- Renamed the Fixed Format Format language from `fortran_fixed-form` to
`FortranFixedForm`, an alias has been added for backwards compatibility
([#259](https://github.com/krvajal/vscode-fortran-support/issues/259))

### Added

- Adds prompts for installing Fortran IntelliSense and fortran-language-server

### Removed

- Removes `paths.js` for detecting binaries in favour of `which`
Expand Down Expand Up @@ -306,7 +319,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Initial release

[unreleased]: https://github.com/krvajal/vscode-fortran-support/compare/v2.4.3...HEAD
[unreleased]: https://github.com/krvajal/vscode-fortran-support/compare/v2.5.0...HEAD
[2.5.0]: https://github.com/krvajal/vscode-fortran-support/compare/v2.4.3...v2.5.0
[2.4.3]: https://github.com/krvajal/vscode-fortran-support/compare/v2.4.2...v2.4.3
[2.4.2]: https://github.com/krvajal/vscode-fortran-support/compare/v2.4.1...v2.4.2
[2.4.1]: https://github.com/krvajal/vscode-fortran-support/compare/v2.4.0...v2.4.1
Expand Down
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- Code autocompletion (beta)
- Symbols provider
- Debugger, uses Microsoft's [C/C++ extension](https://github.com/Microsoft/vscode-cpptools)
- Formatting with [findent](https://github.com/gnikit/findent-pypi) or [fprettify](https://github.com/pseewald/fprettify)

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

Expand Down Expand Up @@ -137,6 +138,44 @@ More details about how to setup the debugger can be found in Microsoft's website
}
```

## Formatting

Two formatters are supported [`findent`](https://github.com/gnikit/findent-pypi)
and [`fprettify`](https://github.com/pseewald/fprettify). Both of them can be
installed with `pip` automatically through the extension.

findent | fprettify
:-------------------------:|:-------------------------:
![](./images/findent-demo.gif) | ![](./images/fprettify-demo.gif)

The formatter is controlled by the user option

```json
{
"fortran.formatting.formatter": "Disabled" | "findent" | "fprettify",
}
```

Additional arguments to the formatter can be input using

```json
{
"fortran.formatting.args":, ["-Cn", "--align-paren=1"]
}
```

If the formatter is not present in the `PATH` its location can be input with

```json
{
"fortran.formattting.path": "/custom-path-to-formatter-binary"
}
```

### NOTE: About `findent`

`findent` can also be used to generate dependency files for a project.

## Requirements

For the linter to work you need to have `gfortran` on your path, or wherever you configure it to be.
Expand Down
Binary file added images/findent-demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/fprettify-demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 23 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "linter-gfortran",
"displayName": "Modern Fortran",
"description": "Modern Fortran language support, including syntax highlighting and error detection.",
"version": "2.4.0",
"version": "2.5.0",
"publisher": "krvajalm",
"license": "MIT",
"author": {
Expand Down Expand Up @@ -36,7 +36,8 @@
"Programming Languages",
"Snippets",
"Linters",
"Debuggers"
"Debuggers",
"Formatters"
],
"activationEvents": [
"onLanguage:FortranFreeForm",
Expand Down Expand Up @@ -159,6 +160,26 @@
],
"description": "Specify additional options to use when calling the gfortran compiler"
},
"fortran.formatting.formatter": {
"type": "string",
"default": "findent",
"enum": [
"findent",
"fprettify",
"Disabled"
],
"description": "Fortran formatter, currently supports findent and fprettify"
},
"fortran.formatting.args": {
"type": "array",
"default": [],
"description": "Additional arguments for the formatter"
},
"fortran.formatting.path": {
"type": "string",
"default": "",
"description": "Specify the full path of where the formatter is installed"
},
"fortran.provideSymbols": {
"type": "boolean",
"default": true,
Expand Down
12 changes: 12 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { FORTRAN_DOCUMENT_SELECTOR, EXTENSION_ID, promptForMissingTool } from '.
import { LoggingService } from './services/logging-service';
import * as pkg from '../package.json';
import { LANG_SERVER_TOOL_ID } from './lib/tools';
import { FortranFormattingProvider } from './features/formatting-provider';

export function activate(context: vscode.ExtensionContext) {
const loggingService = new LoggingService();
Expand All @@ -29,6 +30,17 @@ export function activate(context: vscode.ExtensionContext) {
loggingService.logInfo('Linter is not enabled');
}

if (extensionConfig.get('formatter') !== 'Disabled') {
const disposable: vscode.Disposable = vscode.languages.registerDocumentFormattingEditProvider(
FORTRAN_DOCUMENT_SELECTOR,
new FortranFormattingProvider(loggingService)
);
context.subscriptions.push(disposable);
loggingService.logInfo('Formatting is enabled');
} else {
loggingService.logInfo('Formatting is disabled');
}

if (extensionConfig.get('provideCompletion', true)) {
const completionProvider = new FortranCompletionProvider(loggingService);
vscode.languages.registerCompletionItemProvider(FORTRAN_DOCUMENT_SELECTOR, completionProvider);
Expand Down
162 changes: 162 additions & 0 deletions src/features/formatting-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
'use strict';

import * as fs from 'fs';
import * as path from 'path';
import * as which from 'which';
import * as vscode from 'vscode';
import * as cp from 'child_process';

import { FORMATTERS } from '../lib/tools';
import { LoggingService } from '../services/logging-service';
import { EXTENSION_ID, promptForMissingTool } from '../lib/helper';

export class FortranFormattingProvider implements vscode.DocumentFormattingEditProvider {
constructor(private logger: LoggingService) {}

public provideDocumentFormattingEdits(
document: vscode.TextDocument,
options: vscode.FormattingOptions,
token: vscode.CancellationToken
): vscode.ProviderResult<vscode.TextEdit[]> {
const formatterName: string = this.getFormatter();

if (formatterName === 'fprettify') {
this.doFormatFprettify(document);
} else if (formatterName === 'findent') {
this.doFormatFindent(document);
} else {
this.logger.logError('Cannot format document with formatter set to Disabled');
}

return;
}

/**
* Use `fprettify` to format a Fortran file.
*
* @param document vscode.TextDocument document to operate on
*/
private doFormatFprettify(document: vscode.TextDocument) {
// fprettify can only do FortranFreeFrom
if (document.languageId !== 'FortranFreeForm') {
this.logger.logError(`fprettify can only format FortranFreeForm, change
to findent for FortranFixedForm formatting`);
return;
}

const formatterName = 'fprettify';
const formatterPath: string = this.getFormatterPath();
// If no formatter path is present check that formatter is present in $PATH
if (!formatterPath) {
if (!which.sync(formatterName, { nothrow: true })) {
this.logger.logWarning(`Formatter: ${formatterName} not detected in your system.
Attempting to install now.`);
const msg = `Installing ${formatterName} through pip with --user option`;
promptForMissingTool(formatterName, msg, 'Python');
}
}
const formatter: string = path.join(formatterPath, formatterName);

const args: string[] = [document.fileName, ...this.getFormatterArgs()];
// args.push('--silent'); // TODO: pass?

// Get current file (name rel to path), run extension can be in a shell??
const process = cp.spawn(formatter, args);

// if the findent then capture the output from that and parse it back to the file
process.stdout.on('data', data => {
this.logger.logInfo(`formatter stdout: ${data}`);
});
process.stderr.on('data', data => {
this.logger.logError(`formatter stderr: ${data}`);
});
process.on('close', (code: number) => {
if (code !== 0) this.logger.logInfo(`formatter exited with code: ${code}`);
});
process.on('error', code => {
this.logger.logInfo(`formatter exited with code: ${code}`);
});
}

/**
* Use `findent` to format a Fortran file.
* Creates a temporary file where the output is placed and then deleted
*
* @param document vscode.TextDocument document to operate on
*/
private doFormatFindent(document: vscode.TextDocument) {
const formatterName = 'findent';
const formatterPath: string = this.getFormatterPath();
// If no formatter path is present check that formatter is present in $PATH
if (!formatterPath) {
if (!which.sync(formatterName, { nothrow: true })) {
this.logger.logWarning(`Formatter: ${formatterName} not detected in your system.
Attempting to install now.`);
const msg = `Installing ${formatterName} through pip with --user option`;
promptForMissingTool(formatterName, msg, 'Python');
}
}
let formatter: string = path.join(formatterPath, formatterName);

// Annoyingly findent only outputs to a file and not to a stream so
// let us go and create a temporary file
const out = document.uri.path + '.findent.tmp';
const args: string = ['< ' + document.fileName + ' >', out, ...this.getFormatterArgs()].join(
' '
);
formatter = formatter + ' ' + args;

// @note It is wise to have all IO operations being synchronous we don't
// want to copy or delete the temp file before findent has completed.
// I cannot forsee a situation where a performance bottleneck is created
// since findent performs something like ~100k lines per second
cp.execSync(formatter, { stdio: 'inherit' });
fs.copyFileSync(out, document.fileName);
fs.unlinkSync(out);
}

/**
* Get the formatter type
* Currently supporting: `findent` and `fprettify`
*
* Formatters are defined in FORMATTERS (./lib/tools.ts)
*
* @returns {string} formatter name or `Disabled`
*/
private getFormatter(): string {
const config = vscode.workspace.getConfiguration(EXTENSION_ID);
const formatter: string = config.get('formatting.formatter', 'Disabled');

if (!FORMATTERS.includes(formatter)) {
this.logger.logError(`Unsupported formatter: ${formatter}`);
}
return formatter;
}

/**
* Read in any custom arguments for the formatter
*
* @returns {string[]} list of additional arguments
*/
private getFormatterArgs(): string[] {
const config = vscode.workspace.getConfiguration(EXTENSION_ID);
const args: string[] = config.get('formatting.args', []);

return args;
}

/**
* Installation directory for formatter (if not in PATH)
*
* @returns {string} path of formatter
*/
private getFormatterPath(): string {
const config = vscode.workspace.getConfiguration(EXTENSION_ID);
const formatterPath: string = config.get('formatting.path', '');
if (formatterPath !== '') {
this.logger.logInfo(`Formatter located in: ${formatterPath}`);
}

return formatterPath;
}
}