gradientgrove 0.1.4__tar.gz → 0.1.5.dev1__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.
Files changed (18) hide show
  1. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/PKG-INFO +80 -3
  2. gradientgrove-0.1.4/src/gradientgrove.egg-info/PKG-INFO → gradientgrove-0.1.5.dev1/README.md +75 -16
  3. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/pyproject.toml +7 -3
  4. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/src/gradientgrove/gradientgrove.css +5 -1
  5. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/src/gradientgrove/latex_fast_renderer.py +19 -0
  6. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/src/gradientgrove/latex_fence.py +1 -1
  7. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/src/gradientgrove/markdown_ast.py +45 -17
  8. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/src/gradientgrove/markdown_publish.py +100 -30
  9. gradientgrove-0.1.4/README.md → gradientgrove-0.1.5.dev1/src/gradientgrove.egg-info/PKG-INFO +93 -1
  10. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/src/gradientgrove.egg-info/SOURCES.txt +1 -0
  11. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/src/gradientgrove.egg-info/entry_points.txt +0 -1
  12. gradientgrove-0.1.5.dev1/src/gradientgrove.egg-info/requires.txt +3 -0
  13. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/LICENSE +0 -0
  14. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/setup.cfg +0 -0
  15. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/src/__init__.py +0 -0
  16. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/src/gradientgrove/publish.py +0 -0
  17. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/src/gradientgrove.egg-info/dependency_links.txt +0 -0
  18. {gradientgrove-0.1.4 → gradientgrove-0.1.5.dev1}/src/gradientgrove.egg-info/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gradientgrove
3
- Version: 0.1.4
4
- Summary: Python scripts to allow the creation of both documents and slideshow from a single Markdown file, or a Mkdocs project. Create a markdown file with mkdocs-style admonitions, compile to html, revealjs, latex, and beamer outputs.
3
+ Version: 0.1.5.dev1
4
+ Summary: Python scripts for teaching and scholarship, under development. Currently contains scripts that allow the creation of both documents and slideshow from a single Markdown file, or a Mkdocs project. Create a markdown file with mkdocs-style admonitions, compile to html, revealjs, latex, and beamer outputs.
5
5
  Author-email: Stephen Flood <stephen.flood@bridgew.edu>
6
6
  License-Expression: GPL-3.0-only
7
7
  Project-URL: Homepage, https://gradientgrove.com
@@ -11,6 +11,9 @@ Classifier: Operating System :: OS Independent
11
11
  Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
+ Requires-Dist: markdown
15
+ Requires-Dist: mkdocs
16
+ Requires-Dist: pymdown-extensions
14
17
  Dynamic: license-file
15
18
 
16
19
  # gradientgrove
@@ -29,10 +32,84 @@ gradientgrove-latex-to-markdown --help
29
32
  After installation, setuptools exposes the console scripts shown above. When running from a source checkout instead of an installed package, use the equivalent module form and prefix commands with `PYTHONPATH=src`:
30
33
 
31
34
  ```bash
32
- PYTHONPATH=src python -m gradientgrove.markdown_publish --help
35
+ PYTHONPATH=src python -m gradientgrove.publish --help
33
36
  PYTHONPATH=src python -m gradientgrove.markdown_ast --help
34
37
  ```
35
38
 
39
+ ## Markdown Syntax
40
+
41
+ - Standard Mkdocs/python-markdown syntax
42
+ - Several additional fences, with behavior dependent on output format
43
+ - Contents of `frame` become slides in revealjs/beamer output. Contents of `pause` are revealed when advancing.
44
+ - A page break is inserted before and after the contents of `page`
45
+ - A `newpage` environment with no contents inserts a pagebreak.
46
+ - You cannot put (sub)*section divisions inside a `frame`
47
+
48
+ | environment | article (html/pdf) | slides (revealjs/beamer) |
49
+ | ------- | ------ | ------ |
50
+ | `frame`, `pause` | ignored | yes |
51
+ | `newpage`, `page`, `vspace`, `vfill` | yes | ignored |
52
+ | `exercise`, `answer` | yes | yes |
53
+ | `theorem`, `definition` | yes | yes |
54
+
55
+ ```
56
+ ---
57
+ title : "My Document"
58
+ author: "Firstname Lastname"
59
+ ---
60
+
61
+ # Background
62
+
63
+ !!! note
64
+ Standard MkDocs/Python Markdown admonitions work
65
+
66
+ ??? info
67
+ Collapsable admonitions work too
68
+
69
+ # Slideshows
70
+
71
+ !!! frame "Frame Title"
72
+
73
+ Frame contents go here
74
+
75
+ !!! pause
76
+ Displayed when advanced
77
+
78
+ !!! exercise
79
+ You can put exercises between frames
80
+
81
+ ??? answer
82
+ And you can put answers too.
83
+
84
+ Answers are **excluded** from handout mode
85
+
86
+ !!! frame
87
+ You can put the next frame here
88
+
89
+ !!! page
90
+ !!! exercise
91
+ You can also make a worksheet with spaces
92
+
93
+ !!! vfill
94
+
95
+ !!! exercise
96
+ Another exercise
97
+
98
+ !!! vfill
99
+
100
+ # Mathematics environments
101
+
102
+ !!! definition
103
+ Definitions work
104
+
105
+ !!! theorem
106
+ Theorems too
107
+
108
+ Currently supported environments are hardcoded into the template, particularly for latex output.
109
+ Eventually there should be a more dynamic solution.
110
+ ```
111
+
112
+
36
113
  ## Publishing Markdown documents
37
114
 
38
115
  `gradientgrove.markdown_publish` converts Markdown files into HTML, Reveal.js slides, LaTeX articles, LaTeX handouts, and Beamer slides.
@@ -1,18 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: gradientgrove
3
- Version: 0.1.4
4
- Summary: Python scripts to allow the creation of both documents and slideshow from a single Markdown file, or a Mkdocs project. Create a markdown file with mkdocs-style admonitions, compile to html, revealjs, latex, and beamer outputs.
5
- Author-email: Stephen Flood <stephen.flood@bridgew.edu>
6
- License-Expression: GPL-3.0-only
7
- Project-URL: Homepage, https://gradientgrove.com
8
- Project-URL: Issues, https://gradientgrove.com
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.10
12
- Description-Content-Type: text/markdown
13
- License-File: LICENSE
14
- Dynamic: license-file
15
-
16
1
  # gradientgrove
17
2
 
18
3
  Local Python scripts for reusable Markdown, LaTeX, and publishing workflows.
@@ -29,10 +14,84 @@ gradientgrove-latex-to-markdown --help
29
14
  After installation, setuptools exposes the console scripts shown above. When running from a source checkout instead of an installed package, use the equivalent module form and prefix commands with `PYTHONPATH=src`:
30
15
 
31
16
  ```bash
32
- PYTHONPATH=src python -m gradientgrove.markdown_publish --help
17
+ PYTHONPATH=src python -m gradientgrove.publish --help
33
18
  PYTHONPATH=src python -m gradientgrove.markdown_ast --help
34
19
  ```
35
20
 
21
+ ## Markdown Syntax
22
+
23
+ - Standard Mkdocs/python-markdown syntax
24
+ - Several additional fences, with behavior dependent on output format
25
+ - Contents of `frame` become slides in revealjs/beamer output. Contents of `pause` are revealed when advancing.
26
+ - A page break is inserted before and after the contents of `page`
27
+ - A `newpage` environment with no contents inserts a pagebreak.
28
+ - You cannot put (sub)*section divisions inside a `frame`
29
+
30
+ | environment | article (html/pdf) | slides (revealjs/beamer) |
31
+ | ------- | ------ | ------ |
32
+ | `frame`, `pause` | ignored | yes |
33
+ | `newpage`, `page`, `vspace`, `vfill` | yes | ignored |
34
+ | `exercise`, `answer` | yes | yes |
35
+ | `theorem`, `definition` | yes | yes |
36
+
37
+ ```
38
+ ---
39
+ title : "My Document"
40
+ author: "Firstname Lastname"
41
+ ---
42
+
43
+ # Background
44
+
45
+ !!! note
46
+ Standard MkDocs/Python Markdown admonitions work
47
+
48
+ ??? info
49
+ Collapsable admonitions work too
50
+
51
+ # Slideshows
52
+
53
+ !!! frame "Frame Title"
54
+
55
+ Frame contents go here
56
+
57
+ !!! pause
58
+ Displayed when advanced
59
+
60
+ !!! exercise
61
+ You can put exercises between frames
62
+
63
+ ??? answer
64
+ And you can put answers too.
65
+
66
+ Answers are **excluded** from handout mode
67
+
68
+ !!! frame
69
+ You can put the next frame here
70
+
71
+ !!! page
72
+ !!! exercise
73
+ You can also make a worksheet with spaces
74
+
75
+ !!! vfill
76
+
77
+ !!! exercise
78
+ Another exercise
79
+
80
+ !!! vfill
81
+
82
+ # Mathematics environments
83
+
84
+ !!! definition
85
+ Definitions work
86
+
87
+ !!! theorem
88
+ Theorems too
89
+
90
+ Currently supported environments are hardcoded into the template, particularly for latex output.
91
+ Eventually there should be a more dynamic solution.
92
+ ```
93
+
94
+
36
95
  ## Publishing Markdown documents
37
96
 
38
97
  `gradientgrove.markdown_publish` converts Markdown files into HTML, Reveal.js slides, LaTeX articles, LaTeX handouts, and Beamer slides.
@@ -4,13 +4,18 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gradientgrove"
7
- version = "0.1.4" # dev versions with "0.1.4.dev1"
7
+ version = "0.1.5.dev1" # dev versions with "0.1.5.dev1"
8
8
  authors = [
9
9
  {name="Stephen Flood", email="stephen.flood@bridgew.edu"}
10
10
  ]
11
- description = "Python scripts to allow the creation of both documents and slideshow from a single Markdown file, or a Mkdocs project. Create a markdown file with mkdocs-style admonitions, compile to html, revealjs, latex, and beamer outputs."
11
+ description = "Python scripts for teaching and scholarship, under development. Currently contains scripts that allow the creation of both documents and slideshow from a single Markdown file, or a Mkdocs project. Create a markdown file with mkdocs-style admonitions, compile to html, revealjs, latex, and beamer outputs."
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.10"
14
+ dependencies = [
15
+ "markdown",
16
+ "mkdocs",
17
+ "pymdown-extensions",
18
+ ]
14
19
  classifiers = [
15
20
  "Programming Language :: Python :: 3",
16
21
  "Operating System :: OS Independent",
@@ -27,5 +32,4 @@ Issues = "https://gradientgrove.com"
27
32
 
28
33
  [project.scripts]
29
34
  gradientgrove-publish = "gradientgrove.markdown_publish:main"
30
- gradientgrove-pdf-review = "gradientgrove.pdf_review_tool:main"
31
35
  gradientgrove-latex-to-markdown = "gradientgrove.markdown_ast:latex_to_markdown_main"
@@ -253,6 +253,7 @@ details > :last-child {
253
253
  padding: 0.75in;
254
254
  background: var(--gg-bg);
255
255
  box-shadow: 0 0 0.2in rgb(0 0 0 / 15%);
256
+ break-before: page;
256
257
  break-after: page;
257
258
  }
258
259
 
@@ -291,7 +292,7 @@ details > :last-child {
291
292
  @media print {
292
293
  @page {
293
294
  size: letter;
294
- margin: 0;
295
+ margin: 1in;
295
296
  }
296
297
 
297
298
  html,
@@ -300,6 +301,9 @@ details > :last-child {
300
301
  min-height: 11in;
301
302
  background: white;
302
303
  color: black;
304
+
305
+ font-size: 10pt;
306
+ font-family: serif;
303
307
  }
304
308
 
305
309
  body.markdown-body {
@@ -123,6 +123,21 @@ def render_latex_fast(root, omit_envs=None, transparent_envs=None):
123
123
  if node.kind == "document":
124
124
  return "".join(render(child) for child in node.children)
125
125
 
126
+ if node.name == "page":
127
+ return "\n\\newpage\n" + body(node) + "\n\\newpage\n"
128
+
129
+ if node.name == "newpage":
130
+ return "\n\\newpage\n"
131
+
132
+ if node.name == "vfill":
133
+ return "\n\\vspace{\\stretch{1}}\n"
134
+
135
+ if node.name == "vspace":
136
+ amount = (node.title or "").strip()
137
+ if amount.lower() in {"", "vspace"}:
138
+ amount = "1in"
139
+ return f"\n\\vspace{{{amount}}}\n"
140
+
126
141
  key = node.name if node.kind in {"admonition", "details"} else (node.tag or node.name)
127
142
 
128
143
  # Math produced by pymdownx.arithmatex is already LaTeX-like content.
@@ -131,6 +146,10 @@ def render_latex_fast(root, omit_envs=None, transparent_envs=None):
131
146
  math = raw(node).strip("\n")
132
147
  return f"\n\n{math}\n\n" if key == "div" else math
133
148
 
149
+ if key == "img": # Render image
150
+ src = node.attrs.get("src", "")
151
+ return rf"\includegraphics[width=\linewidth]{{{src}}}"
152
+
134
153
  if key not in LATEX_RULES:
135
154
  if node.kind in {"admonition", "details"}:
136
155
  # escaped_title = "".join(
@@ -112,7 +112,7 @@ def _compile_to_svg(latex_body: str) -> bytes:
112
112
 
113
113
  p = subprocess.run(
114
114
  # ["pdf2svg", str(td / "x.pdf"), str(td / "x.svg")],
115
- ["dvisvgm", "--bbox=min", "--pdf", str(td / "x.pdf"), "-o", str(td / "x.svg")],
115
+ ["dvisvgm", "--no-fonts", "--bbox=min", "--pdf", str(td / "x.pdf"), "-o", str(td / "x.svg")],
116
116
  cwd=td,
117
117
  stdout=subprocess.PIPE,
118
118
  stderr=subprocess.STDOUT,
@@ -69,6 +69,9 @@ REVEALJS_TEMPLATE = Template("""<!doctype html>
69
69
 
70
70
  .reveal .slides section {
71
71
  text-align: left;
72
+ height: 100%;
73
+ overflow-y: auto;
74
+ overflow-x: auto;
72
75
  }
73
76
 
74
77
  .reveal .slides section h1,
@@ -263,15 +266,6 @@ HTML_HEADER_TEMPLATE = Template(r"""<!doctype html>
263
266
  </style>
264
267
  <style><!-- https://github.com/sindresorhus/github-markdown-css -->
265
268
  </style>
266
- <style>
267
- /* Optional: center like GitHub / VS Code preview */
268
- .markdown-body {
269
- box-sizing: border-box;
270
- min-width: 200px;
271
- max-width: 980px;
272
- margin: 0 auto;
273
- padding: 32px;
274
- }</style>
275
269
  </head>
276
270
  <body class="markdown-body">
277
271
  $html_body
@@ -342,6 +336,7 @@ showstringspaces=false,
342
336
  \setlength{\parindent}{0pt}
343
337
  \usepackage{longtable}
344
338
  \usepackage{booktabs}
339
+ \newcounter{none}
345
340
  \newcommand{\tightlist}{}
346
341
  \usetheme{Madrid}
347
342
  \usepackage{multicol}
@@ -356,6 +351,7 @@ showstringspaces=false,
356
351
  }
357
352
  \title{$title}
358
353
  \author{$author}
354
+ $dateline
359
355
  \begin{document}
360
356
  \begin{frame}
361
357
  \maketitle
@@ -365,6 +361,7 @@ showstringspaces=false,
365
361
  ARTICLE_HEADER_TEMPLATE = Template(r"""
366
362
  \documentclass{article}
367
363
  \usepackage{beamerarticle}
364
+ \usepackage[margin=1in,top=0.5in,bottom=0.5in, paperwidth=8.5in, paperheight=11in]{geometry}
368
365
  \usepackage{tikz}
369
366
  \usetikzlibrary{shapes.geometric}
370
367
  \usetikzlibrary{shadings}
@@ -426,19 +423,26 @@ breaklines=true,
426
423
  keepspaces=true,
427
424
  showstringspaces=false,
428
425
  }
429
- \setlength{\parindent}{0pt}
430
- \setlength{\parskip}{0.6\baselineskip}
426
+ %\setlength{\parindent}{0pt}
427
+ %\setlength{\parskip}{0.6\baselineskip}
428
+ \usepackage{parskip}
429
+ % format tables
431
430
  \usepackage{longtable}
432
431
  \usepackage{booktabs}
432
+ %\setlength{\tabcolsep}{0.5em} % for the horizontal padding
433
+ \renewcommand{\arraystretch}{1.2}% for the vertical padding
434
+ \newcounter{none}
435
+ %
433
436
  \newcommand{\tightlist}{}
434
437
  \usepackage[most]{tcolorbox}
435
438
  \BeforeBeginEnvironment{frame}{\begin{tcolorbox}[enhanced,breakable,boxrule=0.6pt,colback=white,colframe=black,arc=6pt,left=6pt,right=6pt,top=6pt,bottom=6pt,]}
436
439
  \AfterEndEnvironment{frame}{\end{tcolorbox}}
437
440
  \title{$title}
438
441
  \author{$author}
442
+ $dateline
439
443
  \begin{document}
440
444
  \maketitle
441
- \tableofcontents
445
+ %\tableofcontents
442
446
  """.strip())
443
447
 
444
448
  # ------------------------------------------------------------
@@ -915,6 +919,13 @@ class SyntaxTree:
915
919
 
916
920
  protected_text = "\n".join(protected_lines)
917
921
 
922
+ # Convert \newpage to !!! newpage
923
+ protected_text = re.sub(
924
+ r"\\newpage\b",
925
+ "\n\n!!! newpage\n\n",
926
+ protected_text,
927
+ )
928
+
918
929
  # Strip out latex commands with on markdown analog
919
930
  strip_latex_commands = ["alert", "only", "onslide"]
920
931
  for command in strip_latex_commands:
@@ -1039,6 +1050,18 @@ class SyntaxTree:
1039
1050
  )
1040
1051
  # print("length of text after strip comments", len(text))
1041
1052
 
1053
+ # Capture document metadata, store as yaml
1054
+ pandoc_md = subprocess.run(
1055
+ ["pandoc", "-f", "latex", "-t", "markdown", "-s"],
1056
+ input=text,
1057
+ text=True,
1058
+ capture_output=True,
1059
+ check=True,
1060
+ ).stdout
1061
+ yaml = re.match(r"---\n.*?\n---\n", pandoc_md, re.S)
1062
+ yaml = yaml.group(0) if yaml else ""
1063
+
1064
+
1042
1065
  if "\\begin{document}" in text:
1043
1066
  text = text.split("\\begin{document}", 1)[1]
1044
1067
 
@@ -1083,8 +1106,8 @@ class SyntaxTree:
1083
1106
  extensions=extensions,
1084
1107
  extension_configs=extension_configs,
1085
1108
  )
1086
- tree.markdown_text = markdown_text
1087
-
1109
+ # tree.markdown_text = markdown_text
1110
+ tree.markdown_text = yaml + "\n" + markdown_text # Store yaml metadata
1088
1111
 
1089
1112
 
1090
1113
  return tree
@@ -1097,9 +1120,10 @@ class SyntaxTree:
1097
1120
  heading_names = {"h1", "h2", "h3", "h4", "h5", "h6"}
1098
1121
 
1099
1122
  if self.name in heading_names and not in_document_root:
1100
- raise ValueError(
1101
- f"Heading {self.name!r} must be top-level in the document"
1102
- )
1123
+ # raise ValueError(
1124
+ # f"Heading {self.name!r} must be top-level in the document"
1125
+ # )
1126
+ print(f"Warning: Heading {self.name!r} with title {self.text!r} must be top-level in the document")
1103
1127
 
1104
1128
  if self.name == "frame":
1105
1129
  for child in self.children:
@@ -1597,6 +1621,7 @@ class SyntaxTree:
1597
1621
  *,
1598
1622
  title="Document",
1599
1623
  author="Stephen Flood",
1624
+ date=None,
1600
1625
  beamer=False,
1601
1626
  omit_envs=None,
1602
1627
  transparent_envs=None,
@@ -1618,6 +1643,9 @@ class SyntaxTree:
1618
1643
 
1619
1644
  body = self._render_latex(omit_envs, transparent_envs, progress=progress)
1620
1645
 
1646
+ # Define date parameter
1647
+ dateline = rf"\date{{{date}}}" if date else ""
1648
+
1621
1649
  if beamer:
1622
1650
  template = BEAMER_HEADER_TEMPLATE
1623
1651
  else:
@@ -1,4 +1,4 @@
1
- from gradientgrove.markdown_ast import SyntaxTree
1
+ from gradientgrove.markdown_ast import SyntaxTree, latex_to_markdown_main
2
2
  from gradientgrove import latex_fence
3
3
 
4
4
  import argparse
@@ -6,6 +6,10 @@ import base64
6
6
  import mimetypes
7
7
  import subprocess
8
8
  import sys
9
+ import shutil
10
+
11
+ # import yaml # mkdocs already depends on `pyyaml`
12
+ from mkdocs.utils.meta import get_data
9
13
 
10
14
  from mkdocs.commands.build import get_files
11
15
  from mkdocs.config import load_config
@@ -23,6 +27,8 @@ DEFAULT_EXTENSIONS = [
23
27
  "sane_lists",
24
28
  "admonition",
25
29
  "attr_list",
30
+ "def_list",
31
+ "footnotes",
26
32
  "pymdownx.arithmatex",
27
33
  "pymdownx.details",
28
34
  "pymdownx.superfences",
@@ -90,9 +96,15 @@ def compile_latex(filename):
90
96
  # stderr=subprocess.STDOUT,
91
97
  )
92
98
  if result.returncode != 0:
93
- print(f"Compile failed: {filename}")
94
- print(result.stdout)
95
- return False
99
+ pdf = filename.with_suffix(".pdf")
100
+ if not pdf.exists():
101
+ print(f"Compile failed: {filename}")
102
+ print(result.stdout)
103
+ return False
104
+ else:
105
+ print(f"Compile succeded with errors: {filename}")
106
+ print(result.stdout)
107
+ return True
96
108
  return True
97
109
 
98
110
  def resolve_local_image_paths(tree, markdown_parent):
@@ -109,7 +121,8 @@ def resolve_local_image_paths(tree, markdown_parent):
109
121
 
110
122
  resolved = (markdown_parent / src).resolve()
111
123
  if resolved.exists():
112
- node.attrs["src"] = str(resolved)
124
+ # node.attrs["src"] = str(resolved)
125
+ node.attrs["src"] = resolved.as_posix()
113
126
 
114
127
 
115
128
  def embed_local_images(tree, markdown_parent):
@@ -178,15 +191,28 @@ def convert_mkdocs_directory(path, output_directory, *, page_zip=True, **options
178
191
  nav = get_navigation(files, config)
179
192
  pages = [page for page in nav.pages if page.file.src_uri.endswith(".md")]
180
193
 
194
+ site_title = config['site_name']
195
+ site_title = re.sub(r'[^A-Za-z0-9 -_]', '', site_title)
196
+ site_title = re.sub(r'[ -]+', '_', site_title)
197
+ site_title_md = site_title + ".md"
198
+ site_title_zip = site_title + ".zip"
199
+
181
200
  generated = []
182
- merged_file = output_directory / "mkdocs-merged.md"
201
+ # merged_file = output_directory / "mkdocs-merged.md"
202
+ merged_file = output_directory / site_title_md
183
203
  try:
184
204
  merged = "\n\n".join(
185
205
  Path(page.file.abs_src_path).read_text(encoding="utf-8")
186
206
  for page in pages
187
207
  )
188
208
  merged_file.write_text(merged, encoding="utf-8")
189
- generated.extend(convert_file(merged_file, output_directory, **options, package_zip=False))
209
+ generated.extend(
210
+ convert_file(
211
+ merged_file, output_directory,
212
+ image_base=Path(config.docs_dir),
213
+ **options, package_zip=False,
214
+ )
215
+ )
190
216
  finally:
191
217
  merged_file.unlink(missing_ok=True)
192
218
 
@@ -195,28 +221,49 @@ def convert_mkdocs_directory(path, output_directory, *, page_zip=True, **options
195
221
  page_source = Path(page.file.abs_src_path)
196
222
  page_output_directory = output_directory / Path(page.file.src_uri).with_suffix("").parent
197
223
  page_output_directory.mkdir(parents=True, exist_ok=True)
198
- generated.extend(convert_file(page_source, page_output_directory, **options, package_zip=False))
224
+ generated.extend(
225
+ convert_file(page_source, page_output_directory,
226
+ image_base=Path(config.docs_dir),
227
+ **options, package_zip=False
228
+ )
229
+ )
199
230
 
200
231
  version = options.get("version", "")
201
- zip_name = f"mkdocs-{version}.zip" if version else "mkdocs.zip"
232
+ # zip_name = f"mkdocs-{version}.zip" if version else "mkdocs.zip"
233
+ zip_name = f"{site_title_zip}-{version}.zip" if version else site_title_zip
202
234
  package_outputs(output_directory / zip_name, generated, base_directory=output_directory)
203
235
  return generated
204
236
 
205
- def convert_file(filename, output_directory, *, base=False, tex=False, revealjs=False,beamer=False, handout=False, tex_handout=False, version="", package_zip=True):
237
+ def convert_file(filename, output_directory, *,
238
+ base=False, tex=False, revealjs=False,beamer=False, handout=False, tex_handout=False,
239
+ version="", package_zip=True,
240
+ image_base=None,
241
+ ):
206
242
  tex_generated = []
207
243
  generated = []
208
244
  version_str = f"-{version}" if version else ""
209
245
 
246
+ image_base = image_base or filename.parent
247
+
210
248
  page_name = filename.stem
211
- title = re.sub(r"[_-]+", " ", page_name).title()
249
+ default_title = re.sub(r"[_-]+", " ", page_name).title()
212
250
 
213
251
  # text = Path(filename).read_text(encoding="utf-8")
214
252
  text = filename.read_text(encoding="utf-8")
215
253
 
254
+ # Extract metadata, separate from body
255
+ text, meta = get_data(text)
256
+ title = meta.get("title", default_title)
257
+ author = meta.get("author", "Stephen Flood")
258
+ if isinstance(author, list):
259
+ author = ", ".join(author)
260
+ date = meta.get("date", "")
261
+
216
262
  if base:
217
263
  tree = build_tree(text, number=True, render_latex_fences=True)
218
- embed_local_images(tree, filename.parent)
219
- variant=version_str+"-base"
264
+ embed_local_images(tree, image_base)
265
+ # variant=version_str+"-base"
266
+ variant = version_str
220
267
 
221
268
  output = tree.to_html(title=title)
222
269
  output_file = output_directory / f"{page_name}{variant}.html"
@@ -226,7 +273,7 @@ def convert_file(filename, output_directory, *, base=False, tex=False, revealjs=
226
273
 
227
274
  if handout:
228
275
  tree = build_tree(text, omit_envs=["answer"], number=True, render_latex_fences=True)
229
- embed_local_images(tree, filename.parent)
276
+ embed_local_images(tree, image_base)
230
277
 
231
278
  variant=version_str+"-handout"
232
279
 
@@ -238,7 +285,7 @@ def convert_file(filename, output_directory, *, base=False, tex=False, revealjs=
238
285
 
239
286
  if revealjs:
240
287
  tree = build_tree(text, number=True, render_latex_fences=True)
241
- embed_local_images(tree, filename.parent)
288
+ embed_local_images(tree, image_base)
242
289
  variant=version_str+"-revealjs"
243
290
 
244
291
  output = tree.to_revealjs(title=title)
@@ -250,11 +297,14 @@ def convert_file(filename, output_directory, *, base=False, tex=False, revealjs=
250
297
 
251
298
  if tex:
252
299
  tree = build_tree(text, number=False, render_latex_fences=False)
253
- resolve_local_image_paths(tree, filename.parent)
254
- variant=version_str+"-base"
300
+ resolve_local_image_paths(tree, image_base)
301
+ # variant=version_str+"-base"
302
+ variant = version_str
255
303
  output = tree.to_latex(
256
304
  title=title,
257
- author="Stephen Flood",
305
+ # author="Stephen Flood",
306
+ author=author,
307
+ date=date,
258
308
  beamer=False,
259
309
  )
260
310
 
@@ -262,11 +312,13 @@ def convert_file(filename, output_directory, *, base=False, tex=False, revealjs=
262
312
  output_file.write_text(output, encoding="utf-8")
263
313
 
264
314
  tex_generated.append(output_file)
265
- generated.append(output_file)
315
+
316
+ # Do/don't include tex in zip
317
+ # generated.append(output_file)
266
318
 
267
319
  if tex_handout:
268
320
  tree = build_tree(text, number=False, omit_envs = ["answer"], render_latex_fences=False)
269
- resolve_local_image_paths(tree, filename.parent)
321
+ resolve_local_image_paths(tree, image_base)
270
322
  variant=version_str+"-handout"
271
323
  output = tree.to_latex(
272
324
  title=title,
@@ -278,11 +330,13 @@ def convert_file(filename, output_directory, *, base=False, tex=False, revealjs=
278
330
  output_file.write_text(output, encoding="utf-8")
279
331
  # output = output_latex_article(filename,output_directory,variant=version_str+"-base")
280
332
  tex_generated.append(output_file)
281
- generated.append(output_file)
333
+
334
+ # Do/don't include tex in zip
335
+ # generated.append(output_file)
282
336
 
283
337
  if beamer:
284
338
  tree = build_tree(text, number=False, render_latex_fences=False)
285
- resolve_local_image_paths(tree, filename.parent)
339
+ resolve_local_image_paths(tree, image_base)
286
340
  variant=version_str+"-slides"
287
341
  output = tree.to_latex(
288
342
  title=title,
@@ -294,7 +348,9 @@ def convert_file(filename, output_directory, *, base=False, tex=False, revealjs=
294
348
  output_file.write_text(output, encoding="utf-8")
295
349
  # output = output_latex_article(filename,output_directory,variant=version_str+"-base")
296
350
  tex_generated.append(output_file)
297
- generated.append(output_file)
351
+
352
+ # Do/don't include tex in zip
353
+ # generated.append(output_file)
298
354
 
299
355
  # Compile LaTeX output
300
356
  for output in tex_generated:
@@ -341,14 +397,15 @@ def main():
341
397
  parser.add_argument("--revealjs", action="store_true", help="Generate revealjs slides")
342
398
  parser.add_argument("--html", action="store_true", help="Generate *all* HTML documents")
343
399
  parser.add_argument("--tex", action="store_true", help="Generate TeX base document")
344
- parser.add_argument("--tex_handout", action="store_true", help="Generate TeX handout")
400
+ parser.add_argument("--pdf", action="store_true", help="Generate TeX base document")
401
+ parser.add_argument("--pdf-handout", action="store_true", help="Generate TeX handout")
345
402
  parser.add_argument("--beamer", action="store_true", help="Generate Beamer slides")
346
403
  parser.add_argument("--all", action="store_true", help="Generate all outputs")
347
404
  parser.add_argument(
348
405
  "--mkdocs-page-zip",
349
406
  dest="mkdocs_page_zip",
350
407
  action="store_true",
351
- default=True,
408
+ default=False,
352
409
  help="In MkDocs mode, include each source page's outputs in the single .publish_cache/mkdocs.zip package (default)",
353
410
  )
354
411
  parser.add_argument(
@@ -370,10 +427,12 @@ def main():
370
427
 
371
428
  options = {
372
429
  "base" : args.base or args.all or args.html,
373
- "handout" : args.all or args.html or args.handout,
374
- "revealjs" : args.all or args.html or args.revealjs,
375
- "tex" : args.all or args.tex,
376
- "tex_handout" : args.all or args.tex_handout ,
430
+ # "handout" : args.all or args.html or args.handout,
431
+ # "revealjs" : args.all or args.html or args.revealjs,
432
+ "handout" : args.all or args.handout,
433
+ "revealjs" : args.all or args.revealjs,
434
+ "tex" : args.all or args.tex or args.pdf,
435
+ "tex_handout" : args.all or args.pdf_handout ,
377
436
  "beamer" : args.all or args.beamer ,
378
437
  "version" : args.version,
379
438
  }
@@ -388,14 +447,25 @@ def main():
388
447
  convert_mkdocs_directory(path, output_directory, page_zip=args.mkdocs_page_zip, **options)
389
448
 
390
449
  elif path.is_file():
450
+ tex_directory = path.parent
391
451
  output_directory = path.parent / ".publish_cache"
392
452
  output_directory.mkdir(parents=True, exist_ok=True)
453
+
393
454
  print(f"Got a file: {path}")
394
- convert_file(
455
+
456
+ if path.suffix.lower() == ".tex":
457
+ markdown_path = output_directory / path.with_suffix(".md").name
458
+ latex_to_markdown_main([str(path), str(markdown_path)])
459
+ path = markdown_path
460
+
461
+ generated = convert_file(
395
462
  path,
396
463
  output_directory,
397
464
  **options
398
465
  )
466
+ # copy any generated PDFs back into the tex file directory.
467
+ for pdf in (p for p in generated if p.suffix == ".pdf"):
468
+ shutil.copy2(pdf, tex_directory)
399
469
 
400
470
  elif path.is_dir():
401
471
  output_directory = path / ".publish_cache"
@@ -1,3 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: gradientgrove
3
+ Version: 0.1.5.dev1
4
+ Summary: Python scripts for teaching and scholarship, under development. Currently contains scripts that allow the creation of both documents and slideshow from a single Markdown file, or a Mkdocs project. Create a markdown file with mkdocs-style admonitions, compile to html, revealjs, latex, and beamer outputs.
5
+ Author-email: Stephen Flood <stephen.flood@bridgew.edu>
6
+ License-Expression: GPL-3.0-only
7
+ Project-URL: Homepage, https://gradientgrove.com
8
+ Project-URL: Issues, https://gradientgrove.com
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: markdown
15
+ Requires-Dist: mkdocs
16
+ Requires-Dist: pymdown-extensions
17
+ Dynamic: license-file
18
+
1
19
  # gradientgrove
2
20
 
3
21
  Local Python scripts for reusable Markdown, LaTeX, and publishing workflows.
@@ -14,10 +32,84 @@ gradientgrove-latex-to-markdown --help
14
32
  After installation, setuptools exposes the console scripts shown above. When running from a source checkout instead of an installed package, use the equivalent module form and prefix commands with `PYTHONPATH=src`:
15
33
 
16
34
  ```bash
17
- PYTHONPATH=src python -m gradientgrove.markdown_publish --help
35
+ PYTHONPATH=src python -m gradientgrove.publish --help
18
36
  PYTHONPATH=src python -m gradientgrove.markdown_ast --help
19
37
  ```
20
38
 
39
+ ## Markdown Syntax
40
+
41
+ - Standard Mkdocs/python-markdown syntax
42
+ - Several additional fences, with behavior dependent on output format
43
+ - Contents of `frame` become slides in revealjs/beamer output. Contents of `pause` are revealed when advancing.
44
+ - A page break is inserted before and after the contents of `page`
45
+ - A `newpage` environment with no contents inserts a pagebreak.
46
+ - You cannot put (sub)*section divisions inside a `frame`
47
+
48
+ | environment | article (html/pdf) | slides (revealjs/beamer) |
49
+ | ------- | ------ | ------ |
50
+ | `frame`, `pause` | ignored | yes |
51
+ | `newpage`, `page`, `vspace`, `vfill` | yes | ignored |
52
+ | `exercise`, `answer` | yes | yes |
53
+ | `theorem`, `definition` | yes | yes |
54
+
55
+ ```
56
+ ---
57
+ title : "My Document"
58
+ author: "Firstname Lastname"
59
+ ---
60
+
61
+ # Background
62
+
63
+ !!! note
64
+ Standard MkDocs/Python Markdown admonitions work
65
+
66
+ ??? info
67
+ Collapsable admonitions work too
68
+
69
+ # Slideshows
70
+
71
+ !!! frame "Frame Title"
72
+
73
+ Frame contents go here
74
+
75
+ !!! pause
76
+ Displayed when advanced
77
+
78
+ !!! exercise
79
+ You can put exercises between frames
80
+
81
+ ??? answer
82
+ And you can put answers too.
83
+
84
+ Answers are **excluded** from handout mode
85
+
86
+ !!! frame
87
+ You can put the next frame here
88
+
89
+ !!! page
90
+ !!! exercise
91
+ You can also make a worksheet with spaces
92
+
93
+ !!! vfill
94
+
95
+ !!! exercise
96
+ Another exercise
97
+
98
+ !!! vfill
99
+
100
+ # Mathematics environments
101
+
102
+ !!! definition
103
+ Definitions work
104
+
105
+ !!! theorem
106
+ Theorems too
107
+
108
+ Currently supported environments are hardcoded into the template, particularly for latex output.
109
+ Eventually there should be a more dynamic solution.
110
+ ```
111
+
112
+
21
113
  ## Publishing Markdown documents
22
114
 
23
115
  `gradientgrove.markdown_publish` converts Markdown files into HTML, Reveal.js slides, LaTeX articles, LaTeX handouts, and Beamer slides.
@@ -12,4 +12,5 @@ src/gradientgrove.egg-info/PKG-INFO
12
12
  src/gradientgrove.egg-info/SOURCES.txt
13
13
  src/gradientgrove.egg-info/dependency_links.txt
14
14
  src/gradientgrove.egg-info/entry_points.txt
15
+ src/gradientgrove.egg-info/requires.txt
15
16
  src/gradientgrove.egg-info/top_level.txt
@@ -1,4 +1,3 @@
1
1
  [console_scripts]
2
2
  gradientgrove-latex-to-markdown = gradientgrove.markdown_ast:latex_to_markdown_main
3
- gradientgrove-pdf-review = gradientgrove.pdf_review_tool:main
4
3
  gradientgrove-publish = gradientgrove.markdown_publish:main
@@ -0,0 +1,3 @@
1
+ markdown
2
+ mkdocs
3
+ pymdown-extensions