markdown-exec 1.7.0__py3-none-any.whl → 1.8.1__py3-none-any.whl

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.
markdown_exec/__init__.py CHANGED
@@ -19,6 +19,7 @@ from markdown_exec.formatters.bash import _format_bash
19
19
  from markdown_exec.formatters.console import _format_console
20
20
  from markdown_exec.formatters.markdown import _format_markdown
21
21
  from markdown_exec.formatters.pycon import _format_pycon
22
+ from markdown_exec.formatters.pyodide import _format_pyodide
22
23
  from markdown_exec.formatters.python import _format_python
23
24
  from markdown_exec.formatters.sh import _format_sh
24
25
  from markdown_exec.formatters.tree import _format_tree
@@ -34,6 +35,7 @@ formatters = {
34
35
  "py": _format_python,
35
36
  "python": _format_python,
36
37
  "pycon": _format_pycon,
38
+ "pyodide": _format_pyodide,
37
39
  "sh": _format_sh,
38
40
  "tree": _format_tree,
39
41
  }
@@ -62,7 +64,7 @@ def validator(
62
64
  Success or not.
63
65
  """
64
66
  exec_value = _to_bool(inputs.pop("exec", "no"))
65
- if language != "tree" and not exec_value:
67
+ if language not in {"tree", "pyodide"} and not exec_value:
66
68
  return False
67
69
  id_value = inputs.pop("id", "")
68
70
  id_prefix_value = inputs.pop("idprefix", None)
markdown_exec/ansi.css CHANGED
@@ -15,49 +15,57 @@
15
15
 
16
16
  .-Color-Green,
17
17
  .-Color-Faint-Green,
18
- .-Color-Bold-Green {
18
+ .-Color-Bold-Green,
19
+ .-Color-BrightGreen {
19
20
  color: var(--ansi-green);
20
21
  }
21
22
 
22
23
  .-Color-Red,
23
24
  .-Color-Faint-Red,
24
- .-Color-Bold-Red {
25
+ .-Color-Bold-Red,
26
+ .-Color-BrightRed {
25
27
  color: var(--ansi-red);
26
28
  }
27
29
 
28
30
  .-Color-Yellow,
29
31
  .-Color-Faint-Yellow,
30
- .-Color-Bold-Yellow {
32
+ .-Color-Bold-Yellow,
33
+ .-Color-BrightYellow {
31
34
  color: var(--ansi-yellow);
32
35
  }
33
36
 
34
37
  .-Color-Blue,
35
38
  .-Color-Faint-Blue,
36
- .-Color-Bold-Blue {
39
+ .-Color-Bold-Blue,
40
+ .-Color-BrightBlue {
37
41
  color: var(--ansi-blue);
38
42
  }
39
43
 
40
44
  .-Color-Magenta,
41
45
  .-Color-Faint-Magenta,
42
- .-Color-Bold-Magenta {
46
+ .-Color-Bold-Magenta,
47
+ .-Color-BrightMagenta {
43
48
  color: var(--ansi-magenta);
44
49
  }
45
50
 
46
51
  .-Color-Cyan,
47
52
  .-Color-Faint-Cyan,
48
- .-Color-Bold-Cyan {
53
+ .-Color-Bold-Cyan,
54
+ .-Color-BrightCyan {
49
55
  color: var(--ansi-cyan);
50
56
  }
51
57
 
52
58
  .-Color-White,
53
59
  .-Color-Faint-White,
54
- .-Color-Bold-White {
60
+ .-Color-Bold-White,
61
+ .-Color-BrightWhite {
55
62
  color: var(--ansi-white);
56
63
  }
57
64
 
58
65
  .-Color-Black,
59
66
  .-Color-Faint-Black,
60
- .-Color-Bold-Black {
67
+ .-Color-Bold-Black,
68
+ .-Color-BrightBlack {
61
69
  color: var(--ansi-black);
62
70
  }
63
71
 
@@ -73,14 +81,23 @@
73
81
  .-Color-Black-BGBlack,
74
82
  .-Color-Blue-BGBlack,
75
83
  .-Color-Bold-BGBlack,
84
+ .-Color-BrightBGBlack,
76
85
  .-Color-Bold-Black-BGBlack,
86
+ .-Color-BrightBlack-BGBlack,
77
87
  .-Color-Bold-Green-BGBlack,
88
+ .-Color-BrightGreen-BGBlack,
78
89
  .-Color-Bold-Cyan-BGBlack,
90
+ .-Color-BrightCyan-BGBlack,
79
91
  .-Color-Bold-Blue-BGBlack,
92
+ .-Color-BrightBlue-BGBlack,
80
93
  .-Color-Bold-Magenta-BGBlack,
94
+ .-Color-BrightMagenta-BGBlack,
81
95
  .-Color-Bold-Red-BGBlack,
96
+ .-Color-BrightRed-BGBlack,
82
97
  .-Color-Bold-White-BGBlack,
98
+ .-Color-BrightWhite-BGBlack,
83
99
  .-Color-Bold-Yellow-BGBlack,
100
+ .-Color-BrightYellow-BGBlack,
84
101
  .-Color-Cyan-BGBlack,
85
102
  .-Color-Green-BGBlack,
86
103
  .-Color-Magenta-BGBlack,
@@ -94,14 +111,23 @@
94
111
  .-Color-Black-BGRed,
95
112
  .-Color-Blue-BGRed,
96
113
  .-Color-Bold-BGRed,
114
+ .-Color-BrightBGRed,
97
115
  .-Color-Bold-Black-BGRed,
116
+ .-Color-BrightBlack-BGRed,
98
117
  .-Color-Bold-Green-BGRed,
118
+ .-Color-BrightGreen-BGRed,
99
119
  .-Color-Bold-Cyan-BGRed,
120
+ .-Color-BrightCyan-BGRed,
100
121
  .-Color-Bold-Blue-BGRed,
122
+ .-Color-BrightBlue-BGRed,
101
123
  .-Color-Bold-Magenta-BGRed,
124
+ .-Color-BrightMagenta-BGRed,
102
125
  .-Color-Bold-Red-BGRed,
126
+ .-Color-BrightRed-BGRed,
103
127
  .-Color-Bold-White-BGRed,
128
+ .-Color-BrightWhite-BGRed,
104
129
  .-Color-Bold-Yellow-BGRed,
130
+ .-Color-BrightYellow-BGRed,
105
131
  .-Color-Cyan-BGRed,
106
132
  .-Color-Green-BGRed,
107
133
  .-Color-Magenta-BGRed,
@@ -115,14 +141,23 @@
115
141
  .-Color-Black-BGGreen,
116
142
  .-Color-Blue-BGGreen,
117
143
  .-Color-Bold-BGGreen,
144
+ .-Color-BrightBGGreen,
118
145
  .-Color-Bold-Black-BGGreen,
146
+ .-Color-BrightBlack-BGGreen,
119
147
  .-Color-Bold-Green-BGGreen,
148
+ .-Color-BrightGreen-BGGreen,
120
149
  .-Color-Bold-Cyan-BGGreen,
150
+ .-Color-BrightCyan-BGGreen,
121
151
  .-Color-Bold-Blue-BGGreen,
152
+ .-Color-BrightBlue-BGGreen,
122
153
  .-Color-Bold-Magenta-BGGreen,
154
+ .-Color-BrightMagenta-BGGreen,
123
155
  .-Color-Bold-Red-BGGreen,
156
+ .-Color-BrightRed-BGGreen,
124
157
  .-Color-Bold-White-BGGreen,
158
+ .-Color-BrightWhite-BGGreen,
125
159
  .-Color-Bold-Yellow-BGGreen,
160
+ .-Color-BrightYellow-BGGreen,
126
161
  .-Color-Cyan-BGGreen,
127
162
  .-Color-Green-BGGreen,
128
163
  .-Color-Magenta-BGGreen,
@@ -136,14 +171,23 @@
136
171
  .-Color-Black-BGYellow,
137
172
  .-Color-Blue-BGYellow,
138
173
  .-Color-Bold-BGYellow,
174
+ .-Color-BrightBGYellow,
139
175
  .-Color-Bold-Black-BGYellow,
176
+ .-Color-BrightBlack-BGYellow,
140
177
  .-Color-Bold-Green-BGYellow,
178
+ .-Color-BrightGreen-BGYellow,
141
179
  .-Color-Bold-Cyan-BGYellow,
180
+ .-Color-BrightCyan-BGYellow,
142
181
  .-Color-Bold-Blue-BGYellow,
182
+ .-Color-BrightBlue-BGYellow,
143
183
  .-Color-Bold-Magenta-BGYellow,
184
+ .-Color-BrightMagenta-BGYellow,
144
185
  .-Color-Bold-Red-BGYellow,
186
+ .-Color-BrightRed-BGYellow,
145
187
  .-Color-Bold-White-BGYellow,
188
+ .-Color-BrightWhite-BGYellow,
146
189
  .-Color-Bold-Yellow-BGYellow,
190
+ .-Color-BrightYellow-BGYellow,
147
191
  .-Color-Cyan-BGYellow,
148
192
  .-Color-Green-BGYellow,
149
193
  .-Color-Magenta-BGYellow,
@@ -157,14 +201,23 @@
157
201
  .-Color-Black-BGBlue,
158
202
  .-Color-Blue-BGBlue,
159
203
  .-Color-Bold-BGBlue,
204
+ .-Color-BrightBGBlue,
160
205
  .-Color-Bold-Black-BGBlue,
206
+ .-Color-BrightBlack-BGBlue,
161
207
  .-Color-Bold-Green-BGBlue,
208
+ .-Color-BrightGreen-BGBlue,
162
209
  .-Color-Bold-Cyan-BGBlue,
210
+ .-Color-BrightCyan-BGBlue,
163
211
  .-Color-Bold-Blue-BGBlue,
212
+ .-Color-BrightBlue-BGBlue,
164
213
  .-Color-Bold-Magenta-BGBlue,
214
+ .-Color-BrightMagenta-BGBlue,
165
215
  .-Color-Bold-Red-BGBlue,
216
+ .-Color-BrightRed-BGBlue,
166
217
  .-Color-Bold-White-BGBlue,
218
+ .-Color-BrightWhite-BGBlue,
167
219
  .-Color-Bold-Yellow-BGBlue,
220
+ .-Color-BrightYellow-BGBlue,
168
221
  .-Color-Cyan-BGBlue,
169
222
  .-Color-Green-BGBlue,
170
223
  .-Color-Magenta-BGBlue,
@@ -178,14 +231,23 @@
178
231
  .-Color-Black-BGMagenta,
179
232
  .-Color-Blue-BGMagenta,
180
233
  .-Color-Bold-BGMagenta,
234
+ .-Color-BrightBGMagenta,
181
235
  .-Color-Bold-Black-BGMagenta,
236
+ .-Color-BrightBlack-BGMagenta,
182
237
  .-Color-Bold-Green-BGMagenta,
238
+ .-Color-BrightGreen-BGMagenta,
183
239
  .-Color-Bold-Cyan-BGMagenta,
240
+ .-Color-BrightCyan-BGMagenta,
184
241
  .-Color-Bold-Blue-BGMagenta,
242
+ .-Color-BrightBlue-BGMagenta,
185
243
  .-Color-Bold-Magenta-BGMagenta,
244
+ .-Color-BrightMagenta-BGMagenta,
186
245
  .-Color-Bold-Red-BGMagenta,
246
+ .-Color-BrightRed-BGMagenta,
187
247
  .-Color-Bold-White-BGMagenta,
248
+ .-Color-BrightWhite-BGMagenta,
188
249
  .-Color-Bold-Yellow-BGMagenta,
250
+ .-Color-BrightYellow-BGMagenta,
189
251
  .-Color-Cyan-BGMagenta,
190
252
  .-Color-Green-BGMagenta,
191
253
  .-Color-Magenta-BGMagenta,
@@ -199,14 +261,23 @@
199
261
  .-Color-Black-BGCyan,
200
262
  .-Color-Blue-BGCyan,
201
263
  .-Color-Bold-BGCyan,
264
+ .-Color-BrightBGCyan,
202
265
  .-Color-Bold-Black-BGCyan,
266
+ .-Color-BrightBlack-BGCyan,
203
267
  .-Color-Bold-Green-BGCyan,
268
+ .-Color-BrightGreen-BGCyan,
204
269
  .-Color-Bold-Cyan-BGCyan,
270
+ .-Color-BrightCyan-BGCyan,
205
271
  .-Color-Bold-Blue-BGCyan,
272
+ .-Color-BrightBlue-BGCyan,
206
273
  .-Color-Bold-Magenta-BGCyan,
274
+ .-Color-BrightMagenta-BGCyan,
207
275
  .-Color-Bold-Red-BGCyan,
276
+ .-Color-BrightRed-BGCyan,
208
277
  .-Color-Bold-White-BGCyan,
278
+ .-Color-BrightWhite-BGCyan,
209
279
  .-Color-Bold-Yellow-BGCyan,
280
+ .-Color-BrightYellow-BGCyan,
210
281
  .-Color-Cyan-BGCyan,
211
282
  .-Color-Green-BGCyan,
212
283
  .-Color-Magenta-BGCyan,
@@ -220,14 +291,23 @@
220
291
  .-Color-Black-BGWhite,
221
292
  .-Color-Blue-BGWhite,
222
293
  .-Color-Bold-BGWhite,
294
+ .-Color-BrightBGWhite,
223
295
  .-Color-Bold-Black-BGWhite,
296
+ .-Color-BrightBlack-BGWhite,
224
297
  .-Color-Bold-Green-BGWhite,
298
+ .-Color-BrightGreen-BGWhite,
225
299
  .-Color-Bold-Cyan-BGWhite,
300
+ .-Color-BrightCyan-BGWhite,
226
301
  .-Color-Bold-Blue-BGWhite,
302
+ .-Color-BrightBlue-BGWhite,
227
303
  .-Color-Bold-Magenta-BGWhite,
304
+ .-Color-BrightMagenta-BGWhite,
228
305
  .-Color-Bold-Red-BGWhite,
306
+ .-Color-BrightRed-BGWhite,
229
307
  .-Color-Bold-White-BGWhite,
308
+ .-Color-BrightWhite-BGWhite,
230
309
  .-Color-Bold-Yellow-BGWhite,
310
+ .-Color-BrightYellow-BGWhite,
231
311
  .-Color-Cyan-BGWhite,
232
312
  .-Color-Green-BGWhite,
233
313
  .-Color-Magenta-BGWhite,
@@ -239,21 +319,30 @@
239
319
 
240
320
  .-Color-Black,
241
321
  .-Color-Bold-Black,
322
+ .-Color-BrightBlack,
242
323
  .-Color-Black-BGBlack,
243
324
  .-Color-Bold-Black-BGBlack,
325
+ .-Color-BrightBlack-BGBlack,
244
326
  .-Color-Black-BGGreen,
245
327
  .-Color-Red-BGRed,
246
328
  .-Color-Bold-Red-BGRed,
329
+ .-Color-BrightRed-BGRed,
247
330
  .-Color-Bold-Blue-BGBlue,
331
+ .-Color-BrightBlue-BGBlue,
248
332
  .-Color-Blue-BGBlue {
249
333
  text-shadow: 0 0 1px var(--ansi-white);
250
334
  }
251
335
 
252
336
  .-Color-Bold-Cyan-BGCyan,
337
+ .-Color-BrightCyan-BGCyan,
253
338
  .-Color-Bold-Magenta-BGMagenta,
339
+ .-Color-BrightMagenta-BGMagenta,
254
340
  .-Color-Bold-White,
341
+ .-Color-BrightWhite,
255
342
  .-Color-Bold-Yellow-BGYellow,
343
+ .-Color-BrightYellow-BGYellow,
256
344
  .-Color-Bold-Green-BGGreen,
345
+ .-Color-BrightGreen-BGGreen,
257
346
  .-Color-Cyan-BGCyan,
258
347
  .-Color-Cyan-BGGreen,
259
348
  .-Color-Green-BGCyan,
markdown_exec/debug.py CHANGED
@@ -37,6 +37,8 @@ class Environment:
37
37
  """Python interpreter name."""
38
38
  interpreter_version: str
39
39
  """Python interpreter version."""
40
+ interpreter_path: str
41
+ """Path to Python executable."""
40
42
  platform: str
41
43
  """Operating System."""
42
44
  packages: list[Package]
@@ -83,6 +85,7 @@ def get_debug_info() -> Environment:
83
85
  return Environment(
84
86
  interpreter_name=py_name,
85
87
  interpreter_version=py_version,
88
+ interpreter_path=sys.executable,
86
89
  platform=platform.platform(),
87
90
  variables=[Variable(var, val) for var in variables if (val := os.getenv(var))],
88
91
  packages=[Package(pkg, get_version(pkg)) for pkg in packages],
@@ -93,7 +96,7 @@ def print_debug_info() -> None:
93
96
  """Print debug/environment information."""
94
97
  info = get_debug_info()
95
98
  print(f"- __System__: {info.platform}")
96
- print(f"- __Python__: {info.interpreter_name} {info.interpreter_version}")
99
+ print(f"- __Python__: {info.interpreter_name} {info.interpreter_version} ({info.interpreter_path})")
97
100
  print("- __Environment variables__:")
98
101
  for var in info.variables:
99
102
  print(f" - `{var.name}`: `{var.value}`")
@@ -0,0 +1,60 @@
1
+ """Formatter for creating a Pyodide interactive editor."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ if TYPE_CHECKING:
8
+ from markdown import Markdown
9
+
10
+ play_emoji = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8 5.14v14l11-7-11-7Z"></path></svg>'
11
+ clear_emoji = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.14 3c-.51 0-1.02.2-1.41.59L2.59 14.73c-.78.77-.78 2.04 0 2.83L5.03 20h7.66l8.72-8.73c.79-.77.79-2.04 0-2.83l-4.85-4.85c-.39-.39-.91-.59-1.42-.59M17 18l-2 2h7v-2"></path></svg>'
12
+
13
+ template = """
14
+ <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.16.0/ace.js"></script>
15
+ <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
16
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/pyodide/v0.23.0/full/pyodide.js"></script>
17
+ <link title="light" rel="alternate stylesheet" href="https://cdn.jsdelivr.net/npm/highlightjs-themes@1.0.0/tomorrow.min.css" disabled="disabled">
18
+ <link title="dark" rel="alternate stylesheet" href="https://cdn.jsdelivr.net/npm/highlightjs-themes@1.0.0/tomorrow-night-blue.min.css" disabled="disabled">
19
+
20
+ <div class="pyodide">
21
+ <div class="pyodide-editor-bar">
22
+ <span class="pyodide-bar-item">Editor (session: %(session)s)</span><span id="%(id_prefix)srun" title="Run: press Ctrl-Enter" class="pyodide-bar-item pyodide-clickable"><span class="twemoji">%(play_emoji)s</span> Run</span>
23
+ </div>
24
+ <div><pre id="%(id_prefix)seditor" class="pyodide-editor">%(initial_code)s</pre></div>
25
+ <div class="pyodide-editor-bar">
26
+ <span class="pyodide-bar-item">Output</span><span id="%(id_prefix)sclear" class="pyodide-bar-item pyodide-clickable"><span class="twemoji">%(clear_emoji)s</span> Clear</span>
27
+ </div>
28
+ <pre><code id="%(id_prefix)soutput" class="pyodide-output"></code></pre>
29
+ </div>
30
+
31
+ <script>
32
+ document.addEventListener('DOMContentLoaded', (event) => {
33
+ setupPyodide('%(id_prefix)s', install=%(install)s, themeLight='%(theme_light)s', themeDark='%(theme_dark)s', session='%(session)s');
34
+ });
35
+ </script>
36
+ """
37
+
38
+ _counter = 0
39
+
40
+
41
+ def _format_pyodide(code: str, md: Markdown, session: str, extra: dict, **options: Any) -> str: # noqa: ARG001
42
+ global _counter # noqa: PLW0603
43
+ _counter += 1
44
+ install = extra.pop("install", "")
45
+ install = install.split(",") if install else []
46
+ theme = extra.pop("theme", "tomorrow,tomorrow_night")
47
+ if "," not in theme:
48
+ theme = f"{theme},{theme}"
49
+ theme_light, theme_dark = theme.split(",")
50
+ data = {
51
+ "id_prefix": f"exec-{_counter}--",
52
+ "initial_code": code,
53
+ "install": install,
54
+ "theme_light": theme_light.strip(),
55
+ "theme_dark": theme_dark.strip(),
56
+ "session": session or "default",
57
+ "play_emoji": play_emoji,
58
+ "clear_emoji": clear_emoji,
59
+ }
60
+ return template % data
@@ -8,6 +8,7 @@ from pathlib import Path
8
8
  from typing import TYPE_CHECKING, Any, MutableMapping
9
9
 
10
10
  from mkdocs.config import config_options
11
+ from mkdocs.config.base import Config
11
12
  from mkdocs.plugins import BasePlugin
12
13
  from mkdocs.utils import write_file
13
14
 
@@ -45,10 +46,20 @@ def _get_logger(name: str) -> _LoggerAdapter:
45
46
  patch_loggers(_get_logger)
46
47
 
47
48
 
48
- class MarkdownExecPlugin(BasePlugin):
49
- """MkDocs plugin to easily enable custom fences for code blocks execution."""
49
+ class MarkdownExecPluginConfig(Config):
50
+ """Configuration of the plugin (for `mkdocs.yml`)."""
51
+
52
+ ansi = config_options.Choice(("auto", "off", "required", True, False), default="auto")
53
+ """Whether the `ansi` extra is required when installing the package."""
54
+ languages = config_options.ListOfItems(
55
+ config_options.Choice(formatters.keys()),
56
+ default=list(formatters.keys()),
57
+ )
58
+ """Which languages to enabled the extension for."""
50
59
 
51
- config_scheme = (("languages", config_options.Type(list, default=list(formatters.keys()))),)
60
+
61
+ class MarkdownExecPlugin(BasePlugin[MarkdownExecPluginConfig]):
62
+ """MkDocs plugin to easily enable custom fences for code blocks execution."""
52
63
 
53
64
  def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None:
54
65
  """Configure the plugin.
@@ -67,7 +78,7 @@ class MarkdownExecPlugin(BasePlugin):
67
78
  """
68
79
  self.mkdocs_config_dir = os.getenv("MKDOCS_CONFIG_DIR")
69
80
  os.environ["MKDOCS_CONFIG_DIR"] = os.path.dirname(config["config_file_path"])
70
- self.languages = self.config["languages"]
81
+ self.languages = self.config.languages
71
82
  mdx_configs = config.setdefault("mdx_configs", {})
72
83
  superfences = mdx_configs.setdefault("pymdownx.superfences", {})
73
84
  custom_fences = superfences.setdefault("custom_fences", [])
@@ -80,7 +91,7 @@ class MarkdownExecPlugin(BasePlugin):
80
91
  "format": formatter,
81
92
  },
82
93
  )
83
- markdown_config.save(config["markdown_extensions"], config["mdx_configs"])
94
+ markdown_config.save(config.markdown_extensions, config.mdx_configs)
84
95
  return config
85
96
 
86
97
  def on_env( # noqa: D102
@@ -90,10 +101,11 @@ class MarkdownExecPlugin(BasePlugin):
90
101
  config: MkDocsConfig,
91
102
  files: Files, # noqa: ARG002
92
103
  ) -> Environment | None:
93
- css_filename = "assets/_markdown_exec_ansi.css"
94
- css_content = Path(__file__).parent.joinpath("ansi.css").read_text()
95
- write_file(css_content.encode("utf-8"), os.path.join(config["site_dir"], css_filename))
96
- config["extra_css"].insert(0, css_filename)
104
+ if self.config.ansi in ("required", True) or (self.config.ansi == "auto" and ansi_ok):
105
+ self._add_css(config, "ansi.css")
106
+ if "pyodide" in self.languages:
107
+ self._add_css(config, "pyodide.css")
108
+ self._add_js(config, "pyodide.js")
97
109
  return env
98
110
 
99
111
  def on_post_build(self, *, config: MkDocsConfig) -> None: # noqa: ARG002,D102
@@ -103,3 +115,15 @@ class MarkdownExecPlugin(BasePlugin):
103
115
  os.environ.pop("MKDOCS_CONFIG_DIR", None)
104
116
  else:
105
117
  os.environ["MKDOCS_CONFIG_DIR"] = self.mkdocs_config_dir
118
+
119
+ def _add_asset(self, config: MkDocsConfig, asset_file: str, asset_type: str) -> None:
120
+ asset_filename = f"assets/_markdown_exec_{asset_file}"
121
+ asset_content = Path(__file__).parent.joinpath(asset_file).read_text()
122
+ write_file(asset_content.encode("utf-8"), os.path.join(config.site_dir, asset_filename))
123
+ config[f"extra_{asset_type}"].insert(0, asset_filename)
124
+
125
+ def _add_css(self, config: MkDocsConfig, css_file: str) -> None:
126
+ self._add_asset(config, css_file, "css")
127
+
128
+ def _add_js(self, config: MkDocsConfig, js_file: str) -> None:
129
+ self._add_asset(config, js_file, "javascript")
@@ -64,7 +64,7 @@ class HeadingReportingTreeprocessor(Treeprocessor):
64
64
  el = copy.copy(el) # noqa: PLW2901
65
65
  # 'toc' extension's first pass (which we require to build heading stubs/ids) also edits the HTML.
66
66
  # Undo the permalink edit so we can pass this heading to the outer pass of the 'toc' extension.
67
- if len(el) > 0 and el[-1].get("class") == self.md.treeprocessors["toc"].permalink_class:
67
+ if len(el) > 0 and el[-1].get("class") == self.md.treeprocessors["toc"].permalink_class: # type: ignore[attr-defined]
68
68
  del el[-1]
69
69
  self.headings.append(el)
70
70
 
@@ -0,0 +1,49 @@
1
+ html[data-theme="light"] {
2
+ @import "https://cdn.jsdelivr.net/npm/highlightjs-themes@1.0.0/tomorrow.css"
3
+ }
4
+
5
+ html[data-theme="dark"] {
6
+ @import "https://cdn.jsdelivr.net/npm/highlightjs-themes@1.0.0/tomorrow-night-blue.min.css"
7
+ }
8
+
9
+
10
+ .ace_gutter {
11
+ z-index: 1;
12
+ }
13
+
14
+ .pyodide-editor {
15
+ width: 100%;
16
+ min-height: 200px;
17
+ max-height: 400px;
18
+ font-size: .85em;
19
+ }
20
+
21
+ .pyodide-editor-bar {
22
+ color: var(--md-primary-bg-color);
23
+ background-color: var(--md-primary-fg-color);
24
+ width: 100%;
25
+ font: monospace;
26
+ font-size: 0.75em;
27
+ padding: 2px 0 2px;
28
+ }
29
+
30
+ .pyodide-bar-item {
31
+ padding: 0 18px 0;
32
+ display: inline-block;
33
+ width: 50%;
34
+ }
35
+
36
+ .pyodide pre {
37
+ margin: 0;
38
+ }
39
+
40
+ .pyodide-output {
41
+ width: 100%;
42
+ margin-bottom: -15px;
43
+ max-height: 400px
44
+ }
45
+
46
+ .pyodide-clickable {
47
+ cursor: pointer;
48
+ text-align: right;
49
+ }
@@ -0,0 +1,109 @@
1
+ var _sessions = {};
2
+
3
+ function getSession(name, pyodide) {
4
+ if (!(name in _sessions)) {
5
+ _sessions[name] = pyodide.globals.get("dict")();
6
+ }
7
+ return _sessions[name];
8
+ }
9
+
10
+ function writeOutput(element, string) {
11
+ element.innerHTML += string + '\n';
12
+ }
13
+
14
+ function clearOutput(element) {
15
+ element.innerHTML = '';
16
+ }
17
+
18
+ async function evaluatePython(pyodide, editor, output, session) {
19
+ pyodide.setStdout({ batched: (string) => { writeOutput(output, string); } });
20
+ let result, code = editor.getValue();
21
+ clearOutput(output);
22
+ try {
23
+ result = await pyodide.runPythonAsync(code, { globals: getSession(session, pyodide) });
24
+ } catch (error) {
25
+ writeOutput(output, error);
26
+ }
27
+ if (result) writeOutput(output, result);
28
+ hljs.highlightElement(output);
29
+ }
30
+
31
+ async function initPyodide() {
32
+ try {
33
+ let pyodide = await loadPyodide();
34
+ await pyodide.loadPackage("micropip");
35
+ return pyodide;
36
+ } catch(error) {
37
+ return null;
38
+ }
39
+ }
40
+
41
+ function getTheme() {
42
+ return document.body.getAttribute('data-md-color-scheme');
43
+ }
44
+
45
+ function setTheme(editor, currentTheme, light, dark) {
46
+ // https://gist.github.com/RyanNutt/cb8d60997d97905f0b2aea6c3b5c8ee0
47
+ if (currentTheme === "default") {
48
+ editor.setTheme("ace/theme/" + light);
49
+ document.querySelector(`link[title="light"]`).removeAttribute("disabled");
50
+ document.querySelector(`link[title="dark"]`).setAttribute("disabled", "disabled");
51
+ } else if (currentTheme === "slate") {
52
+ editor.setTheme("ace/theme/" + dark);
53
+ document.querySelector(`link[title="dark"]`).removeAttribute("disabled");
54
+ document.querySelector(`link[title="light"]`).setAttribute("disabled", "disabled");
55
+ }
56
+ }
57
+
58
+ function updateTheme(editor, light, dark) {
59
+ // Create a new MutationObserver instance
60
+ const observer = new MutationObserver((mutations) => {
61
+ // Loop through the mutations that occurred
62
+ mutations.forEach((mutation) => {
63
+ // Check if the mutation was a change to the data-md-color-scheme attribute
64
+ if (mutation.attributeName === 'data-md-color-scheme') {
65
+ // Get the new value of the attribute
66
+ const newColorScheme = mutation.target.getAttribute('data-md-color-scheme');
67
+ // Update the editor theme
68
+ setTheme(editor, newColorScheme, light, dark);
69
+ }
70
+ });
71
+ });
72
+
73
+ // Configure the observer to watch for changes to the data-md-color-scheme attribute
74
+ observer.observe(document.body, {
75
+ attributes: true,
76
+ attributeFilter: ['data-md-color-scheme'],
77
+ });
78
+ }
79
+
80
+ async function setupPyodide(idPrefix, install = null, themeLight = 'tomorrow', themeDark = 'tomorrow_night', session = null) {
81
+ const editor = ace.edit(idPrefix + "editor");
82
+ const run = document.getElementById(idPrefix + "run");
83
+ const clear = document.getElementById(idPrefix + "clear");
84
+ const output = document.getElementById(idPrefix + "output");
85
+
86
+ updateTheme(editor, themeLight, themeDark);
87
+
88
+ editor.session.setMode("ace/mode/python");
89
+ setTheme(editor, getTheme(), themeLight, themeDark);
90
+
91
+ writeOutput(output, "Initializing...");
92
+ let pyodide = await pyodidePromise;
93
+ if (install && install.length) {
94
+ micropip = pyodide.pyimport("micropip");
95
+ for (const package of install)
96
+ await micropip.install(package);
97
+ }
98
+ clearOutput(output);
99
+ run.onclick = () => evaluatePython(pyodide, editor, output, session);
100
+ clear.onclick = () => clearOutput(output);
101
+ output.parentElement.parentElement.addEventListener("keydown", (event) => {
102
+ if (event.ctrlKey && event.key.toLowerCase() === 'enter') {
103
+ event.preventDefault();
104
+ run.click();
105
+ }
106
+ });
107
+ }
108
+
109
+ var pyodidePromise = initPyodide();
@@ -123,10 +123,10 @@ class MarkdownConfig:
123
123
  return cls._singleton
124
124
 
125
125
  def __init__(self) -> None: # noqa: D107
126
- self.exts: list[str | Extension] | None = None
126
+ self.exts: list[str] | None = None
127
127
  self.exts_config: dict[str, dict[str, Any]] | None = None
128
128
 
129
- def save(self, exts: list[str | Extension], exts_config: dict[str, dict[str, Any]]) -> None:
129
+ def save(self, exts: list[str], exts_config: dict[str, dict[str, Any]]) -> None:
130
130
  """Save Markdown extensions and their configuration.
131
131
 
132
132
  Parameters:
@@ -221,11 +221,11 @@ def _mimic(md: Markdown, headings: list[Element], *, update_toc: bool = True) ->
221
221
  def _id_prefix(md: Markdown, prefix: str | None) -> Iterator[None]:
222
222
  MarkdownConverter.counter += 1
223
223
  id_prepending_processor = md.treeprocessors[IdPrependingTreeprocessor.name]
224
- id_prepending_processor.id_prefix = prefix if prefix is not None else f"exec-{MarkdownConverter.counter}--"
224
+ id_prepending_processor.id_prefix = prefix if prefix is not None else f"exec-{MarkdownConverter.counter}--" # type: ignore[attr-defined]
225
225
  try:
226
226
  yield
227
227
  finally:
228
- id_prepending_processor.id_prefix = ""
228
+ id_prepending_processor.id_prefix = "" # type: ignore[attr-defined]
229
229
 
230
230
 
231
231
  class MarkdownConverter:
@@ -243,7 +243,7 @@ class MarkdownConverter:
243
243
  return getattr(self._md_ref, "_original_md", self._md_ref)
244
244
 
245
245
  def _report_headings(self, markup: Markup) -> None:
246
- self._original_md.treeprocessors[InsertHeadings.name].headings[markup] = self._headings
246
+ self._original_md.treeprocessors[InsertHeadings.name].headings[markup] = self._headings # type: ignore[attr-defined]
247
247
  self._headings = []
248
248
 
249
249
  def convert(self, text: str, stash: dict[str, str] | None = None, id_prefix: str | None = None) -> Markup:
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: markdown-exec
3
- Version: 1.7.0
3
+ Version: 1.8.1
4
4
  Summary: Utilities to execute code blocks in Markdown files.
5
- Keywords: markdown python exec shell bash mkdocs
6
- Author-Email: Timothée Mazzucotelli <pawamoy@pm.me>
5
+ Keywords: markdown,python,exec,shell,bash,mkdocs
6
+ Author-Email: =?utf-8?q?Timoth=C3=A9e_Mazzucotelli?= <dev@pawamoy.fr>
7
7
  License: ISC
8
8
  Classifier: Development Status :: 4 - Beta
9
9
  Classifier: Intended Audience :: Developers
@@ -39,7 +39,7 @@ Description-Content-Type: text/markdown
39
39
  [![documentation](https://img.shields.io/badge/docs-mkdocs%20material-blue.svg?style=flat)](https://pawamoy.github.io/markdown-exec/)
40
40
  [![pypi version](https://img.shields.io/pypi/v/markdown-exec.svg)](https://pypi.org/project/markdown-exec/)
41
41
  [![gitpod](https://img.shields.io/badge/gitpod-workspace-blue.svg?style=flat)](https://gitpod.io/#https://github.com/pawamoy/markdown-exec)
42
- [![gitter](https://badges.gitter.im/join%20chat.svg)](https://gitter.im/markdown-exec/community)
42
+ [![gitter](https://badges.gitter.im/join%20chat.svg)](https://app.gitter.im/#/room/#markdown-exec:gitter.im)
43
43
 
44
44
  Utilities to execute code blocks in Markdown files.
45
45
 
@@ -0,0 +1,25 @@
1
+ markdown_exec-1.8.1.dist-info/METADATA,sha256=WGMAd07fW9tcSzIt6U4P_bUJL1B7CtF0LJeXTmxe4p8,4954
2
+ markdown_exec-1.8.1.dist-info/WHEEL,sha256=gZRWN_1fGFDwBnXrZ9N3dgvbKlKgo5AUcDIMajlGpKM,90
3
+ markdown_exec-1.8.1.dist-info/entry_points.txt,sha256=W-JWRoZzS5TXRcyVnxYmsaVBV4HSl7B_7uTgtaZ-Pms,81
4
+ markdown_exec-1.8.1.dist-info/licenses/LICENSE,sha256=eZQBcJKqlN0QepmOi0u09hlqKMPFdzWjY6NUWYeJGZs,754
5
+ markdown_exec/__init__.py,sha256=cdQDNiSeWnQ8NK3hqNOfyxKT8uoxLkKm4VI_8E7ztcM,4366
6
+ markdown_exec/ansi.css,sha256=6PTJxTSsExVgPbMySCuKjih0gr-fdfx2aZ9--u7zWf0,8090
7
+ markdown_exec/debug.py,sha256=dy0bTd9mTTyTaWuUGNkH0UUdMp2ZThsmGh5q9wt9O0c,2840
8
+ markdown_exec/formatters/__init__.py,sha256=w8ui1JaGUA5SCyWd2pPAAopQ5y6QYtDvOUHUa7KW2Wg,51
9
+ markdown_exec/formatters/base.py,sha256=frtAFV1mxi0JMmgESrbmLk5XD-MMAgc6SrmpwLcS3gQ,4761
10
+ markdown_exec/formatters/bash.py,sha256=qVn6nPqitUuFX72ll00w_x343zl_bMuXrr-Xyox4dJY,886
11
+ markdown_exec/formatters/console.py,sha256=D2JBIC4MU0ct2MiRCkBO-qo4MiH6Hjy6LXjYAsRmuRA,815
12
+ markdown_exec/formatters/markdown.py,sha256=pd0akvFGUXrc41NABcHUTTkKFA3k5Ju8im-b3kzOvIw,276
13
+ markdown_exec/formatters/pycon.py,sha256=F9xpSRKFWsVpGu5XXybtCkMMJ_PAfyd48Qqo1SWl6RA,854
14
+ markdown_exec/formatters/pyodide.py,sha256=fsAkEq9cgI_-AipV4tS4iXbaOcqQVi-HjJ-VcfMv6aE,2898
15
+ markdown_exec/formatters/python.py,sha256=57OTm36fKxcskELcJHy9sf3rrusYb5zQmP01YMbQgPY,2406
16
+ markdown_exec/formatters/sh.py,sha256=41kmwFjkyisWYmfJeBMC40kqhEe7sI2E0vvbO9ixjCg,876
17
+ markdown_exec/formatters/tree.py,sha256=4XU1KaNqChkkNxMYanwy6glTE2uwcY8Mz9jBZiIf3zY,2046
18
+ markdown_exec/logger.py,sha256=e06Ih9EonG3KCAPbwraCEYmS0Nt9yRytyMjVJMAREIQ,2109
19
+ markdown_exec/mkdocs_plugin.py,sha256=Bc18zHDQ3b4Q6gvIk2JMTHHebfXQF9z8v5Ox0xt6ReM,4701
20
+ markdown_exec/processors.py,sha256=oRZ6QGEm9V2UfqQij5W4Ygp2vZE8MuY-5nDwoPKrE1w,4291
21
+ markdown_exec/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ markdown_exec/pyodide.css,sha256=rJ-HW-ymcgUfrZ9Mm6QB1qo6eE-I3YQcqSxTmG1NhvM,849
23
+ markdown_exec/pyodide.js,sha256=6iL-9xA4b9UeZgsxVYq_BiCE-Bwu58NfYwYCzz9C9j0,3845
24
+ markdown_exec/rendering.py,sha256=ssWg6U-7Ez45N6sLak-oGD2e55qtEkPY8T8l7h1RbDM,9459
25
+ markdown_exec-1.8.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: pdm-backend (2.1.7)
2
+ Generator: pdm-backend (2.2.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,22 +0,0 @@
1
- markdown_exec-1.7.0.dist-info/METADATA,sha256=hTREwfyiDB91wNHNAyduJAx-2gksSPVoG2bQK6yhRgQ,4925
2
- markdown_exec-1.7.0.dist-info/WHEEL,sha256=C8f_gqhOWmHrh81n3Ukx5iURrqMhsHla81fuY1yuwvs,90
3
- markdown_exec-1.7.0.dist-info/entry_points.txt,sha256=W-JWRoZzS5TXRcyVnxYmsaVBV4HSl7B_7uTgtaZ-Pms,81
4
- markdown_exec-1.7.0.dist-info/licenses/LICENSE,sha256=eZQBcJKqlN0QepmOi0u09hlqKMPFdzWjY6NUWYeJGZs,754
5
- markdown_exec/__init__.py,sha256=nhknYUBhlofzE7_F7N3brXU69YgI_04kueND2O0MX7w,4256
6
- markdown_exec/ansi.css,sha256=o0G4eo43wBikw5TaKbgTszxe1WEcHXAJCcYGlpvs1ZM,5657
7
- markdown_exec/debug.py,sha256=mX_HjANf2x_X078kPwSMeq0Go_LO8eexe7ZZdzMo6-I,2710
8
- markdown_exec/formatters/__init__.py,sha256=w8ui1JaGUA5SCyWd2pPAAopQ5y6QYtDvOUHUa7KW2Wg,51
9
- markdown_exec/formatters/base.py,sha256=frtAFV1mxi0JMmgESrbmLk5XD-MMAgc6SrmpwLcS3gQ,4761
10
- markdown_exec/formatters/bash.py,sha256=qVn6nPqitUuFX72ll00w_x343zl_bMuXrr-Xyox4dJY,886
11
- markdown_exec/formatters/console.py,sha256=D2JBIC4MU0ct2MiRCkBO-qo4MiH6Hjy6LXjYAsRmuRA,815
12
- markdown_exec/formatters/markdown.py,sha256=pd0akvFGUXrc41NABcHUTTkKFA3k5Ju8im-b3kzOvIw,276
13
- markdown_exec/formatters/pycon.py,sha256=F9xpSRKFWsVpGu5XXybtCkMMJ_PAfyd48Qqo1SWl6RA,854
14
- markdown_exec/formatters/python.py,sha256=57OTm36fKxcskELcJHy9sf3rrusYb5zQmP01YMbQgPY,2406
15
- markdown_exec/formatters/sh.py,sha256=41kmwFjkyisWYmfJeBMC40kqhEe7sI2E0vvbO9ixjCg,876
16
- markdown_exec/formatters/tree.py,sha256=4XU1KaNqChkkNxMYanwy6glTE2uwcY8Mz9jBZiIf3zY,2046
17
- markdown_exec/logger.py,sha256=e06Ih9EonG3KCAPbwraCEYmS0Nt9yRytyMjVJMAREIQ,2109
18
- markdown_exec/mkdocs_plugin.py,sha256=_b2EhmsJZGPrtDSexWgnOmrwH8cu-KsO2teXD8CdLpk,3647
19
- markdown_exec/processors.py,sha256=z2zy1rbK9huIG2rRL-5ue5GMyc_qhlxl19dHDor6acI,4261
20
- markdown_exec/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- markdown_exec/rendering.py,sha256=nGaJ0fRtk7XpOYs5XMf6vT5qxeAMsjggPCUsjImDO24,9393
22
- markdown_exec-1.7.0.dist-info/RECORD,,