Sorawee Porncharoenwase <sorawee.pwase@gmail.com>
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.
Make sure Racket 8.0 or later is installed. Run raco pkg install fmt to install the formatter.
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.
Given the file "example.rkt" shown on the left, running raco fmt --width 40 example.rkt outputs the program on the right:
example.rkt
;low :: number? -> listof number?'())(elseargument1)3)))next(low...........................;high :: number? -> listof number?
formatted example.rkt
;low :: number? -> listof number?(cond;this is the base case[else(low...........................;high :: number? -> listof number?
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 at this 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 fallback formatter maps to handle formatting instead.
procedure
[ #:formatter-mapformatter-map#:widthwidth#:max-blank-linesmax-blank-liness:string?
(define (foo)
(bar baz)
food)
(define-like (foo) (bar baz) food)
(cond(define (foo)
(bar baz)
food)
(define-like (foo)
(bar baz)
food)
(define (foo)
(bar
baz)
food)
(define-like (foo)
(bar
baz)
food)
lib-define-formatter-maplib-bar-formatter-map)))(define (foo)
(bar
baz)
food)
(define-like (foo)
(bar
baz)
food)
augment augment-final augride begin begin-for-syntax begin0 case
case-lambda class class* cond define define-check
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
delay delay/idle delay/name delay/strict delay/sync delay/thread
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 lazy let let*
let*-values let-syntax let-syntaxes let-values let/cc let/ec
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 send 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.
procedure
( compose-formatter-map f...)→formatter-map/c
parameter
( current-width )→(or/c +inf.0natural-number/c )
= 102
parameter
( current-max-blank-lines )→(or/c +inf.0natural-number/c )
= 1
parameter
indent:natural-number/c= 0
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 provide d elements), but doesn’t preserve parenthesis shape.