- Version 0.7.0.22
- Dateigrösse 3MB
- Erstellungsdatum 3. Juli 2026
- Zuletzt aktualisiert 17. August 2026
-
Changelog
======================================================================= MSys Delphi Formatter 0.6.0.21 — What's New Maenken Systems · https://maenken.systems Release 0.6.0.21 (from release 0.5.0.17) =======================================================================
----------------------------------------------------------------------- 1. New -----------------------------------------------------------------------
- Indent
type/constsections inside a class body. Many libraries — and the RTL itself — put atypeorconstsection inside a class or record body and indent its declarations one level under the keyword. The formatter used to pull them back to the level of the section keyword, and the existing "indent after sections" option did not help: that one only ever covered the unit sectionsinterfaceandimplementation. The new option Indent type/const sections inside a class or record body (Indentation page, or the.editorconfigkeydelphi_indent_nested_sections) covers the class-internal case. Default off, so nothing changes unless you ask for it; the indented region ends at the next visibility specifier, method declaration, further section keyword or the type'send, so it cannot spill into the rest of the file. - Indent case-else statements under their own else.
With the case-else placed on the
casecolumn, its statements used to stay on the arm column — two levels away from theelsethey belong to. The new option Indent case-else statements under their own else (Indentation page,.editorconfigkeydelphi_indent_case_else_contents) closes that gap. It only differs in exactly that pairing; with the default case-else placement both readings coincide. - Indent directive lines under their routine header. A
stand-alone
inline;,overload;orstdcall;line — including the conditional form{$IF …}inline;{$IFEND}— can now be indented one continuation step under the header it belongs to, via Indent directive lines under their routine header (Indentation page,.editorconfigkeydelphi_indent_routine_directives). This is a matter of style rather than a defect: the;after the parameter list ends the declaration, so the directive really is a line of its own and the flat reading is just as defensible — which is why the default is off. A comment between the header and the directive does not break the association. - Keep hand-set columns. Manually aligned trailing
comments and
=columns in const blocks used to be collapsed to a single space — the formatter threw away work someone had done on purpose. The align options were no answer: they compute the minimal column and so replace one normalisation with another. The new option Keep hand-set columns (Align page,.editorconfigkeydelphi_preserve_manual_columns) simply leaves such a run alone. It never widens a single space, so it cannot create alignment — it only keeps what is there. Default off.
======================================================================= MSys Delphi Formatter 0.5.0.17 — What's New Maenken Systems · https://maenken.systems Release 0.5.0.17 (from release 0.4.0.10) =======================================================================
All changes in this release were driven by community feedback from the Delphi-PRAXiS beta threads — thank you to everyone who tested and reported.
----------------------------------------------------------------------- 1. Fixed -----------------------------------------------------------------------
- The branch-swap conditional idiom no longer blocks
formatting. The pattern where one preprocessor branch opens a
case … ofand the other contributes abegininstead — both sharing the closingends, with{$ELSE}and{$ENDIF}sitting in the middle of one code line (else{$ELSE}begin{$ENDIF}) — used to make the whole file count as structurally unbalanced: with several occurrences the formatter refused the file (this is what made Spring4D'sSpring.pasappear "unformattable"), and with exactly one occurrence everything after the pattern silently drifted two columns to the right. The formatter now recognizes this shape, follows the first branch — consistent with how conditional regions are handled everywhere else — and keeps the indentation stable. Other mid-line directive regions remain deliberately untouched, as documented under Known limits. - The options dialog is readable again under a light IDE theme. The pane holding the options took its background from the editor colour scheme instead of the IDE theme. Since that scheme is chosen independently of the theme, anyone running a light IDE with a dark editor scheme — a very common combination — got a black options pane while the captions stayed dark, which left whole pages unreadable. Editor colours now dress the two preview panes only, where they belong; everything else follows the IDE theme, in both the light and the dark variant.
- The command-line formatter carries version
information.
Formatter.exeshipped without any version resource at all: neither Windows' file properties nor a deployment script could tell which build was in use. It now reports its version and vendor like the plugin does, and both are built from the same version number.
----------------------------------------------------------------------- 2. New -----------------------------------------------------------------------
- Blank-line separators without switching on reflow.
The separators that put blank lines at structural boundaries — between
methods, before the final
end., around sections — used to require the reflow master to be off, which meant that anyone who only wanted a blank line between methods had to hand the formatter their whole line layout as well. Inserting a blank line moves no code, so it never needed that: the new option Apply the separators even when user line breaks are kept (Blank Lines page, or the.editorconfigkeydelphi_apply_blank_line_separators) releases them on their own. The default is off, so nothing changes unless you ask for it. Verified against a large real-world code base: with the option on, the only difference to a normal run is blank lines — not a single token moves. - Product page, version and contact are now in plain sight. The options dialog carries a slim header above every page: the product name with a link straight to the product page — opening the English or the German edition to match the IDE language — and the installed version on the right. Beta testers told us the previous placement was easy to miss, which made it unnecessarily hard to find out where to send feedback.
- Format while typing (pilot, opt-in). On IDEs that
offer the native formatter interface — prepared for future RAD Studio
versions — the formatter can now re-format the line the caret leaves
with Enter — same rules and safety gates as Ctrl+D, but completely
silent: an incomplete or unbalanced buffer (the normal state while
typing) or an already-formatted line is a quiet no-op, and no dialog
ever appears. Caret, breakpoints and bookmarks follow exactly. Strictly
opt-in (default: off) via the new General-page option Format line on
Enter or per project via the new
.editorconfigkeydelphi_format_on_type; semicolons, pasting and navigation never trigger it. - The command-line formatter no longer overwrites files it
could not read properly. When the formatter cannot make sense
of a file's structure — it ends up with more block openers than closers
— its indentation is a guess. The IDE has always refused such a buffer
and left it alone; the command-line tool used to mention the fact in
passing and rewrite the file anyway, with a success exit code. A batch
run over a repository therefore wrote guessed indentation into exactly
the files the IDE protects, and
--checkreported them as an ordinary formatting difference. Both now give the same answer: the file is reported asKEEPand left untouched, the run ends with its own exit code 3 so a build pipeline can tell "needs formatting" from "cannot be formatted safely", and--outstill writes the file into the mirror directory, where it overwrites nothing. The new switch--best-effortrestores the previous behaviour for anyone who wants it, exit code included.
----------------------------------------------------------------------- 3. Under the hood -----------------------------------------------------------------------
- Conditional branches no longer add up in the line-break
pass. The reflow stage kept one structural tally across all
branches of a
{$IFDEF}region instead of following the first one, the way the indentation stage already did. A branch that opened or closed a block without closing or opening it again shifted that tally for the rest of the unit, after which whole families of line-break rules quietly stopped applying — or started applying — far away from the directive that caused it. The effect was invisible from the outside: the output stayed structurally sound and stable under repeated formatting, only the line breaks were placed as if a different file had been read. Both stages now follow the same rule. This only ever affected profiles with reflow enabled. - A
varorconstparameter is no longer mistaken for a declaration section. With per-element wrapping ofvar/constlists enabled, a routine taking avarparameter had the comma in a generic return type (IDictionary) broken as if it were a name-list separator, leaving the continuation dangling. The two meanings of the keyword are now kept apart.
======================================================================= MSys Delphi Formatter — History 0.4.0.10 =======================================================================
Release 0.4.0.10 (from beta build 3.0.1 / GetIt). All changes below were driven by community feedback from the Delphi-PRAXiS beta threads — thank you to everyone who tested and reported.
----------------------------------------------------------------------- 1. Fixed -----------------------------------------------------------------------
Sources the formatter refused, or changed in ways it must not
Conditional compilation ({$IFDEF} / {$ELSE} / {$ENDIF}) — the big one
Sources whose conditional branches open or close blocks (begin, try,
class, asm …) could not be formatted at all: the formatter saw the code of
every branch at once, counted openers and closers across branches and
refused the whole file as "unbalanced block structure". The mirror case — a
closer duplicated across branches — silently produced drifted indentation.
The structural bookkeeping is now branch-aware: at {$IF*} the formatter
snapshots its state, walks every {$ELSE} / {$ELSEIF} branch from that same
entry state and continues after {$ENDIF} / {$IFEND} with the first
branch's exit state. Both directive families are supported, nested regions
work, and column alignment no longer bridges across branch boundaries. The
safety guarantee is unchanged: nothing is ever written when the source truly
is unbalanced.
Known limits: include files ({$I}) that contribute block edges and
directives sharing a line with code are by-design limits — now documented
in the manual's "Known limits" section; some reflow-mode edge cases
remain tracked.
Variant records refused every unit
Any unit containing a variant record (case Integer of inside a record)
was refused with the same "unbalanced" message — without a single compiler
directive involved. Fixed.
A closing end at the end of a statement line refused the whole file
A line that both finishes a statement and closes its block — B; end;, or the
end); a compact one-line anonymous method leaves behind — made the formatter
report the source as unbalanced and refuse it entirely, although the code is
perfectly valid. The closer was consuming the pending continuation of an
enclosing if … then / while … do instead of the block itself, so the block
stayed open until the end of the file. A closer now always ends a block, wherever
it sits on the line. This affected the default profile too, not just reflow —
and in the cases that were not refused outright it silently pushed everything
after that line further and further right.
asm blocks that end mid-line refused the file
The same class of defect as the previous fix, one code path over: after the end of an
asm block the formatter stopped looking at the rest of that line, so a
routine written as asm … end; end; lost its outer block and the file was
refused. The remaining closers on the line are now counted.
Reflow could silently change what a string literal means
With line-break rules active, if C = '''' then Q; was reflowed so that the
apostrophe literal ended up as the last token on its line. Delphi 12 reads a
run of three or more apostrophes followed only by whitespace as the opening
delimiter of a multiline string — so on the next run the formatter (correctly)
read its own output as a multiline string and swallowed the following code. The
result was a program with different meaning, and in some shapes one that no
longer even parses. Such a literal is now never left at the end of a line.
This also removes the last known case where formatting twice gave a different
result than formatting once.
An unrelated .editorconfig could be applied to your file
The settings cascade walks from the file's own directory upwards — but one step
past the drive root it produced the drive-relative form (C:), and asking
Windows for C:.editorconfig means ".editorconfig in the current directory of
that drive". Files that had no .editorconfig of their own therefore silently
picked up the one belonging to whatever directory the formatter happened to be
started from — in the IDE that is not even a directory you chose. The cascade
now stops at the drive root, so only the file's own path decides its settings.
Broken parentheses no longer produce file-wide indent drift
A source with a missing ) or ] used to pass the safety check silently —
it only measured begin/end blocks — and the continuation indent then
drifted through the rest of the file. Unbalanced parentheses or brackets now
share the same protection as unbalanced blocks: the IDE refuses with a
precise message ("unbalanced parentheses or brackets") and leaves the buffer
untouched. Such files cannot compile anyway; once the syntax is fixed, a
single format run restores canonical indentation everywhere.
Layout
Alignment stopped working after branch-asymmetric conditionals
The aligner's nesting counters read every {$IFDEF} branch as if all of
them were compiled at once — a begin in each branch counted twice, so
behind such a conditional the aligner believed it was still inside
executable code and quietly stopped aligning const/var/field blocks.
The counters now follow the first branch only (the same
first-branch-wins rule the conditional-fork indenter uses); behind the
region the alignment is identical to a file containing just that branch.
Generics with conditional type arguments were spaced as comparisons
TList came out as
TList ; — the generic matcher silently swallowed the directives
and read both branches as one invalid token stream. The scan now follows
the first branch and skips {$ELSE}…{$ENDIF} whole (the same
first-branch-wins rule the conditional-fork indenter uses), so the
angle brackets stay generic-tight in every branch. Real comparisons
next to directives keep their operator spacing.
Box-art comment headers were gutted
Under the default profile, decorative comment blocks such as the classic
{ Framework Name } unit headers lost their interior padding, and
whitespace-only filler lines collapsed to {}. The comment-spacing option now
does exactly what it says — it normalizes the single space inside the
delimiters ({x} ↔ { x }) — and treats everything beyond that (padding
runs, frame lines like {******}, multi-line comments) as deliberate layout
that survives byte-for-byte.
Nested if/else indented misleadingly
In if A then if B then … else … chains the else branch was visually
re-bound to the outer if, although Delphi binds it to the nearest one.
The indentation now follows the language's actual binding — including through
while … do in between, and without disturbing case-else handling.
Multi-line signatures and calls lost their continuation indent
Continuation lines of a multi-line parameter list or call were flattened to the same column as their head line. They now indent one continuation step past the line that opened the bracket; a closing-bracket line aligns with that opener line.
Statements after a mid-line finally / except were mis-indented
try / if A then / B; finally left the pending then continuation
standing, so the statements of the finally part sat one step too deep.
The else of an unparenthesized if-expression looked like a second else
In if C then / X := if A / then 1 / else 2 / else / Y := 3; the
first else belongs to the expression, the second to the statement — but the
formatter pulled both onto the same column, so the code read as if one if had
two else branches. The expression's else now stays at the expression's
level. (The branch lines themselves keep their layout: an unparenthesized
continuation is never indented an extra step — the same as X := A + / B;.)
Generic constraints were spaced as comparisons
TList came out as TList .
Constraint lists (class, record, constructor, interface types, multiple
parameter groups) are now recognized as generics.
Generics in parameter defaults were torn apart
A default value glued to a generic parameter type — Symbols: TArray= []
(no space before the =) — made the scanner read >= as a single
greater-or-equal operator. The generic then failed to be recognized and came
out spaced as a comparison: TArray = []. Both the tight original
and the previously damaged form now heal to TArray = []; a generic
< also glues back to its type name. Real comparisons like a = c
are untouched.
Delphi 13 if-expressions were staircased
A multi-line if-expression in parentheses — (if cond then '-' else '')
spread over lines — had its branch lines indented like a statement-if, one
extra level per then/else. Combined with the bracket-indent option this
produced a staircase drifting right with every branch. Inside parentheses an
if is always an expression (only an anonymous method's begin re-enters
statement territory — that case is recognized and unchanged), so the branch
lines now get plain continuation indent. Statement-if formatting, dangling-
else binding and case-else handling are untouched.
"else if" line breaks left the else hanging
With line-break rules active, if A then B else if C then D reflowed to
then B else ⏎ if C. A statement-level else now always starts its own
line; the existing option keeps controlling the gap between else and if
(both settings of it now produce clean shapes). Delphi 13 if-expressions
(x := if a then b else c) are never broken apart.
Line-break rules tore if-expressions apart
With reflow enabled, a Delphi 13 if-expression was laid out like a statement:
S := (if A then 'yes' else 'no'); came back split across four lines. The
first round of protection covered only the unparenthesized form and only two of
the four rules involved, so both the parenthesized form and — with the then
and simple instruction rules armed — even the bare one were still broken up.
Inside parentheses an if is always an expression (an anonymous method's
begin re-enters statement territory), and those rules now leave both forms
alone. Statement ifs keep breaking exactly as configured.
Command line
One bad file no longer aborts the whole run
A source that cannot be decoded (a stray byte in a file claiming UTF-8) made
Formatter.exe stop right there — silently truncating a recursive sweep, even
under --check where nothing is written at all. Such a file is now reported,
counted as skipped and left untouched; the run continues and the exit code
still reports the error.
----------------------------------------------------------------------- 2. New -----------------------------------------------------------------------
Blank lines around initialization/finalization, and before the final end.
Two new structure separators and a new indent option close the gap the
section separators left: delphi_blank_lines_around_initialization
guarantees blank lines before and after the initialization/
finalization keywords, delphi_blank_lines_before_final_end puts
them before the closing end., and Indent initialization/finalization
contents indents the sections' statements one level like a begin..end
block. All three are off by default — existing output stays
byte-identical.
Unusable options are now hidden
When a master option turns a group of settings off, those settings used to stay visible — at best with a grayed group title, while the controls below still looked active ("It's disturbing"). Dependent options are now hidden outright: with "Keep user line breaks" on (the default), the line-break rules, the whole Reflow page and the blank-line separators disappear (an explanatory note stays behind); the alignment tuning numbers hide while no alignment case is active; coupled or inert switches (colons-before-types coupling, case options without block indent, bracket indent under reflow) vanish with their masters. Toggling the master brings everything back — live, across pages, without reopening the dialog.
Readable, complete option texts
Longer labels were cut off — most visibly the note under Blank Lines and the "colons before type names" switch under Alignment, and more often in German, where the translations are longer than the English originals. Every page was measured against both languages: notes have room for their full text, long switch captions wrap instead of being clipped, and the drop-downs sit far enough right that no label can run into them. The explanatory notes are now laid out in paragraphs instead of one dense block.
The option previews now show real cases
The live before/after preview on each options page demonstrates the
constellations this release fixed: conditional branches carrying a try,
case with else, box-art comment headers, generic constraints and
defaults, multi-line call continuations, dangling else binding,
{$REGION} blank lines and alignment groups broken by a directive — so
every page shows its own options working on real code.
The line-break master is now a regular .editorconfig key
"Keep user line breaks" can be set from a project's .editorconfig
(delphi_keep_user_linebreaks) like every other option, so a team can pin its
line-break policy in the repository and an exported profile round-trips
completely. This deliberately reverses the earlier safety stance that a
repository file must never enable reflow.
Export writes what you see
Both export buttons (.config and .editorconfig) now write the values currently set in the options dialog, including pages you have edited but not yet applied — previously they silently wrote the last saved state, and the note explaining that is gone along with the behaviour.
The installer now serves both IDEs
The setup installs the 32-bit and the 64-bit design package side by side and registers each with its IDE (Known Packages / Known Packages x64) — Ctrl+D works in whichever RAD Studio 13 you launch. Both packages always carry the same version number; the installer build refuses to package mismatched builds.
Option: placement of the case-else line
A new switch "Indent else line" (delphi_indent_case_else) controls where
the else of a case statement sits: at the level of the alternative labels
(default, unchanged behaviour) or at the case keyword — the classic RTL
style. The statements below it remain governed by the existing case options.
----------------------------------------------------------------------- 3. Clarified and pinned -----------------------------------------------------------------------
- Blank lines around
{$REGION}: both halves of the request are covered by existing options — set Max. consecutive blank lines to 2 to preserve a two-blank region spacing, and Blank lines around compiler directives (reflow tier) to insert them. Documented in the manual and locked in by tests. - "Ensure final newline" and "Enable formatting": both
reported against beta build 3.0.1; the current code base behaves correctly
(the disable switch is honoured end to end, including the
.editorconfigcascade, and the final-newline option is exact in both directions). Both behaviours are now locked in by tests. The 3.0.1 symptoms came from that build's Revive-based IDE integration, which the native RAD Studio 13.2 formatter interface has since replaced. - Options pages opening slowly: verified not to be the plugin — even empty pages build up slowly; the cost sits in RAD Studio's own Tools/Options page embedding and would affect any add-in equally.
The limits of conditional handling are documented
Two constellations the conditional-fork model cannot cover by principle
now have their own "Known limits" manual section (German and English):
include files that contribute block structure (the formatter refuses
honestly or, for an included begin, may indent differently after the
spot - never damaging anything), and directive regions starting or
ending next to code on the same line (left untouched). Each comes with
a minimal example, the observable behavior and an .editorconfig
opt-out recipe.
----------------------------------------------------------------------- 4. By design -----------------------------------------------------------------------
- The options tree stays under the MSys node: requested twice from the community ("Third Party" placement); declined deliberately — the MSys node is the shared home for current and future MSys settings.
- Ctrl+D stays Ctrl+D: the format shortcut is not configurable — Ctrl+D has been the Delphi formatter's key since the built-in one, and on RAD Studio 13.2 the IDE owns the command anyway. Plugins that also claim Ctrl+D (e.g. GExperts) offer configurable shortcuts on their side.
----------------------------------------------------------------------- 5. Under the hood -----------------------------------------------------------------------
- The regression suite grew from 744 to 970 checks; every repository fixture is now also verified to format balanced, and formatting twice is now pinned for reflow profiles too, not just the default one.
- New shared conditional-directive classifier used by the re-indenter and the aligner; community-provided reproduction sources joined the fixture set.
- Several of the defects above were found by the fix for another one: the
mid-line closer and the multiline-string cases came out of reviewing the
if-expression reflow, and the
.editorconfigcascade bug out of measuring the multiline-string fix.