gradientgrove 0.1.5.dev1__tar.gz → 0.1.6__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.
- {gradientgrove-0.1.5.dev1/src/gradientgrove.egg-info → gradientgrove-0.1.6}/PKG-INFO +3 -2
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/README.md +2 -1
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/pyproject.toml +1 -1
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/gradientgrove/gradientgrove.css +59 -37
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/gradientgrove/latex_fast_renderer.py +77 -1
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/gradientgrove/markdown_ast.py +343 -139
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/gradientgrove/markdown_publish.py +26 -7
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6/src/gradientgrove.egg-info}/PKG-INFO +3 -2
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/LICENSE +0 -0
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/setup.cfg +0 -0
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/__init__.py +0 -0
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/gradientgrove/latex_fence.py +0 -0
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/gradientgrove/publish.py +0 -0
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/gradientgrove.egg-info/SOURCES.txt +0 -0
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/gradientgrove.egg-info/dependency_links.txt +0 -0
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/gradientgrove.egg-info/entry_points.txt +0 -0
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/gradientgrove.egg-info/requires.txt +0 -0
- {gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/gradientgrove.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gradientgrove
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
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
|
|
@@ -55,7 +55,8 @@ PYTHONPATH=src python -m gradientgrove.markdown_ast --help
|
|
|
55
55
|
```
|
|
56
56
|
---
|
|
57
57
|
title : "My Document"
|
|
58
|
-
author:
|
|
58
|
+
author:
|
|
59
|
+
- Firstname Lastname
|
|
59
60
|
---
|
|
60
61
|
|
|
61
62
|
# Background
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "gradientgrove"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.6" # dev versions with "0.1.5.dev1"
|
|
8
8
|
authors = [
|
|
9
9
|
{name="Stephen Flood", email="stephen.flood@bridgew.edu"}
|
|
10
10
|
]
|
|
@@ -43,7 +43,7 @@ html {
|
|
|
43
43
|
line-height: 1.5;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
body
|
|
46
|
+
body {
|
|
47
47
|
min-width: 200px;
|
|
48
48
|
max-width: 980px;
|
|
49
49
|
margin: 0 auto;
|
|
@@ -70,6 +70,10 @@ h4 { font-size: 1em; }
|
|
|
70
70
|
h5 { font-size: 0.875em; }
|
|
71
71
|
h6 { font-size: 0.85em; color: var(--gg-muted); }
|
|
72
72
|
|
|
73
|
+
dt {
|
|
74
|
+
font-weight: bold;
|
|
75
|
+
}
|
|
76
|
+
|
|
73
77
|
p, blockquote, ul, ol, dl, table, pre, details, .admonition {
|
|
74
78
|
margin-top: 0;
|
|
75
79
|
margin-bottom: 1rem;
|
|
@@ -241,6 +245,21 @@ details > :last-child {
|
|
|
241
245
|
margin-bottom: 0;
|
|
242
246
|
}
|
|
243
247
|
|
|
248
|
+
.gg-maketitle {
|
|
249
|
+
font-size: 1.25em;
|
|
250
|
+
text-align: center;
|
|
251
|
+
margin: 2rem 0 3rem;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.gg-maketitle h1 {
|
|
255
|
+
margin-bottom: 0.5rem;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.gg-maketitle-author,
|
|
259
|
+
.gg-maketitle-date {
|
|
260
|
+
margin: 0.25rem 0;
|
|
261
|
+
}
|
|
262
|
+
|
|
244
263
|
.gg-transparent-env {
|
|
245
264
|
display: contents;
|
|
246
265
|
}
|
|
@@ -249,16 +268,17 @@ details > :last-child {
|
|
|
249
268
|
box-sizing: border-box;
|
|
250
269
|
width: 8.5in;
|
|
251
270
|
min-height: 11in;
|
|
252
|
-
margin: 1rem auto
|
|
271
|
+
/*margin: 1rem auto;*/
|
|
272
|
+
margin: 0in;
|
|
253
273
|
padding: 0.75in;
|
|
254
274
|
background: var(--gg-bg);
|
|
255
275
|
box-shadow: 0 0 0.2in rgb(0 0 0 / 15%);
|
|
256
|
-
break-before: page;
|
|
276
|
+
/* break-before: page; */
|
|
257
277
|
break-after: page;
|
|
258
278
|
}
|
|
259
279
|
|
|
260
280
|
.gg-page-content {
|
|
261
|
-
min-height:
|
|
281
|
+
min-height: 9in;
|
|
262
282
|
display: flex;
|
|
263
283
|
flex-direction: column;
|
|
264
284
|
}
|
|
@@ -266,7 +286,9 @@ details > :last-child {
|
|
|
266
286
|
.gg-vfill {
|
|
267
287
|
flex: 1 1 auto;
|
|
268
288
|
}
|
|
269
|
-
|
|
289
|
+
.gg-vfillbox {
|
|
290
|
+
border: 1px solid currentColor;
|
|
291
|
+
}
|
|
270
292
|
.gg-vspace {
|
|
271
293
|
flex: 0 0 auto;
|
|
272
294
|
}
|
|
@@ -275,56 +297,56 @@ details > :last-child {
|
|
|
275
297
|
break-before: page;
|
|
276
298
|
}
|
|
277
299
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
300
|
+
.gg-question {
|
|
301
|
+
margin: 1em 0;
|
|
302
|
+
display: flex;
|
|
303
|
+
flex-direction: column;
|
|
304
|
+
}
|
|
305
|
+
.gg-question:has(.gg-vfill) {
|
|
306
|
+
flex: 1 1 auto;
|
|
307
|
+
}
|
|
308
|
+
.gg-question-2 {
|
|
309
|
+
margin-left: 2em;
|
|
310
|
+
}
|
|
311
|
+
.gg-question-3 {
|
|
312
|
+
margin-left: 4em;
|
|
290
313
|
}
|
|
291
314
|
|
|
292
315
|
@media print {
|
|
293
316
|
@page {
|
|
294
317
|
size: letter;
|
|
295
|
-
margin: 1in;
|
|
318
|
+
/* margin: 1in; */
|
|
319
|
+
margin-bottom:0in;
|
|
320
|
+
padding: 0;
|
|
296
321
|
}
|
|
297
322
|
|
|
298
323
|
html,
|
|
299
324
|
body {
|
|
300
|
-
|
|
301
|
-
|
|
325
|
+
margin: 0;
|
|
326
|
+
padding: 0;
|
|
302
327
|
background: white;
|
|
303
328
|
color: black;
|
|
304
|
-
|
|
305
|
-
font-size: 10pt;
|
|
329
|
+
font-size: 9pt;
|
|
306
330
|
font-family: serif;
|
|
307
331
|
}
|
|
308
|
-
|
|
309
|
-
body.markdown-body {
|
|
310
|
-
max-width: none;
|
|
311
|
-
margin: 0;
|
|
312
|
-
padding: 0.75in;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
body.markdown-body:has(.gg-page) {
|
|
316
|
-
padding: 0;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
332
|
.gg-page {
|
|
333
|
+
height: 9in;
|
|
334
|
+
min-height: 0;
|
|
335
|
+
width: 100%;
|
|
320
336
|
margin: 0;
|
|
337
|
+
padding: 0;
|
|
321
338
|
box-shadow: none;
|
|
322
|
-
background: white;
|
|
323
|
-
color: black;
|
|
324
339
|
}
|
|
325
|
-
|
|
340
|
+
.gg-page-content {
|
|
341
|
+
height: 100%;
|
|
342
|
+
min-height: 0;
|
|
343
|
+
}
|
|
344
|
+
.gg-vfill {
|
|
345
|
+
flex: 1 1 0;
|
|
346
|
+
}
|
|
347
|
+
|
|
326
348
|
a {
|
|
327
349
|
color: inherit;
|
|
328
350
|
text-decoration: underline;
|
|
329
351
|
}
|
|
330
|
-
}
|
|
352
|
+
}
|
|
@@ -123,21 +123,97 @@ 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
|
+
### CONTROLLING SPACING and PAGEBREAKS
|
|
127
|
+
|
|
126
128
|
if node.name == "page":
|
|
127
129
|
return "\n\\newpage\n" + body(node) + "\n\\newpage\n"
|
|
128
130
|
|
|
129
131
|
if node.name == "newpage":
|
|
130
132
|
return "\n\\newpage\n"
|
|
131
|
-
|
|
133
|
+
|
|
132
134
|
if node.name == "vfill":
|
|
133
135
|
return "\n\\vspace{\\stretch{1}}\n"
|
|
134
136
|
|
|
137
|
+
if node.name == "vfillbox":
|
|
138
|
+
# return "\n\\begin{tcolorbox}[height fill]\n\\end{tcolorbox}\n"
|
|
139
|
+
# return "\n\\begin{tcolorbox}\\vspace{\\stretch{1}}\\end{tcolorbox}\n"
|
|
140
|
+
return "\n\\noindent\\rule[-1em]{.4pt}{1em}\\hrulefill\\rule[-1em]{.4pt}{1em}\\par\\vspace{\\stretch{1}}\\par\\noindent\\rule{.4pt}{1em}\\hrulefill\\rule{.4pt}{1em}\\par"
|
|
141
|
+
|
|
135
142
|
if node.name == "vspace":
|
|
136
143
|
amount = (node.title or "").strip()
|
|
137
144
|
if amount.lower() in {"", "vspace"}:
|
|
138
145
|
amount = "1in"
|
|
139
146
|
return f"\n\\vspace{{{amount}}}\n"
|
|
140
147
|
|
|
148
|
+
### FORMATTING DOCUMENTS
|
|
149
|
+
if node.name == "maketitle":
|
|
150
|
+
return "\n\\maketitle"
|
|
151
|
+
|
|
152
|
+
if node.tag == "div" and "toc" in node.attrs.get("class", "").split():
|
|
153
|
+
return "\n\\tableofcontents\n"
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
### EXAM-LIKE ENVIRONMENT
|
|
157
|
+
if node.name == "exam":
|
|
158
|
+
# return "\n\\begin{enumerate}\n" + body(node) + "\\end{enumerate}\n"
|
|
159
|
+
out = ""
|
|
160
|
+
questions_started = False
|
|
161
|
+
for c in node.children:
|
|
162
|
+
if c.name == "question" and not questions_started:
|
|
163
|
+
out += "\n\\begin{enumerate}\n"
|
|
164
|
+
questions_started = True
|
|
165
|
+
out += render(c)
|
|
166
|
+
if questions_started:
|
|
167
|
+
out += "\n\\end{enumerate}\\n"
|
|
168
|
+
return out
|
|
169
|
+
|
|
170
|
+
if node.name == "question":
|
|
171
|
+
|
|
172
|
+
points = (node.title or "").strip()
|
|
173
|
+
points = f"({points} points)" if points.isdigit() else ""
|
|
174
|
+
out = f"\n\\item {points}\n"
|
|
175
|
+
|
|
176
|
+
has_subparts = False
|
|
177
|
+
|
|
178
|
+
for c in node.children:
|
|
179
|
+
if c.name =="question" and not has_subparts:
|
|
180
|
+
out += "\n\\begin{enumerate}\n"
|
|
181
|
+
has_subparts = True
|
|
182
|
+
out += render(c)
|
|
183
|
+
|
|
184
|
+
if has_subparts:
|
|
185
|
+
out += "\\end{enumerate}\n"
|
|
186
|
+
|
|
187
|
+
return out
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
if node.name == "gradetable":
|
|
191
|
+
exam = node.parent
|
|
192
|
+
questions = [
|
|
193
|
+
child for child in exam.children
|
|
194
|
+
if child.name == "question"
|
|
195
|
+
]
|
|
196
|
+
cols = "|c|" + "|".join(["c" for qn in questions]) + "|c|"
|
|
197
|
+
title_row = "Question & " + " & ".join( [ qn.attrs["number"] for qn in questions ] )
|
|
198
|
+
points_row = "Points & " + " & ".join([ qn.attrs["points"] for qn in questions])
|
|
199
|
+
score_row = "Score & " + " & ".join([ " " for qn in questions ])
|
|
200
|
+
|
|
201
|
+
total = sum([ int(qn.attrs["points"]) for qn in questions])
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
"\n\\begin{center}\n"
|
|
205
|
+
+ "\\setlength{\\tabcolsep}{1em} \n {\\renewcommand{\\arraystretch}{1.75} \n"
|
|
206
|
+
+ "\\begin{tabular}{"+cols+"}\n\\hline\n"
|
|
207
|
+
+ title_row + " & Total \\\\ \\hline \n"
|
|
208
|
+
+ points_row + " & " + str(total) + "\\\\ \\hline \n"
|
|
209
|
+
+ score_row + " & \\\\ \\hline"
|
|
210
|
+
+ "\\end{tabular}\n"
|
|
211
|
+
+ "\\end{center}\n"
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
### OTHER THINGS:
|
|
141
217
|
key = node.name if node.kind in {"admonition", "details"} else (node.tag or node.name)
|
|
142
218
|
|
|
143
219
|
# Math produced by pymdownx.arithmatex is already LaTeX-like content.
|
|
@@ -9,6 +9,8 @@ from markdown.treeprocessors import Treeprocessor
|
|
|
9
9
|
import subprocess
|
|
10
10
|
import html
|
|
11
11
|
|
|
12
|
+
import requests # To fetch mathjax source
|
|
13
|
+
|
|
12
14
|
from gradientgrove.latex_fast_renderer import render_latex_fast
|
|
13
15
|
|
|
14
16
|
from pathlib import Path
|
|
@@ -47,6 +49,11 @@ DEFAULT_LATEX_ENV_MAP = {
|
|
|
47
49
|
|
|
48
50
|
}
|
|
49
51
|
|
|
52
|
+
MATHJAX_URL = "https://cdn.jsdelivr.net/npm/mathjax@4/tex-mml-chtml.js"
|
|
53
|
+
|
|
54
|
+
REVEAL_VERSION = "6.0.1"
|
|
55
|
+
REVEAL_BASE = f"https://cdn.jsdelivr.net/npm/reveal.js@{REVEAL_VERSION}/dist"
|
|
56
|
+
|
|
50
57
|
REVEALJS_TEMPLATE = Template("""<!doctype html>
|
|
51
58
|
<html lang="en">
|
|
52
59
|
<head>
|
|
@@ -54,127 +61,138 @@ REVEALJS_TEMPLATE = Template("""<!doctype html>
|
|
|
54
61
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
55
62
|
<title>$title</title>
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
<
|
|
64
|
+
<!-- Essential scripts packaged for Blackboard -->
|
|
65
|
+
<style> $reveal_js_css_source </style>
|
|
66
|
+
<script> $reveal_js_script_source </script>
|
|
67
|
+
<style> $reveal_js_theme_source </style>
|
|
68
|
+
<script> $mathjax_source </script>
|
|
59
69
|
|
|
70
|
+
<!-- Nice to have scripts loaded at runtime -->
|
|
71
|
+
<script src="https://cdn.jsdelivr.net/npm/reveal.js-menu@2.1.0/menu.js"></script>
|
|
72
|
+
|
|
60
73
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
74
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"></script>
|
|
75
|
+
|
|
61
76
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js-plugins@latest/customcontrols/style.css">
|
|
62
|
-
<
|
|
77
|
+
<script src="https://cdn.jsdelivr.net/npm/reveal.js-plugins@latest/customcontrols/plugin.js"></script>
|
|
63
78
|
|
|
64
|
-
<
|
|
79
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js-plugins@latest/chalkboard/style.css">
|
|
80
|
+
<script src="https://cdn.jsdelivr.net/npm/reveal.js-plugins@latest/chalkboard/plugin.js"></script>
|
|
65
81
|
|
|
82
|
+
|
|
66
83
|
<style>
|
|
84
|
+
.reveal {
|
|
85
|
+
width: 100%;
|
|
86
|
+
height: 900px;
|
|
87
|
+
font-size: 18pt;
|
|
88
|
+
}
|
|
67
89
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
.reveal .slides section {
|
|
90
|
+
.reveal .slides section {
|
|
71
91
|
text-align: left;
|
|
72
92
|
height: 100%;
|
|
73
93
|
overflow-y: auto;
|
|
74
94
|
overflow-x: auto;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.reveal .slides section h1,
|
|
98
|
+
.reveal .slides section h2,
|
|
99
|
+
.reveal .slides section h3,
|
|
100
|
+
.reveal .slides section h4,
|
|
101
|
+
.reveal .slides section p,
|
|
102
|
+
.reveal .slides section ul,
|
|
103
|
+
.reveal .slides section ol,
|
|
104
|
+
.reveal .slides section blockquote {
|
|
85
105
|
text-align: left;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.reveal pre {
|
|
109
|
+
width: 100%;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.reveal pre code {
|
|
113
|
+
font-size: 15.75pt;
|
|
114
|
+
line-height: 1.35;
|
|
115
|
+
max-height: none;
|
|
116
|
+
padding: 0.4em 0.4em;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.reveal h1 { font-size: 33pt; }
|
|
120
|
+
.reveal h2 { font-size: 26.5pt; }
|
|
121
|
+
.reveal h3 { font-size: 21.5pt; }
|
|
122
|
+
.reveal h4 { font-size: 19pt; }
|
|
123
|
+
|
|
124
|
+
.reveal .title-slide h1 {
|
|
125
|
+
font-size: 36.25pt;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.reveal .section-slide h2 {
|
|
129
|
+
font-size: 29.75pt;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.reveal .title-slide,
|
|
133
|
+
.reveal .section-slide {
|
|
134
|
+
display: flex;
|
|
135
|
+
align-items: center;
|
|
136
|
+
justify-content: center;
|
|
137
|
+
text-align: center;
|
|
138
|
+
height: 100%;
|
|
139
|
+
}
|
|
140
|
+
|
|
111
141
|
/* format frame titles like h2 without making them h2 */
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
142
|
+
.reveal .frame-title {
|
|
143
|
+
font-size: 26.5pt;
|
|
144
|
+
font-weight: bold;
|
|
145
|
+
margin: 0 0 0.4em;
|
|
146
|
+
line-height: 1.2;
|
|
147
|
+
}
|
|
118
148
|
|
|
119
149
|
/* Prevent spaces from building up between containers */
|
|
120
150
|
.reveal section > * {
|
|
121
|
-
|
|
122
|
-
|
|
151
|
+
margin-top: 0;
|
|
152
|
+
margin-bottom: 0;
|
|
123
153
|
}
|
|
124
154
|
|
|
125
155
|
.reveal section > * + * {
|
|
126
|
-
|
|
156
|
+
margin-top: 0.4em;
|
|
127
157
|
}
|
|
128
158
|
|
|
129
159
|
.reveal p {
|
|
130
|
-
|
|
160
|
+
line-height: 1.25;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.reveal .theorem,
|
|
164
|
+
.reveal .example,
|
|
165
|
+
.reveal .answer,
|
|
166
|
+
.reveal .note {
|
|
167
|
+
margin: 1rem 0;
|
|
168
|
+
padding: 0.75rem 1rem;
|
|
169
|
+
border-left: 4px solid #888;
|
|
170
|
+
background: rgba(127,127,127,0.08);
|
|
171
|
+
text-align: left;
|
|
172
|
+
border-radius: 0.25rem;
|
|
131
173
|
}
|
|
132
|
-
|
|
174
|
+
|
|
175
|
+
.reveal .theorem-title,
|
|
176
|
+
.reveal .example-title,
|
|
177
|
+
.reveal .answer-title,
|
|
178
|
+
.reveal .note-title {
|
|
179
|
+
font-weight: bold;
|
|
180
|
+
margin-bottom: 0.5rem;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.reveal img {
|
|
184
|
+
max-width: 100%;
|
|
185
|
+
height: auto;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* scale images to match rescaled font size */
|
|
189
|
+
.reveal img.latex-svg {
|
|
190
|
+
zoom: 1.8;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
$extra_css
|
|
133
194
|
</style>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
<style>
|
|
137
|
-
|
|
138
|
-
.reveal .title-slide,
|
|
139
|
-
.reveal .section-slide {
|
|
140
|
-
display: flex;
|
|
141
|
-
align-items: center;
|
|
142
|
-
justify-content: center;
|
|
143
|
-
text-align: center;
|
|
144
|
-
height: 100%;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
.reveal .theorem,
|
|
148
|
-
.reveal .example,
|
|
149
|
-
.reveal .answer,
|
|
150
|
-
.reveal .note {
|
|
151
|
-
margin: 1rem 0;
|
|
152
|
-
padding: 0.75rem 1rem;
|
|
153
|
-
border-left: 4px solid #888;
|
|
154
|
-
background: rgba(127,127,127,0.08);
|
|
155
|
-
text-align: left;
|
|
156
|
-
border-radius: 0.25rem;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.reveal .theorem-title,
|
|
160
|
-
.reveal .example-title,
|
|
161
|
-
.reveal .answer-title,
|
|
162
|
-
.reveal .note-title {
|
|
163
|
-
font-weight: bold;
|
|
164
|
-
margin-bottom: 0.5rem;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
.reveal pre {
|
|
168
|
-
width: 100%;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.reveal img {
|
|
172
|
-
max-width: 100%;
|
|
173
|
-
height: auto;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
$extra_css
|
|
177
|
-
</style>
|
|
195
|
+
|
|
178
196
|
</head>
|
|
179
197
|
<body>
|
|
180
198
|
<div class="reveal">
|
|
@@ -183,14 +201,9 @@ REVEALJS_TEMPLATE = Template("""<!doctype html>
|
|
|
183
201
|
</div>
|
|
184
202
|
</div>
|
|
185
203
|
|
|
186
|
-
<script src="$reveal_js_path/reveal.js"></script>
|
|
187
|
-
<script src="https://cdn.jsdelivr.net/npm/reveal.js-menu@2.1.0/menu.js"></script>
|
|
188
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"></script>
|
|
189
|
-
<script src="https://cdn.jsdelivr.net/npm/reveal.js-plugins@latest/customcontrols/plugin.js"></script>
|
|
190
|
-
<script src="https://cdn.jsdelivr.net/npm/reveal.js-plugins@latest/chalkboard/plugin.js"></script>
|
|
191
|
-
|
|
192
204
|
<script>
|
|
193
205
|
Reveal.initialize({
|
|
206
|
+
embedded: true,
|
|
194
207
|
hash: true,
|
|
195
208
|
controls: true,
|
|
196
209
|
controlsTutorial: true,
|
|
@@ -216,17 +229,21 @@ REVEALJS_TEMPLATE = Template("""<!doctype html>
|
|
|
216
229
|
//height: 720,
|
|
217
230
|
width: 1000,
|
|
218
231
|
height: 700,
|
|
219
|
-
|
|
220
|
-
|
|
232
|
+
|
|
233
|
+
menu: {
|
|
221
234
|
side: "left",
|
|
222
235
|
width: "normal",
|
|
223
236
|
numbers: true,
|
|
237
|
+
headers: 'h1, h2',
|
|
224
238
|
titleSelector: "",
|
|
225
239
|
hideMissingTitles: true,
|
|
226
240
|
openButton: true,
|
|
227
|
-
keyboard: true
|
|
228
|
-
|
|
241
|
+
keyboard: true,
|
|
242
|
+
loadIcons: false,
|
|
243
|
+
},
|
|
244
|
+
//plugins: [ RevealMenu ]
|
|
229
245
|
|
|
246
|
+
|
|
230
247
|
customcontrols: {
|
|
231
248
|
controls: [
|
|
232
249
|
{
|
|
@@ -245,6 +262,7 @@ REVEALJS_TEMPLATE = Template("""<!doctype html>
|
|
|
245
262
|
chalkboard: {},
|
|
246
263
|
|
|
247
264
|
plugins: [ RevealMenu, RevealCustomControls, RevealChalkboard ]
|
|
265
|
+
|
|
248
266
|
});
|
|
249
267
|
</script>
|
|
250
268
|
</body>
|
|
@@ -257,12 +275,11 @@ HTML_HEADER_TEMPLATE = Template(r"""<!doctype html>
|
|
|
257
275
|
<head>
|
|
258
276
|
<meta charset="utf-8">
|
|
259
277
|
<title>$title</title>
|
|
260
|
-
<script
|
|
278
|
+
<script>
|
|
279
|
+
$mathjax_source
|
|
280
|
+
</script>
|
|
261
281
|
<style>
|
|
262
|
-
|
|
263
|
-
</style>
|
|
264
|
-
<style>
|
|
265
|
-
$bootstrap_min_css_text
|
|
282
|
+
$gradientgrove_css
|
|
266
283
|
</style>
|
|
267
284
|
<style><!-- https://github.com/sindresorhus/github-markdown-css -->
|
|
268
285
|
</style>
|
|
@@ -354,7 +371,7 @@ showstringspaces=false,
|
|
|
354
371
|
$dateline
|
|
355
372
|
\begin{document}
|
|
356
373
|
\begin{frame}
|
|
357
|
-
|
|
374
|
+
%\maketitle
|
|
358
375
|
\end{frame}
|
|
359
376
|
""".strip())
|
|
360
377
|
|
|
@@ -401,13 +418,19 @@ ARTICLE_HEADER_TEMPLATE = Template(r"""
|
|
|
401
418
|
\def\drawtikzspline(#1,#2,#3,#4,#5,#6){ \draw[curve,domain=(#1):(#4)] plot (\x , { ( (((#3) + (#6))*(#1) - ((#3) + (#6))*(#4) - 2*(#2) + 2*(#5))/((#1)^3 - 3*((#1)^2)*(#4) + 3*(#1)*((#4)^2) - (#4)^3) )*((\x)^3) + ( -(((#3) + 2*(#6))*((#1)^2) + ((#3) - (#6))*(#1)*(#4) - (2*(#3) + (#6))*((#4)^2) - 3*((#1) + (#4))*(#2) + 3*((#1) + (#4))*(#5))/((#1)^3 - 3*((#1)^2)*(#4) + 3*(#1)*((#4)^2) - (#4)^3) ) *((\x)^2) + ( ((#6)*((#1)^3) + (2*(#3) + (#6))*((#1)^2)*(#4) - ((#3) + 2*(#6))*(#1)*((#4)^2) - (#3)*((#4)^3) - 6*(#1)*(#4)*(#2) + 6*(#1)*(#4)*(#5))/((#1)^3 - 3*((#1)^2)*(#4) + 3*(#1)*((#4)^2) - (#4)^3) ) * (\x) + ( -((#6)*((#1)^3)*(#4) + ((#3) - (#6))*((#1)^2)*(#4)^2 - (#3)*(#1)*((#4)^3) - (3*(#1)*((#4)^2) - (#4)^3)*(#2) - ((#1)^3 - 3*((#1)^2)*(#4))*(#5))/((#1)^3 - 3*((#1)^2)*(#4) + 3*(#1)*((#4)^2) - (#4)^3))}) }
|
|
402
419
|
%%%% End: TikZ SPLINE
|
|
403
420
|
\usepackage{unicode-math}
|
|
404
|
-
\usepackage{hyperref}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
\
|
|
421
|
+
\usepackage[colorlinks={true},urlcolor=blue,bookmarks={false}]{hyperref}
|
|
422
|
+
%\usepackage[lastexercise]{exercise}
|
|
423
|
+
%\renewcommand{\ExerciseHeader}{\textbf{\ExerciseName\ \ExerciseHeaderNB}.}
|
|
424
|
+
%\newenvironment{exercise}{\begin{Exercise}}{\end{Exercise}}
|
|
425
|
+
%\newenvironment{answer}{\begin{Answer}}{\end{Answer}}
|
|
426
|
+
%\renewcommand{\AnswerHeader}{\textit{Solution (\ExerciseName~\ExerciseHeaderNB}). }
|
|
427
|
+
\newcounter{exercise}
|
|
428
|
+
\newenvironment{exercise}{\refstepcounter{exercise}\par\medskip\noindent\textbf{Exercise \theexercise.}\ }{\par\medskip}
|
|
429
|
+
%\newenvironment{answer}{\par\smallskip\noindent\textit{Answer (Exercise \theexercise).}\ }{\dotfill$\square$\par\medskip}
|
|
430
|
+
%\newenvironment{answer}{\begin{adjustwidth}{1.5em}{0pt}\smallskip\noindent\textit{Answer (Exercise \theexercise).}\ }{\end{adjustwidth}\medskip}
|
|
431
|
+
\newenvironment{answer}{\par\smallskip\noindent\textit{Answer (Exercise \theexercise.}\begin{tcolorbox}[boxrule=.4pt,left=1em,right=1em,top=.5em,bottom=.5em]}{\dotfill$\square$\end{tcolorbox}}
|
|
432
|
+
\setcounter{tocdepth}{1}
|
|
433
|
+
%\AtEndEnvironment{Answer}{\dotfill$\square$}
|
|
411
434
|
\usepackage{listings}
|
|
412
435
|
\newcommand{\passthrough}[1]{#1}
|
|
413
436
|
\newcommand{\pandocbounded}[1]{#1}
|
|
@@ -435,14 +458,18 @@ showstringspaces=false,
|
|
|
435
458
|
%
|
|
436
459
|
\newcommand{\tightlist}{}
|
|
437
460
|
\usepackage[most]{tcolorbox}
|
|
461
|
+
% Formatting for beamerarticle frame enviornment
|
|
438
462
|
\BeforeBeginEnvironment{frame}{\begin{tcolorbox}[enhanced,breakable,boxrule=0.6pt,colback=white,colframe=black,arc=6pt,left=6pt,right=6pt,top=6pt,bottom=6pt,]}
|
|
439
463
|
\AfterEndEnvironment{frame}{\end{tcolorbox}}
|
|
464
|
+
% New environments
|
|
465
|
+
\newtcolorbox{warning}{colback=orange!10,colframe=orange!80!black,arc=2mm,boxrule=0.8pt}
|
|
466
|
+
\newtcolorbox{todo}{colback=orange!10,colframe=orange!80!black,arc=2mm,boxrule=0.8pt}
|
|
467
|
+
|
|
468
|
+
|
|
440
469
|
\title{$title}
|
|
441
470
|
\author{$author}
|
|
442
471
|
$dateline
|
|
443
472
|
\begin{document}
|
|
444
|
-
\maketitle
|
|
445
|
-
%\tableofcontents
|
|
446
473
|
""".strip())
|
|
447
474
|
|
|
448
475
|
# ------------------------------------------------------------
|
|
@@ -501,6 +528,10 @@ class SyntaxTree:
|
|
|
501
528
|
self.etree = etree # original etree node (escape hatch / backing store)
|
|
502
529
|
self.call_pandoc = False
|
|
503
530
|
|
|
531
|
+
self.parent = None
|
|
532
|
+
for child in self.children:
|
|
533
|
+
child.parent = self
|
|
534
|
+
|
|
504
535
|
# @classmethod
|
|
505
536
|
# def from_markdown(cls, text, *, extensions=None, extension_configs=None):
|
|
506
537
|
# sink = {}
|
|
@@ -810,12 +841,26 @@ class SyntaxTree:
|
|
|
810
841
|
while line_index < len(lines):
|
|
811
842
|
|
|
812
843
|
current_line = lines[line_index]
|
|
844
|
+
|
|
813
845
|
stripped_line = current_line.strip()
|
|
846
|
+
if stripped_line == r"\maketitle":
|
|
847
|
+
protected_lines.append("!!! maketitle")
|
|
848
|
+
line_index += 1
|
|
849
|
+
continue
|
|
850
|
+
|
|
851
|
+
if stripped_line == r"\tableofcontents":
|
|
852
|
+
token = new_placeholder()
|
|
853
|
+
placeholder_map[token] = "[TOC]"
|
|
854
|
+
protected_lines.append(token)
|
|
855
|
+
line_index += 1
|
|
856
|
+
continue
|
|
857
|
+
|
|
814
858
|
# begin_match = re.match(r"\\begin\{([^}]+)\}(.*)", current_line)
|
|
815
859
|
begin_match = re.match(r"^(\s*)\\begin\{([^}]+)\}(.*)", current_line)
|
|
816
860
|
|
|
817
861
|
# print("converting", current_line[:30])
|
|
818
862
|
|
|
863
|
+
|
|
819
864
|
if not begin_match:
|
|
820
865
|
protected_lines.append(current_line)
|
|
821
866
|
line_index += 1
|
|
@@ -1050,6 +1095,11 @@ class SyntaxTree:
|
|
|
1050
1095
|
)
|
|
1051
1096
|
# print("length of text after strip comments", len(text))
|
|
1052
1097
|
|
|
1098
|
+
# Strip everything after the first \end{document}
|
|
1099
|
+
before, marker, _ = text.partition(r"\end{document}")
|
|
1100
|
+
if marker:
|
|
1101
|
+
text = before + marker
|
|
1102
|
+
|
|
1053
1103
|
# Capture document metadata, store as yaml
|
|
1054
1104
|
pandoc_md = subprocess.run(
|
|
1055
1105
|
["pandoc", "-f", "latex", "-t", "markdown", "-s"],
|
|
@@ -1200,6 +1250,47 @@ class SyntaxTree:
|
|
|
1200
1250
|
else:
|
|
1201
1251
|
node.text = prefix
|
|
1202
1252
|
|
|
1253
|
+
|
|
1254
|
+
def number_questions(self, depth=0, prefix=""):
|
|
1255
|
+
"""
|
|
1256
|
+
Number question environments to simulate latex exam class
|
|
1257
|
+
Also record level to identify part/subparts when building grade table
|
|
1258
|
+
Finally record the label that will be used when printing
|
|
1259
|
+
"""
|
|
1260
|
+
questions = [child for child in self.children if child.name == "question"]
|
|
1261
|
+
total_points = 0
|
|
1262
|
+
|
|
1263
|
+
for i, question in enumerate(questions, 1):
|
|
1264
|
+
level = depth + 1
|
|
1265
|
+
|
|
1266
|
+
if level == 1: # Questions
|
|
1267
|
+
number = str(i)
|
|
1268
|
+
label = number
|
|
1269
|
+
elif level == 2: # Parts
|
|
1270
|
+
number = chr(ord("a") + i - 1)
|
|
1271
|
+
label = f"{prefix}({number})"
|
|
1272
|
+
else: # Subparts
|
|
1273
|
+
number = str(i)
|
|
1274
|
+
label = f"{prefix}({number})"
|
|
1275
|
+
|
|
1276
|
+
question.attrs["level"] = str(level)
|
|
1277
|
+
question.attrs["number"] = number
|
|
1278
|
+
question.attrs["label"] = label
|
|
1279
|
+
|
|
1280
|
+
points_below = question.number_questions(level, label)
|
|
1281
|
+
points_labeled = (question.title or "").strip()
|
|
1282
|
+
|
|
1283
|
+
if points_labeled.isdigit():
|
|
1284
|
+
points = int(points_labeled)
|
|
1285
|
+
else:
|
|
1286
|
+
points = points_below
|
|
1287
|
+
|
|
1288
|
+
question.attrs["points"] = str(points)
|
|
1289
|
+
total_points += points
|
|
1290
|
+
|
|
1291
|
+
return total_points
|
|
1292
|
+
|
|
1293
|
+
|
|
1203
1294
|
# def pretty_print(self, indent=0):
|
|
1204
1295
|
# """Print the current AST in a human readable form for debugging"""
|
|
1205
1296
|
# pad = " " * indent
|
|
@@ -1264,6 +1355,11 @@ class SyntaxTree:
|
|
|
1264
1355
|
el.tail = self.tail
|
|
1265
1356
|
return el
|
|
1266
1357
|
|
|
1358
|
+
if self.name == "vfillbox":
|
|
1359
|
+
el = ET.Element("div", {"class": "gg-vfill gg-vfillbox"})
|
|
1360
|
+
el.tail = self.tail
|
|
1361
|
+
return el
|
|
1362
|
+
|
|
1267
1363
|
if self.name == "vspace":
|
|
1268
1364
|
amount = self.title
|
|
1269
1365
|
if amount in {None, "", "vspace", "Vspace"}:
|
|
@@ -1271,7 +1367,7 @@ class SyntaxTree:
|
|
|
1271
1367
|
el = ET.Element("div", {"class": "gg-vspace", "style": f"height: {amount}"})
|
|
1272
1368
|
el.tail = self.tail
|
|
1273
1369
|
return el
|
|
1274
|
-
|
|
1370
|
+
|
|
1275
1371
|
if self.kind in {"admonition", "details"} and self.name in transparent_envs:
|
|
1276
1372
|
el = ET.Element("div", {"class": "gg-transparent-env"})
|
|
1277
1373
|
el.text = self.text
|
|
@@ -1280,6 +1376,62 @@ class SyntaxTree:
|
|
|
1280
1376
|
el.append(child.to_etree(transparent_envs))
|
|
1281
1377
|
return el
|
|
1282
1378
|
|
|
1379
|
+
if self.name == "exam":
|
|
1380
|
+
el = ET.Element("div", {"class": "gg-exam"})
|
|
1381
|
+
el.tail = self.tail
|
|
1382
|
+
|
|
1383
|
+
for child in self.children:
|
|
1384
|
+
el.append(child.to_etree(transparent_envs))
|
|
1385
|
+
|
|
1386
|
+
return el
|
|
1387
|
+
|
|
1388
|
+
if self.name == "question":
|
|
1389
|
+
level = self.attrs["level"]
|
|
1390
|
+
number = self.attrs["number"]
|
|
1391
|
+
|
|
1392
|
+
label = f"{number}." if level == "1" else f"({number})"
|
|
1393
|
+
points = (self.title or "").strip()
|
|
1394
|
+
text = label + (f" [{points} points]" if points.isdigit() else "") + " "
|
|
1395
|
+
|
|
1396
|
+
if level == "1":
|
|
1397
|
+
el = ET.Element("section", {"class": "gg-page"})
|
|
1398
|
+
content = ET.SubElement(el, "div", {"class": "gg-page-content"})
|
|
1399
|
+
else:
|
|
1400
|
+
el = ET.Element("div", {"class": f"gg-question gg-question-{level}"})
|
|
1401
|
+
content = el
|
|
1402
|
+
|
|
1403
|
+
content.text = text + (self.text or "")
|
|
1404
|
+
|
|
1405
|
+
for child in self.children:
|
|
1406
|
+
content.append(child.to_etree(transparent_envs))
|
|
1407
|
+
|
|
1408
|
+
el.tail = self.tail
|
|
1409
|
+
return el
|
|
1410
|
+
|
|
1411
|
+
if self.name == "gradetable":
|
|
1412
|
+
questions = [
|
|
1413
|
+
child for child in self.parent.children
|
|
1414
|
+
if child.name == "question"
|
|
1415
|
+
]
|
|
1416
|
+
|
|
1417
|
+
total = sum(int(q.attrs["points"]) for q in questions)
|
|
1418
|
+
|
|
1419
|
+
rows = [
|
|
1420
|
+
["Question"] + [q.attrs["number"] for q in questions] + ["Total"],
|
|
1421
|
+
["Points"] + [q.attrs["points"] for q in questions] + [str(total)],
|
|
1422
|
+
["Score"] + ["" for q in questions] + [""],
|
|
1423
|
+
]
|
|
1424
|
+
|
|
1425
|
+
table = ET.Element("table", {"class": "gg-gradetable"})
|
|
1426
|
+
|
|
1427
|
+
for values in rows:
|
|
1428
|
+
row = ET.SubElement(table, "tr")
|
|
1429
|
+
for value in values:
|
|
1430
|
+
ET.SubElement(row, "td").text = value
|
|
1431
|
+
|
|
1432
|
+
table.tail = self.tail
|
|
1433
|
+
return table
|
|
1434
|
+
|
|
1283
1435
|
if self.kind == "admonition":
|
|
1284
1436
|
attrs = dict(self.attrs)
|
|
1285
1437
|
attrs["class"] = f"admonition {self.name}"
|
|
@@ -1321,32 +1473,73 @@ class SyntaxTree:
|
|
|
1321
1473
|
el.append(child.to_etree(transparent_envs))
|
|
1322
1474
|
return el
|
|
1323
1475
|
|
|
1324
|
-
def to_html(self, omit_envs=None, title="Document", transparent_envs=None):
|
|
1476
|
+
# def to_html(self, omit_envs=None, title="Document", transparent_envs=None):
|
|
1477
|
+
def to_html(
|
|
1478
|
+
self,
|
|
1479
|
+
omit_envs=None,
|
|
1480
|
+
title="",
|
|
1481
|
+
author="",
|
|
1482
|
+
date="",
|
|
1483
|
+
transparent_envs=None,
|
|
1484
|
+
):
|
|
1325
1485
|
if omit_envs is None:
|
|
1326
1486
|
omit_envs = []
|
|
1327
1487
|
|
|
1328
1488
|
omit_envs = set(omit_envs or [])
|
|
1329
1489
|
|
|
1330
1490
|
if self.kind == "document":
|
|
1331
|
-
html_body = "".join(
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1491
|
+
# html_body = "".join(
|
|
1492
|
+
# ET.tostring(
|
|
1493
|
+
# child.to_etree(transparent_envs),
|
|
1494
|
+
# encoding="unicode",
|
|
1495
|
+
# method="html",
|
|
1496
|
+
# )
|
|
1497
|
+
# for child in self.children
|
|
1498
|
+
# if child.name not in omit_envs
|
|
1499
|
+
# )
|
|
1500
|
+
html_parts = []
|
|
1501
|
+
|
|
1502
|
+
# Build HTML body. Handle special node cases
|
|
1503
|
+
for child in self.children:
|
|
1504
|
+
if child.name in omit_envs:
|
|
1505
|
+
continue
|
|
1506
|
+
|
|
1507
|
+
if child.name == "maketitle":
|
|
1508
|
+
|
|
1509
|
+
html_parts.append(
|
|
1510
|
+
f"""
|
|
1511
|
+
<div class="gg-maketitle">
|
|
1512
|
+
<h1>{html.escape(str(title))}</h1>
|
|
1513
|
+
<div class="gg-maketitle-author">{html.escape(str(author))}</div>
|
|
1514
|
+
<div class="gg-maketitle-date">{html.escape(str(date))}</div>
|
|
1515
|
+
</div>
|
|
1516
|
+
"""
|
|
1517
|
+
)
|
|
1518
|
+
continue
|
|
1519
|
+
|
|
1520
|
+
html_parts.append(
|
|
1521
|
+
ET.tostring(
|
|
1522
|
+
child.to_etree(transparent_envs),
|
|
1523
|
+
encoding="unicode",
|
|
1524
|
+
method="html",
|
|
1525
|
+
)
|
|
1336
1526
|
)
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
)
|
|
1527
|
+
|
|
1528
|
+
html_body = "".join(html_parts)
|
|
1340
1529
|
|
|
1341
1530
|
from pathlib import Path
|
|
1342
1531
|
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
1343
|
-
|
|
1344
|
-
# base_css_text = f.read()
|
|
1345
|
-
# with (SCRIPT_DIR / "bootstrap.min.css").open() as f:
|
|
1346
|
-
# bootstrap_min_css_text = f.read()
|
|
1532
|
+
|
|
1347
1533
|
with (SCRIPT_DIR / "gradientgrove.css").open() as f:
|
|
1348
|
-
|
|
1349
|
-
|
|
1534
|
+
gradientgrove_css = f.read()
|
|
1535
|
+
|
|
1536
|
+
# Download mathjax script to embed into html
|
|
1537
|
+
try:
|
|
1538
|
+
response = requests.get(MATHJAX_URL)
|
|
1539
|
+
response.raise_for_status()
|
|
1540
|
+
mathjax_source = response.text
|
|
1541
|
+
except:
|
|
1542
|
+
print("ERROR: Unable to download mathjax script")
|
|
1350
1543
|
|
|
1351
1544
|
return HTML_HEADER_TEMPLATE.safe_substitute(locals())
|
|
1352
1545
|
|
|
@@ -1457,8 +1650,16 @@ class SyntaxTree:
|
|
|
1457
1650
|
)
|
|
1458
1651
|
body = "".join(child._render_reveal_content(transparent_envs) for child in node.children)
|
|
1459
1652
|
slides.append(f"<section>\n{slide_title}{body}\n</section>")
|
|
1460
|
-
|
|
1653
|
+
|
|
1654
|
+
# Collect slide contents
|
|
1461
1655
|
slides_html = "\n".join(slides)
|
|
1656
|
+
|
|
1657
|
+
# Download mathjax script to embed into html
|
|
1658
|
+
mathjax_source = requests.get(MATHJAX_URL).text
|
|
1659
|
+
reveal_js_css_source = requests.get(f"{REVEAL_BASE}/reveal.css").text
|
|
1660
|
+
reveal_js_theme_source = requests.get(f"{REVEAL_BASE}/theme/{theme}.css").text
|
|
1661
|
+
reveal_js_script_source = requests.get(f"{REVEAL_BASE}/reveal.js").text
|
|
1662
|
+
|
|
1462
1663
|
return REVEALJS_TEMPLATE.safe_substitute(locals())
|
|
1463
1664
|
|
|
1464
1665
|
def mark_call_pandoc(self):
|
|
@@ -1587,6 +1788,9 @@ class SyntaxTree:
|
|
|
1587
1788
|
|
|
1588
1789
|
body = "".join(child._render_latex(omit_envs, transparent_envs, progress=progress) for child in self.children)
|
|
1589
1790
|
|
|
1791
|
+
if env == "maketitle":
|
|
1792
|
+
return "\n\\maketitle"
|
|
1793
|
+
|
|
1590
1794
|
if env == "frame":
|
|
1591
1795
|
title = f"{{{self.title}}}" if self.title else ""
|
|
1592
1796
|
return f"\\begin{{frame}}[fragile]{title}\n{body}\\end{{frame}}\n"
|
|
@@ -35,6 +35,9 @@ DEFAULT_EXTENSIONS = [
|
|
|
35
35
|
]
|
|
36
36
|
|
|
37
37
|
HTML_EXTENSION_CONFIGS = {
|
|
38
|
+
"toc": {
|
|
39
|
+
"toc_depth": 2,
|
|
40
|
+
},
|
|
38
41
|
"pymdownx.arithmatex": {"generic": True},
|
|
39
42
|
"pymdownx.superfences": {
|
|
40
43
|
"custom_fences": [
|
|
@@ -91,10 +94,11 @@ def compile_latex(filename):
|
|
|
91
94
|
["lualatex", "-interaction=nonstopmode", filename.name],
|
|
92
95
|
cwd=filename.parent,
|
|
93
96
|
text=True,
|
|
94
|
-
|
|
95
|
-
stdout=subprocess.DEVNULL,
|
|
97
|
+
capture_output=True,
|
|
98
|
+
# stdout=subprocess.DEVNULL,
|
|
96
99
|
# stderr=subprocess.STDOUT,
|
|
97
100
|
)
|
|
101
|
+
|
|
98
102
|
if result.returncode != 0:
|
|
99
103
|
pdf = filename.with_suffix(".pdf")
|
|
100
104
|
if not pdf.exists():
|
|
@@ -157,9 +161,15 @@ def build_tree(text, *, omit_envs=(), number=False, render_latex_fences=True):
|
|
|
157
161
|
extension_configs=HTML_EXTENSION_CONFIGS if render_latex_fences else TEX_EXTENSION_CONFIGS,
|
|
158
162
|
)
|
|
159
163
|
tree.prune_envs(set(omit_envs))
|
|
164
|
+
|
|
165
|
+
for node in tree.walk():
|
|
166
|
+
if node.name == "exam":
|
|
167
|
+
node.number_questions()
|
|
168
|
+
|
|
160
169
|
if number:
|
|
161
170
|
tree.number_envs(DEFAULT_NUMBERED_ENVS)
|
|
162
171
|
tree.number_sections()
|
|
172
|
+
|
|
163
173
|
return tree
|
|
164
174
|
|
|
165
175
|
|
|
@@ -265,7 +275,11 @@ def convert_file(filename, output_directory, *,
|
|
|
265
275
|
# variant=version_str+"-base"
|
|
266
276
|
variant = version_str
|
|
267
277
|
|
|
268
|
-
output = tree.to_html(
|
|
278
|
+
output = tree.to_html(
|
|
279
|
+
title=title,
|
|
280
|
+
author=author,
|
|
281
|
+
date=date,
|
|
282
|
+
)
|
|
269
283
|
output_file = output_directory / f"{page_name}{variant}.html"
|
|
270
284
|
output_file.write_text(output, encoding="utf-8")
|
|
271
285
|
|
|
@@ -277,7 +291,11 @@ def convert_file(filename, output_directory, *,
|
|
|
277
291
|
|
|
278
292
|
variant=version_str+"-handout"
|
|
279
293
|
|
|
280
|
-
output = tree.to_html(
|
|
294
|
+
output = tree.to_html(
|
|
295
|
+
title=title,
|
|
296
|
+
author=author,
|
|
297
|
+
date=date,
|
|
298
|
+
)
|
|
281
299
|
output_file = output_directory / f"{page_name}{variant}.html"
|
|
282
300
|
output_file.write_text(output, encoding="utf-8")
|
|
283
301
|
|
|
@@ -286,7 +304,8 @@ def convert_file(filename, output_directory, *,
|
|
|
286
304
|
if revealjs:
|
|
287
305
|
tree = build_tree(text, number=True, render_latex_fences=True)
|
|
288
306
|
embed_local_images(tree, image_base)
|
|
289
|
-
variant=version_str+"-revealjs"
|
|
307
|
+
# variant=version_str+"-revealjs"
|
|
308
|
+
variant=version_str+"-slides"
|
|
290
309
|
|
|
291
310
|
output = tree.to_revealjs(title=title)
|
|
292
311
|
output_file = output_directory / f"{page_name}{variant}.html"
|
|
@@ -464,8 +483,8 @@ def main():
|
|
|
464
483
|
**options
|
|
465
484
|
)
|
|
466
485
|
# copy any generated PDFs back into the tex file directory.
|
|
467
|
-
for pdf in (p for p in generated if p.suffix == ".pdf"):
|
|
468
|
-
|
|
486
|
+
#for pdf in (p for p in generated if p.suffix == ".pdf"):
|
|
487
|
+
# shutil.copy2(pdf, tex_directory)
|
|
469
488
|
|
|
470
489
|
elif path.is_dir():
|
|
471
490
|
output_directory = path / ".publish_cache"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gradientgrove
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
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
|
|
@@ -55,7 +55,8 @@ PYTHONPATH=src python -m gradientgrove.markdown_ast --help
|
|
|
55
55
|
```
|
|
56
56
|
---
|
|
57
57
|
title : "My Document"
|
|
58
|
-
author:
|
|
58
|
+
author:
|
|
59
|
+
- Firstname Lastname
|
|
59
60
|
---
|
|
60
61
|
|
|
61
62
|
# Background
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/gradientgrove.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{gradientgrove-0.1.5.dev1 → gradientgrove-0.1.6}/src/gradientgrove.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|