engrapha-notes 0.1.0__tar.gz → 0.1.1__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.
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/PKG-INFO +20 -4
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/README.md +19 -3
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/pyproject.toml +2 -2
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes/cli.py +457 -6
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes/helpers.py +33 -12
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes.egg-info/PKG-INFO +20 -4
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes.egg-info/requires.txt +1 -1
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/setup.cfg +0 -0
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes/__init__.py +0 -0
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes/document.py +0 -0
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes/packet.py +0 -0
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes/palette.py +0 -0
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes/styles.py +0 -0
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes/theme.py +0 -0
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes.egg-info/SOURCES.txt +0 -0
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes.egg-info/dependency_links.txt +0 -0
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes.egg-info/entry_points.txt +0 -0
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes.egg-info/top_level.txt +0 -0
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/tests/test_exports.py +0 -0
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/tests/test_markdown_compiler.py +0 -0
- {engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/tests/test_math.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: engrapha-notes
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Themed ReportLab notes toolkit with markdown, HTML, PPTX, and flashcard exports
|
|
5
5
|
Author: Bharat Dangi
|
|
6
6
|
License-Expression: MIT
|
|
@@ -11,7 +11,7 @@ Description-Content-Type: text/markdown
|
|
|
11
11
|
Requires-Dist: reportlab>=4.5.1
|
|
12
12
|
Requires-Dist: pygments>=2.20.0
|
|
13
13
|
Requires-Dist: matplotlib>=3.10
|
|
14
|
-
Requires-Dist: engrapha-diagrams>=0.1.
|
|
14
|
+
Requires-Dist: engrapha-diagrams>=0.1.1
|
|
15
15
|
Provides-Extra: flashcards
|
|
16
16
|
Requires-Dist: genanki>=0.13.1; extra == "flashcards"
|
|
17
17
|
Provides-Extra: split
|
|
@@ -315,6 +315,14 @@ en.formula(r"E = mc^2", color="#fbbf24", fontsize=14.0)
|
|
|
315
315
|
en.formula_block(r"\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}", color="#38bdf8")
|
|
316
316
|
```
|
|
317
317
|
|
|
318
|
+
#### Matplotlib Mathtext Limitations
|
|
319
|
+
Since inline math uses matplotlib's internal mathtext parser (rather than a full-scale LaTeX compiler), there are a few syntax constraints:
|
|
320
|
+
* **No short-form inequality macros**: Use `\geq` and `\leq` instead of `\ge` and `\le`.
|
|
321
|
+
* **No `\iff` and extensible arrows**: Use `\Leftrightarrow` instead of `\iff`, and use `\overset{label}{\rightarrow}` instead of extensible arrows like `\xrightarrow{label}`.
|
|
322
|
+
* **No `\pmod`**: Use `\ (\mathrm{mod}\ N)` instead of `\pmod{N}` or `\pmod N`.
|
|
323
|
+
* **Set vertical bars**: Use `\vert` or `\mid` for vertical bars in sets.
|
|
324
|
+
|
|
325
|
+
|
|
318
326
|
### 6. Advanced Styling, Custom Layouts & Overrides
|
|
319
327
|
|
|
320
328
|
```python
|
|
@@ -442,10 +450,18 @@ en.packet_format(
|
|
|
442
450
|
|
|
443
451
|
## 💻 Markdown CLI Compiler
|
|
444
452
|
|
|
445
|
-
You can compile markdown notes files directly to PDF via the command line interface using either `
|
|
453
|
+
You can compile markdown notes files directly to PDF via the command line interface using either `engrapha` or `pdfnotes`:
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
engrapha input.md --output output.pdf --theme catppuccin-mocha
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### Display Help & Documentation
|
|
460
|
+
To print the comprehensive API reference, theme listing, and Markdown syntax guide directly in your terminal, run:
|
|
446
461
|
|
|
447
462
|
```bash
|
|
448
|
-
|
|
463
|
+
engrapha --info
|
|
464
|
+
# or: pdfnotes --info
|
|
449
465
|
```
|
|
450
466
|
|
|
451
467
|
### Options:
|
|
@@ -87,7 +87,7 @@ en.cover_card(
|
|
|
87
87
|
banner_svg="asset_images/network_topology.svg",
|
|
88
88
|
banner_width=400.0,
|
|
89
89
|
banner_align="center",
|
|
90
|
-
)
|
|
90
|
+
)
|
|
91
91
|
|
|
92
92
|
# Add a faint SVG background illustration (optional svglib for native vector)
|
|
93
93
|
en.cover_image(
|
|
@@ -282,6 +282,14 @@ en.formula(r"E = mc^2", color="#fbbf24", fontsize=14.0)
|
|
|
282
282
|
en.formula_block(r"\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}", color="#38bdf8")
|
|
283
283
|
```
|
|
284
284
|
|
|
285
|
+
#### Matplotlib Mathtext Limitations
|
|
286
|
+
Since inline math uses matplotlib's internal mathtext parser (rather than a full-scale LaTeX compiler), there are a few syntax constraints:
|
|
287
|
+
* **No short-form inequality macros**: Use `\geq` and `\leq` instead of `\ge` and `\le`.
|
|
288
|
+
* **No `\iff` and extensible arrows**: Use `\Leftrightarrow` instead of `\iff`, and use `\overset{label}{\rightarrow}` instead of extensible arrows like `\xrightarrow{label}`.
|
|
289
|
+
* **No `\pmod`**: Use `\ (\mathrm{mod}\ N)` instead of `\pmod{N}` or `\pmod N`.
|
|
290
|
+
* **Set vertical bars**: Use `\vert` or `\mid` for vertical bars in sets.
|
|
291
|
+
|
|
292
|
+
|
|
285
293
|
### 6. Advanced Styling, Custom Layouts & Overrides
|
|
286
294
|
|
|
287
295
|
```python
|
|
@@ -409,10 +417,18 @@ en.packet_format(
|
|
|
409
417
|
|
|
410
418
|
## 💻 Markdown CLI Compiler
|
|
411
419
|
|
|
412
|
-
You can compile markdown notes files directly to PDF via the command line interface using either `
|
|
420
|
+
You can compile markdown notes files directly to PDF via the command line interface using either `engrapha` or `pdfnotes`:
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
engrapha input.md --output output.pdf --theme catppuccin-mocha
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Display Help & Documentation
|
|
427
|
+
To print the comprehensive API reference, theme listing, and Markdown syntax guide directly in your terminal, run:
|
|
413
428
|
|
|
414
429
|
```bash
|
|
415
|
-
|
|
430
|
+
engrapha --info
|
|
431
|
+
# or: pdfnotes --info
|
|
416
432
|
```
|
|
417
433
|
|
|
418
434
|
### Options:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "engrapha-notes"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.1"
|
|
8
8
|
description = "Themed ReportLab notes toolkit with markdown, HTML, PPTX, and flashcard exports"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -20,7 +20,7 @@ dependencies = [
|
|
|
20
20
|
"reportlab>=4.5.1",
|
|
21
21
|
"pygments>=2.20.0",
|
|
22
22
|
"matplotlib>=3.10",
|
|
23
|
-
"engrapha-diagrams>=0.1.
|
|
23
|
+
"engrapha-diagrams>=0.1.1",
|
|
24
24
|
]
|
|
25
25
|
|
|
26
26
|
[project.optional-dependencies]
|
|
@@ -64,6 +64,7 @@ def format_inline_markdown(text: str) -> str:
|
|
|
64
64
|
escaped = escaped.replace("<u>", "<u>").replace("</u>", "</u>")
|
|
65
65
|
|
|
66
66
|
code_spans: list[str] = []
|
|
67
|
+
|
|
67
68
|
def _code_repl(m: re.Match[str]) -> str:
|
|
68
69
|
code_spans.append(m.group(1))
|
|
69
70
|
return f"@@CODE{len(code_spans)-1}@@"
|
|
@@ -654,8 +655,7 @@ def parse_markdown_lines(content_lines: List[str]) -> None:
|
|
|
654
655
|
if in_table and table_header:
|
|
655
656
|
formatted_header = [format_inline_markdown(h) for h in table_header]
|
|
656
657
|
formatted_rows = [
|
|
657
|
-
[format_inline_markdown(cell) for cell in row]
|
|
658
|
-
for row in table_rows
|
|
658
|
+
[format_inline_markdown(cell) for cell in row] for row in table_rows
|
|
659
659
|
]
|
|
660
660
|
en.info_table(formatted_header, formatted_rows)
|
|
661
661
|
table_rows.clear()
|
|
@@ -742,9 +742,7 @@ def parse_markdown_lines(content_lines: List[str]) -> None:
|
|
|
742
742
|
if parts and parts[-1] == "":
|
|
743
743
|
parts = parts[:-1]
|
|
744
744
|
if len(parts) >= 2:
|
|
745
|
-
is_separator = all(
|
|
746
|
-
re.match(r"^:?-+:?$", p) for p in parts
|
|
747
|
-
)
|
|
745
|
+
is_separator = all(re.match(r"^:?-+:?$", p) for p in parts)
|
|
748
746
|
if is_separator:
|
|
749
747
|
in_table = True
|
|
750
748
|
idx += 1
|
|
@@ -838,12 +836,452 @@ def parse_markdown_lines(content_lines: List[str]) -> None:
|
|
|
838
836
|
flush_table()
|
|
839
837
|
|
|
840
838
|
|
|
839
|
+
def print_package_help() -> None:
|
|
840
|
+
"""Print comprehensive package usage guide and API documentation to stdout."""
|
|
841
|
+
guide = """================================================================================
|
|
842
|
+
ENGRAPHA SUITE DOCUMENTATION
|
|
843
|
+
================================================================================
|
|
844
|
+
|
|
845
|
+
Welcome to the Engrapha Suite. This utility includes:
|
|
846
|
+
1. engrapha_notes: A themed ReportLab notes generator API.
|
|
847
|
+
2. engrapha_diagrams: A vector-native diagram builder API.
|
|
848
|
+
3. engrapha/pdfnotes CLI: A markdown-to-PDF notes compiler.
|
|
849
|
+
|
|
850
|
+
For standalone diagrams API and DSL reference, run:
|
|
851
|
+
engrapha-diagram (or engrapha-diagrams, engrapha_diagram, pdfdiagram)
|
|
852
|
+
|
|
853
|
+
--------------------------------------------------------------------------------
|
|
854
|
+
1. PYTHON NOTES API REFERENCE (engrapha_notes)
|
|
855
|
+
--------------------------------------------------------------------------------
|
|
856
|
+
import engrapha_notes as en
|
|
857
|
+
|
|
858
|
+
THEMES:
|
|
859
|
+
Preset themes: en.DARK, en.LIGHT, en.OCEAN_DARK, en.FOREST_DARK, en.SUNSET_DARK,
|
|
860
|
+
en.MIDNIGHT_DARK, en.OCEAN_LIGHT, en.SEPIA, en.CATPPUCCIN_LATTE, en.CATPPUCCIN_MOCHA,
|
|
861
|
+
en.LINEAR, en.NOTION, en.GITHUB, en.ACADEMIC, en.TEXTBOOK.
|
|
862
|
+
|
|
863
|
+
- en.set_theme(theme_obj)
|
|
864
|
+
Applies the theme. Custom themes can be created using `ThemeBuilder` or:
|
|
865
|
+
my_theme = en.LIGHT.copy_with(name="Custom", body_font="Times-Roman")
|
|
866
|
+
- en.get_theme() -> NotesTheme
|
|
867
|
+
Returns current theme metadata and styles.
|
|
868
|
+
|
|
869
|
+
GLOBAL FORMATTING & LAYOUT:
|
|
870
|
+
- en.set_global_header(left="", center="", right="")
|
|
871
|
+
Configures the page header running text.
|
|
872
|
+
- en.set_global_footer(left="", center="", right="", show_page_num=True)
|
|
873
|
+
Configures the page footer running text.
|
|
874
|
+
- en.suppress_header(page_only=True)
|
|
875
|
+
Hides page headers on the active page (or all pages if page_only=False).
|
|
876
|
+
- en.suppress_footer(page_only=True)
|
|
877
|
+
Hides page footers on the active page (or all pages if page_only=False).
|
|
878
|
+
|
|
879
|
+
COVER PAGES:
|
|
880
|
+
- en.cover_preset(preset_name, title, subtitle="", author="", date="")
|
|
881
|
+
Presets: 'engineering', 'research-paper', 'course-notes', 'networking', 'database', 'programming'.
|
|
882
|
+
- en.cover_card(title, subtitle="", author="", date="", cover_theme="linear", icon="", tags=[],
|
|
883
|
+
logo_svg=None, logo_width=120.0, banner_svg=None, banner_width=400.0, banner_align="left")
|
|
884
|
+
Themes: linear, notion, catppuccin, textbook, modern, minimal, corporate, academic, book.
|
|
885
|
+
- en.cover_image(path, opacity=0.06, placement="background")
|
|
886
|
+
Faint SVG background backdrop.
|
|
887
|
+
|
|
888
|
+
HEADINGS & PAGE NAVIGATION:
|
|
889
|
+
- en.toc(style="standard", col_widths=None)
|
|
890
|
+
Renders TOC. Style: 'standard' or 'index' (grid-based).
|
|
891
|
+
- en.part_box(title, subtitle="", topics=[])
|
|
892
|
+
Full-page part separator screen.
|
|
893
|
+
- en.chap_box(title, subtitle="")
|
|
894
|
+
Chapter title block.
|
|
895
|
+
- en.section(title)
|
|
896
|
+
Section header.
|
|
897
|
+
- en.subsection(title)
|
|
898
|
+
Subsection header.
|
|
899
|
+
- en.br()
|
|
900
|
+
Forces a page break.
|
|
901
|
+
- en.sp(height_in_points)
|
|
902
|
+
Inserts a vertical spacer.
|
|
903
|
+
|
|
904
|
+
BODY ELEMENTS & CALLOUTS:
|
|
905
|
+
- en.body(text, font_name=None, font_size=None, text_color=None, leading=None)
|
|
906
|
+
Normal paragraph text. Inline LaTeX '$...$' inside text is auto-compiled on the fly.
|
|
907
|
+
- en.bullet(items_list)
|
|
908
|
+
Bullet point list.
|
|
909
|
+
- en.formula(latex_str, color=None, fontsize=None) -> str
|
|
910
|
+
Inline LaTeX compiler. Returns string with XML image tag.
|
|
911
|
+
- en.formula_block(latex_str, color=None, fontsize=None)
|
|
912
|
+
Centers LaTeX formula block.
|
|
913
|
+
- en.code_block(code_text, lang="python", theme=en.DRACULA)
|
|
914
|
+
Syntax-highlighted code block. Themes: DRACULA, MONOKAI, GITHUB_DARK.
|
|
915
|
+
- en.info_table(headers, rows, col_widths=None)
|
|
916
|
+
Styled data table. Col widths can be percentages (e.g. ["40%", "60%"]).
|
|
917
|
+
- en.image(path, caption="", width=None, height=None, link=None, fallbacks=[])
|
|
918
|
+
Image loader with automatic URL caching, fallback lists, and missing placeholders.
|
|
919
|
+
- en.warning(text), en.note(text), en.tip(text), en.important(text)
|
|
920
|
+
Semantic callout cards.
|
|
921
|
+
- en.definition(title, text), en.theorem(title, text), en.proof(text)
|
|
922
|
+
Academic callout blocks.
|
|
923
|
+
- en.frame_format(title, fields)
|
|
924
|
+
Renders protocol frame segments. fields is a list of (label, bytes_desc).
|
|
925
|
+
- en.packet_format(title, fields, bit_ruler=True)
|
|
926
|
+
Renders network packet structures. fields is list of (label, bit_width).
|
|
927
|
+
- en.revision_card(title, items)
|
|
928
|
+
Revision checklist card.
|
|
929
|
+
|
|
930
|
+
ACTIVE RECALL & EXPORT:
|
|
931
|
+
- en.flashcard(question, answer)
|
|
932
|
+
Defines a flashcard study question. Gathered for Anki APKG compiler.
|
|
933
|
+
- en.question(text), en.answer(text), en.qbox(text)
|
|
934
|
+
Study questions layout.
|
|
935
|
+
- en.mcq(question, options, correct_index)
|
|
936
|
+
Multiple choice question layout.
|
|
937
|
+
|
|
938
|
+
CROSS-REFERENCING:
|
|
939
|
+
- en.label(name)
|
|
940
|
+
Attaches a target reference label to the preceding heading.
|
|
941
|
+
- en.ref(name) -> str
|
|
942
|
+
Resolves the target reference label page number.
|
|
943
|
+
|
|
944
|
+
DOCUMENT BUILD & EXPORT:
|
|
945
|
+
- en.build_doc(output_path, title=None, author=None)
|
|
946
|
+
Compiles everything into a PDF file.
|
|
947
|
+
- en.build_html(output_path)
|
|
948
|
+
Exports notes to HTML structure.
|
|
949
|
+
- en.build_pptx(output_path)
|
|
950
|
+
Exports notes to PowerPoint slides.
|
|
951
|
+
- en.build_split_doc(output_path, split_by="chapter")
|
|
952
|
+
Splits output PDF into multiple files by chapter boundaries or page ranges.
|
|
953
|
+
|
|
954
|
+
--------------------------------------------------------------------------------
|
|
955
|
+
2. PYTHON DIAGRAMS API REFERENCE (engrapha_diagrams)
|
|
956
|
+
--------------------------------------------------------------------------------
|
|
957
|
+
import engrapha_diagrams as ed
|
|
958
|
+
|
|
959
|
+
To print standalone diagrams package reference guide, run:
|
|
960
|
+
engrapha-diagram (or engrapha-diagrams, engrapha_diagram, pdfdiagram)
|
|
961
|
+
|
|
962
|
+
All diagram constructors accept:
|
|
963
|
+
width, height, theme=None, caption=None
|
|
964
|
+
|
|
965
|
+
Available diagram classes:
|
|
966
|
+
- ed.Flowchart(width, height, theme=None, direction='TB', scale_factor=None)
|
|
967
|
+
* Methods:
|
|
968
|
+
.terminal(id, label) - Oval terminal node
|
|
969
|
+
.process(id, label) - Rectangular process node
|
|
970
|
+
.decision(id, label) - Diamond decision node
|
|
971
|
+
.io_box(id, label) - Parallelogram input/output node
|
|
972
|
+
.connector(id, label) - Circle connector
|
|
973
|
+
.predefined(id, label) - Predefined process box node
|
|
974
|
+
.edge(src, dst, label="", orthogonal=False, branch=None) - Link edge
|
|
975
|
+
* Example:
|
|
976
|
+
fc = ed.Flowchart(width=300, height=150, direction="LR")
|
|
977
|
+
fc.terminal("start", "START").process("calc", "Calc").terminal("end", "END")
|
|
978
|
+
fc.edge("start", "calc").edge("calc", "end")
|
|
979
|
+
|
|
980
|
+
- ed.SequenceDiagram(width, height, theme=None)
|
|
981
|
+
* Methods:
|
|
982
|
+
.actor(id, label) - Lifeline actor (person)
|
|
983
|
+
.participant(id, label) - Lifeline participant (box)
|
|
984
|
+
.activate(id) - Start activation bar
|
|
985
|
+
.deactivate(id) - End activation bar
|
|
986
|
+
.message(src, dst, text, arrow='solid') - Message arrow ('solid', 'dashed', etc.)
|
|
987
|
+
.divider(text) - Horizontal partition divider
|
|
988
|
+
* Example:
|
|
989
|
+
seq = ed.SequenceDiagram(width=400, height=220)
|
|
990
|
+
seq.actor("c", "Client").actor("s", "Server")
|
|
991
|
+
seq.activate("c").message("c", "s", "Request").activate("s")
|
|
992
|
+
seq.message("s", "c", "Response", arrow="dashed").deactivate("s")
|
|
993
|
+
|
|
994
|
+
- ed.LayeredStack(width, height, theme=None)
|
|
995
|
+
* Methods:
|
|
996
|
+
.layer(label, sublabel="") - Add a stack layer
|
|
997
|
+
.divider() - Insert thick border line
|
|
998
|
+
* Example:
|
|
999
|
+
stack = ed.LayeredStack(width=300, height=150)
|
|
1000
|
+
stack.layer("Application", "HTTP").layer("Transport", "TCP")
|
|
1001
|
+
|
|
1002
|
+
- ed.NetworkDiagram(width, height, theme=None)
|
|
1003
|
+
* Methods:
|
|
1004
|
+
.node(id, label, x, y, kind='host') - kinds: host, server, cloud, switch, database, router, firewall
|
|
1005
|
+
.link(id1, id2, label="")
|
|
1006
|
+
* Example:
|
|
1007
|
+
net = ed.NetworkDiagram(width=400, height=200)
|
|
1008
|
+
net.node("client", "PC", 50, 100).node("srv", "Server", 250, 100)
|
|
1009
|
+
net.link("client", "srv")
|
|
1010
|
+
|
|
1011
|
+
- ed.ClassDiagram(width, height, theme=None, class_w=120)
|
|
1012
|
+
* Methods:
|
|
1013
|
+
.uml_class(id, name, stereotype="", attributes=[], methods=[])
|
|
1014
|
+
.relate(src, dst, kind='association', label="") - kinds: inheritance, realization, composition, aggregation, association, dependency
|
|
1015
|
+
* Example:
|
|
1016
|
+
cd = ed.ClassDiagram(width=300, height=200)
|
|
1017
|
+
cd.uml_class("Shape", "Shape", stereotype="abstract")
|
|
1018
|
+
cd.uml_class("Circle", "Circle", attributes=["- r: double"])
|
|
1019
|
+
cd.relate("Circle", "Shape", kind="inheritance")
|
|
1020
|
+
|
|
1021
|
+
- ed.ERDiagram(width, height, theme=None)
|
|
1022
|
+
* Methods:
|
|
1023
|
+
.entity(id)
|
|
1024
|
+
.relationship(id)
|
|
1025
|
+
.entity_attributes(entity_id, attribute_list) - attribute_list elements: "Name" or ("ID", {"pk": True})
|
|
1026
|
+
.connect(node1, node2, card_from=None, card_to=None)
|
|
1027
|
+
* Example:
|
|
1028
|
+
er = ed.ERDiagram(width=400, height=180)
|
|
1029
|
+
er.entity("User").relationship("Owns").entity("Device")
|
|
1030
|
+
er.entity_attributes("User", [("ID", {"pk": True}), "Email"])
|
|
1031
|
+
er.connect("User", "Owns", card_from="1", card_to="N")
|
|
1032
|
+
|
|
1033
|
+
- ed.StateMachine(width, height, theme=None)
|
|
1034
|
+
* Methods:
|
|
1035
|
+
.state(id, label, x, y, initial=False, accepting=False)
|
|
1036
|
+
.transition(src, dst, label="")
|
|
1037
|
+
* Example:
|
|
1038
|
+
sm = ed.StateMachine(width=300, height=150)
|
|
1039
|
+
sm.state("s0", "Init", 50, 75, initial=True).state("s1", "Done", 250, 75, accepting=True)
|
|
1040
|
+
sm.transition("s0", "s1", "process")
|
|
1041
|
+
|
|
1042
|
+
- ed.TimingDiagram(width, height, theme=None)
|
|
1043
|
+
* Methods:
|
|
1044
|
+
.clock(label, period, cycles)
|
|
1045
|
+
.signal(label, transitions) - transitions: list of (time, state_0_or_1)
|
|
1046
|
+
* Example:
|
|
1047
|
+
td = ed.TimingDiagram(width=400, height=120)
|
|
1048
|
+
td.clock("CLK", 20.0, 5).signal("RESET", [(0, 1), (15, 0)])
|
|
1049
|
+
|
|
1050
|
+
- ed.SchemaDiagram(width, height, theme=None)
|
|
1051
|
+
* Methods:
|
|
1052
|
+
.table(name, columns, x=0, y=0) - columns: list of (col_name, col_type, {"pk": True/False, "fk": True/False})
|
|
1053
|
+
.relation(table1, col1, table2, col2)
|
|
1054
|
+
* Example:
|
|
1055
|
+
schema = ed.SchemaDiagram(width=400, height=200)
|
|
1056
|
+
schema.table("users", [("id", "INT", {"pk": True}), ("name", "VARCHAR", {})])
|
|
1057
|
+
|
|
1058
|
+
- ed.ArchitectureDiagram(width, height, theme=None, orientation='horizontal')
|
|
1059
|
+
* Methods:
|
|
1060
|
+
.client(id, label), .service(id, label), .database(id, label), .queue(id, label)
|
|
1061
|
+
.connect(src, dst, label="")
|
|
1062
|
+
* Example:
|
|
1063
|
+
arch = ed.ArchitectureDiagram(width=400, height=200)
|
|
1064
|
+
arch.client("client", "Browser").service("api", "API Gateway")
|
|
1065
|
+
arch.connect("client", "api", "HTTPS")
|
|
1066
|
+
|
|
1067
|
+
- ed.C4ContainerDiagram(width, height, theme=None)
|
|
1068
|
+
* Methods:
|
|
1069
|
+
.system(id, label, desc="")
|
|
1070
|
+
.container(id, label, technology, desc="")
|
|
1071
|
+
.relate(src, dst, label="")
|
|
1072
|
+
* Example:
|
|
1073
|
+
c4 = ed.C4ContainerDiagram(width=400, height=180)
|
|
1074
|
+
c4.system("user", "User").container("spa", "SPA", "React")
|
|
1075
|
+
c4.relate("user", "spa", "Uses")
|
|
1076
|
+
|
|
1077
|
+
- ed.GitDiagram(width, height, theme=None)
|
|
1078
|
+
* Methods:
|
|
1079
|
+
.commit(branch, label)
|
|
1080
|
+
.branch(parent, child)
|
|
1081
|
+
.merge(from_branch, to_branch, label)
|
|
1082
|
+
* Example:
|
|
1083
|
+
git = ed.GitDiagram(width=300, height=120)
|
|
1084
|
+
git.commit("main", "Init").branch("main", "dev").commit("dev", "Feature")
|
|
1085
|
+
|
|
1086
|
+
- ed.AWSDiagram(width, height, theme=None, orientation='horizontal')
|
|
1087
|
+
* Methods:
|
|
1088
|
+
.ec2(id, label), .rds(id, label), .s3(id, label), .lambda_fn(id, label), .sqs(id, label)
|
|
1089
|
+
.connect(src, dst, label="")
|
|
1090
|
+
* Example:
|
|
1091
|
+
aws = ed.AWSDiagram(width=400, height=200)
|
|
1092
|
+
aws.ec2("web", "Instance").rds("db", "RDS")
|
|
1093
|
+
aws.connect("web", "db", "SQL Connection")
|
|
1094
|
+
|
|
1095
|
+
To save standalone images:
|
|
1096
|
+
diagram.save("output.svg") # Supports SVG, PDF, PNG, JPG formats.
|
|
1097
|
+
|
|
1098
|
+
To embed inside engrapha_notes:
|
|
1099
|
+
# Calling .as_flowable() returns a list[Flowable] containing the drawing
|
|
1100
|
+
# and caption. This is fully accepted by en.add().
|
|
1101
|
+
en.add(diagram.as_flowable())
|
|
1102
|
+
|
|
1103
|
+
--------------------------------------------------------------------------------
|
|
1104
|
+
3. CLI USAGE & COMPILER
|
|
1105
|
+
--------------------------------------------------------------------------------
|
|
1106
|
+
Compile a Markdown file into a themed PDF notes document:
|
|
1107
|
+
engrapha <input_file.md> [-o <output_file.pdf>] [-t <theme_name>]
|
|
1108
|
+
|
|
1109
|
+
Options:
|
|
1110
|
+
-o, --output Path to the output PDF (defaults to <input_name>.pdf).
|
|
1111
|
+
-t, --theme Theme name: dark (default), light, ocean-dark, forest-dark,
|
|
1112
|
+
sunset-dark, midnight-dark, ocean-light, sepia,
|
|
1113
|
+
catppuccin-latte, catppuccin-mocha.
|
|
1114
|
+
--title Metadata title.
|
|
1115
|
+
--author Metadata author.
|
|
1116
|
+
--info Display this detailed guide.
|
|
1117
|
+
|
|
1118
|
+
Markdown Syntax Supported:
|
|
1119
|
+
- Metadata Front-Matter:
|
|
1120
|
+
---
|
|
1121
|
+
title: Note Title
|
|
1122
|
+
author: Author Name
|
|
1123
|
+
theme: midnight-dark
|
|
1124
|
+
---
|
|
1125
|
+
- Headings:
|
|
1126
|
+
# Part Title -> Creates a Part Separator Box
|
|
1127
|
+
## Chapter Title -> Creates a Chapter Title Box
|
|
1128
|
+
### Section Title -> Creates a Section Title
|
|
1129
|
+
#### Subsection Title -> Creates a Subsection Title
|
|
1130
|
+
- Standard markdown paragraphs, **bold**, *italics*, `inline code`.
|
|
1131
|
+
- LaTeX Math: Inline LaTeX '$...$' is automatically compiled into inline vector math.
|
|
1132
|
+
(Note: Uses matplotlib's mathtext parser; use \\geq/\\leq instead of \\ge/\\le,
|
|
1133
|
+
\\Leftrightarrow instead of \\iff, \\ (\\mathrm{mod}\\ N) instead of \\pmod,
|
|
1134
|
+
and \\overset{label}{\\rightarrow} instead of \\xrightarrow).
|
|
1135
|
+
- Lists: Bullet lines starting with '-', '*' or '+' map to bullet lists.
|
|
1136
|
+
- Tables: Standard markdown tables map to styled Info Tables.
|
|
1137
|
+
- Alerts (GFM Alert blocks):
|
|
1138
|
+
> [!NOTE] Note text... (creates a Note callout box)
|
|
1139
|
+
> [!TIP] Tip text... (creates a Tip callout box)
|
|
1140
|
+
> [!WARNING] Warning text... (creates a Warning highlight box)
|
|
1141
|
+
> [!CAUTION] Caution text... (creates a Caution highlight box)
|
|
1142
|
+
|
|
1143
|
+
--------------------------------------------------------------------------------
|
|
1144
|
+
4. MARKDOWN DIAGRAM DSL CODE BLOCKS
|
|
1145
|
+
--------------------------------------------------------------------------------
|
|
1146
|
+
You can embed vector diagrams directly in your markdown using fenced code blocks.
|
|
1147
|
+
Supported block types: flowchart, sequence, layeredstack, schema, er, git,
|
|
1148
|
+
architecture, c4, aws.
|
|
1149
|
+
|
|
1150
|
+
Valid configuration keys at the start of any block (no spaces around '='):
|
|
1151
|
+
width=VAL - Drawing width in points (default: 450)
|
|
1152
|
+
height=VAL - Drawing height in points (default: 240)
|
|
1153
|
+
direction=DIR - Flow direction: TB (Top-to-Bottom) or LR (Left-to-Right)
|
|
1154
|
+
scale_factor=VAL - Decimal scale factor (default: auto-computed)
|
|
1155
|
+
caption="TEXT" - Optional caption centered below diagram
|
|
1156
|
+
|
|
1157
|
+
- **flowchart**:
|
|
1158
|
+
* Syntax & Commands:
|
|
1159
|
+
- terminal <id> "<label>" - Oval shape node
|
|
1160
|
+
- process <id> "<label>" - Rectangular shape node
|
|
1161
|
+
- decision <id> "<label>" - Diamond shape node
|
|
1162
|
+
- io <id> "<label>" - Parallelogram input/output node
|
|
1163
|
+
- connector <id> "<label>" - Circle shape node
|
|
1164
|
+
- predefined <id> "<label>" - Predefined process box node
|
|
1165
|
+
- edge <src> <dst> ["label"] [orthogonal=true] - Connects two nodes
|
|
1166
|
+
* Example:
|
|
1167
|
+
```flowchart
|
|
1168
|
+
width=400
|
|
1169
|
+
height=180
|
|
1170
|
+
direction=LR
|
|
1171
|
+
terminal s "START"
|
|
1172
|
+
process p "Compute Value"
|
|
1173
|
+
terminal e "END"
|
|
1174
|
+
edge s p
|
|
1175
|
+
edge p e
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1178
|
+
- **sequence**:
|
|
1179
|
+
* Syntax & Commands:
|
|
1180
|
+
- actor <id> "<label>" - Lifeline actor (person)
|
|
1181
|
+
- participant <id> "<label>" - Lifeline participant (box)
|
|
1182
|
+
- message <src> <dst> "<text>" [arrow=solid/dashed/solid_open/dashed_open]
|
|
1183
|
+
- divider ["label"] - Horizontal divider line
|
|
1184
|
+
* Example:
|
|
1185
|
+
```sequence
|
|
1186
|
+
actor c "Client"
|
|
1187
|
+
participant s "Server"
|
|
1188
|
+
message c s "GET /index"
|
|
1189
|
+
divider "Processing"
|
|
1190
|
+
message s c "200 OK" arrow=dashed
|
|
1191
|
+
```
|
|
1192
|
+
|
|
1193
|
+
- **layeredstack**:
|
|
1194
|
+
* Syntax & Commands:
|
|
1195
|
+
- layer "<label>" ["sublabel"] - Add a layer
|
|
1196
|
+
- divider - Thicker layer divider line
|
|
1197
|
+
* Example:
|
|
1198
|
+
```layeredstack
|
|
1199
|
+
layer "Application" "HTTP"
|
|
1200
|
+
layer "Transport" "TCP"
|
|
1201
|
+
divider
|
|
1202
|
+
layer "Network" "IP"
|
|
1203
|
+
```
|
|
1204
|
+
|
|
1205
|
+
- **schema**:
|
|
1206
|
+
* Syntax & Commands:
|
|
1207
|
+
- table <name> [x=coord] [y=coord] - Starts a database table definition
|
|
1208
|
+
- <col_name>: <type> [(pk)] [(fk)] [-> target_table.col] - Field entry
|
|
1209
|
+
- relation <table1>.<col1> <table2>.<col2> - FK link
|
|
1210
|
+
* Example:
|
|
1211
|
+
```schema
|
|
1212
|
+
table users x=50 y=100
|
|
1213
|
+
id: INT (pk)
|
|
1214
|
+
email: VARCHAR
|
|
1215
|
+
table orders x=250 y=100
|
|
1216
|
+
id: INT (pk)
|
|
1217
|
+
user_id: INT (fk) -> users.id
|
|
1218
|
+
```
|
|
1219
|
+
|
|
1220
|
+
- **git**:
|
|
1221
|
+
* Syntax & Commands:
|
|
1222
|
+
- commit <branch> "<message>" - Create a commit node
|
|
1223
|
+
- branch <parent> <child> - Spawn child branch lane
|
|
1224
|
+
- merge <from> <to> "<message>" - Merge two branch lanes
|
|
1225
|
+
* Example:
|
|
1226
|
+
```git
|
|
1227
|
+
commit main "Init"
|
|
1228
|
+
branch main dev
|
|
1229
|
+
commit dev "Feature"
|
|
1230
|
+
merge dev main "Merge feature"
|
|
1231
|
+
```
|
|
1232
|
+
|
|
1233
|
+
- **architecture**:
|
|
1234
|
+
* Syntax & Commands:
|
|
1235
|
+
- client <id> "<label>" - Client component box
|
|
1236
|
+
- service <id> "<label>" - Service component box
|
|
1237
|
+
- database <id> "<label>" - Database component cylinder
|
|
1238
|
+
- queue <id> "<label>" - Message queue component box
|
|
1239
|
+
- connect <src> <dst> "<label>" - Direct arrow connection
|
|
1240
|
+
* Example:
|
|
1241
|
+
```architecture
|
|
1242
|
+
client web "Web App"
|
|
1243
|
+
service api "Backend"
|
|
1244
|
+
database db "DB"
|
|
1245
|
+
connect web api "HTTP"
|
|
1246
|
+
connect api db "SQL"
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
- **aws**:
|
|
1250
|
+
* Syntax & Commands:
|
|
1251
|
+
- ec2 <id> "<label>" - EC2 instance icon
|
|
1252
|
+
- rds <id> "<label>" - RDS database icon
|
|
1253
|
+
- s3 <id> "<label>" - S3 bucket icon
|
|
1254
|
+
- lambda <id> "<label>" - Lambda function icon
|
|
1255
|
+
- sqs <id> "<label>" - SQS queue icon
|
|
1256
|
+
- connect <src> <dst> "<label>" - Connection arrow
|
|
1257
|
+
* Example:
|
|
1258
|
+
```aws
|
|
1259
|
+
ec2 web "Web App"
|
|
1260
|
+
rds db "Database"
|
|
1261
|
+
connect web db "SQL"
|
|
1262
|
+
```
|
|
1263
|
+
|
|
1264
|
+
- **c4**:
|
|
1265
|
+
* Syntax & Commands:
|
|
1266
|
+
- system <id> "<label>" ["desc"] - System Context block
|
|
1267
|
+
- container <id> "<label>" "<tech>" ["desc"] - Container block
|
|
1268
|
+
- relate <src> <dst> "<label>" - Relationship arrow
|
|
1269
|
+
* Example:
|
|
1270
|
+
```c4
|
|
1271
|
+
system user "Customer"
|
|
1272
|
+
container spa "SPA" "React" "Provides UI"
|
|
1273
|
+
relate user spa "Uses"
|
|
1274
|
+
```
|
|
1275
|
+
================================================================================"""
|
|
1276
|
+
print(guide)
|
|
1277
|
+
|
|
1278
|
+
|
|
841
1279
|
def main() -> None:
|
|
842
1280
|
"""CLI entrypoint."""
|
|
843
1281
|
parser = argparse.ArgumentParser(
|
|
844
1282
|
description="Compile Markdown documents to themed ReportLab PDFs with native diagrams."
|
|
845
1283
|
)
|
|
846
|
-
parser.add_argument("input", help="Path to the input markdown file.")
|
|
1284
|
+
parser.add_argument("input", nargs="?", help="Path to the input markdown file.")
|
|
847
1285
|
parser.add_argument(
|
|
848
1286
|
"-o",
|
|
849
1287
|
"--output",
|
|
@@ -857,9 +1295,22 @@ def main() -> None:
|
|
|
857
1295
|
)
|
|
858
1296
|
parser.add_argument("--title", help="Document title metadata.")
|
|
859
1297
|
parser.add_argument("--author", help="Document author metadata.")
|
|
1298
|
+
parser.add_argument(
|
|
1299
|
+
"--info",
|
|
1300
|
+
action="store_true",
|
|
1301
|
+
help="Print comprehensive package usage guide and API documentation.",
|
|
1302
|
+
)
|
|
860
1303
|
|
|
861
1304
|
args = parser.parse_args()
|
|
862
1305
|
|
|
1306
|
+
if args.info:
|
|
1307
|
+
print_package_help()
|
|
1308
|
+
sys.exit(0)
|
|
1309
|
+
|
|
1310
|
+
if not args.input:
|
|
1311
|
+
parser.print_help()
|
|
1312
|
+
sys.exit(1)
|
|
1313
|
+
|
|
863
1314
|
try:
|
|
864
1315
|
compile_markdown_to_pdf(
|
|
865
1316
|
input_file=args.input,
|
|
@@ -15,7 +15,7 @@ from typing import Any, TYPE_CHECKING, Literal
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
16
|
from reportlab.pdfgen.canvas import Canvas
|
|
17
17
|
|
|
18
|
-
from reportlab.lib.enums import TA_CENTER,
|
|
18
|
+
from reportlab.lib.enums import TA_CENTER, TA_LEFT
|
|
19
19
|
from reportlab.lib.styles import ParagraphStyle
|
|
20
20
|
from reportlab.platypus import (
|
|
21
21
|
Flowable,
|
|
@@ -645,6 +645,7 @@ def cover_card(
|
|
|
645
645
|
banner_align: str = "left",
|
|
646
646
|
logo_svg: str | None = None,
|
|
647
647
|
logo_width: float = 120.0,
|
|
648
|
+
**extra: Any,
|
|
648
649
|
) -> None:
|
|
649
650
|
"""
|
|
650
651
|
Add a styled cover-title card to the story.
|
|
@@ -657,10 +658,28 @@ def cover_card(
|
|
|
657
658
|
tags_max_w: float = float(w_val) if isinstance(w_val, (int, float)) else float(CW)
|
|
658
659
|
effective_style = cover_theme if cover_theme is not None else style
|
|
659
660
|
|
|
661
|
+
def _load_image_flowable(img_path: str, target_width: float) -> Any:
|
|
662
|
+
is_svg = img_path.lower().endswith(".svg")
|
|
663
|
+
if is_svg:
|
|
664
|
+
return InlineSVG(img_path, target_width=target_width)
|
|
665
|
+
else:
|
|
666
|
+
from reportlab.lib.utils import ImageReader
|
|
667
|
+
from reportlab.platypus import Image as RLImage
|
|
668
|
+
try:
|
|
669
|
+
reader = ImageReader(img_path)
|
|
670
|
+
iw, ih = reader.getSize()
|
|
671
|
+
aspect = ih / iw if iw > 0 else 1.0
|
|
672
|
+
target_height = target_width * aspect
|
|
673
|
+
return RLImage(img_path, width=target_width, height=target_height)
|
|
674
|
+
except Exception:
|
|
675
|
+
from reportlab.platypus import Spacer
|
|
676
|
+
return Spacer(1, 0)
|
|
677
|
+
|
|
660
678
|
add(CoverBackgroundFlowable(effective_style, t_theme, bg_svg=bg_svg))
|
|
661
679
|
|
|
662
680
|
if logo_svg:
|
|
663
|
-
|
|
681
|
+
logo_flowable = _load_image_flowable(logo_svg, target_width=logo_width)
|
|
682
|
+
add(logo_flowable)
|
|
664
683
|
sp(16)
|
|
665
684
|
|
|
666
685
|
on_dark_color = t_theme.rl(_contrast_text_color(t_theme))
|
|
@@ -788,7 +807,7 @@ def cover_card(
|
|
|
788
807
|
|
|
789
808
|
if arch == "hero":
|
|
790
809
|
# Massive typography, huge whitespace, left aligned
|
|
791
|
-
sp(80)
|
|
810
|
+
sp(30 if logo_svg else 80)
|
|
792
811
|
if icon:
|
|
793
812
|
add(render_icon(icon, size=56.0))
|
|
794
813
|
sp(24)
|
|
@@ -819,7 +838,7 @@ def cover_card(
|
|
|
819
838
|
|
|
820
839
|
elif arch == "book":
|
|
821
840
|
# Classic structured textbook aesthetic
|
|
822
|
-
sp(120)
|
|
841
|
+
sp(40 if logo_svg else 120)
|
|
823
842
|
st_title = ParagraphStyle(
|
|
824
843
|
_uid(),
|
|
825
844
|
parent=s.COVER_H1,
|
|
@@ -854,7 +873,7 @@ def cover_card(
|
|
|
854
873
|
|
|
855
874
|
elif arch in ("academic_modern", "diagram"):
|
|
856
875
|
# Clean university layout (diagram uses same text layout but relies on SVG background)
|
|
857
|
-
sp(60)
|
|
876
|
+
sp(20 if logo_svg else 60)
|
|
858
877
|
if icon:
|
|
859
878
|
add(render_icon(icon, size=48.0))
|
|
860
879
|
sp(20)
|
|
@@ -889,10 +908,10 @@ def cover_card(
|
|
|
889
908
|
sp(24)
|
|
890
909
|
from reportlab.platypus import Table, TableStyle, Indenter
|
|
891
910
|
|
|
892
|
-
|
|
911
|
+
banner_flowable = _load_image_flowable(banner_svg, target_width=banner_width)
|
|
893
912
|
|
|
894
913
|
if banner_align == "center":
|
|
895
|
-
center_table = Table([[
|
|
914
|
+
center_table = Table([[banner_flowable]], colWidths=["100%"])
|
|
896
915
|
center_table.setStyle(
|
|
897
916
|
TableStyle(
|
|
898
917
|
[
|
|
@@ -908,11 +927,12 @@ def cover_card(
|
|
|
908
927
|
else:
|
|
909
928
|
if base_indent > 0:
|
|
910
929
|
add(Indenter(left=base_indent))
|
|
911
|
-
add(
|
|
930
|
+
add(banner_flowable)
|
|
912
931
|
if base_indent > 0:
|
|
913
932
|
add(Indenter(left=-base_indent))
|
|
914
933
|
|
|
915
|
-
|
|
934
|
+
banner_h = getattr(banner_flowable, "height", 0) or (banner_width * (640.0 / 1280.0))
|
|
935
|
+
consumed += banner_h + 24.0
|
|
916
936
|
|
|
917
937
|
flexible_spacer(consumed)
|
|
918
938
|
|
|
@@ -1253,6 +1273,7 @@ def cover_preset(preset_name: str, **kwargs: Any) -> None:
|
|
|
1253
1273
|
tags=tags,
|
|
1254
1274
|
icon=icon,
|
|
1255
1275
|
cover_theme=cover_theme,
|
|
1276
|
+
**merged,
|
|
1256
1277
|
)
|
|
1257
1278
|
|
|
1258
1279
|
|
|
@@ -1462,7 +1483,7 @@ def body(
|
|
|
1462
1483
|
fontName=f_name,
|
|
1463
1484
|
leading=lead,
|
|
1464
1485
|
spaceAfter=5,
|
|
1465
|
-
alignment=
|
|
1486
|
+
alignment=TA_LEFT,
|
|
1466
1487
|
)
|
|
1467
1488
|
add(Paragraph(text, st))
|
|
1468
1489
|
|
|
@@ -1481,7 +1502,7 @@ def definition(text: str, bg: Any = None, border: Any = None) -> None:
|
|
|
1481
1502
|
leading=f_size * 1.6,
|
|
1482
1503
|
spaceBefore=4,
|
|
1483
1504
|
spaceAfter=6,
|
|
1484
|
-
alignment=
|
|
1505
|
+
alignment=TA_LEFT,
|
|
1485
1506
|
)
|
|
1486
1507
|
|
|
1487
1508
|
if getattr(t_theme, "plain_questions", False):
|
|
@@ -1865,7 +1886,7 @@ def proof(text: str) -> None:
|
|
|
1865
1886
|
leftIndent=20,
|
|
1866
1887
|
spaceBefore=6,
|
|
1867
1888
|
spaceAfter=6,
|
|
1868
|
-
alignment=
|
|
1889
|
+
alignment=TA_LEFT,
|
|
1869
1890
|
)
|
|
1870
1891
|
p = Paragraph(f"<i>Proof.</i> {text} [Q.E.D.]", st)
|
|
1871
1892
|
add(p)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: engrapha-notes
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Themed ReportLab notes toolkit with markdown, HTML, PPTX, and flashcard exports
|
|
5
5
|
Author: Bharat Dangi
|
|
6
6
|
License-Expression: MIT
|
|
@@ -11,7 +11,7 @@ Description-Content-Type: text/markdown
|
|
|
11
11
|
Requires-Dist: reportlab>=4.5.1
|
|
12
12
|
Requires-Dist: pygments>=2.20.0
|
|
13
13
|
Requires-Dist: matplotlib>=3.10
|
|
14
|
-
Requires-Dist: engrapha-diagrams>=0.1.
|
|
14
|
+
Requires-Dist: engrapha-diagrams>=0.1.1
|
|
15
15
|
Provides-Extra: flashcards
|
|
16
16
|
Requires-Dist: genanki>=0.13.1; extra == "flashcards"
|
|
17
17
|
Provides-Extra: split
|
|
@@ -315,6 +315,14 @@ en.formula(r"E = mc^2", color="#fbbf24", fontsize=14.0)
|
|
|
315
315
|
en.formula_block(r"\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}", color="#38bdf8")
|
|
316
316
|
```
|
|
317
317
|
|
|
318
|
+
#### Matplotlib Mathtext Limitations
|
|
319
|
+
Since inline math uses matplotlib's internal mathtext parser (rather than a full-scale LaTeX compiler), there are a few syntax constraints:
|
|
320
|
+
* **No short-form inequality macros**: Use `\geq` and `\leq` instead of `\ge` and `\le`.
|
|
321
|
+
* **No `\iff` and extensible arrows**: Use `\Leftrightarrow` instead of `\iff`, and use `\overset{label}{\rightarrow}` instead of extensible arrows like `\xrightarrow{label}`.
|
|
322
|
+
* **No `\pmod`**: Use `\ (\mathrm{mod}\ N)` instead of `\pmod{N}` or `\pmod N`.
|
|
323
|
+
* **Set vertical bars**: Use `\vert` or `\mid` for vertical bars in sets.
|
|
324
|
+
|
|
325
|
+
|
|
318
326
|
### 6. Advanced Styling, Custom Layouts & Overrides
|
|
319
327
|
|
|
320
328
|
```python
|
|
@@ -442,10 +450,18 @@ en.packet_format(
|
|
|
442
450
|
|
|
443
451
|
## 💻 Markdown CLI Compiler
|
|
444
452
|
|
|
445
|
-
You can compile markdown notes files directly to PDF via the command line interface using either `
|
|
453
|
+
You can compile markdown notes files directly to PDF via the command line interface using either `engrapha` or `pdfnotes`:
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
engrapha input.md --output output.pdf --theme catppuccin-mocha
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### Display Help & Documentation
|
|
460
|
+
To print the comprehensive API reference, theme listing, and Markdown syntax guide directly in your terminal, run:
|
|
446
461
|
|
|
447
462
|
```bash
|
|
448
|
-
|
|
463
|
+
engrapha --info
|
|
464
|
+
# or: pdfnotes --info
|
|
449
465
|
```
|
|
450
466
|
|
|
451
467
|
### Options:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engrapha_notes-0.1.0 → engrapha_notes-0.1.1}/src/engrapha_notes.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|