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

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 pprint-compact, a very expressive pretty printer library, to compute the most optimal layout of the output code, and uses syntax-color/module-lexer to lex the input program.

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 would output 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 137 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/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 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 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
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
See Running raco fmt for details.

parameter

(current-indent)  natural-number/c

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

7 Related work