DprintMarkdownFormatter

Hex.pmDocumentation

A fast, configurable markdown formatter for Elixir that combines the power of Rust's dprint-plugin-markdown with native Elixir integration.

Features

Installation

Add to your mix.exs:

def deps do
[
{:dprint_markdown_formatter, "~> 0.7.1"}
]
end

Quick Start

Sigil Usage

Use the ~M sigil for embedding markdown content that gets automatically formatted by mix format:

import DprintMarkdownFormatter.Sigil
# This markdown will be automatically formatted when you run `mix format`
markdown = ~M"""
# API Documentation
This is **bold** text with extra spaces.
* Poorly formatted list
"""
# After `mix format`, the sigil content becomes properly formatted

Integration with mix format

Add to your .formatter.exs:

[
plugins: [DprintMarkdownFormatter],
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}", "*.{md,markdown}"]
]

This enables automatic formatting of .md and .markdown files. To also format module attributes, configure format_module_attributes in your project.

Configuration

Global Configuration

Configure in your mix.exs:

def project do
[
# ... other config
dprint_markdown_formatter: [
line_width: 100,
text_wrap: :never,
emphasis_kind: :underscores,
format_module_attributes: true # Enable module attribute formatting
]
]
end

Available Options

OptionDefaultDescription
:line_width80Maximum line width
:text_wrap:alwaysText wrapping: :always, :never, :maintain
:emphasis_kind:asterisksEmphasis style: :asterisks, :underscores
:strong_kind:asterisksStrong text style: :asterisks, :underscores
:new_line_kind:autoLine ending type: :auto, :lf, :crlf
:unordered_list_kind:dashesList style: :dashes, :asterisks
:heading_kind:atxHeading style: :atx (#), :setext (===)
:list_indent_kind:common_markNested list indent: :common_mark, :python_markdown
:format_module_attributesnilModule attribute formatting (see below)

Note: Configuration values can be provided as atoms (:never) or strings ("never"). Atoms are preferred for consistency with Elixir conventions.

Module Attribute Configuration

# Skip all formatting (default)
format_module_attributes: nil
# Format common doc attributes
format_module_attributes: true # [:moduledoc, :doc, :typedoc, :shortdoc, :deprecated]
# Format specific attributes only
format_module_attributes: [:moduledoc, :doc, :custom_doc]

Module Attribute Formatting Example

Before mix format:

defmodule MyModule do
@moduledoc """
This is messy markdown content.
* Poorly formatted list
* Another item
"""
@doc """
Function documentation with extra spaces.
"""
def my_function, do: :ok
end

After mix format:

defmodule MyModule do
@moduledoc """
This is messy markdown content.
- Properly formatted list
- Another item
"""
@doc """
Function documentation with extra spaces.
"""
def my_function, do: :ok
end

Troubleshooting

Module attributes not being formatted

Make sure you have:

  1. Added plugins: [DprintMarkdownFormatter] to .formatter.exs
  2. Configured format_module_attributes: true in your mix.exs
  3. Run mix format on your .ex files

Compilation issues

If you see Rust compilation errors, you can force using precompiled binaries:

export RUSTLER_PRECOMPILED_FORCE_BUILD=false
mix deps.get

Development

Prerequisites

Commands

# Setup
mix deps.get
mix compile
# Development
mix test # Run tests
mix check # Run all quality checks (format, credo, dialyzer, cargo fmt, cargo clippy)
mix format # Format Elixir code
mix credo # Static analysis
mix dialyzer # Type checking
# Rust development (in native/dprint_markdown_formatter/)
cargo build # Build the NIF
cargo test # Run Rust tests

Architecture

Key Components

License

MIT License - see the LICENSE file for details.

Code Generation

This project was generated and developed with assistance from Claude Code, Anthropic's AI coding assistant. All commits in this repository include co-author attribution to Claude.

Acknowledgments