Ada Language Formatter (ALS-backed, Customizable)
Project description
adafmt โ Ada Language Formatter
Version: 0.0.0 License: BSD-3-Clause Copyright: ยฉ 2025 Michael Gardner, A Bit of Help, Inc.
adafmt is an opinionated Ada 2022 formatter that leverages the Ada Language Server (ALS) to provide consistent, modern formatting while maintaining compatibility with earlier Ada versions. Built with extensibility in mind, it supports custom pattern formatting functions that allow teams to enforce project-specific style rules beyond what GNATFORMAT provides. It delivers a robust, production-ready solution for maintaining consistent code style across Ada projects of any size.
Why Use AdaFmt?
๐ Single-Pass Formatting
Unlike tools that require multiple passes to converge on a stable format, adafmt achieves consistent results in a single run. No need to run it three times hoping for convergence.
๐ Comprehensive Logging
Every formatting transformation is logged in structured JSON Lines format, providing complete visibility into what changed and why. Perfect for auditing and debugging formatting decisions.
โจ Modern Architecture
Built on the Ada Language Server (ALS) using the Language Server Protocol, avoiding known issues with chaining gnatformat and gnatpp. Get reliable, consistent results every time.
๐ฏ Extensible Pattern System
Configure custom formatting patterns in a simple JSON file. Override defaults, add project-specific transformations, or enforce team style guides beyond what standard tools provide.
๐ก๏ธ Safe by Default
- Dry-run mode shows changes before applying them
- Atomic file updates prevent partial writes
- Automatic validation catches syntax errors before writing
- Comprehensive error reporting for troubleshooting
๐ง Additional Benefits
- CI/CD Integration: Check mode with proper exit codes for automated pipelines
- Performance Metrics: Detailed statistics on processing time and throughput
- Cross-Platform: Works on Linux, macOS, and Windows with appropriate ALS
- Project-Aware: Understands GNAT project files (.gpr) for accurate formatting
- Flexible Discovery: Smart file finding with include/exclude path support
Features
- Language Server Protocol (LSP) Integration: Uses the official Ada Language Server for accurate, specification-compliant formatting
- Multiple UI Modes: Choose from pretty (curses), basic, plain, or headless operation modes
- Standalone Operation: Works directly with Ada Language Server without external package managers
- Robust Error Handling: Retry logic for transient failures with configurable timeouts
- Dry-Run by Default: Preview changes safely before applying them
- CI/CD Ready: Exit codes and check mode for integration into automated workflows
- Comprehensive Logging: Structured JSON Lines logging for debugging and auditing
- Cross-Platform: Works on Linux, macOS, and Windows (with appropriate ALS installation)
- Syntax Error Detection: Compiler verification to catch GNATFORMAT false positives
- Performance Statistics: Detailed summary with files processed, time elapsed, and processing rate
- Atomic File Updates: Safe file writing with automatic backup during updates
Quick Start
Installation
From PyPI (Recommended)
pip install adafmt
From GitHub Releases
Download the appropriate package from the latest release:
Python Wheel (All Platforms)
# Download the wheel file, then:
pip install adafmt-0.0.0-py3-none-any.whl
Python Zipapp (Portable, No Installation)
# Download adafmt.pyz, then run directly:
python3 adafmt.pyz --help
# Or make it executable (Unix-like systems):
chmod +x adafmt.pyz
./adafmt.pyz --help
Standalone Executables (No Python Required)
# Linux
wget https://github.com/abitofhelp/adafmt/releases/latest/download/adafmt-linux-x64
chmod +x adafmt-linux-x64
./adafmt-linux-x64 --help
# macOS
curl -LO https://github.com/abitofhelp/adafmt/releases/latest/download/adafmt-macos-x64
chmod +x adafmt-macos-x64
./adafmt-macos-x64 --help
# Windows (PowerShell)
Invoke-WebRequest -Uri https://github.com/abitofhelp/adafmt/releases/latest/download/adafmt-windows-x64.exe -OutFile adafmt.exe
.\adafmt.exe --help
From Source (Development Mode)
# Clone the repository
git clone https://github.com/abitofhelp/adafmt.git
cd adafmt
# Create virtual environment and install
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
pip install -e .
# Verify installation
adafmt --version
System Requirements
- Python 3.8 or higher
- Ada Language Server (ALS) installed and available in PATH
Requirements
Ada Language Server (ALS)
This tool uses the Ada Language Server, but does not bundle or redistribute it.
You must have ada_language_server available on your PATH before running adafmt.
Install ALS
Pick one of the following options:
-
Via Alire (recommended for Ada developers):
# Install Alire if you don't already have it, then: alr search ada_language_server # discover the crate alr get ada_language_server # fetch locally (buildable project) # follow Alire's instructions to build/install; after install it should be on PATH
-
Via GNAT Studio: If you have GNAT Studio installed, it includes the Ada Language Server.
-
Via GitHub Releases: Download pre-built binaries from Ada Language Server releases.
Basic Usage
Format Ada Files in a Directory
# Preview changes (dry-run mode)
adafmt --project-path /path/to/project.gpr \
--include-path /path/to/src
# Apply changes
adafmt --project-path /path/to/project.gpr \
--include-path /path/to/src \
--write
Format Specific Files
# Format individual files
adafmt --project-path /path/to/project.gpr \
main.adb utils.ads types.ads
# Mix files and directories
adafmt --project-path /path/to/project.gpr \
--include-path /path/to/src \
special_file.adb
CI/CD Integration
# Check if any files need formatting (exits 1 if changes needed)
adafmt --project-path /path/to/project.gpr \
--include-path /path/to/src \
--check
# Use plain output for CI logs
adafmt --project-path /path/to/project.gpr \
--include-path /path/to/src \
--ui plain \
--check
Command-Line Interface
Required Arguments
--project-path PATH: Path to your GNAT project file (.gpr)
Optional Arguments
File Selection
--include-path PATH: Directory to search for Ada files (can be specified multiple times)--exclude-path PATH: Directory to exclude from search (can be specified multiple times)FILES...: Specific Ada files to format (positional arguments)
Output Options
--write: Apply changes to files (default: dry-run mode)--diff/--no-diff: Show/hide unified diffs of changes (default: --diff)--check: Exit with code 1 if any files need formatting
User Interface
--ui {off,auto,pretty,basic,plain}: UI mode selectionoff: No UI, only output diffsauto: Best available UI (default)pretty: Curses UI with progress barbasic: Simple text UIplain: Minimal output for scripts
Advanced Error Handling
- Smart Error Detection: Distinguishes between syntax errors (prevent formatting) and semantic errors (allow formatting)
- Compiler Verification: Automatically verifies GNATFORMAT syntax errors to detect false positives
- Detailed Error Reporting: Comprehensive stderr output with timestamps, error types, and actionable guidance
Advanced Options
--preflight {off,warn,safe,kill,kill+clean,aggressive,fail}: Handle existing ALS processesoff/none: Skip all checkswarn: Report processes and locks onlysafe(default): Kill ALS processes older than--als-stale-minuteskill: Same assafekill+clean: Kill stale ALS + remove stale lock filesaggressive: Kill ALL user's ALS processes + remove all locksfail: Exit with error if any processes/locks found
--als-stale-minutes N: Age threshold for stale ALS processes (default: 30)--init-timeout SECONDS: Timeout for ALS initialization (default: 180.0)--warmup-seconds SECONDS: Time to let ALS warm up (default: 10.0)--format-timeout SECONDS: Timeout per file formatting (default: 60.0)--max-attempts N: Retry attempts for transient errors (default: 2)
Debugging
--log-file-path PATH: Write structured logs to JSONL file--stderr-file-path PATH: Capture ALS stderr output to file
Environment Variables
ADAFMT_UI_FORCE: Override the UI mode parameterADAFMT_UI_DEBUG: Enable UI selection debug output
File Discovery
adafmt searches for Ada source files using these rules:
- File Extensions:
.ads(spec),.adb(body),.ada(either) - Search Behavior:
- Recursively searches
--include-pathdirectories - Skips
--exclude-pathdirectories and their subdirectories - Processes explicitly named files regardless of location
- Recursively searches
- Common Exclusions: Consider excluding:
- Build directories (
obj/,lib/,.build/) - Dependencies (
alire/,deps/) - Generated files (
b__*.ad[sb])
- Build directories (
Integration Examples
Makefile Integration
.PHONY: format format-check
format:
adafmt --project-file-path $(PROJECT_GPR) \
--include-path src \
--exclude-path obj \
--write
format-check:
adafmt --project-file-path $(PROJECT_GPR) \
--include-path src \
--exclude-path obj \
--check
Git Pre-commit Hook
#!/bin/bash
# .git/hooks/pre-commit
# Check Ada files formatting
adafmt --project-file-path project.gpr \
--include-path src \
--check \
--ui plain
if [ $? -ne 0 ]; then
echo "Error: Ada files need formatting. Run 'make format' and try again."
exit 1
fi
GitHub Actions
name: Ada Format Check
on: [push, pull_request]
jobs:
format-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Ada
uses: ada-actions/ada-toolchain@v1
with:
target: native
distrib: community
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install adafmt
run: |
pip install adafmt
- name: Check formatting
run: |
adafmt --project-file-path project.gpr \
--include-path src \
--check \
--ui plain
Troubleshooting
Common Issues
"Ada Language Server not found"
- Ensure ALS is installed:
which ada_language_server - Add ALS to PATH or ensure it's available in your environment
"Existing ALS processes detected"
- Use
--preflight killto clean up stuck processes - Or manually:
pkill -f ada_language_server
Timeout Errors
- Increase timeouts:
--init-timeout 300 --warmup-seconds 20 --format-timeout 120 - Check ALS stderr:
--stderr-file-path als-debug.log
Understanding Error Types
Syntax vs Semantic Errors:
- Syntax errors: Malformed code structure (missing semicolons, unmatched parentheses, etc.)
- These prevent formatting - ALS cannot parse the code structure
- adafmt reports these as failures with error code -32803
- Semantic errors: Valid syntax but incorrect meaning (undefined types, missing imports, etc.)
- These do NOT prevent formatting - code structure is valid
- Examples:
"Domain_Event" not declared,invalid prefix in selected component - Your code will format successfully but won't compile
When ALS Reports Syntax Errors:
- adafmt attempts compilation to verify (only for .adb/.ada files)
- False positives are tracked and shown as yellow warnings
- Real syntax errors prevent formatting and are reported as failures
- Failed files show "(details in the stderr log)" on terminal
- Full error details with timestamps are written to the stderr log file
No Changes Applied
- Ensure
--writeflag is used (default is dry-run) - Check file permissions and disk space
Debugging
Enable comprehensive logging to diagnose issues:
adafmt --project-file-path /path/to/project.gpr \
--include-path /path/to/src \
--log-file-path adafmt-debug.jsonl \
--stderr-file-path als-stderr.log \
--ui plain
View logs:
# View structured logs
jq . adafmt-debug.jsonl
# View ALS errors
cat als-stderr.log
Architecture
adafmt follows a modular architecture:
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ CLI โโโโโโถโ ALS Client โโโโโโถโ ALS โ
โ (cli.py) โ โ(als_client) โ โ (subprocessโ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ โ
โผ โผ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ TUI โ โ Edits โ
โ (tui.py) โ โ (edits.py) โ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
Project Structure
adafmt/
โโโ src/adafmt/ # Main package source code
โ โโโ __init__.py # Package initialization
โ โโโ cli.py # Command-line interface and main entry point
โ โโโ als_client.py # Ada Language Server async client
โ โโโ tui.py # Terminal UI with curses/plain fallback
โ โโโ file_discovery.py # Ada source file discovery logic
โ โโโ edits.py # LSP TextEdit application and diff generation
โ โโโ utils.py # Utility functions (atomic write, Alire detection)
โ โโโ logging_jsonl.py # Structured JSON Lines logging
โโโ tests/ # Test suite
โ โโโ test_*.py # Unit tests for each module
โ โโโ test_integration.py # Integration tests with ALS
โโโ docs/ # Comprehensive documentation
โ โโโ api/ # API reference documentation
โ โโโ guides/ # User and developer guides
โ โโโ formal/ # Requirements and design documents
โ โโโ reference/ # Technical references and deep-dives
โ โโโ user/ # User guides and troubleshooting
โโโ scripts/ # Build and release scripts
โโโ pyproject.toml # Project configuration and dependencies
โโโ Makefile # Common development tasks
โโโ README.md # This file
Key Components
- CLI (
cli.py): Command-line argument parsing and orchestration - ALS Client (
als_client.py): Async JSON-RPC client for Language Server Protocol - TUI (
tui.py): Terminal UI with automatic fallback to simpler modes - File Discovery (
file_discovery.py): Smart Ada source file detection with exclusion support - Edit Engine (
edits.py): LSP TextEdit application with unified diff generation - Logger (
logging_jsonl.py): Structured logging for debugging and auditing - Utilities (
utils.py): Atomic file writes, process management, preflight checks
Contributing
We welcome contributions! Please see our Developer Documentation for:
- Setting up a development environment
- Code style guidelines
- Testing requirements
- Submitting pull requests
Documentation
๐ Complete documentation is available in the docs/ directory:
For Users
- Getting Started Guide - New users start here! Complete examples and workflows
- User Guides - Troubleshooting, configuration, and usage guides
- Timeout Configuration - ALS timeout tuning and optimization
For Developers
- Developer Documentation - Complete development guide
- API Reference - Technical API documentation
- Testing Guide - Comprehensive testing documentation
Technical References
- Software Requirements Specification - Formal requirements
- Software Design Document - Architecture and design decisions
- Technical Reference - Advanced technical details
License
BSD-3-Clause โ see LICENSE for the full text.
ยฉ 2025 Michael Gardner, A Bit of Help, Inc. SPDX-License-Identifier: BSD-3-Clause
Acknowledgments
- Ada Language Server team for providing a robust LSP implementation
- Alire community for modern Ada package management
- Python asyncio contributors for excellent async subprocess support
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file adafmt-1.0.0.tar.gz.
File metadata
- Download URL: adafmt-1.0.0.tar.gz
- Upload date:
- Size: 68.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eb4786184f67864580e35279bef9e070f7fc8adab1b469baf8e1e051368c326e
|
|
| MD5 |
aabbe01afc4c890af2d3f81b686a9aa9
|
|
| BLAKE2b-256 |
82cb4099fdf451c7a5ca3823b929efa490a9e90299124747753b4f8ecd82f347
|
File details
Details for the file adafmt-1.0.0-py3-none-any.whl.
File metadata
- Download URL: adafmt-1.0.0-py3-none-any.whl
- Upload date:
- Size: 72.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
909c19ce6c531cb11a91c3890d104253e35dbd303446d65a0e57eeaa8ccdb5d3
|
|
| MD5 |
edbfd328c5bce11ff746d0eca65a4a08
|
|
| BLAKE2b-256 |
592d24c433a86665668142daac9db3d83f50e85ce8b41dd8612d67967dce7a07
|