New README for latest program

This commit is contained in:
2025-08-09 16:25:41 +01:00
parent 8e869004ab
commit 3f0650dac7

271
README.md
View File

@@ -1,128 +1,205 @@
# Mojolicious Template Formatter
# mojofmt
This Python program formats Mojolicious template files to make their structure easily understandable by humans. It properly indents HTML tags, Mojolicious commands, helper commands, and Perl constructs.
Formatter for Mojolicious Embedded Perl templates (.ep, .htm.ep, .html.ep)
mojofmt formats HTML and Mojolicious EP templates without breaking embedded Perl. It understands line directives (% ...), inline tags (<% ... %>), raw HTML blocks, and can reformat multi-line Perl blocks inside <% ... %> using perltidy (with a safe fallback if perltidy isnt available).
## Features
- **HTML Tag Indentation**: Properly indents HTML tags and nested elements
- **Mojolicious Command Formatting**: Formats Mojolicious command lines (% lines) with proper spacing
- **Perl Code Block Formatting**: Intelligently handles Perl code blocks and their nesting
- **Special Syntax Handling**: Special handling for Mojolicious-specific syntax (form_for, content_for blocks)
- **Embedded Perl Formatting**: Uses perltidy to format embedded Perl code blocks
- **Smart Tag Handling**: Special handling for self-closing tags, minimal indentation for span/p tags
- **Customizable Indentation**: Configurable indentation size (default: 4 spaces)
- **Perltidy Output Files**: Option to save original and formatted Perl code to separate files
- Indents HTML structure and Mojolicious line directives consistently
- Preserves chomp markers (<%- ... -%>) and does not alter newline semantics
- Formats inline EP tags:
- <%= ... %> expressions (keeps them single-line)
- <% ... %> one-line statements
- Re-formats extended multi-line Perl blocks between lines with only <% and %> (or chomped variants), using perltidy or a naive brace-aware indenter
- Treats pre/script/style/textarea content as opaque (unchanged)
- Optional spacing normalization inside <% %> delimiters
- Optional aggressive spacing after common Perl keywords (--perl-keyword-spacing)
- End-of-line normalization (lf, crlf, or preserve)
- CLI with --write, --check, --diff, --out, --stdin/--stdout
- Self-test mode to sanity-check behavior and perltidy availability
## Installation
## Requirements
No installation is required. The formatter is a standalone Python script that can be run directly.
- Python 3.8+ (3.11+ recommended)
- Optional but recommended: perltidy (Perl::Tidy)
- Debian/Ubuntu: apt-get install perltidy
- CPAN: cpanm Perl::Tidy
- mojofmt will fall back to a simple brace-based indenter for extended blocks if perltidy is absent or fails
### Requirements
## Install
- Python 3.6 or higher
- perltidy (for Perl code formatting)
- Clone this repository
- Make the script executable and put it on your PATH, or run it in place
To install perltidy:
```bash
sudo apt-get install perltidy
```
chmod +x mojofmt.py
./mojofmt.py --version
```
## Usage
### Basic Usage
Basic formatting to stdout:
- ./mojofmt.py path/to/template.html.ep
- cat file.ep | ./mojofmt.py --stdin --stdout
```bash
./mojo_formatter_final_fixed8.py input_file.mojo > output_file.mojo
Write changes in place (creates a .bak backup):
- ./mojofmt.py -w templates/
Check mode (exit 1 if any file would change):
- ./mojofmt.py --check templates/
Show a diff:
- ./mojofmt.py --diff path/to/file.ep
Write output to a separate file:
- ./mojofmt.py -o formatted.ep path/to/file.ep
- cat file.ep | ./mojofmt.py --stdin -o formatted.ep
Control indentation (spaces per level):
- ./mojofmt.py --indent 4 file.ep
Normalize EOLs:
- ./mojofmt.py --eol lf file.ep
- ./mojofmt.py --eol crlf file.ep
- ./mojofmt.py --eol preserve file.ep
Perl spacing knobs:
- Add spacing after common Perl keywords: ./mojofmt.py --perl-keyword-spacing file.ep
- Pass a specific perltidy binary: ./mojofmt.py --perltidy /usr/bin/perltidy file.ep
- See perltidy status: ./mojofmt.py --self-test
Increase logging:
- ./mojofmt.py --log-level debug file.ep
- ./mojofmt.py --verbose file.ep (shorthand for info)
## How it works
- HTML indentation:
- Tracks opening/closing tags; avoids indenting void/self-closing tags
- pre/script/style/textarea bodies are untouched
- Mojolicious directives:
- Lines starting with % are indented relative to HTML and Perl block depth
- begin/end and { ... } braces adjust indentation depth
- Inline EP tags on a line:
- <%= ... %> expressions are normalized via perltidy in an expression-safe wrapper
- <% ... %> one-line statements are normalized via perltidy (or left as-is if perltidy is missing)
- Optional normalization of spaces inside <% %> delimiters can be disabled with --no-space-in-delims
- Extended multi-line Perl blocks:
- Detected when <% (or <%-) is on a line by itself, and %> (or -%>) is on a line by itself
- The inner Perl is dedented, wrapped in do { ... } and run through perltidy; if that fails or perltidy is missing, a brace-aware fallback indenter is used
- Inner lines are re-indented to match the opening/closing delimiters indentation
- EOL normalization:
- Input CRLF/CR are normalized internally; output can be forced to lf/crlf or preserve the original
## Examples
Before:
```
<ul>
% for my $i (1..3) {
<li><%= $i%></li>
%}
</ul>
```
### With Custom Indentation
```bash
./mojo_formatter_final_fixed8.py --indent 2 input_file.mojo > output_file.mojo
After:
```
<ul>
% for my $i (1 .. 3) {
<li><%= $i %></li>
% }
</ul>
```
### With Perltidy Output Files
```bash
./mojo_formatter_final_fixed8.py --perltidy-output-dir=/path/to/output/dir input_file.mojo > output_file.mojo
Extended Perl block:
```
### With Debug Logging
```bash
./mojo_formatter_final_fixed8.py --debug input_file.mojo > output_file.mojo
```
## How It Works
The formatter processes Mojolicious template files in several passes:
1. **Embedded Perl Processing**: Extracts and formats embedded Perl code using perltidy
2. **Line-by-Line Processing**: Processes each line based on its type (HTML or Mojolicious command)
3. **Post-Processing**: Handles special cases like multiple closing tags on a single line
4. **Duplicate Tag Cleanup**: Normalizes and removes duplicate closing tags
## Special Features
### Smart HTML Tag Handling
- Non-indenting tags like `<br>`, `<hr>`, `<img>`, etc. don't cause indentation changes
- Minimal indentation for `<span>` and `<p>` tags (half the normal indentation)
- Special handling for lines with multiple closing tags
### Embedded Perl Formatting
The formatter uses perltidy to format embedded Perl code blocks (enclosed in `<%` and `%>` tags). This ensures that your Perl code follows consistent formatting rules.
### Perltidy Output Files
When using the `--perltidy-output-dir` option, the formatter saves both the original and formatted Perl code for each embedded Perl block to separate files:
- `perl_block_N_original.pl`: The original Perl code before formatting
- `perl_block_N_formatted.pl`: The formatted Perl code after perltidy processing
## Example
### Input
```perl
<div>
<%
# This is a test of pure Perl code with minimal indentation
if ($status) {
$c->desktopBackupRecordStatus($backup_rec, 'pre-backup', $status);
return ($c->l('bac_OPERATION_STATUS_REPORT').$c->l('bac_ERR_PRE_BACKUP'));
my $x=1;
if($x){
say"hi";
}
my $clvl = $c->stash('compressionlevel');
my $cmd = "/bin/tar --create --file=- --directory / @{$c->stash('exclude')} "
. "@{$c->stash('directories')} | /usr/bin/gzip $clvl ";
%>
</div>
```
### Output
```perl
<div>
<%
# This is a test of pure Perl code with minimal indentation
if ($status) {
$c->desktopBackupRecordStatus($backup_rec, 'pre-backup', $status);
return ($c->l('bac_OPERATION_STATUS_REPORT') . $c->l('bac_ERR_PRE_BACKUP'));
}
my $clvl = $c->stash('compressionlevel');
my $cmd = "/bin/tar --create --file=- --directory / @{$c->stash('exclude')} "
. "@{$c->stash('directories')} | /usr/bin/gzip $clvl ";
%>
</div>
Becomes (with --indent 4):
```
<%
my $x = 1;
if ($x) {
say "hi";
}
%>
```
## Options
- -w, --write: Overwrite files in place (writes a .bak backup)
- -o, --out FILE: Write formatted output to FILE (single input or --stdin)
- --check: Exit non-zero if any file would change
- --diff: Print unified diff
- --stdin / --stdout: Pipe mode
- --perltidy PATH: Path to perltidy executable
- --indent N: Indent width (spaces; default 2)
- --eol lf|crlf|preserve: End-of-line handling (default lf)
- --no-space-in-delims: Do not normalize spacing inside <% %> delimiters
- --perl-keyword-spacing: Aggressively insert a space after common Perl keywords
- --self-test: Run internal sanity checks and perltidy probe
- --log-level error|info|debug: Logging verbosity (or use --verbose)
- --version: Print version
## File selection
By default, mojofmt processes:
- .ep
- .htm.ep
- .html.ep
Directories are walked recursively; only matching files are formatted.
## Tips and caveats
- perltidy recommended: For best results on complex Perl inside templates, install perltidy. mojofmt falls back to a brace-aware indenter for extended blocks, but wont do token-level Perl formatting without perltidy.
- Extended block detection: Only triggers when the opening <% (or <%-) and closing %> (or -%>) are on their own lines. Inline <% ... %> on the same line are handled by the inline path.
- Raw blocks: Content inside pre/script/style/textarea is not changed.
- Chomp markers: Left/right chomps (<%- and -%>) are preserved and not moved.
- Idempotent: Running mojofmt repeatedly should not keep changing the file (self-test checks this).
- EOLs: Use --eol preserve to retain original line endings.
## Troubleshooting
If you encounter issues with perltidy, the formatter will fall back to a simple indentation-based formatter for Perl code. Enable debug logging with the `--debug` flag to see detailed information about the formatting process.
- perltidy non-zero exit N in debug logs:
- mojofmt wraps extended blocks in do { ... } for perltidy; if it still fails, run perltidy manually on the wrapper to see the error.
- Ensure perltidy is on PATH or pass --perltidy /path/to/perltidy.
- Extended block didnt reformat:
- Confirm the delimiters are on their own lines (no code on the <% / %> lines).
- Run with --log-level debug to see whether perltidy or the naive indenter handled the block.
- Spaces around Perl keywords:
- Off by default. Enable with --perl-keyword-spacing if you want if(...)->if (...), my$->my $, return(...)->return (...), etc.
## Development
Run self-tests:
- ./mojofmt.py --self-test
- Use --log-level debug for detailed logs
Format from stdin to stdout:
- python3 mojofmt.py --stdin --stdout < in.ep > out.ep
Generate a diff without writing:
- python3 mojofmt.py --diff path/to/file.html.ep
## Contributing
- Open an issue or pull request with a clear description and a minimal repro template
- Please include before/after snippets and your command-line flags
- If you modify formatting rules, add/adjust a self-test where possible
## License
This software is provided as-is, without any warranties or conditions of any kind.
See LICENSE file in this repository. If you dont have one yet, consider MIT or Apache-2.0.
## Acknowledgments
- Mojolicious and Mojo::Template for the EP syntax
- Perl::Tidy for robust Perl formatting