An opinionated Fortran formatter with Fypp and OpenACC support
Project description
ffmt
An opinionated, idempotent Fortran formatter with first-class Fypp preprocessor and OpenACC/OpenMP directive support.
ffmt is a single-pass formatter written in Rust.
It replaces fprettify and produces consistent output on the first run -- no multi-pass convergence needed.
Installation
From PyPI
pip install ffmt
From crates.io
cargo install ffmt
From source
git clone https://github.com/sbryngelson/ffmt
cd ffmt
cargo install --path .
Usage
# Format files in-place
ffmt file.fpp
ffmt src/
# Check mode (CI) -- exit 1 if any file would change
ffmt --check src/
# Show what would change (with color)
ffmt --diff src/
# Both
ffmt --check --diff src/
# Parallel formatting
ffmt -j 8 src/
# Read from stdin, write to stdout (for editor integration)
cat file.fpp | ffmt -
ffmt --stdin-filepath file.fpp - < file.fpp
# Exclude patterns
ffmt --exclude "autogen/**" src/
Stdin/stdout mode
Use - as the path to read from stdin and write formatted output to stdout. This enables editor integration (format-on-save) and piping:
# Format stdin to stdout
echo "INTEGER::x" | ffmt -
# Output: integer :: x
# Check stdin (exit 1 if it would change)
cat file.fpp | ffmt --check --stdin-filepath file.fpp -
# Diff stdin
cat file.fpp | ffmt --diff --stdin-filepath file.fpp -
The --stdin-filepath flag provides a filename for diagnostics.
.gitignore support
ffmt automatically respects .gitignore, .ignore, .fdignore, and .git/info/exclude when walking directories. Files ignored by git are skipped.
Editor integration
Vim/Neovim
" Format on save
autocmd BufWritePost *.fpp,*.f90 silent !ffmt %
" Or use as formatprg
set formatprg=ffmt\ -
VS Code
Add to settings.json:
{
"[fortran]": {
"editor.formatOnSave": true
},
"fortran.formatting.formatter": "ffmt",
"fortran.formatting.path": "ffmt",
"fortran.formatting.args": ["--stdin-filepath", "${file}", "-"]
}
CI integration
GitHub Actions
- uses: sbryngelson/ffmt@v1
with:
args: "--check src/"
Or install directly:
- run: pip install ffmt
- run: ffmt --check src/
pre-commit
Add to .pre-commit-config.yaml:
repos:
- repo: https://github.com/sbryngelson/ffmt
rev: v0.1.0
hooks:
- id: ffmt
Use ffmt-check instead of ffmt for check-only mode (no modifications).
What it does
ffmt formats Fortran free-form source files (.fpp, .f90, .f95, .f03) through a single-pass pipeline:
- Indentation -- 4-space indentation based on scope tracking (
if/do/subroutine/module/type/...) - Fypp block indentation --
#:if,#:for,#:call,#:def, etc. are indented as nested blocks - Directive indentation --
!$acc,!$omp,!DIR$lines indented to match surrounding Fortran scope - Whitespace normalization -- consistent spacing around operators, commas, colons, parentheses
- Case normalization -- Fortran keywords lowercased (
IF->if,END DO->end do)
Formatting rules
Indentation:
- 4 spaces per scope level
- Fypp blocks (
#:if/#:for/#:call/#:def/#:block/#:mute) create scope #ifdef/#endifpreprocessor blocks do not change indentation- Continuation lines (
&) preserve their original spacing !!Doxygen continuation comments preserve their original alignment
Operators -- space each side:
==, /=, <=, >=, <, >, .and., .or., .not., = (assignment), =>, +, - (binary), // (concatenation), ::
Operators -- no spaces:
*, /, **
Other:
- Commas: one space after, none before
- Array slices: no spaces around
:--a(1:n) - Keyword arguments: no spaces around
=--call foo(bar=1) - Parentheses: no internal padding --
f(x)notf( x ) - Trailing whitespace: always stripped
- Blank lines: 3+ consecutive collapsed to 2
- Blank lines after
!$acc loopdirectives: removed
Preserved as-is:
- String literal contents (
'...',"...") - Inline Fypp expressions (
${...}$,@{...}@) - Comment contents
- Doxygen comment alignment (
!<,!>,!!) - Continuation line structure and alignment
Design
ffmt is opinionated like gofmt -- one style, no configuration file, minimal CLI flags.
Why not fprettify?
- Not idempotent -- fprettify requires 2-4 passes to converge
- No directive awareness -- requires a separate indenter script for
!$acc/!$omplines - Fragile Fypp support -- treats Fypp lines as "not Fortran," causing inconsistent indentation
- Unmaintained -- last release circa 2020
Architecture
Source lines -> Join continuations -> Classify (LineKind enum) ->
Track scope depth -> Apply indentation -> Normalize whitespace ->
Normalize case -> Emit formatted lines
| Module | Responsibility |
|---|---|
reader.rs |
Join & continuations, mark opaque regions (strings, ${...}$, comments) |
classifier.rs |
Classify lines into LineKind enum with disambiguation rules |
scope.rs |
Scope tracking state machine (push/pop on block open/close) |
indent.rs |
Apply 4 * depth leading spaces |
whitespace.rs |
Operator/comma/colon/paren spacing normalization |
case_norm.rs |
Lowercase Fortran keywords outside strings/Fypp/comments |
formatter.rs |
Pipeline orchestrator |
cli.rs |
CLI with stdin/stdout, .gitignore, color, exclude patterns |
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success (all files formatted, or no changes needed in --check mode) |
| 1 | Files would change (--check mode only) |
| 2 | Usage error or I/O failure |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ffmt-0.1.0.tar.gz.
File metadata
- Download URL: ffmt-0.1.0.tar.gz
- Upload date:
- Size: 37.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8833e7adaf48f77c94d4b5607c4e81080475f0b91865ea1f372d5ad0dfa4804b
|
|
| MD5 |
a50a7667cd60aa94f08b316790461b5a
|
|
| BLAKE2b-256 |
f0ece264c141bd093b39b0091f64b946dff0f22f550947472009b52c6ff68cd1
|
Provenance
The following attestation bundles were made for ffmt-0.1.0.tar.gz:
Publisher:
release.yml on sbryngelson/ffmt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ffmt-0.1.0.tar.gz -
Subject digest:
8833e7adaf48f77c94d4b5607c4e81080475f0b91865ea1f372d5ad0dfa4804b - Sigstore transparency entry: 1143055077
- Sigstore integration time:
-
Permalink:
sbryngelson/ffmt@b432b2cc61971c2eab481fcf7cbd81ffe5aa3841 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sbryngelson
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b432b2cc61971c2eab481fcf7cbd81ffe5aa3841 -
Trigger Event:
release
-
Statement type:
File details
Details for the file ffmt-0.1.0-py3-none-win_amd64.whl.
File metadata
- Download URL: ffmt-0.1.0-py3-none-win_amd64.whl
- Upload date:
- Size: 1.3 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33d3f02c6970844b875deb4a81a31393c5d771e662d6523f615a61252f66ba0c
|
|
| MD5 |
e226a94cc88bab823fbe95b8a0909008
|
|
| BLAKE2b-256 |
75cfccdf6a6a30dbec497916754f41c6d61ff1c3fdba80494b055213de3b30ed
|
Provenance
The following attestation bundles were made for ffmt-0.1.0-py3-none-win_amd64.whl:
Publisher:
release.yml on sbryngelson/ffmt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ffmt-0.1.0-py3-none-win_amd64.whl -
Subject digest:
33d3f02c6970844b875deb4a81a31393c5d771e662d6523f615a61252f66ba0c - Sigstore transparency entry: 1143055225
- Sigstore integration time:
-
Permalink:
sbryngelson/ffmt@b432b2cc61971c2eab481fcf7cbd81ffe5aa3841 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sbryngelson
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b432b2cc61971c2eab481fcf7cbd81ffe5aa3841 -
Trigger Event:
release
-
Statement type:
File details
Details for the file ffmt-0.1.0-py3-none-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: ffmt-0.1.0-py3-none-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 1.7 MB
- Tags: Python 3, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8c05ee74183f1775cfff085d87d52c8e4e184bc386f3ea668cd528b8fd2ae71
|
|
| MD5 |
8463c609e92675e86ea83e3b641baf07
|
|
| BLAKE2b-256 |
49850bc0772be2354f587938ebec9d0ee615f3aaec5a9864eef251687497d9c6
|
Provenance
The following attestation bundles were made for ffmt-0.1.0-py3-none-manylinux_2_34_x86_64.whl:
Publisher:
release.yml on sbryngelson/ffmt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ffmt-0.1.0-py3-none-manylinux_2_34_x86_64.whl -
Subject digest:
f8c05ee74183f1775cfff085d87d52c8e4e184bc386f3ea668cd528b8fd2ae71 - Sigstore transparency entry: 1143055174
- Sigstore integration time:
-
Permalink:
sbryngelson/ffmt@b432b2cc61971c2eab481fcf7cbd81ffe5aa3841 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sbryngelson
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b432b2cc61971c2eab481fcf7cbd81ffe5aa3841 -
Trigger Event:
release
-
Statement type:
File details
Details for the file ffmt-0.1.0-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: ffmt-0.1.0-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.5 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0f3580be0926da37684db3e9b981c2579ff40e6301e35b19a32e57f0329340b4
|
|
| MD5 |
07e9a767570d6ee9ccc6ba39831c810e
|
|
| BLAKE2b-256 |
31bcb8736e1e305e2383e60d130aa58959537247cbf22a97074eaecb20312953
|
Provenance
The following attestation bundles were made for ffmt-0.1.0-py3-none-macosx_11_0_arm64.whl:
Publisher:
release.yml on sbryngelson/ffmt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ffmt-0.1.0-py3-none-macosx_11_0_arm64.whl -
Subject digest:
0f3580be0926da37684db3e9b981c2579ff40e6301e35b19a32e57f0329340b4 - Sigstore transparency entry: 1143055132
- Sigstore integration time:
-
Permalink:
sbryngelson/ffmt@b432b2cc61971c2eab481fcf7cbd81ffe5aa3841 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sbryngelson
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b432b2cc61971c2eab481fcf7cbd81ffe5aa3841 -
Trigger Event:
release
-
Statement type: