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.
@@ -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