lhtml-markup 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lhtml_markup-2.0.0/LICENSE.md +21 -0
- lhtml_markup-2.0.0/PKG-INFO +402 -0
- lhtml_markup-2.0.0/README.md +386 -0
- lhtml_markup-2.0.0/pyproject.toml +34 -0
- lhtml_markup-2.0.0/setup.cfg +4 -0
- lhtml_markup-2.0.0/src/lhtml/__init__.py +97 -0
- lhtml_markup-2.0.0/src/lhtml/__main__.py +5 -0
- lhtml_markup-2.0.0/src/lhtml/ast_nodes.py +124 -0
- lhtml_markup-2.0.0/src/lhtml/cli.py +62 -0
- lhtml_markup-2.0.0/src/lhtml/code.py +74 -0
- lhtml_markup-2.0.0/src/lhtml/element_extract.py +21 -0
- lhtml_markup-2.0.0/src/lhtml/errors.py +58 -0
- lhtml_markup-2.0.0/src/lhtml/export_html.py +147 -0
- lhtml_markup-2.0.0/src/lhtml/insert_in_text.py +7 -0
- lhtml_markup-2.0.0/src/lhtml/listing.py +54 -0
- lhtml_markup-2.0.0/src/lhtml/patterns.py +92 -0
- lhtml_markup-2.0.0/src/lhtml/pipeline.py +215 -0
- lhtml_markup-2.0.0/src/lhtml/process.py +236 -0
- lhtml_markup-2.0.0/src/lhtml/tag_element.lark +30 -0
- lhtml_markup-2.0.0/src/lhtml/tag_parser.py +214 -0
- lhtml_markup-2.0.0/src/lhtml/wrap_html.py +50 -0
- lhtml_markup-2.0.0/src/lhtml_markup.egg-info/PKG-INFO +402 -0
- lhtml_markup-2.0.0/src/lhtml_markup.egg-info/SOURCES.txt +26 -0
- lhtml_markup-2.0.0/src/lhtml_markup.egg-info/dependency_links.txt +1 -0
- lhtml_markup-2.0.0/src/lhtml_markup.egg-info/entry_points.txt +2 -0
- lhtml_markup-2.0.0/src/lhtml_markup.egg-info/requires.txt +7 -0
- lhtml_markup-2.0.0/src/lhtml_markup.egg-info/top_level.txt +1 -0
- lhtml_markup-2.0.0/test/test_lhtml.py +236 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Damien Rohmer <damien.rohmer@polytechnique.edu>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lhtml-markup
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Lightweight HTML markup language — simplifies HTML authoring with shorthand syntax
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE.md
|
|
9
|
+
Requires-Dist: lark>=1.1
|
|
10
|
+
Requires-Dist: pygments>=2.15
|
|
11
|
+
Requires-Dist: pyyaml>=6.0
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
14
|
+
Requires-Dist: ansicolors; extra == "dev"
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# LHTML — Lightweight HTML
|
|
18
|
+
|
|
19
|
+
LHTML is a markup language that simplifies HTML authoring with embedded CSS styling. It is designed to be **HTML-first**: raw HTML passes through untouched, and only a few shorthand symbols (`::`, `*`, `=`, `**`, `__`) trigger conversions.
|
|
20
|
+
|
|
21
|
+
LHTML is used to build static websites and presentation slides, typically combined with Jinja2 templates.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install .
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or in development mode:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install -e .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Dependencies**: `lark`, `pygments`, `pyyaml` (installed automatically).
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
### Command Line
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
lhtml input.l.html # Convert to stdout
|
|
44
|
+
lhtml input.l.html -o output.html # Convert to file
|
|
45
|
+
lhtml input.l.html -w # Wrap in full HTML document
|
|
46
|
+
python -m lhtml input.l.html # Alternative invocation
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Python API
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
import lhtml
|
|
53
|
+
|
|
54
|
+
html = lhtml.run('= Hello World\nSome **bold** text.\n')
|
|
55
|
+
|
|
56
|
+
html = lhtml.run(text, {
|
|
57
|
+
'wrap-auto': True,
|
|
58
|
+
'title': 'My Page',
|
|
59
|
+
'css': ['style.css'],
|
|
60
|
+
'js': ['script.js'],
|
|
61
|
+
})
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
## Syntax Reference
|
|
66
|
+
|
|
67
|
+
### Headings
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
= Main Title
|
|
71
|
+
== Subtitle
|
|
72
|
+
=== Level 3
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Output:
|
|
76
|
+
```html
|
|
77
|
+
<h1>Main Title</h1>
|
|
78
|
+
<h2>Subtitle</h2>
|
|
79
|
+
<h3>Level 3</h3>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
With classes/IDs:
|
|
83
|
+
```
|
|
84
|
+
=(.highlight #intro) Styled Title
|
|
85
|
+
```
|
|
86
|
+
```html
|
|
87
|
+
<h1 class="highlight" id="intro">Styled Title</h1>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
### Lists
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
* First item
|
|
95
|
+
* Second item
|
|
96
|
+
** Nested item A
|
|
97
|
+
** Nested item B
|
|
98
|
+
*** Deep nested
|
|
99
|
+
* Back to top level
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Produces nested `<ul><li>` structures.
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
### Inline Formatting
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
This is **bold** text.
|
|
109
|
+
This is __italic__ text.
|
|
110
|
+
This is `inline code` text.
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Output:
|
|
114
|
+
```html
|
|
115
|
+
This is <strong>bold</strong> text.
|
|
116
|
+
This is <em>italic</em> text.
|
|
117
|
+
This is <code class="code-inline">inline code</code> text.
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
### Tag Elements (the `::` system)
|
|
122
|
+
|
|
123
|
+
The core of LHTML. The general syntax is:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
tagName::(.classes #id)[cssStyle]{htmlAttributes} content ::
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
All bracket groups are optional. If `tagName` is omitted, defaults to `div`.
|
|
130
|
+
|
|
131
|
+
#### Div / Span with Styles
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
div::[color:red; font-size:120%;]
|
|
135
|
+
This text is big and red.
|
|
136
|
+
::
|
|
137
|
+
|
|
138
|
+
span::(.highlight)[font-weight:bold;] inline content ::
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Output:
|
|
142
|
+
```html
|
|
143
|
+
<div style="color:red; font-size:120%;">
|
|
144
|
+
This text is big and red.
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<span class="highlight" style="font-weight:bold;"> inline content </span>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### Anonymous Div (no tag name)
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
::[padding:10px; background:#eee;]
|
|
154
|
+
Content in a styled div.
|
|
155
|
+
::
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Output:
|
|
159
|
+
```html
|
|
160
|
+
<div style="padding:10px; background:#eee;">
|
|
161
|
+
Content in a styled div.
|
|
162
|
+
</div>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
#### Classes, IDs, and Inline Attributes
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
::(.classA .classB #myId)[margin:10px;]{data-role="main"}
|
|
169
|
+
Content
|
|
170
|
+
::
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Output:
|
|
174
|
+
```html
|
|
175
|
+
<div class="classA classB" id="myId" style="margin:10px;" data-role="main">
|
|
176
|
+
Content
|
|
177
|
+
</div>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
#### Self-Closing (inline)
|
|
181
|
+
|
|
182
|
+
End the content with `::` on the same line:
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
div::[color:blue;] short text ::
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Output:
|
|
189
|
+
```html
|
|
190
|
+
<div style="color:blue;"> short text </div>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
### Links
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
link::https://example.com[Click here]
|
|
198
|
+
link::page.html(.nav)[Back to home]
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Output:
|
|
202
|
+
```html
|
|
203
|
+
<a href="https://example.com">Click here</a>
|
|
204
|
+
<a class="nav" href="page.html">Back to home</a>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
### Images
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
img::photo.jpg[width:400px;]
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Output:
|
|
215
|
+
```html
|
|
216
|
+
<img style="width:400px;" src="photo.jpg" alt="photo.jpg">
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
### Videos
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
video::assets/clip.mp4[width:600px;]
|
|
224
|
+
videoplay::assets/clip.mp4[width:600px;]
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
`videoplay` adds `autoplay loop muted` attributes. The parser automatically detects transcoded codec variants (`-vp9.webm`, `-h265.mp4`, `-h264.mp4`) and poster images (`-poster.jpg`).
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
### Code Blocks
|
|
231
|
+
|
|
232
|
+
````
|
|
233
|
+
code::[python]
|
|
234
|
+
def hello():
|
|
235
|
+
print("Hello, world!")
|
|
236
|
+
code::[-]
|
|
237
|
+
````
|
|
238
|
+
|
|
239
|
+
Syntax highlighting is powered by Pygments. Any language supported by Pygments can be used.
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
### Spacer
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
::nl
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Output:
|
|
249
|
+
```html
|
|
250
|
+
<div style="height:1em;"></div>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
### Verbatim (raw passthrough)
|
|
255
|
+
|
|
256
|
+
Content inside verbatim blocks is preserved exactly as-is, with no LHTML processing:
|
|
257
|
+
|
|
258
|
+
```
|
|
259
|
+
verbatim::[]
|
|
260
|
+
This = is not a title
|
|
261
|
+
**not bold** __not italic__
|
|
262
|
+
div::[not a tag]
|
|
263
|
+
verbatim::[-]
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
### Comments
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
Some text ::# This comment will be removed
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
### File Inclusion
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
include::header.html
|
|
278
|
+
include::components/nav.html
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Included files are recursively processed (up to 20 levels).
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
### YAML Front Matter
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
---
|
|
288
|
+
title: "My Page"
|
|
289
|
+
css: ["style.css", "theme.css"]
|
|
290
|
+
js: "app.js"
|
|
291
|
+
wrap-auto: true
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
= Page content starts here
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Supported metadata keys:
|
|
298
|
+
|
|
299
|
+
| Key | Type | Description |
|
|
300
|
+
|-----|------|-------------|
|
|
301
|
+
| `title` | string | Page title (used in HTML wrapper) |
|
|
302
|
+
| `css` | string or list | CSS files to include |
|
|
303
|
+
| `js` | string or list | JavaScript files to include |
|
|
304
|
+
| `wrap-auto` | boolean | Wrap output in full HTML document |
|
|
305
|
+
| `directory_include` | list | Directories to search for includes |
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
## Plugin System
|
|
309
|
+
|
|
310
|
+
### Custom Tag Handlers
|
|
311
|
+
|
|
312
|
+
Register handlers for new `::` tag types:
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
from lhtml.pipeline import tag_registry
|
|
316
|
+
|
|
317
|
+
def handle_alert(element, tag_to_close, current_directory):
|
|
318
|
+
style = element.get('[]', '')
|
|
319
|
+
text = element.get('text', '')
|
|
320
|
+
return f'<div class="alert" style="{style}">{text}</div>', True
|
|
321
|
+
|
|
322
|
+
tag_registry.register('alert', handle_alert)
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Then use in LHTML:
|
|
326
|
+
```
|
|
327
|
+
alert::[background:yellow; padding:10px;] Warning message ::
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Custom Code Lexers
|
|
331
|
+
|
|
332
|
+
Register custom Pygments lexers for syntax highlighting:
|
|
333
|
+
|
|
334
|
+
```python
|
|
335
|
+
from lhtml.pipeline import lexer_registry
|
|
336
|
+
from pygments.lexers import PythonLexer
|
|
337
|
+
|
|
338
|
+
lexer_registry.register('mypython', PythonLexer)
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Custom Pipeline
|
|
342
|
+
|
|
343
|
+
Create an isolated pipeline with its own tag registry:
|
|
344
|
+
|
|
345
|
+
```python
|
|
346
|
+
from lhtml.pipeline import ProcessingPipeline, TagRegistry
|
|
347
|
+
|
|
348
|
+
registry = TagRegistry()
|
|
349
|
+
registry.register('note', my_note_handler)
|
|
350
|
+
|
|
351
|
+
pipeline = ProcessingPipeline(registry=registry)
|
|
352
|
+
html = pipeline.run(text, {'wrap-auto': True})
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
## Configuration Reference
|
|
357
|
+
|
|
358
|
+
All keys for the `meta` dict passed to `lhtml.run()`:
|
|
359
|
+
|
|
360
|
+
```python
|
|
361
|
+
{
|
|
362
|
+
'wrap-auto': False, # Wrap in HTML document
|
|
363
|
+
'title': 'Webpage', # Document title
|
|
364
|
+
'css': [], # CSS files (string or list)
|
|
365
|
+
'js': [], # JS files (string or list)
|
|
366
|
+
'directory_include': [], # Search paths for include::
|
|
367
|
+
'current_directory': '', # Base directory for video codec detection
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
## Design Principles
|
|
373
|
+
|
|
374
|
+
- **HTML-first**: Raw HTML is never modified. Only LHTML syntax triggers conversions.
|
|
375
|
+
- **Island grammar**: LHTML syntax "islands" float in a sea of opaque content (HTML, Jinja2 templates, LaTeX, etc.) that passes through untouched.
|
|
376
|
+
- **Minimal**: A few symbols (`::`, `=`, `*`, `**`, `__`, `` ` ``) cover most needs. No complex configuration required.
|
|
377
|
+
- **Composable**: LHTML works seamlessly with Jinja2 templates, making it suitable for static site generators.
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
## Project Structure
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
src/lhtml/
|
|
384
|
+
__init__.py # Public API: run(), analyse_tag(), read_yaml()
|
|
385
|
+
cli.py # Command-line interface
|
|
386
|
+
pipeline.py # ProcessingPipeline, TagRegistry, LexerRegistry
|
|
387
|
+
process.py # Core transformation functions
|
|
388
|
+
patterns.py # Centralized regex patterns and utilities
|
|
389
|
+
tag_parser.py # Lark-based parser for :: bracket syntax
|
|
390
|
+
tag_element.lark # Lark grammar definition
|
|
391
|
+
export_html.py # HTML generation for tag elements
|
|
392
|
+
listing.py # List processing
|
|
393
|
+
code.py # Code syntax highlighting (Pygments)
|
|
394
|
+
wrap_html.py # HTML document wrapping
|
|
395
|
+
ast_nodes.py # AST node dataclasses
|
|
396
|
+
errors.py # Structured error types
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
## License
|
|
401
|
+
|
|
402
|
+
MIT
|