DelphiFmt
DelphiFmt - A fully configurable Delphi source code formatter engine for .pas, .dpr, .dpk, and .inc files. Controls indentation, spacing, line breaks, capitalisation, and alignment through a single options record. Idempotent by design. Format a string, a file, or an entire directory tree in one call. Built on ParseKit.
Install / Use
/learn @tinyBigGAMES/DelphiFmtREADME

What is DelphiFmt?
DelphiFmt is a Delphi source code formatter. It reads your code, applies your rules, and writes it back clean.
DelphiFmt is a Delphi library that formats .pas, .dpr, .dpk, and .inc source files according to a fully configurable set of formatting rules. You obtain a default options record, adjust any settings you care about, then call one method. The formatter tokenizes your source using Parse(), applies indentation, spacing, line break, capitalisation, and alignment rules, and returns the formatted result. All formatting operations are idempotent — running the formatter on already-formatted source produces identical output.
var
LFmt: TDelphiFmt;
LOptions: TDelphiFmtOptions;
LResults: TArray<TDelphiFmtFormatResult>;
LResult: TDelphiFmtFormatResult;
begin
LFmt := TDelphiFmt.Create();
try
LOptions := LFmt.DefaultOptions();
// Adjust any options you need
LOptions.LineBreaks.RightMargin := 120;
LOptions.Capitalization.ReservedWordsAndDirectives := capLowerCase;
LOptions.Spacing.AroundBinaryOperators := spBeforeAndAfter;
// Format an entire folder in one call
LResults := LFmt.FormatFolder('src\', LOptions, True, True);
for LResult in LResults do
begin
if LResult.Success and LResult.Changed then
WriteLn('Formatted: ', LResult.FilePath)
else if not LResult.Success then
WriteLn('Error: ', LResult.ErrorMsg);
end;
finally
LFmt.Free();
end;
end;
✨ Key Features
- 🔧 Fully configurable: Every formatting decision is controlled through a single
TDelphiFmtOptionsrecord with over 60 options grouped into five logical categories: indentation, spacing, line breaks, capitalisation, and alignment. - 🔁 Idempotent by design: Running the formatter on already-formatted source produces byte-for-byte identical output. Safe to integrate into CI pipelines, pre-commit hooks, and save-on-format workflows.
- 📂 Three entry points: Format a string in memory with
FormatSource, format a single file withFormatFile, or recursively format an entire directory tree withFormatFolder. All three share the same options record. - 💾 Automatic backups:
FormatFileandFormatFolderaccept aCreateBackupflag. When enabled, the original file is written to a.bakcopy before any changes are applied. - 🔍 Change detection: Every file-level result reports whether the file was actually changed. Unchanged files are never rewritten.
- 🧩 ParseKit-powered lexer: Tokenization is handled by Parse(), giving the formatter a precise, complete token stream for every Delphi construct.
- 📐 Indentation control: 16 independent indentation options covering
begin/end, class bodies, function bodies, nested functions,caselabels, assembly sections, compiler directives, and continuation lines. - 🔡 Capitalisation normalisation: Reserved words, compiler directives, numeric literals, and all other identifiers can each be independently set to upper case, lower case, as-is, or normalised to match the first occurrence in the file.
- ↔️ Spacing precision: Independent control over spacing around colons, commas, semicolons, assignment operators, binary operators, unary operators, parentheses, square brackets, angle brackets, and both line and block comments.
- 📏 Right margin and line break rules: Configurable right margin, CRLF/LF/CR line ending choice, maximum adjacent empty lines, and fine-grained control over when line breaks are inserted around
begin,then,else,uses,var,const, and anonymous functions. - ▦ Vertical alignment: Optional column-aligned formatting for
=in constants, type declarations and initialisations,:=in consecutive assignments, end-of-line comments, property fields, and parameter type annotations.
🎯 Who is DelphiFmt For?
DelphiFmt is for anyone who writes Delphi and wants their source formatted consistently without thinking about it.
- Individual developers: Stop adjusting whitespace by hand. Define your style once in a
TDelphiFmtOptionsrecord and let the formatter enforce it every time. - Teams: Eliminate style debates. Check a shared options configuration into source control and run
FormatFolderon every commit. Every file, every developer, every time. - Tool builders: Embed DelphiFmt into an IDE plugin, a build script, a language server, or a code review tool. The API is three methods. There is no configuration file format to parse, no process to shell out to, no external binary to ship.
- CI pipelines: Add a formatting check to your build. Run
FormatFolderwithCreateBackup := False, collect the results, and fail the build if any file reportsChanged = True. Formatting drift never reaches the main branch. - Legacy codebases: Point
FormatFolderat a directory tree, pick a style, and reformat years of inconsistently styled code in one pass. The.bakbackup flag means nothing is lost.
🔄 How It Works
DelphiFmt is four source files and Parse():
DelphiFmt.Lexer.pas - keyword and operator registration for the Delphi token set
DelphiFmt.Grammar.pas - grammar rules describing Delphi syntactic structure
DelphiFmt.Emitter.pas - formatting output rules applied to each token and construct
DelphiFmt.pas - public API: TDelphiFmt, TDelphiFmtOptions, TDelphiFmtFormatResult
Parse() provides the tokenizer and the token stream infrastructure. DelphiFmt provides the Delphi language definition and all formatting logic.
Delphi source
|
v
+-----------+ tokens +----------+ structured +-------------+
| Lexer | --------> | Grammar | -------------> | Emitter |
| (Parse()) | | (Parse())| token stream | (rules) |
+-----------+ +----------+ +-------------+
|
v
formatted source
🚀 Getting Started
Prerequisites: Directory Layout
DelphiFmt requires the ParseKit sources to be present as a sibling directory alongside DelphiFmt. The Delphi project references ParseKit's source directly. The required layout is:
C:\Dev\ <- or any root you choose
ParseKit\ <- ParseKit repo root (contains src\, bin\, etc.)
DelphiFmt\ <- DelphiFmt repo root (contains src\, bin\, etc.)
Both repos must share the same parent directory. If they do not, the Delphi project will not compile.
Step 1: Get ParseKit
Option 1: Download ParseKit ZIP
Option 2: Git clone
git clone https://github.com/tinyBigGAMES/ParseKit.git
Place (or clone) it so the folder structure matches the layout above.
Step 2: Get DelphiFmt
Option 1: Download DelphiFmt ZIP
Option 2: Git clone
git clone https://github.com/tinyBigGAMES/DelphiFmt.git
System Requirements
| | Requirement | |---|---| | Host OS | Windows 10/11 x64 | | Delphi | Delphi 11 Alexandria or later |
Step 3: Open in Delphi and Build
- Open
src\DelphiFmt - Delphi Source Code Formatter.groupprojin Delphi - Build all projects in the group (
DelphiFmt,Testbed) - Run
Testbedto verify the formatter is working correctly against the included test sources
Step 4: Use the API
uses
DelphiFmt;
var
LFmt: TDelphiFmt;
LOptions: TDelphiFmtOptions;
LResult: TDelphiFmtFormatResult;
begin
LFmt := TDelphiFmt.Create();
try
// Start from the built-in defaults (Castalia-compatible style)
LOptions := LFmt.DefaultOptions();
// Override whatever you need
LOptions.LineBreaks.RightMargin := 120;
LOptions.Capitalization.ReservedWordsAndDirectives := capLowerCase;
// Format a single file, creating a .bak backup before writing
LResult := LFmt.FormatFile('MyUnit.pas', LOptions, True);
if LResult.Success then
begin
if LResult.Changed then
WriteLn('File was reformatted.')
else
WriteLn('File was already correctly formatted.');
end
else
WriteLn('Error: ', LResult.ErrorMsg);
finally
LFmt.Free();
end;
end;
📖 Option Reference
| Group | Options | Description |
|---|---|---|
| Indentation | 16 | begin/end keywords, class bodies, function bodies, inner functions, case labels, assembly sections, compiler directives, continuation indent size, and more |
| Spacing | 13 | Colons, commas, semicolons, assignment operators, binary operators, unary operators, parentheses, square brackets, angle brackets, line comments, block comments |
| Line Breaks | 30+ | Right margin, line ending characters, begin/then/else break placement, uses/var/const sections, anonymous functions, empty line counts around sections, directives, and visibility modifiers |
| Capitalisation | 4 | Reserved words and directives, compiler directives, numeric literals, all other identifiers — each independently set to capUpperCase, capLowerCase, capAsIs, or capAsFirstOccurrence |
| Alignment | 11 | = in constants, type declarations, and initialisations;
