A formatter for the Ceylon programming language.

Command line usage

(If the ceylon format plugin wasn’t installed by default in your distribution, you can add it by cloning the formatter repository and running ant install; alternatively, write ceylon run ceylon.formatter instead of ceylon format.)

To format all Ceylon code in the source and test-source directories:

ceylon format source test-source

To format all Ceylon code in the source directory into the source-formatted directory:

ceylon format source --to source-formatted

To format all Ceylon code in the source and test-source directories into the source-formatted directory:

ceylon format source --and test-source --to source-formatted

(This results in two subdirectories source and test-source of source-formatted.)

You can specify an arbitrary amount of these formatting commands:

ceylon format \
        source --to source-formatted \
        test-source --to test-source-formatted

(The line breaks are only included for clarity and not a part of the command line syntax.)

If no formatting commands are present, the formatter operates in “pipe mode”, reading code from standard input and writing to standard output.


You can specify formatting options using the following syntax:

# or
--optionName optionValue

For available option names, see FormattingOptions. The syntax of optionValue is:

  • for Boolean or Integer values, use a Ceylon-style literal (1, true)
  • for Range values, use a Ceylon-style range operator x..y
  • for IndentMode values, see the documentation of parseIndentMode
  • for Iterable values, list the individual elements, separated by spaces
  • for LineBreakStrategy, the only valid value is default
  • for enumerated types, use the name of one of the object cases (lf, all)

Library usage

Use the format function to format any AST node. This can be a compilation unit (simply speaking, a complete file) or any other node.

If the node was parsed from an existing file, don’t forget to pass the token stream to format (tokens) – without the token stream, the formatter can’t obtain the comments, so they’ll not be present in the formatted file.

To construct FormattingOptions, usage of named arguments is highly recommended:

FormattingOptions {
    indentMode = Spaces(8);
    maxLineLength = 80;

You can also use SparseFormattingOptions and combinedOptions to compose several sets of options, like this:

combinedOptions {
    baseOptions = companyWideOptions;
    SparseFormattingOptions {
        indentMode = Spaces(1); // our department has very small screens :-(
By: Lucas Werkmeister
License: http://www.apache.org/licenses/LICENSE-2.0.html

A formatter for the Ceylon programming language.


Options for the Ceylon formatter.


A formatter for the Ceylon programming language.

The main class of this package is FormattingVisitor, which visits an AST Node (typically a CompilationUnit) and writes it out to a Writer. See the ceylon.formatter.options package on how to influence the format of the written code.

maxDesireshared Integer maxDesire= runtime.maxIntegerValue / 2

The maximum value that is safe to use as FormattingWriter.writeToken’s space[Before|After] argument.

Using a greater value risks inverting the intended result due to overflow.

minDesireshared Integer minDesire= runtime.minIntegerValue / 2 + 1

The minimum value that is safe to use as FormattingWriter.writeToken’s space[Before|After] argument.

Using a smaller value risks inverting the intended result due to overflow.

noLineBreakshared Range<Integer> noLineBreak
commonRootshared Path commonRoot([Path+] paths)

Determines the common root of several paths. For example, the common root of a/b/c and a/b/d is a/b, the common root of /a/b/c and /a/d/e is /a and the common root of a and b is the empty path.

  • paths

    The paths. Must be either all absolute or all relative.

desireshared Integer desire(Boolean|Integer desire)

Parses a Boolean or Integer value into a desire in range minDesire..maxDesire.

If desire is Integer, it is clamped to that range; if it’s Boolean, the returned value is minDesire for false and maxDesire for true.

formatshared void format(Node node, FormattingOptions options = ..., Writer output = ..., TokenStream? tokens = null, Integer initialIndentation = 0)

Format the given CompilationUnit and write it to the given Writer.

  • node

    A node that you want to format, e. g. a CompilationUnit from the Ceylon compiler.

  • options = FormattingOptions()

    The options for the formatter. These dictate the line breaking strategy, the bracing style, the maximum line length, and much more.

    The default options are modeled after the ceylon.language module and the Ceylon SDK. You can adapt them through the named arguments syntax, keeping the default values of the options that you don’t want to change.

    You can also adapt any other FormattingOptions by using SparseFormattingOptions and combinedOptions, like this:

    value myOptions = combinedOptions(bossOptions,
        SparseFormattingOptions {
            indentMode = Spaces(4); // I don’t care what the boss says, spaces rule
  • output = stdoutWriter

    The Writer to which the formatted node is written.

    Defaults to standard output.

  • tokens = null

    An ANTLR Token Stream from which the CompilationUnit was parsed. This only makes sense if you got node from the Ceylon compiler, otherwise you should keep the default value null.

    Note that you probably do not want a CommonTokenStream (which is what you normally give to the compiler), because that skips comments. Use BufferedTokenStream instead.

  • initialIndentation = 0

    The initial indentation to use.

    You probably shouldn’t use this when node is a CompilationUnit, but it’s useful when formatting other nodes.

parseTranslationsshared <String[]->String>[] parseTranslations(String[] arguments)

Parses translations from the arguments.

For example, the arguments

a/b/c --and a/b/d --to x/a/b   d/e   f/g --to m/n/f/g

correspond to the translations

  [a/b/c, a/b/d] -> x/a/b,
  d/e -> d/e,
  f/g -> m/n/f/g
perftestshared void perftest()
runshared void run()

Run the module ceylon.formatter.

FormattingVisitorshared FormattingVisitor

A Visitor that writes a formatted version of the element (typically a Tree.CompilationUnit) to a Writer.

FormattingWritershared FormattingWriter

Writes tokens to an underlying FormattingWriter.writer, respecting certain formatting settings and a maximum line width.

The FormattingWriter manages the following aspects:

  • Indentation
  • Line Breaking
  • Spacing

Additionally, it also writes comments if a token stream is given.


Two indentation levels are associated with each token: one before the token, and one after it. Warning: they are not symmetrical!

The indentAfter of a token introduces a context (instance of FormattingWriter.FormattingContext) that is pushed onto a context stack when the token is written. The indentation of each line is the sum of all indentation currently on the context stack. When a context is closed, the context and all contexts on top of it are removed from the context stack.

A context can be closed in two ways:

  1. By associating it with a token. For example, you would say that a closing brace } closes the context of the corresponding opening brace {: The block has ended, and subsequent lines should no longer be indented as if they were still part of the block. Tokens that close another token’s context do not open a context of their own.
  2. By calling FormattingWriter.closeContext.

You can also obtain a context not associated with any token by calling FormattingWriter.openContext. This is mostly useful if you have a closing token with no designated opening token: for example, a statement’s closing semicolon ; should close some context, but there is no corresponding token which opens that context.

The indentBefore of a token does not introduce any context. It is only applied when a line line break has occured immediately before this line, i. e. if it is the first token of its line. For example, the member operator . typically has an indentBefore of 1: A “call chain” foo.bar.baz should, if spread across several lines, be indented, but that indentation should not stack across multiple member operators.

Line Breaking

Two Integer ranges are associated with each token. One indicates how many line breaks may occur before the token, and the other indicates how many may occur after the token. Additionally, one may call FormattingWriter.requireAtLeastLineBreaks to further restrict how many line breaks may occur between two tokens.

The intersection of these ranges for the border between two tokens is then used to determine how many line breaks should be written before the token.

  • If FormattingWriter.tokens exists, then each time a token is written, the token stream is fast-forwarded until the token is met (if a token with a different text is met, an exception is thrown). In fast-forwarding, the amount of line breaks is counted. After fast-forwarding has finished, the number of line breaks that were counted is clamped into the line break range, and this many line breaks are written.
  • If FormattingWriter.tokens doesn’t exist, then the first element of the range is used (usually the lowest, unless the range is decreasing).

(Internally, the FormattingWriter also keeps track if a line break range came from FormattingWriter.writeToken, FormattingWriter.requireAtLeastLineBreaks, or was added internally when dealing with comments; an empty intersection of two ranges is usually a bug, unless one of the ranges comes from a comment, in which case we just use that range instead.)

Additionally, the FormattingWriter also breaks lines according to a maximum line length and a LineBreakStrategy, as determined by FormattingWriter.options. To achieve this, tokens are not directly written to the underlying writer; instead, they are added to a token queue (not to be confused with the token stack, which is used for indentation). Each time a token is added, the FormattingWriter checks if there are enough tokens on the queue for the line break strategy to decide where a line break should be placed. Line breaks are allowed between tokens if their respecive ranges included at least one value greater than zero (in other words, to disallow a line breaks between two tokens, pass a range of 0..0 to either of them). When a line break location is known, that line is written and its tokens removed from the queue (their contexts are then added to the token stack).


If you’ve made it this far, relax, this is the easiest section :)

Two Integers are associated with each token. One indicates the token’s desire to have a space before it, the other indicates the desire to have a space after it. When the two tokens are written, these integers are added, and if the sum is >= 0, then a space is written.

To avoid inverting the intended result by numerical overflow, don’t use values outside the range minDesire..maxDesire. You can also give false and true to FormattingWriter.writeToken, which are convenient and readable syntax sugar for these two values (spaceBefore = true).


The fast-forwarding of the token stream (if given) was already mentioned in the “Line Breaking” section. If comment tokens are encountered during the fast-forwarding, they are written out like tokens with