On Wed, Mar 18, 2026 at 06:13:59PM +0100, Alejandro Colomar via Mutt-dev wrote:
I don't know if there are any other formatters that would be good.
astyle has a reputation for being ok-ish. maybe worth a try.
And I don't think writing a formatter from scratch just for mutt(1)
would be reasonable.
says WHO?! :-D
of course it would be bonkers to create a full formatter, but a simple
solution that gets 99% done is easy enough. in fact, i did just that a
quarter century ago for my projects. i'm attaching it for everyone's
masochistic enjoyment. :-)=)
#! /bin/bash
# XXX this does not handle c++ namespacing.
# XXX this becomes *incredibly* slow for some files -
# have to replace the regexp voodoo with a proper parser, i guess.
# ki18n( "str" ) => ki18n( "str") ?!
me=$(me)
typefile=typedefs.out
it=
ot=
while [ $# -gt 0 ]; do
case $1 in
-it) it=$2; shift 2;;
-ot) ot=$2; shift 2;;
-h) echo "Usage -it <m> -ot <n> file..."; exit 0;;
-*) echo "Unrecognized option $1"; exit 1;;
*) break;;
esac
done
if [ -z "$it" -o -z "$ot" ]; then
echo "Must specify both -it and -ot."
exit 1
fi
if ! test -f $typefile; then
echo "Collecting types ..."
find . \( -name '*.c' -o -name '*.cpp' -o -name '*.h' \) -exec cpp
-DHAVE_CONFIG_H -I. -I.. -I../.. {} \; 2>/dev/null | \
perl ${me}_collect.pl | sort -u | tr '\n' '|' | sed 's,|$,,' > $typefile
fi
maybe_expand() {
if [ $it -gt 0 ]; then
expand -i -t $it | "$@"
else
"$@"
fi
}
maybe_unexpand() {
if [ $ot -gt 0 ]; then
unexpand -t $ot --first-only | "$@"
else
"$@"
fi
}
pty=$(<$typefile)
for i in "$@"; do
echo "Indenting $i ..."
maybe_expand maybe_unexpand perl ${me}_spacing.pl "$pty" < $i | perl
${me}_lineup.pl > $i.tmp && mv $i.tmp $i
done
exit 0
#! /usr/bin/perl
use strict;
use warnings;
use re "eval";
my ($btypes, $bt, $ctypes, $np, $wrd);
$bt = $btypes = "void
(?:(?:un)?signed\\s+)?(?:short\\s+|long\\s+(?:long\\s+)?\\s+)?int
(?:(?:un)?signed\\s+)?(?:short|long(?:\\s+long)?)
(?:un)?signed
(?:(?:un)?signed\\s+)?char
float
(?:long\\s+(?:long\\s+)?)?double";
$ctypes = "(?:struct|union)\\s+\\w+";
$bt =~ s/\n/|/g;
$np = qr{\{(?:(?>[^{}]+)|(??{$np}))*\}}x;
$wrd = qr{(?>\s*)(?>\**)(?>\s*)((?>\b\w+\b))(?{print $^N."\n"})(?>\s*)}x;
read STDIN, $_, 1e9;
s/^\s*typedef\s+(?:$bt\s|(?:struct|union)(?>\s+)(?>\b\w+\b\s+)?(??{$np})|$ctypes\s)$wrd(?:,$wrd)*;//xmg;
s/^\s*class\s+(\w+)(?{print $^N."\n"})//xmg;
print $btypes."\n".$ctypes."\n";
#! /usr/bin/perl
use strict;
use warnings;
use re "eval";
my $pty = $ARGV[0];
my $skw = "if|switch|for|while|return";
my $nskw = "sizeof|offsetof|defined|as|ki18n|i18n|i18nc|i18np|i18npc|I18N_NOOP|I18N_NOOP2|QString::fromLatin1|QLatin1String|SIGNAL|SLOT";
# remove trailing whitespace, append exactly one space after semicolon
sub stws($)
{
local $_ = shift;
s/ *$//;
s/(?<!;);$/; /;
return $_;
}
my ($np, $fp, $pc);
# complex expression: n times (word or basic expression or parenthesized complex expression)
$pc = qr{
(?:
(?>[^()]+)
|
(??{$fp})
|
(??{$np})
)*
}xs;
# parenthesized complex expression
$np = qr{\($pc\)}s;
# basic expression: function( n times complex expression )
$fp = qr{
(
\b(?:
new(?>\s+)
|
(?!$pty|$skw|$nskw|else)
)
(?:\w|\.|::)+
|
\(
\h*\*\h*
(?:
(?>[^()]*)
|
(??{$np})
)*
\)
)
(?>\s*)
\(
(?>\h*)
($pc)
\)
}xs;
sub ffn($)
{
local $_ = shift;
# fix whitespace around function calls
# XXX maybe correct parens in $1, too?
s/$fp/my ($f, $p) = ($1, $2); $f."( ".stws(&ffn($p))." )"/eg;
# fix whitespace around function-like (pseudo-)operators
s/\b($nskw)\s*\(\s*(?!{~)($pc)\)/my ($o, $p) = ($1, $2); $o."(".stws($p).")"/eg;
# fix whitespace around c-style type casts
s/(?<!sizeof)\(($pty)\ *(\**)\ *\)\ *(?!{~)/"(".$1.($2?(" ".$2):"").")"/eg;
return $_;
}
read STDIN, $_, 1e6;
my @subs = ();
my $csub = 0;
# replace strings and comments with {~###~} tokens
s/(\/\*.*?\*\/|\/\/.*?$|"(?:\\.|[^"])*"|^#(?:\\.|[^\n])+(?:\\\n(?:\\.|[^\n])*)*(?=\n))/push(@subs, $1), "{~".($csub++)."~}"/egsm;
# majority of the conversion
$_ = ffn($_);
# fix whitespace around control statements
s/\b($skw)\s*\(\s*(?!{~)($pc)\)/$1." (".stws($2).")"/eg;
# remove spaces between otherwise empty paren pairs
s/\( +\)/()/g;
# convert non-leading tabs to spaces
s/(?<!^)(?<!\t)\t+/ /mgx;
# replace the {~###~} tokens back with strings
for (my $i = 0; $i < @subs; $i++) {
s/{~$i~}/$subs[$i]/e;
}
s/[ \t]+$//mg;
print $_;
#! /usr/bin/perl
use strict;
use warnings;
my $il = "";
my $cmt = 0;
my @pcs = ();
my $cpp = 0;
my @ifst = ();
my $els = 0;
my @elst = ();
while (<>) {
if ($cpp) {
$cpp = /\\$/;
} elsif (/^#/) {
if (/^#\ *if/) {
push @ifst, ($il, @pcs);
push @elst, $els;
$els = 0;
} elsif (/^# *elif/) {
($il, @pcs) = $ifst[$#ifst];
} elsif (/^# *else/) {
($il, @pcs) = pop @ifst;
$els = 1;
} elsif (/^# *endif/) {
if (!$els) {
($il, @pcs) = pop @ifst;
}
$els = pop @elst;
}
$cpp = /\\$/;
} else {
$cmt = 1 if /^([ \t]*)\/\*/;
if (!$cmt) {
if (@pcs) {
s/^[ \t]*/$il.(" " x ($pcs[$#pcs] - length($il)))/e;
} else {
/^([ \t]*)/;
$il = $1;
}
/^(?>[ \t]*)(?:\((?>\ *)(?{push @pcs, pos;})|\)(?{pop @pcs;})|\/\*.*?\*\/|'(?:\\.|[^'])*'|"(?:\\.|[^"])*"|.)*$/x;
}
$cmt = 0 if /\*\/$/;
}
print $_;
}
#! /bin/bash
type -p `tr '\0' '\n' < /proc/$PPID/cmdline | sed '1d;/^-/d;q'`