New README for latest program
This commit is contained in:
273
README.md
273
README.md
@@ -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 isn’t 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 delimiter’s 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 won’t 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 didn’t 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 don’t have one yet, consider MIT or Apache-2.0.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
- Mojolicious and Mojo::Template for the EP syntax
|
||||
- Perl::Tidy for robust Perl formatting
|
Reference in New Issue
Block a user