Clarified and improved error reporting when drawing routines invoke
Macroquad window or rendering functions (such as `screen_width()` or
`screen_height()`) during headless SVG export (`--export-svg`).
[export.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/export.rs)
- Added `ExportError::Execution(String)` variant to represent drawing
execution failures and panics.
- Implemented `std::fmt::Display` and `std::error::Error` for
`ExportError`.
- Created `PanicHookGuard` RAII struct ensuring any installed panic
hooks are automatically restored after execution.
- In `run_headless_svg_export`:
- Chains onto the existing panic hook to preserve standard panic
backtrace and line number information.
- Detects if the panic originated from uninitialized Macroquad context
(`THREAD_ID.is_some()`).
- Emits a clear, prominent diagnostic banner explaining that
window/GUI functions are unavailable in headless mode.
- Catches the panic via `std::panic::catch_unwind` and returns
`Err(ExportError::Execution(...))`.
- In `handle_svg_export`, uses `{e}` (Display) rather than `{e:?}`
(Debug) for cleaner error reporting.
[lib.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib-macros/src/lib.rs)
- Updated the expanded `main` function generated by `#[turtle_main]` to
format errors with `{}` (Display) instead of `{:?}` (Debug).
[sierpinski_triangle.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/sierpinski_triangle.rs)
- Added documentation notes to the module header and
`sierpinski_triangle_auto` noting that the example requires an active
graphics window and cannot be exported to SVG headlessly because it
queries window dimensions.
---
Executed:
```bash
RUST_BACKTRACE=1 cargo run --example sierpinski_triangle --features svg
-- --export-svg sier.svg
```
Output:
```
thread 'main' (49702) panicked at
/home/dietrich/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/macroquad-0.4.16/src/lib.rs:172:13:
assertion failed: THREAD_ID.is_some()
stack backtrace:
0: __rustc::rust_begin_unwind
...
5: macroquad::window::screen_width
6: sierpinski_triangle::sierpinski_triangle_auto
at ./turtle-lib/examples/sierpinski_triangle.rs:100:20
7: sierpinski_triangle::draw_sierpinski
at ./turtle-lib/examples/sierpinski_triangle.rs:39:5
...
================================================================================
Headless SVG Export Note:
A Macroquad window/rendering function (e.g. `screen_width()`,
`screen_height()`,
or input check) was called while running in headless export mode.
Headless export does not initialize a graphics window. To resolve this:
- Use relative turtle commands or fixed coordinates instead of window
queries, or
- Run the program in windowed GUI mode without the `--export-svg`
flag.
================================================================================
Error exporting SVG: execution error: Drawing function called Macroquad
window/GUI functions (e.g. `screen_width()`, `screen_height()`) which
are unavailable in headless SVG export mode.
```
- Process exited cleanly with exit code 1.
Executed:
```bash
cargo run --example koch --features svg -- --export-svg /tmp/koch.svg
```
Output:
```
SVG exported successfully to: /tmp/koch.svg
```
Exit code 0.
```bash
cargo test --package turtle-lib
cargo clippy --package turtle-lib --features svg -- -Wclippy::pedantic
-Aclippy::cast_precision_loss -Aclippy::cast_sign_loss
-Aclippy::cast_possible_truncation
```
- 17 unit tests + 34 doctests passed (1 ignored doctest).
- Clippy completed with zero warnings.
turtle-lib-macros
Procedural macros for turtle-lib.
turtle_main Macro
The turtle_main macro simplifies creating turtle graphics programs by automatically setting up:
- The Macroquad window
- Turtle initialization
- The main rendering loop
- Quit handling (ESC or Q keys)
Usage
With a function parameter:
use macroquad::prelude::*;
use turtle_lib::*;
#[turtle_main("My Drawing")]
fn my_drawing(turtle: &mut TurtlePlan) {
turtle.set_pen_color(RED);
turtle.forward(100.0);
turtle.right(90.0);
turtle.forward(100.0);
}
With inline code:
use macroquad::prelude::*;
use turtle_lib::*;
#[turtle_main("My Drawing")]
fn my_drawing() {
turtle.set_pen_color(RED);
turtle.forward(100.0);
turtle.right(90.0);
turtle.forward(100.0);
}
What it does
The macro expands your code into a full Macroquad application with:
#[macroquad::main]attribute for window creation- Turtle instance creation
- TurtleApp initialization with your commands
- A main loop that:
- Clears the background to WHITE
- Updates the turtle app
- Renders the drawing
- Shows "Press ESC or Q to quit" message
- Handles quit keys
Benefits
- Less boilerplate: No need to write the same loop structure in every example
- Consistent UI: All examples have the same quit behavior
- Beginner-friendly: Makes turtle graphics examples more approachable
- Focus on drawing: Your code focuses on the turtle commands, not the framework
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.