NAME
Eshu - indentation fixer and syntax highlighter for C, Perl, XS, XML, HTML, CSS, JavaScript, TypeScript, Python, Go, Rust, Java, PHP, Ruby, Lua, Bash, SQL, YAML, JSON, POD and more
SYNOPSIS
use Eshu;
# Fix indentation — one method per language
my $fixed_c = Eshu->indent_c($source);
my $fixed_pl = Eshu->indent_pl($source);
my $fixed_xs = Eshu->indent_xs($source);
my $fixed_xml = Eshu->indent_xml($source);
my $fixed_html = Eshu->indent_html($source);
my $fixed_css = Eshu->indent_css($source);
my $fixed_js = Eshu->indent_js($source);
my $fixed_ts = Eshu->indent_ts($source);
my $fixed_pod = Eshu->indent_pod($source);
my $fixed_bash = Eshu->indent_bash($source);
my $fixed_go = Eshu->indent_go($source);
my $fixed_lua = Eshu->indent_lua($source);
my $fixed_rust = Eshu->indent_rust($source);
my $fixed_py = Eshu->indent_python($source);
my $fixed_java = Eshu->indent_java($source);
my $fixed_php = Eshu->indent_php($source);
my $fixed_ruby = Eshu->indent_ruby($source);
my $fixed_json = Eshu->indent_json($source);
my $fixed_sql = Eshu->indent_sql($source);
my $fixed_yaml = Eshu->indent_yaml($source);
# Auto-dispatch by language name
my $fixed = Eshu->indent_string($source, lang => 'perl');
# Use spaces instead of tabs
my $fixed = Eshu->indent_c($source,
indent_char => ' ',
indent_width => 4,
);
# Syntax highlight — returns HTML with <span class="esh-X"> tokens
my $html = Eshu->highlight_string($source, lang => 'perl');
my $html = Eshu->highlight_ts($source);
my $html = Eshu->highlight_java($source);
my $html = Eshu->highlight_php($source);
my $html = Eshu->highlight_ruby($source);
my $html = Eshu->highlight_json($source);
my $html = Eshu->highlight_sql($source);
my $html = Eshu->highlight_go($source);
my $html = Eshu->highlight_lua($source);
my $html = Eshu->highlight_rust($source);
my $html = Eshu->highlight_bash($source);
my $html = Eshu->highlight_yaml($source);
# Detect language from filename
my $lang = Eshu->detect_lang('lib/Foo.pm'); # 'perl'
# Fix a single file (read, detect, indent, optionally write back)
my $result = Eshu->indent_file('lib/Foo.pm', fix => 1);
# Fix an entire directory tree
my $report = Eshu->indent_dir('lib/', fix => 1);
DESCRIPTION
Eshu is an XS-powered indentation fixer and syntax highlighter. The indentation engine rewrites leading whitespace, tracking nesting depth and re-emitting each line with correct indentation while leaving content untouched. The highlighting engine wraps recognised tokens in HTML <span class="esh-X"> elements.
Supported languages: C, Perl, XS, XML, HTML, CSS, JavaScript, TypeScript, Python, Go, Rust, Java, PHP, Ruby, Lua, Bash, SQL, YAML, JSON, POD.
Eshu understands language-specific constructs that affect indentation:
- C — strings, comments, preprocessor directives, block nesting
- Perl — heredocs, regex,
qw()/qq()/q(),s////tr////y///, pod sections, comments - XS — dual-mode scanning (C section above
MODULE =, XS section below), XSUB boundaries, label detection (CODE:,OUTPUT:,BOOT:, etc.), C nesting within code body sections - HTML — element nesting, void elements (
br,hr,img, etc.), verbatim content in<script>,<style>, and<pre>blocks, comments - CSS — rule-block brace nesting,
/* */comments, string literals,url()tokens, at-rules (@media,@keyframes, etc.) - JavaScript — brace/paren/bracket nesting, double and single-quoted strings, template literals (
`...${expr}...`) with nested interpolation, regex literals (/pattern/flags), line and block comments.<script>blocks in HTML are automatically indented as JS. - TypeScript — same engine as JavaScript;
.ts/.tsx/.mtsfiles are detected automatically. - Python — indentation-significant; reads logical depth from existing whitespace (depth stack), re-emits with configured style. Continuation lines (backslash or open bracket) are tracked. Strings (
"...",'...', triple-quoted),#comments, and decorator lines (@name) are recognised. - Go —
{},(),[]brace/paren/bracket nesting, interpreted strings"...", raw string literals (backtick, can span multiple lines), rune literals'.',//line comments,/* */block comments,case/defaultlabels placed at switch-brace level, and all Go numeric literals (decimal, hex0x, binary0b, octal0o,_separators, imaginaryisuffix). - Rust — brace-based model identical to Go; nested
/* */block comments, raw stringsr"..."/r#"..."#, byte stringsb"...", byte charsb'.', and lifetime annotations'a(distinguished from char literals). - Java — brace/paren/bracket nesting, strings (double-quoted, text blocks
"""..."""), char literals,//and/* */comments,@Annotationhandling, andswitchcase-label de-indentation. - PHP — brace-based nesting,
$variabletracking,///#//* */comments, heredoc/nowdoc (<<EOT/<<'EOT'), single and double-quoted strings,#[Attribute]blocks. - Ruby — brace/paren/bracket nesting plus keyword blocks (
def/end,do/end,class/end, etc.), heredocs (<<~HEREDOC), single and double-quoted strings, regex literals,#comments. - Lua — keyword-based block nesting (
do/end,if/then/end,function/end,repeat/until,else/elseiftransitions), table constructor{}brace tracking, long strings[[...]]/[=[...]=]and long comments--[[...]]spanning multiple lines,"..."/'...'strings, and--line comments. - Bash — keyword-pair blocks (
if/fi,for/done,while/done,until/done,case/esac,select/done), brace grouping{ },functionkeyword, heredocs (<<EOF>,<<-EOF>),$( )subshell and$(( ))arithmetic depth tracking, single and double-quoted strings,$'...'ANSI-C strings, and#comments. - SQL — keyword-based clause indentation (
SELECT/FROM/WHERE/JOIN/GROUP BY/ORDER BY/HAVING/UNIONetc.),CASE/WHEN/THEN/ELSE/ENDexpression tracking, PL/pgSQLBEGIN/ENDblocks,--//* */comments, single-quoted strings. Case-insensitive. - YAML — reads logical depth from existing leading whitespace (depth stack identical to Python engine), re-emits with configured style (default: 2-space). Block scalar bodies (
|and>) are re-normalised. Document markers (---/...) reset the depth stack. - JSON — structural formatting of
{}/[]nesting; no language-specific constructs beyond brace tracking and string recognition. - POD — directive lines (
=head1,=over,=item,=back,=cut, etc.) normalised to column 0, text paragraphs at column 0, verbatim blocks (whitespace-leading lines) normalised to one indent level. POD sections embedded in Perl files are automatically processed.
The engine is written in C for speed and operates as a single-pass line-by-line scanner.
The Eshu distribution also includes a command-line tool (eshu) that can fix files in-place, preview changes as a diff, or run in CI check mode. It supports recursive directory processing with file inclusion/exclusion patterns and automatic language detection by extension. There is also a vim plugin (eshu.vim) that can fix the open file or a selected 'visual' range.
METHODS
indent_c
my $out = Eshu->indent_c($source, %opts);
Fix indentation of C source code. Tracks {}, (), [] nesting, handles C strings, character literals, line and block comments, and preprocessor directives.
indent_pl
my $out = Eshu->indent_pl($source, %opts);
Fix indentation of Perl source code. In addition to brace nesting, handles heredocs (<<EOF, <<~EOF, <<'EOF', <<"EOF"), regex literals, qw()/qq()/q() constructs with paired and non-paired delimiters, multi-section operators (s///, tr///, y///), pod sections (=head1 through =cut), and line comments.
indent_xs
my $out = Eshu->indent_xs($source, %opts);
Fix indentation of XS source files. Operates in dual mode: lines above the first MODULE = ... line are processed as C; lines below are processed as XS with XSUB boundary detection, label recognition, and C nesting tracking within code body sections. BOOT: sections use a shallower indentation depth than other labels.
indent_xml
my $out = Eshu->indent_xml($source, %opts);
Fix indentation of XML source. Tracks element nesting via opening and closing tags, handles self-closing tags (<br/>), comments (<!-- -->), CDATA sections, and processing instructions (<?...?>). Multi-line tags are indented one level beyond the opening tag.
Also used for HTML when called via indent_string with lang => 'html'. In HTML mode, void elements (br, hr, img, input, meta, link, etc.) are treated as self-closing, and content inside <script>, <style>, and <pre> blocks is passed through verbatim. <script> blocks are indented with the JavaScript engine.
indent_html
my $out = Eshu->indent_html($source, %opts);
Fix indentation of HTML source. This is a convenience method equivalent to calling Eshu->indent_xml($source, lang => 'html', %opts). Void elements (br, hr, img, input, meta, link, etc.) are treated as self-closing. <script> blocks are indented with the JavaScript engine, while <style> and <pre> content is passed through verbatim.
indent_css
my $out = Eshu->indent_css($source, %opts);
Fix indentation of CSS, SCSS, and LESS source. Tracks brace nesting for rule blocks and at-rules (@media, @keyframes, @supports, etc.), handles /* */ block comments, string literals (single and double-quoted), and url() tokens with unquoted paths.
indent_js
my $out = Eshu->indent_js($source, %opts);
Fix indentation of JavaScript (and TypeScript) source. Tracks {}, (), [] nesting, handles double-quoted strings, single-quoted strings, template literals (backtick strings with ${expr} interpolation), regex literals (/pattern/flags) with character class support, line comments (//) and block comments (/* */). Multi-line template literal content is preserved verbatim (whitespace is significant).
indent_pod
my $out = Eshu->indent_pod($source, %opts);
Fix indentation of POD (Plain Old Documentation). Directive lines (=head1, =head2, =over, =item, =back, =cut, =pod, =begin, =end, =for, =encoding) are normalised to column 0. Text paragraphs stay at column 0. Code examples (lines with leading whitespace) are normalised to one indent level. POD sections embedded in Perl source files are automatically processed by the Perl engine.
indent_bash
my $out = Eshu->indent_bash($source, %opts);
Fix indentation of Bash/shell scripts. Tracks keyword-pair block depth (if/fi, for/done, while/done, until/done, case/esac, select/done) and brace grouping { }.
Handles then/do as deferred openers (depth increases for the next line). Handles else/elif as combined -1/+1 transitions. case patterns (the PATTERN) lines) are at one indent level inside the case/in block; their bodies are indented one further level; ;; closes each arm.
Strings (single-quoted '...', double-quoted "...", $'...' ANSI-C), heredoc bodies, $( ) subshells, $(( )) arithmetic, and # ... comments are all recognised and their contents are not scanned for keywords.
highlight_bash
my $html = Eshu->highlight_bash($source);
Syntax-highlight Bash/shell source.
indent_go
my $out = Eshu->indent_go($source, %opts);
Fix indentation of Go source code. Tracks {}, (), [] nesting and handles case/default labels (placed one level shallower than their body, matching gofmt output), interpreted strings "...", raw string literals (backtick, spanning any number of lines), rune literals '.', // line comments, and /* */ block comments.
highlight_go
my $html = Eshu->highlight_go($source);
Syntax-highlight Go source. Returns an HTML string with token spans. Recognises keywords (esh-k), predeclared functions and types (esh-b), strings (esh-s, covers interpreted, raw, and rune literals), comments (esh-c), and numbers (esh-n, covers decimal, hex 0x, binary 0b, octal 0o, underscored separators, and imaginary i suffix).
indent_lua
my $out = Eshu->indent_lua($source, %opts);
Fix indentation of Lua source code. Uses keyword-based block nesting: do/then/function open a new indent level on the next line, end/until close the level on their own line, and else/elseif transition (-1 then +1). Table constructors {} are also tracked. Long strings [[...]]/[=[...]=] and long comments --[[...]] that span multiple lines are emitted verbatim.
highlight_lua
my $html = Eshu->highlight_lua($source);
Syntax-highlight Lua source. Returns an HTML string with token spans. Recognises keywords (esh-k), standard library functions and tables (esh-b), strings including long strings (esh-s), comments including long comments (esh-c), and numbers (esh-n, covers decimal, float, and hex 0x literals).
indent_rust
my $out = Eshu->indent_rust($source, %opts);
Fix indentation of Rust source code. Uses a brace-based model identical to Go: { opens a new indent level (deferred to the next line), } closes on its own line, and ()/[] are also tracked for depth balance. Additional Rust constructs handled: nested /* */ block comments, raw strings r"..."/r#"..."#, byte strings b"...", byte chars b'.', and lifetime annotations 'a (distinguished from char literals to avoid misinterpreting them as string openers).
highlight_rust
my $html = Eshu->highlight_rust($source);
Syntax-highlight Rust source. Returns an HTML string with token spans. Recognises keywords (esh-k — fn, let, match, impl, etc.), builtin types and traits (esh-b — i32, String, Vec, Option, etc.), strings and char literals (esh-s), comments including nested block comments (esh-c), numbers (esh-n), attributes #[...] (esh-p), and lifetime annotations (esh-b). Common macros such as println! and vec! are highlighted as builtins.
indent_yaml
my $out = Eshu->indent_yaml($source, %opts);
Normalise YAML indentation. YAML uses indentation-significant structure, so this pass reads the logical depth from existing leading whitespace (using a depth stack identical to the Python engine) and re-emits each line with the configured style. Defaults: indent_char=' ', indent_width=2.
Block scalar bodies (| and >) are re-normalised at the correct depth (key_depth+1) while preserving any relative indentation within the block. Flow collections ({ } and [ ]) that span lines are emitted verbatim. Document markers (---/...) are emitted at depth 0 and reset the depth stack for the next document.
highlight_yaml
my $html = Eshu->highlight_yaml($source);
Syntax-highlight YAML source. Returns an HTML string with token spans. Token classes: esh-a (mapping keys), esh-v (anchors &name and aliases *name), esh-p (tags !!/!tag and directives %YAML/%TAG), esh-k (document markers ---/..., booleans, null, sequence -), esh-s (quoted strings), esh-n (numbers), esh-h (block scalar body lines), esh-c (comments).
indent_ts
my $out = Eshu->indent_ts($source, %opts);
Fix indentation of TypeScript source. Uses the same engine as "indent_js": {}, (), [] nesting, string literals, template literals, regex literals, and line/block comments. TypeScript-specific syntax (type annotations, decorators, generics) is transparent to the indentation pass.
indent_python
my $out = Eshu->indent_python($source, %opts);
Fix indentation of Python source. Reads the logical depth from existing leading whitespace (using a depth stack), and re-emits each line with the configured indent style. Defaults: indent_char=' ', indent_width=4. Continuation lines (trailing backslash or unclosed bracket/paren) are tracked. Strings ("...", '...', triple-quoted """..."""/'''...'''), # comments, and @decorator lines are recognised and their content is not scanned for indentation signals.
indent_java
my $out = Eshu->indent_java($source, %opts);
Fix indentation of Java source. Tracks {}, (), [] nesting, handles double-quoted strings, text blocks ("""..."""), char literals, // line comments, /* */ block comments, and @Annotation lines. switch case labels are placed one level shallower than their body.
indent_php
my $out = Eshu->indent_php($source, %opts);
Fix indentation of PHP source. Tracks brace/paren/bracket nesting, handles $variable sigils (so { inside strings is not counted), single and double-quoted strings, heredoc/nowdoc bodies, ///# line comments, and /* */ block comments.
indent_ruby
my $out = Eshu->indent_ruby($source, %opts);
Fix indentation of Ruby source. Tracks both brace/paren/bracket nesting and keyword-pair blocks (def/end, do/end, class/end, module/end, if/end, etc.). Handles single and double-quoted strings, heredocs (<<~HEREDOC), regex literals, and # comments.
indent_json
my $out = Eshu->indent_json($source, %opts);
Fix indentation of JSON source. Tracks {} and [] nesting and re-emits each value on its own line with the configured indent style. Defaults: indent_char=' ', indent_width=2. String values and keys are passed through verbatim without scanning for structural characters.
indent_sql
my $out = Eshu->indent_sql($source, %opts);
Fix indentation of SQL source. Uses a keyword-based clause model: primary clause keywords (SELECT, FROM, WHERE, JOIN, GROUP BY, ORDER BY, HAVING, UNION, INSERT INTO, UPDATE, DELETE FROM) each start at the base indent level. CASE/WHEN/THEN/ELSE/END expressions are tracked separately with their own nesting depth. PL/pgSQL BEGIN/END blocks add an outer level. -- line and /* */ block comments, single-quoted strings (with '' escape), and quoted identifiers ("...", [...], backtick) are recognised. Matching is case-insensitive.
highlight_ts
my $html = Eshu->highlight_ts($source);
Syntax-highlight TypeScript source. Recognises all JavaScript tokens plus TypeScript-specific keywords (interface, type, enum, namespace, declare, abstract, readonly, override, keyof, typeof, infer, satisfies, as, is, from, implements, type primitives and modifiers), utility type builtins (Partial, Required, Record, Pick, Omit, Awaited, etc.), and decorator expressions (@Name) (esh-p).
highlight_java
my $html = Eshu->highlight_java($source);
Syntax-highlight Java source. Recognises keywords (esh-k), standard library types (esh-b — String, Integer, System, Math, StringBuilder, etc.), annotation names @Override/@Deprecated/etc. (esh-p), strings and char literals (esh-s), comments (esh-c), and numbers (esh-n).
highlight_php
my $html = Eshu->highlight_php($source);
Syntax-highlight PHP source. Recognises keywords (esh-k), builtin functions and classes (esh-b — strlen, array_map, json_encode, Exception, DateTime, PDO, etc.), PHP 8 attribute blocks #[...] (esh-p), variables $name (esh-p), strings (esh-s), ///#//* */ comments (esh-c), and numbers (esh-n).
highlight_ruby
my $html = Eshu->highlight_ruby($source);
Syntax-highlight Ruby source. Recognises keywords (esh-k), builtin methods and module functions (esh-b — puts, require, attr_accessor, private, lambda, etc.), symbols :name and :"...") (esh-r), global/instance/class variables (esh-v), strings (esh-s), # comments (esh-c), and numbers (esh-n).
highlight_json
my $html = Eshu->highlight_json($source);
Syntax-highlight JSON source. Object keys are tagged esh-a, string values esh-s, null/true/false keywords esh-k, and numbers esh-n. When called via highlight_string with lang => 'jsonc', // and /* */ comments (esh-c) are also recognised.
highlight_sql
my $html = Eshu->highlight_sql($source);
Syntax-highlight SQL source. Recognises keywords (esh-k), aggregate and window functions (esh-b — COUNT, SUM, AVG, ROW_NUMBER, RANK, etc.), single-quoted strings (esh-s), quoted identifiers (esh-a), --//* */ comments (esh-c), and numbers (esh-n). Matching is case-insensitive.
indent_string
my $out = Eshu->indent_string($source, lang => $lang, %opts);
Dispatch to the appropriate engine based on the lang parameter:
c,h(default) — calls "indent_c"perl,pl,pm,t— calls "indent_pl"xs— calls "indent_xs"xml,xsl,xslt,svg,xhtml— calls "indent_xml" in XML modehtml,htm,tmpl,tt,ep— calls "indent_xml" in HTML modecss,scss,less— calls "indent_css"js,javascript,jsx,mjs,cjs— calls "indent_js"ts,typescript,tsx,mts— calls "indent_ts"python,py— calls "indent_python"java— calls "indent_java"php,phtml— calls "indent_php"ruby,rb,rake— calls "indent_ruby"json,jsonc— calls "indent_json"pod— calls "indent_pod"bash,sh,shell,zsh,ksh— calls "indent_bash"go— calls "indent_go"rust,rs— calls "indent_rust"lua— calls "indent_lua"sql,psql,ddl— calls "indent_sql"yaml,yml— calls "indent_yaml"
include_dir
my $dir = Eshu->include_dir();
Returns the path to the Eshu C header directory. Useful for sibling modules that need to compile against eshu_hl.h or other Eshu headers without copying them — add the returned path to INC in your Makefile.PL:
eval { require Eshu; $eshu_inc = Eshu->include_dir() };
$eshu_inc //= '../Eshu-0.06/include'; # development fallback
highlight_string
my $html = Eshu->highlight_string($source, lang => $lang);
Syntax-highlight $source for the given language and return an HTML string where recognised tokens are wrapped in <span class="esh-X"> elements. The returned string is HTML-safe (< > & " are escaped throughout). Unknown lang values fall back to HTML-escaping only (no spans).
lang accepts:
corh— C/C++ (default)perl,pl,pm,t— Perljs,javascript,jsx,mjs,cjs— JavaScriptts,typescript,tsx,mts— TypeScript (calls "highlight_ts")css,scss,less— CSS / Sass / Lessxml,html,htm,svg,xhtml— XML / HTMLpod— POD (verbatim blocks sub-highlighted as Perl)python,py— Pythonjson,jsonc— JSON (jsoncalso highlights comments)bash,sh,shell,zsh,ksh— Bash / shellgo— Gorust,rs— Rustjava— Javalua— Luaphp,phtml— PHPruby,rb,rake— Rubysql,psql,ddl— SQLyaml,yml— YAML
Token CSS classes:
esh-k— keywordesh-s— string / quoted literalesh-c— commentesh-n— number literalesh-p— preprocessor directive (C/XS) or at-rule (CSS)esh-r— regex or quoted-like construct (Perl)esh-h— heredoc body (Perl)esh-v— variable sigil and name (Perl:$foo,@bar,%baz)esh-d— documentation (POD command line)esh-g— tag name (XML/HTML)esh-a— attribute name (XML/HTML)
detect_lang
my $lang = Eshu->detect_lang($filename);
Return a language string based on the file extension, suitable for passing to "indent_string". Returns undef for unrecognised extensions.
.c, .h → 'c'
.xs → 'xs'
.pl, .pm, .t → 'perl'
.xml, .xsl, .xslt, .svg → 'xml'
.xhtml → 'xhtml'
.html, .htm, .tmpl, .tt, .ep → 'html'
.css, .scss, .less → 'css'
.js, .jsx, .mjs, .cjs → 'js'
.ts, .tsx, .mts → 'ts'
.json, .jsonc → 'json'
.java → 'java'
.php, .phtml, .php3, .php4, .php5 → 'php'
.rb, .rake → 'ruby'
.pod → 'pod'
.sh, .bash, .zsh, .ksh → 'bash'
.go → 'go'
.rs → 'rust'
.lua → 'lua'
.sql, .psql, .ddl → 'sql'
.yaml, .yml → 'yaml'
indent_file
my $result = Eshu->indent_file($path, %opts);
Read a single file, detect its language, run the indentation fixer, and optionally write the result back. Returns a hashref:
{
file => $path,
status => 'changed', # or 'unchanged', 'needs_fixing',
# 'skipped', 'error'
lang => 'perl',
diff => '...', # only if diff => 1
reason => '...', # only if status is 'skipped'
error => '...', # only if status is 'error'
}
Files are skipped if they are over 1 MB, contain NUL bytes in the first 8 KB (binary detection), or have an unrecognised extension.
Options: all "OPTIONS" keys plus fix, diff, and lang.
indent_dir
my $report = Eshu->indent_dir($path, %opts);
Recursively walk a directory, detect languages by extension, and fix indentation for all recognised files. Returns a report hashref:
{
files_checked => 42,
files_changed => 7,
files_skipped => 3,
files_errored => 0,
changes => [ ... ], # array of indent_file results
}
Options: all "OPTIONS" keys plus:
- fix — write changes back to disk (default: dry-run)
- diff — include diff output in each result
- recursive — recurse into subdirectories (default: 1)
- exclude — regexp or arrayref of regexps; skip files matching any
- include — regexp or arrayref of regexps; only process files matching at least one
- lang — force a language for all files instead of auto-detecting
Symlinks to files are followed; symlinks to directories are not (to avoid cycles).
OPTIONS
All indentation methods accept the following options as key-value pairs:
- indent_char
-
Character to use for indentation. Either
"\t"(tab, the default) or" "(space). - indent_width
-
Number of characters per indentation level. Defaults to
1for tabs. Typically set to2or4when using spaces. - indent_pp
-
Boolean. When true, indent C preprocessor directives according to their
#if/#endifnesting depth. Defaults to0(preprocessor directives stay at column 0). Only meaningful for C and XS engines.
CLI
Eshu ships with a command-line tool:
# Fix a file in-place
eshu --fix lib/Foo.pm
# Preview changes as a diff
eshu --diff lib/Foo.pm
# CI check — exit 1 if file would change
eshu --check lib/Foo.pm
# Read stdin, write stdout
cat messy.c | eshu --lang c
# Use 4-space indentation
eshu --spaces 4 --fix src/bar.c
# Fix all recognised files in a directory tree
eshu --fix lib/
# Fix only Perl files, excluding backups
eshu --fix --include '\.pm$' --exclude '\.bak$' lib/
# Verbose output showing every file processed
eshu --fix --verbose lib/
Run eshu --help for the full list of options.
AUTHOR
LNATION <email@lnation.org>
LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.