an extensible code formatter for Racket (original) (raw)
8.15
This package provides a tool raco fmt to reformat Racket code.
The package uses syntax-color/module-lexer to lex the input program, and uses pretty-expressive, an expressive pretty printer library, to compute an optimal layout of the output code.
The interface to allow users to extend formatting style is extremely unstable and is still a work in progress. For now, the only thing that is stable is the command raco fmt.
1 Requirements and Installation🔗ℹ
Make sure Racket 8.0 or later is installed. Run raco pkg install fmt to install the formatter.
2 Running raco fmt🔗ℹ
raco fmt ‹file.rkt› ... reads ‹file.rkt›s and displays the formatted programs to the standard output. If ‹file.rkt›s are not given, it accepts an input program from the standard input.
The raco fmt command accepts the following flags:
- --width ‹width› — set the page width limit to ‹width›, which must be either a natural number or +inf.0. The default value is 80.
- --max-blank-lines ‹n› — set the maximum consecutive blank lines limit to ‹n›, which must be either a natural number or +inf.0. The default value is 1.
- --indent ‹n› — set the indentation level in spaces to ‹n› for subsequent lines. The default value is 0.
- -i — modify the input files in-place instead of outputting to standard output. This flag has no effect if raco fmt accepts the input from standard input.
3 Examples🔗ℹ
Given the file "example.rkt" shown on the left, running raco fmt --width 40 example.rkt outputs the program on the right:
example.rkt#lang racket ; low :: number? -> listof number?(define low(λ (argument) (cond (; this is the base case (zero? argument) '()) (else (define content (* argument (+ argument 1) (+ argument 2) (+ argument 3))) (define next ( low ........................... ...)) ; recursive call (cons content next))))) ; high :: number? -> listof number?( define high ...) | formatted example.rkt#lang racket ; low :: number? -> listof number?(define low (λ (argument) (cond ; this is the base case [(zero? argument) '()] [else (define content (* argument (+ argument 1) (+ argument 2) (+ argument 3))) (define next (low ........................... ...)) ; recursive call (cons content next)]))) ; high :: number? -> listof number?(define high ...) |
---|
4 Unstable concepts🔗ℹ
A formatter is a function that accepts a code fragment and returns a doc?. In principle, you can create your own formatter, but you need to understand many structures that are currently undocumented and unstable. (If you want to implement one, perhaps take a look atthis file.)
A formatter map is a function that accepts either a string or #f, and returns either a formatter or #f. Conceptually, when the input is a string s, a formatter map should return a formatter that will format a form named s, and When the input is #f, the formatter map should return a formatter that will format function application. An exception is that the formatter map can also return #f, which means the formatter map wants to let other fallbackformatter maps to handle formatting instead.
Recognizes a formatter map.
5 Unstable API🔗ℹ
Formats string s with formatter-map under various configurations (see Running raco fmt for details).
Examples:
> (define s "(define (foo) (bar baz) food) (define-like (foo) (bar baz) food)") > (display (program-format s)) (define (foo) (bar baz) food)(define-like (foo) (bar baz) food) > (display (program-format s #:formatter-map lib-define-formatter-map)) (define (foo) (bar baz) food)(define-like (foo) (bar baz) food) > (display (program-format s #:formatter-map lib-bar-formatter-map)) (define (foo) (bar baz) food)(define-like (foo) (bar baz) food) > (display (program-format s #:formatter-map (compose-formatter-map lib-define-formatter-map lib-bar-formatter-map))) (define (foo) (bar baz) food)(define-like (foo) (bar baz) food)
A formatter map that does not handle any form.
The fallback formatter map. It defines format styles for the following 172 forms:
augment augment-final augride begin begin-for-syntax begin0 case |
---|
case-lambda class class* cond define define-for-syntax |
define-match-expander define-simple-macro define-struct |
define-syntax define-syntax-class define-syntax-parameter |
define-syntax-parse-rule define-syntax-parser define-syntax-rule |
define-syntaxes define-values define-values-for-syntax |
define/augment define/augment-final define/augride |
define/contract define/match define/overment define/override |
define/override-final define/private define/public |
define/public-final define/pubment export field for for* |
for*/and for*/async for*/first for*/fold for*/hash for*/hasheq |
for*/hasheqv for*/last for*/list for*/list/concurrent |
for*/mutable-set for*/mutable-setalw for*/mutable-seteq |
for*/mutable-seteqv for*/or for*/set for*/setalw for*/seteq |
for*/seteqv for*/vector for*/weak-set for*/weak-setalw |
for*/weak-seteq for*/weak-seteqv for-label for-syntax |
for-template for/and for/async for/first for/fold for/hash |
for/hasheq for/hasheqv for/last for/list for/list/concurrent |
for/mutable-set for/mutable-setalw for/mutable-seteq |
for/mutable-seteqv for/or for/set for/setalw for/seteq |
for/seteqv for/vector for/weak-set for/weak-setalw |
for/weak-seteq for/weak-seteqv if import inherit init |
instantiate interface interface* lambda let let* let*-values |
let-syntax let-syntaxes let-values letrec letrec-syntax |
letrec-syntaxes letrec-syntaxes+values letrec-values link match |
match* match-define match-define-values match-lambda |
match-lambda* match-lambda** match-let match-let* |
match-let*-values match-let-values match-letrec |
match-letrec-values mixin module module* module+ overment |
override override-final parameterize parameterize* pattern |
private provide public public-final pubment quasisyntax/loc |
rename require shared splicing-let splicing-let-syntax |
splicing-let-syntaxes splicing-let-values splicing-letrec |
splicing-letrec-syntax splicing-letrec-syntaxes |
splicing-letrec-syntaxes+values splicing-letrec-values |
splicing-parameterize splicing-syntax-parameterize struct |
syntax-case syntax-parameterize syntax-parse syntax-parser |
syntax-rules syntax/loc test-begin test-case test-suite unless |
when with-handlers with-handlers* with-syntax with-syntax* λ |
For other forms, it uses the function application style.
Constructs a formatter map that tries the input functions in order. The first function that returns a formatter will be used.
6 Parameters🔗ℹ
Parameter for the page width limit. See Running raco fmt for details.
Parameter for the maximum number of blank lines. See Running raco fmt for details.
Parameter for the initial indentation level. See Running raco fmt for details.
7 Related work🔗ℹ
- fixw (by 6cdh) is a Racket formatter that only fixes spaces (in the same style as gofmt). It will indent and add/remove spaces to normalize them, but does not add/remove newlines.
- DrRacket (by the Racket team) is a Racket editor. It has an indenter which can re-indent code, but cannot in general re-format code. Users can add custom keywords to the four predefined keyword categories, but cannot define a new category (without a plug-in).
- raco-format (by Dan Anderson) is a command-line tool that invokes DrRacket’s indenter.
- Racket Mode (by Greg Hendershott) is a mode in Emacs for editing Racket code. Similar to DrRacket, it has an indenter. Compared to DrRacket, Racket Mode is more customizable on one axis (more keyword categories) but less customizable on another axis (must map each keyword one-by-one)
- racket/pretty (by the Racket team) is a library for pretty printing an S-expression value. It does not support comments, is less expressive and less optimal than fmt.
- pprint (by Dave Herman and Asumu Takikawa) is a library for pretty printing an arbitrary document. It is based on Wadler/Leijen’s pretty printer, which is less expressive and less optimal than pretty-expressive(but has better performance).
- racket-pretty-printer (by 为世人降下祝福) is a Racket formatter written in Haskell. It uses Wadler’s pretty printer, so it has the limitations as described in the above item.
- racket-formatting (by Alex Owens and Shu-Hung You) is a Racket formatter that attaches formatting information to syntax object properties. It does not attempt to pick the most optimal layout to stay within the column limit, and does not support comments.
- racket-format (by Russell Wallace) is a Racket formatter written manually. It uses a greedy algorithm to decide which layout to pick, which is not optimal. It supports line-comments and the normalization features (such as sorting the list of provided elements), but doesn’t preserve parenthesis shape.