ffmt
A fast, configurable Fortran formatter with support for Fypp, Doxygen, and OpenACC/OpenMP directives. Written in Rust. Installable via pip.
Installation
Or via Cargo:
Usage
|
What it does
- Indentation -- scope-based indentation for all Fortran constructs
- Whitespace -- consistent spacing around operators, commas, colons, parentheses
- Keywords -- case normalization (
IF->if,ENDDO->end do) - Continuation lines -- normalized with proportional re-indentation
- Preprocessor -- Fypp (
#:if,#:for), OpenACC (!$acc), OpenMP (!$omp) handled correctly
Configuration
Create ffmt.toml or add [tool.ffmt] to pyproject.toml. All options have sensible defaults -- most projects need no config file at all.
General
| Option | Default | Description |
|---|---|---|
indent-width |
4 | Number of spaces per indentation level. |
line-length |
132 | Maximum line length. Code and comments are wrapped at this limit. Set to 1000 to disable wrapping. |
keyword-case |
"lower" |
Case for Fortran keywords: "lower", "upper", or "preserve". |
normalize-keywords |
true | Split compound keywords like enddo into end do. |
named-ends |
true | Add procedure/module name to bare end statements (end subroutine -> end subroutine s_foo). |
align-declarations |
true | Vertically align :: in consecutive declaration blocks. |
unicode-to-ascii |
true | Replace Unicode Greek letters and math symbols with LaTeX equivalents in comments (σ -> \sigma). |
rewrap-comments |
true | Re-wrap long comments at line-length, splitting at word boundaries. Doxygen !> / !! blocks are joined and re-wrapped as units. |
rewrap-code |
true | Re-wrap long code lines at line-length using token-aware splitting (never breaks inside numbers or strings). |
space-after-comment |
true | Ensure a space after ! in regular comments (!comment -> ! comment). Does not affect !$acc, !<, !>, !!, or !&. |
collapse-double-spaces |
true | Collapse runs of multiple spaces to a single space in code (not in strings or comments). |
keyword-paren-space |
true | Add a space between control-flow keywords and ( (if( -> if (). Applies to if, call, allocate, select case, where, etc. |
fypp-list-commas |
true | Normalize comma spacing inside Fypp '[...]' list arguments. |
indent-fypp |
true | Indent Fypp preprocessor blocks (#:if, #:for, #:call). |
indent-module |
true | Indent the body of module and program blocks. |
Whitespace
The [whitespace] section controls spacing around specific operators:
| Option | Default | Description |
|---|---|---|
relational |
true | Space around ==, /=, <, <=, >, >=. |
logical |
true | Space around .and., .or., .not., .eqv., .neqv.. |
plusminus |
true | Space around binary + and -. |
multdiv |
false | Space around * and /. |
power |
false | Space around **. |
assignment |
true | Space around = in assignments. |
pointer |
true | Space around =>. |
concatenation |
true | Space around // (string concatenation). |
declaration |
true | Space around :: in declarations. |
comma |
true | Space after ,. |
slice-colon |
false | Space around : in array slices. |
Files
| Option | Default | Description |
|---|---|---|
extensions |
["fpp", "f90", "F90", "f95", "f03", "F", "F95", "F03"] |
File extensions to format. |
exclude |
[] |
Glob patterns to exclude. |
respect-gitignore |
true | Skip files listed in .gitignore. |
Example
= 4
= 132
= "lower"
= true
[]
= true
= true
= true
= false
= false
= true
= true
= true
Preserved as-is
- String literals and inline expressions (
${...}$,@{...}@) - Comment contents and Doxygen alignment (
!<,!>,!!) - Continuation line structure across
#ifdef/#:ifpreprocessor blocks #ifdef/#endifblocks (no indentation change)- Fypp/Python code inside
$:and@:macro invocations
Editor integration
ffmt includes a built-in LSP server for real-time format-on-save:
VS Code
Vim/Neovim
autocmd BufWritePost *.fpp,*.f90 silent !ffmt %
" Or: set formatprg=ffmt\ -
Neovim (LSP)
vim..
CI integration
GitHub Actions
- uses: sbryngelson/ffmt@latest
with:
args: "--check src/"
pre-commit
repos:
- repo: https://github.com/sbryngelson/ffmt
rev: v0.2.1
hooks:
- id: ffmt
To auto-update to the latest version, run:
Or use pre-commit.ci to update hooks automatically via pull requests.
Other Fortran Formatters
| Formatter | Language | Status | Notes |
|---|---|---|---|
| fprettify | Python | Unmaintained (last release 2020) | Free-form only. Fypp support. Requires multiple passes for convergence. |
| findent | C | Active | Indentation and fixed/free conversion. No whitespace normalization. |
| Codee Formatter | Proprietary | Active | Commercial. Tree-sitter based. Fixed and free-form. |
| LFortran fmt | Rust | In development | AST-based. Part of the LFortran compiler project. |
| Fortitude | Rust | Active | Linter with auto-fix, not a full formatter. Tree-sitter based. |
| f90-mode | Emacs Lisp | Active | Emacs built-in. Indentation only. |
License
MIT