Skip to content

Commit c64a2ef

Browse files
jayantpranjal0Jayantpawamoy
authored
feat: Add option to set height of Pyodide/Ace editors
This change also allows the editor to shrink and grow as users type. Issue-41: #41 Co-authored-by: Jayant <[email protected]> Co-authored-by: Timothée Mazzucotelli <[email protected]>
1 parent d64fe2e commit c64a2ef

File tree

4 files changed

+94
-4
lines changed

4 files changed

+94
-4
lines changed

docs/usage/pyodide.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,56 @@ print("Hello.")
4545

4646
NOTE: **All Pyodide blocks on the same page should use the same version!**
4747

48+
## Editor height
49+
50+
The height of the editor can be configured with the `height` option. It accepts the following values:
51+
52+
- `0` or `auto`: A fixed number of lines, based on initial code.
53+
- a positive number, like `10`: A fixed number of lines.
54+
- a positive range, like `5-30`: The minimum and maximum number of lines. The editor will shring/grow as you type.
55+
56+
The default is `auto`.
57+
58+
A few examples:
59+
60+
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered" title="Fixed height (10 lines)"
61+
```pyodide height="10"
62+
from typing import Iterator
63+
64+
# This is an example
65+
class Math:
66+
@staticmethod
67+
def fib(n: int) -> Iterator[int]:
68+
"""Fibonacci series up to n."""
69+
a, b = 0, 1
70+
while a < n:
71+
yield a
72+
a, b = b, a + b
73+
74+
result = sum(Math.fib(42))
75+
print(f"The answer is {result}")
76+
```
77+
````
78+
79+
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered" title="Between 1 and 40 lines"
80+
```pyodide height="1-40"
81+
from typing import Iterator
82+
83+
# This is an example
84+
class Math:
85+
@staticmethod
86+
def fib(n: int) -> Iterator[int]:
87+
"""Fibonacci series up to n."""
88+
a, b = 0, 1
89+
while a < n:
90+
yield a
91+
a, b = b, a + b
92+
93+
result = sum(Math.fib(42))
94+
print(f"The answer is {result}")
95+
```
96+
````
97+
4898
## Sessions
4999

50100
Editors with the same session share the same `globals()` dictionary,

src/markdown_exec/_internal/formatters/pyodide.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,42 @@
3737
3838
<script>
3939
document.addEventListener('DOMContentLoaded', (event) => {
40-
setupPyodide('%(id_prefix)s', install=%(install)s, themeLight='%(theme_light)s', themeDark='%(theme_dark)s', session='%(session)s');
40+
setupPyodide(
41+
'%(id_prefix)s',
42+
install=%(install)s,
43+
themeLight='%(theme_light)s',
44+
themeDark='%(theme_dark)s',
45+
session='%(session)s',
46+
minLines=%(min_lines)s,
47+
maxLines=%(max_lines)s,
48+
);
4149
});
4250
</script>
4351
"""
4452

4553
_counter = 0
4654

4755

56+
def _calculate_height(code: str, extra: dict) -> tuple[int, int]:
57+
"""Calculate height configuration for the Pyodide editor."""
58+
height = extra.pop("height", "auto")
59+
60+
if height in ("auto", "0"):
61+
min_lines = max_lines = len(code.strip().splitlines()) if code.strip() else 5
62+
elif "-" in height:
63+
min_lines, max_lines = height.split("-")
64+
min_lines = max(1, int(min_lines or "5"))
65+
max_lines = max(min_lines, int(max_lines or "30"))
66+
else:
67+
min_lines = max_lines = int(height)
68+
69+
return min_lines, max_lines
70+
71+
4872
def _format_pyodide(code: str, md: Markdown, session: str, extra: dict, **options: Any) -> str: # noqa: ARG001
4973
global _counter # noqa: PLW0603
5074
_counter += 1
75+
5176
version = extra.pop("version", "0.26.4").lstrip("v")
5277
install = extra.pop("install", "")
5378
install = install.split(",") if install else []
@@ -56,6 +81,7 @@ def _format_pyodide(code: str, md: Markdown, session: str, extra: dict, **option
5681
if "," not in theme:
5782
theme = f"{theme},{theme}"
5883
theme_light, theme_dark = theme.split(",")
84+
min_lines, max_lines = _calculate_height(code, extra)
5985

6086
data = {
6187
"id_prefix": f"exec-{_counter}--",
@@ -66,6 +92,8 @@ def _format_pyodide(code: str, md: Markdown, session: str, extra: dict, **option
6692
"session": session or "default",
6793
"play_emoji": _play_emoji,
6894
"clear_emoji": _clear_emoji,
95+
"min_lines": min_lines,
96+
"max_lines": max_lines,
6997
}
7098
rendered = _template % data
7199
if exclude_assets:

src/markdown_exec/assets/pyodide.css

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ html[data-theme="dark"] {
1313

1414
.pyodide-editor {
1515
width: 100%;
16-
min-height: 200px;
17-
max-height: 400px;
1816
font-size: .85em;
1917
}
2018

src/markdown_exec/assets/pyodide.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,15 @@ function updateTheme(editor, light, dark) {
7777
});
7878
}
7979

80-
async function setupPyodide(idPrefix, install = null, themeLight = 'tomorrow', themeDark = 'tomorrow_night', session = null) {
80+
async function setupPyodide(
81+
idPrefix,
82+
install = null,
83+
themeLight = 'tomorrow',
84+
themeDark = 'tomorrow_night',
85+
session = null,
86+
minLines = 5,
87+
maxLines = 30,
88+
) {
8189
const editor = ace.edit(idPrefix + "editor");
8290
const run = document.getElementById(idPrefix + "run");
8391
const clear = document.getElementById(idPrefix + "clear");
@@ -88,6 +96,12 @@ async function setupPyodide(idPrefix, install = null, themeLight = 'tomorrow', t
8896
editor.session.setMode("ace/mode/python");
8997
setTheme(editor, getTheme(), themeLight, themeDark);
9098

99+
editor.setOption("minLines", minLines);
100+
editor.setOption("maxLines", maxLines);
101+
102+
// Force editor to resize after setting options
103+
editor.resize();
104+
91105
writeOutput(output, "Initializing...");
92106
let pyodide = await pyodidePromise;
93107
if (install && install.length) {

0 commit comments

Comments
 (0)