Skip to content
Incremental Formatting
step 1/5

Reading — step 1 of 5

Read

~1 min readProduction

Incremental Formatting

For editors, formatting must be FAST: ms-scale on save, ms-scale on every keystroke (with autoformat).

Strategies:

Reformat full file: simple but slow on big files. Black does this.

Reformat range: only the user's selection. clang-format supports.

Format on save: before write to disk. Most editors.

Format on type: after each ; or }. Some IDEs (JetBrains).

Incremental: detect what changed; reformat only affected nodes.

  • Hard. Requires tracking edit ranges + AST node mapping.
  • Tree-sitter is incremental: parse only what changed.
  • Helps for large files in IDEs.

Performance optimizations:

  • Cache parsed AST per file.
  • Lazy: don't reparse on every keystroke; debounce ~150ms.
  • Skip if unchanged.
  • Multi-thread per file in batch mode.

CI usage:

  • prettier --check returns non-zero if any file would be reformatted.
  • gofmt -l lists unformatted files.
  • Combined with pre-commit hook → only formatted code reaches the repo.

Pre-commit:

- repo: https://github.com/psf/black
  rev: 24.0.0
  hooks:
    - id: black

Editor integration:

  • VSCode: format-on-save + per-language formatter.
  • Vim: :Format command via plugin.
  • Emacs: format-all package.
  • IntelliJ: built-in formatters per language.

LSP textDocument/formatting + textDocument/rangeFormatting:

  • Server returns text edits to apply.
  • Editor displays diff or applies.

Async formatting: large files (~50k lines) may take seconds. Show progress; don't block UI.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…