Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ jobs:
# condition comments, readable types and argument checks, the doctest
# runner and its coverage, and which errors get a hint.
- run: npm run test:runtime
# The trees' layout (our port of van der Ploeg's algorithm) against
# d3-flextree, on the course's trees and random ones.
- run: npm run test:layout
# The console in Chrome (on the runner) with Pyodide from its CDN,
# driving the embed built above: Tests → edit → Tests shows the new
# report (P20).
Expand Down
4 changes: 3 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ npm run build # tsc -b && vite build && copy src/style.css -> dist/ (li
npm run dev # vite build --watch, for use with npm link/yalc in a host shell
npm run lint # oxlint
npm run test:protocol # builds the library, then runs scripts/check-embed-protocol.mjs against dist/
npm run test:runtime # the runtime under CPython: scripts/check-runtime-{columns,values,doctests,coverage,calls,hints,fidelity,replay,lists,…}.py
npm run test:runtime # the runtime under CPython: scripts/check-runtime-{columns,values,doctests,coverage,calls,hints,fidelity,replay,lists,main,trees,…}.py
npm run test:hints # the error hints' wording (de/en) against the built dist/ (run a build first)
npm run test:console # the console in Chrome with Pyodide, against dist-embed/ (run build:embed first)
npm run test:layout # the trees' layout (src/treeLayout.ts) against d3-flextree (a devDependency, only for this check)
npm run build:embed # builds the iframe app + demo page into dist-embed/ (plus embed/public/: coi-serviceworker.js)
npm run preview:embed # serves dist-embed/ with COOP/COEP headers; open /demo.html
```
Expand Down Expand Up @@ -54,6 +55,7 @@ There is no unit test framework. The automated checks are `test:protocol` (plain
- Columns: `ast` counts UTF-8 bytes, `tokenize` characters, the UI UTF-16 code units. Every offset into a line goes through `_glpython_text_before` (the text in front of it, for slicing) or `_glpython_ui_column` (a column for the UI); never slice a line by an `ast` offset directly.
- Values are shown through `_glpython_safe_repr`, which writes types as learners do (`int`, not `<class 'int'>`); the program's own output keeps Python's repr.
- It abbreviates long values (`[1, 2, 3, 4, 5, …, 100]`; levels in `_GLPYTHON_ABBREVIATION_LEVELS`) and notes each full text. The next recorded step gets `fullValues` (`{shown text: index}`), the trace result `values` (`{text, cut, length, kind}`). The UI (`fullValuesUpTo`, `ValueText`, `LocalsValue`, `FullValueDialog`) opens one on click.
- Lists that read as a tree (`listtree`: first element a string): `session.py`'s `_glpython_tree_of` gives `{label, children}`/`{leaf}`, for the REPL's value (`tree`) and, noted like the full values, for the panel's values (step `trees`, result `trees`). The UI draws them with `TreeView` (`src/TreeView.tsx`: HTML nodes, SVG edges, a tree wider than its place scrolls with its root centred and hints at the hidden edges), behind capability `listTree`. The positions come from our port of van der Ploeg's tidy-tree algorithm (`src/treeLayout.ts`, in characters of the code font and in rows; every node one row high), with d3-flextree's changes; `test:layout` compares it with `d3-flextree`, which is a devDependency for that check only and must stay out of the builds.
- A name indexed in a subscript (`dauer` in `dauer[1]`, `_glpython_indexed`) gets no step of its own, so `dauer[1]` is one step to the element.
- A display (`[…]`, `(…)`, `{…}`) gets no step of its own (`_glpython_record_display`), only where its value reads differently (unpacking, duplicates); nor does a negative number literal (`_glpython_is_negative_number`), or `-name` where it already reads as its value. Every step must change something.

Expand Down
42 changes: 40 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,44 @@ variables panel. Texts: `visualizerShowFullValue`, `visualizerValueLength`,
`visualizerFullValueTitle`, `visualizerFullValueCut`, `visualizerCloseFullValue`,
all optional.

### Lists as trees (`listTree`)

With the capability `listTree` (off by default; the embed's `features=listtree`),
a list that reads as a tree is drawn as one, below its text: a non-empty list
whose first element is a string is a node with that label, its other
elements are its children, a subtree where they read as a tree too, else a
leaf. `['+', ['var', 'x'], ['f', 1, 2]]`:

```
+
╱ ╲
var f
│ ╱ ╲
'x' 1 2
```

Labels have no quotes, string leaves do. The rule is generic, so `['Anna', 'Ben']`
is drawn too; the text stays as it is. Where:
- **Variables panel:** below the value; a tree wider than the panel
(48 characters) has a link «Baum zeigen» (`showTree`) to the full-value
dialog instead. The options menu's «Listen als Baum zeigen»
(`visualizerListTrees`) switches the trees off and on.
- **Full-value dialog:** below the value's text.
- **REPL:** a value that reads as a tree has a «Baum» button (`replShowTree`)
next to «Visualisieren»; it shows the tree below the value and hides it
again.

A tree of more than 100 nodes, deeper than 10 or containing itself isn't
drawn; long labels and leaves are shortened in their middle. For screen
readers each tree is an image described by the list's text. A tree wider
than its place (the console, the dialog, a narrow panel) scrolls sideways:
it starts with its root in the middle, a ‹ or › at an edge shows that more is
hidden there, and it takes the focus, so the arrow keys, Home and End scroll
it. The positions come from the package's own implementation of van der Ploeg's
tidy-tree algorithm for nodes of different widths (`src/treeLayout.ts`,
checked against [d3-flextree](https://github.com/Klortho/d3-flextree)), in
characters of the code font, so a tree scales with the text around it.

### Copying the evaluation as a → chain

The **Copy → chain** item in the toolbar's **⋯ Options** menu copies the evaluation of the statement
Expand Down Expand Up @@ -396,8 +434,8 @@ Optional query parameters adapt the embed to a host such as the LiaScript
macro: `features=run,repl,visualize,…` hides the REPL (`repl`), the visualizer
(`visualize`) or its → chain export (`export`) unless listed (capabilities
`repl`, `visualization`, `export`); `coverage` in that list switches on the
coverage after Tests (capability `coverage`), which a missing `features`
doesn't; and `size=large` with
coverage after Tests (capability `coverage`), and `listtree` lists drawn as
trees (capability `listTree`), which a missing `features` doesn't; and `size=large` with
`visualizerHeight=<px>` shows bigger code and a visualizer at least that tall.

The UI language is the optional `lang` query parameter (e.g. the LiaScript
Expand Down
19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"test:protocol": "npm run build && node scripts/check-embed-protocol.mjs",
"test:hints": "node scripts/check-error-hints.mjs",
"test:console": "node scripts/check-console-browser.mjs",
"test:runtime": "python3 -B scripts/check-runtime-columns.py && python3 -B scripts/check-runtime-values.py && python3 -B scripts/check-runtime-doctests.py && python3 -B scripts/check-runtime-coverage.py && python3 -B scripts/check-runtime-calls.py && python3 -B scripts/check-runtime-hints.py && python3 -B scripts/check-runtime-fidelity.py && python3 -B scripts/check-runtime-replay.py && python3 -B scripts/check-runtime-imports.py && python3 -B scripts/check-runtime-repl.py && python3 -B scripts/check-runtime-input.py && python3 -B scripts/check-runtime-lists.py && python3 -B scripts/check-runtime-main.py",
"test:layout": "node --experimental-strip-types --no-warnings scripts/check-tree-layout.mjs",
"test:runtime": "python3 -B scripts/check-runtime-columns.py && python3 -B scripts/check-runtime-values.py && python3 -B scripts/check-runtime-doctests.py && python3 -B scripts/check-runtime-coverage.py && python3 -B scripts/check-runtime-calls.py && python3 -B scripts/check-runtime-hints.py && python3 -B scripts/check-runtime-fidelity.py && python3 -B scripts/check-runtime-replay.py && python3 -B scripts/check-runtime-imports.py && python3 -B scripts/check-runtime-repl.py && python3 -B scripts/check-runtime-input.py && python3 -B scripts/check-runtime-lists.py && python3 -B scripts/check-runtime-main.py && python3 -B scripts/check-runtime-trees.py",
"prepare": "npm run build"
},
"peerDependencies": {
Expand All @@ -44,6 +45,7 @@
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.7",
"@vitejs/plugin-react": "^6.1.1",
"d3-flextree": "2.1.2",
"lucide-react": "^1.47.0",
"oxlint": "^1.81.0",
"playwright-core": "^1.48.2",
Expand Down
Loading
Loading