fmt:   an extensible code formatter for Racket
1 Requirements and Installation
2 Running raco fmt
3 Examples
4 Unstable concepts
formatter-map/  c
5 Unstable API
program-format
empty-formatter-map
standard-formatter-map
compose-formatter-map
6 Parameters
current-width
current-max-blank-lines
current-indent
7 Related work
8.12

fmt: an extensible code formatter for Racket🔗ℹ

Sorawee Porncharoenwase <sorawee.pwase@gmail.com>

 (require fmt) package: fmt

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.rkts and displays the formatted programs to the standard output. If file.rkts are not given, it accepts an input program from the standard input.

The raco fmt command accepts the following flags:

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 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.

value

formatter-map/c : (-> (or/c #f string?) (or/c #f formatter))

Recognizes a formatter map.

5 Unstable API🔗ℹ

procedure

(program-format s    
  [#:formatter-map formatter-map    
  #:width width    
  #:max-blank-lines max-blank-lines    
  #:indent indent])  string?
  s : string?
  formatter-map : formatter-map/c = empty-formatter-map
  width : (or/c natural-number/c +inf.0) = (current-width)
  max-blank-lines : (or/c natural-number/c +inf.0)
   = (current-max-blank-lines)
  indent : natural-number/c = (current-indent)
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)

> (define (lib-define-formatter-map s)
    (cond
      [(and (string? s) (string-prefix? s "define-"))
       (standard-formatter-map "define")]
      [else #f]))
> (define (lib-bar-formatter-map s)
    (case s
      [("bar") (standard-formatter-map "cond")]
      [else #f]))
> (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 144 forms:

augment augment-final augride begin begin-for-syntax begin0 case

case-lambda 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*/or

for*/vector for/and for/async for/first for/fold for/hash

for/hasheq for/hasheqv for/last for/list for/list/concurrent

for/or for/vector 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.

procedure

(compose-formatter-map f ...)  formatter-map/c

  f : formatter-map/c
Constructs a formatter map that tries the input functions in order. The first function that returns a formatter will be used.

6 Parameters🔗ℹ

parameter

(current-width)  (or/c +inf.0 natural-number/c)

(current-width width)  void?
  width : (or/c +inf.0 natural-number/c)
 = 102
Parameter for the page width limit. See Running raco fmt for details.

parameter

(current-max-blank-lines)  (or/c +inf.0 natural-number/c)

(current-max-blank-lines max-blank-lines)  void?
  max-blank-lines : (or/c +inf.0 natural-number/c)
 = 1
Parameter for the maximum number of blank lines. See Running raco fmt for details.

parameter

(current-indent)  natural-number/c

(current-indent indent)  void?
  indent : natural-number/c
 = 0
Parameter for the initial indentation level. See Running raco fmt for details.

7 Related work🔗ℹ