Clarity Formatter

Learn how to use the Clarity formatter to standardize your smart contract code style.


Introduction to the Clarity Formatter

The Clarity formatter is a tool designed to automatically format your Clarity smart contract code according to a standardized style. Using a consistent style improves code readability and maintainability, making it easier for developers to understand, collaborate on, and learn from existing Clarity projects.

As Clarity is a relatively young language, establishing formatting standards helps reduce friction for both new and experienced developers.

Getting Started

The Clarity formatter is integrated into two primary development tools:

  1. 1Clarity VS Code Extension: Allows formatting directly within your editor.
  2. 2Clarinet CLI: Enables formatting via the command line, including formatting entire projects.

Configuration

The formatter applies an opinionated standard with the following default settings:

  • Line Length: Lines wrap at 80 characters.
  • Indentation: Uses 2 spaces for indentation.

These defaults are configurable to match your preferences, although the specific configuration method depends on whether you are using VS Code or Clarinet.

Formatting Rules

The formatter applies specific rules to various Clarity constructs to ensure consistency.

Alongside these settings, the Clarity formatter introduces formatting rules for many basic Clarity constructs:

The following sections provide examples of how common constructs are formatted.

Basic Indentation & Line Wrapping

Code is indented using 2 spaces per level. Long expressions exceeding the configured line length (default 80 characters) are automatically broken across multiple lines.

;; Example of line wrapping
(try! (unwrap!
(complete-deposit-wrapper (get txid deposit) (get vout-index deposit))
(err (+ ERR_DEPOSIT_INDEX_PREFIX (+ u10 index)))
))

Function Definitions

Functions (define-public, define-private, define-read-only) always span multiple lines. Arguments are double-indented if there is more than one. If a single argument fits on the first line, it remains there. The function body is single-indented, aligning with the closing parenthesis of the arguments. A trailing newline is added after each function definition.

(define-public (my-func
(amount uint)
(sender principal)
)
(ok true)
)
(define-read-only (get-balance (who principal))
(ok u0)
)

let Expressions

Bindings within a let expression are placed on separate lines, indented once. The body of the let expression is indented at the same level as the bindings.

(let (
(a u1)
(b u2)
)
(body-expression)
)

begin Blocks

begin blocks are always formatted across multiple lines, even for a single expression. The expressions within the block are indented once.

(begin
(ok true)
)

Boolean Operators (and, or)

If an and or or expression contains more than two conditions, each condition is placed on a new line, indented once.

(or
true
(is-eq 1 2)
false
)

if Statements

The then and else branches of an if statement are always placed on separate lines, indented once.

(if (condition)
(expression-true)
(expression-false)
)

match Expressions

match expressions are always multi-line. Each match arm (pattern and corresponding expression) is placed on a new line, with the pattern and expression aligned.

;; Option syntax
(match opt
value (ok (handle-new-value value))
(ok 1)
)
;; Response syntax
(match (sbtc-transfer amount tx-sender (as-contract tx-sender))
success (ok id)
error (err (* error u1000)))))
)

Tuples & Maps (Sugared Syntax)

Tuples defined using (tuple ...) are automatically converted to the sugared { key: value } syntax.

;; Input: (tuple (n1 u1))
;; Output:
{ n1: u1 }

Maps with multiple key-value pairs are broken across multiple lines. Each pair is indented once and followed by a comma (,), including the last pair.

{
name: (buff 48),
owner: principal,
}

Nested Maps

Indentation is applied consistently for nested map structures.

{
name: {
first: "Hiro",
last: "Protagonist",
},
age: u33,
}

Trait Definitions (define-trait)

Trait definitions follow specific layout rules for function signatures within the trait body.

(define-trait token-trait
(
(transfer? (principal principal uint) (response uint uint))
(get-balance (principal) (response uint uint))
)
)

Trailing Comments

Trailing comments ( ;; comment) are preserved and placed after the expression on the same line. They do not count towards the maximum line length calculation.

(get-value key) ;; Retrieves the stored value

Ignoring Formatting

You can prevent the formatter from modifying specific sections of your code by adding a ;; @format-ignore comment immediately before the block you wish to exclude.

;; @format-ignore
(define-constant something (list
1 2 3 ;; comment
4 5 ))

Usage

In VS Code

The Clarity VS Code extension provides several ways to format your code:

  • Format Document: Formats the entire active file (Right-click -> Format Document or Shift+Option+F / Shift+Alt+F).
  • Format Selection: Formats only the highlighted code (Right-click -> Format Selection).
  • Format On Save: Automatically formats the file when you save it. This can be enabled in VS Code settings (editor.formatOnSave) and is off by default.

With Clarinet CLI

The Clarinet CLI allows you to format contracts from the command line using clarinet format (or the alias clarinet fmt). You can format individual files or all contracts defined in your project's Clarinet.toml manifest.

Format all checkable contracts and print the result without saving:

Terminal
$
clarinet format --dry-run

Format all checkable contracts (--in-place):

Terminal
$
clarinet format --in-place

Format a specific file using tabs and print the result without saving (--dry-run):

Terminal
$
clarinet format -f contracts/my-contract.clar -t --dry-run

Format a specific file, overwriting it (--in-place) with 4-space indents and 120 max line length:

Terminal
$
clarinet format -f contracts/my-contract.clar -i 4 -l 120 --in-place

Refer to the Clarity formatter readme for the full list of commands and options.

Feedback & Further Information

The Clarity formatter is continually evolving based on community feedback. Please try it out and share your thoughts to help improve the standards for the ecosystem.

For more detailed information, please consult the Clarity formatter readme.