From 37d13b30abd9376b127b967b0b3fccf221b970ed Mon Sep 17 00:00:00 2001 From: Johannes Wolf Date: Fri, 18 Oct 2024 21:21:28 +0200 Subject: [PATCH] error: Backtrace POC --- src/anchor.typ | 2 -- src/canvas.typ | 10 +++++----- src/coordinate.typ | 9 +++++---- src/draw/shapes.typ | 10 +++++----- src/error.typ | 32 ++++++++++++++++++++++++++++++++ src/mark.typ | 2 -- src/util.typ | 10 +++------- 7 files changed, 50 insertions(+), 25 deletions(-) create mode 100644 src/error.typ diff --git a/src/anchor.typ b/src/anchor.typ index 9f25a475e..82f92edb2 100644 --- a/src/anchor.typ +++ b/src/anchor.typ @@ -2,8 +2,6 @@ #import deps.oxifmt: strfmt #import "util.typ" -#import util: typst-length - #import "intersection.typ" #import "drawable.typ" #import "path-util.typ" diff --git a/src/canvas.typ b/src/canvas.typ index 0c6fe55b1..d85cca9be 100644 --- a/src/canvas.typ +++ b/src/canvas.typ @@ -7,8 +7,6 @@ #import "process.typ" #import "version.typ" -#import util: typst-length - /// Sets up a canvas for drawing on. /// /// - length (length, ratio): Used to specify what 1 coordinate unit is. If given a ratio, that ratio is relative to the containing elements width! @@ -26,7 +24,7 @@ message: "Incorrect type for body: " + repr(type(body)), ) - assert(type(length) in (typst-length, ratio), message: "Expected `length` to be of type length or ratio, got " + repr(length)) + assert(type(length) in (std.length, ratio), message: "Expected `length` to be of type length or ratio, got " + repr(length)) let length = if type(length) == ratio { length * ly.width } else { @@ -39,6 +37,8 @@ version: version.version, length: length, debug: debug, + // Backtrace info (list of strings) + backtrace: (), // Previous element position & bbox prev: (pt: (0, 0, 0)), style: styles.default, @@ -122,7 +122,7 @@ vertices += pts } } - if type(drawable.stroke) == dictionary and "thickness" in drawable.stroke and type(drawable.stroke.thickness) != typst-length { + if type(drawable.stroke) == dictionary and "thickness" in drawable.stroke and type(drawable.stroke.thickness) != std.length { drawable.stroke.thickness *= length } path( @@ -132,7 +132,7 @@ ..vertices, ) } else if drawable.type == "content" { - let (width, height) = util.typst-measure(drawable.body) + let (width, height) = std.measure(drawable.body) move( dx: (drawable.pos.at(0) - bounds.low.at(0)) * length - width / 2, dy: (drawable.pos.at(1) - bounds.low.at(1)) * length - height / 2, diff --git a/src/coordinate.typ b/src/coordinate.typ index 2fe937e53..7d98b8710 100644 --- a/src/coordinate.typ +++ b/src/coordinate.typ @@ -1,5 +1,6 @@ #import "vector.typ" #import "util.typ" +#import "error.typ" #import "deps.typ" #import deps.oxifmt: strfmt @@ -68,7 +69,7 @@ } // Check if node is known - assert(name in ctx.nodes, + error.assert(ctx, name in ctx.nodes, message: "Unknown element '" + name + "' in elements " + repr(ctx.nodes.keys())) // Resolve length anchors @@ -137,7 +138,7 @@ // Distance between C and P let pc = vector.len(D) if pc < r { - panic("No tangent solution for element " + c.element + " and point " + repr(c.point)) + error.panic(ctx, "No tangent solution for element " + c.element + " and point " + repr(c.point)) } // Distance between P and X0 let d = r*r / pc @@ -297,7 +298,7 @@ } if t == none { - panic("Failed to resolve coordinate: " + repr(c)) + error.panic(ctx, "Failed to resolve coordinate: " + repr(c)) } return t } @@ -354,7 +355,7 @@ } else if t == "function" { resolve-function(resolve, ctx, c) } else { - panic("Failed to resolve coordinate of format: " + repr(c)) + error.panic(ctx, "Failed to resolve coordinate of format: " + repr(c)) }.map(util.resolve-number.with(ctx)) if update { diff --git a/src/draw/shapes.typ b/src/draw/shapes.typ index 7052a7a82..c92ec3ada 100644 --- a/src/draw/shapes.typ +++ b/src/draw/shapes.typ @@ -1,6 +1,3 @@ -#let typst-angle = angle -#let typst-rotate = rotate - #import "/src/coordinate.typ" #import "/src/drawable.typ" #import "/src/styles.typ" @@ -16,6 +13,7 @@ #import "/src/mark-shapes.typ" as mark-shapes_ #import "/src/polygon.typ" #import "/src/aabb.typ" +#import "/src/error.typ" #import "transformations.typ": * #import "styling.typ": * @@ -52,6 +50,8 @@ let style = style.named() (ctx => { + ctx = error.add-element-backtrace(ctx, "circle", name) + let (ctx, pos) = coordinate.resolve(ctx, position) let style = styles.resolve(ctx.style, merge: style, root: "circle") let (rx, ry) = util.resolve-radius(style.radius).map(util.resolve-number.with(ctx)) @@ -773,7 +773,7 @@ (ctx, b) = coordinate.resolve(ctx, b) } - let angle = if type(angle) != typst-angle { + let angle = if type(angle) != std.angle { let c (ctx, c) = coordinate.resolve(ctx, angle) vector.angle2(a, c) @@ -909,7 +909,7 @@ aabb-width, aabb-height, border.segments, - typst-rotate(angle, + std.rotate(angle, reflow: true, origin: center + horizon, block( diff --git a/src/error.typ b/src/error.typ new file mode 100644 index 000000000..186ca2450 --- /dev/null +++ b/src/error.typ @@ -0,0 +1,32 @@ +/// Add a backtrace entry for a single element +/// +/// - ctx (Context): The current context +/// - element (string): The elements type (e.g. circle) +/// - name (none,string): The elements name +/// -> context +#let add-element-backtrace(ctx, element, name) = { + let message = "element: " + element + if name != none { + message += ", name: " + name + } + + ctx.backtrace.push(message) + return ctx +} + +#let _get-backtrace-string(ctx) = { + if ctx != none and ctx.backtrace != () { + return ". Backtrace: " + ctx.backtrace.rev().join("; ") + } + return "" +} + +/// Panic but with cetz backtrace +#let panic(ctx, message) = { + std.panic(message + _get-backtrace-string(ctx)) +} + +/// Assert but with cetz backtrace +#let assert(ctx, cond, message: "") = { + std.assert(cond, message: message + _get-backtrace-string(ctx)) +} diff --git a/src/mark.typ b/src/mark.typ index 8e928464b..a47fe15cf 100644 --- a/src/mark.typ +++ b/src/mark.typ @@ -7,8 +7,6 @@ #import "mark-shapes.typ": get-mark #import "process.typ" -#import util: typst-length - /// Checks if a mark should be drawn according to the current style. /// - style (style): The current style. /// -> bool diff --git a/src/util.typ b/src/util.typ index 059fe32c9..07ca63d6d 100644 --- a/src/util.typ +++ b/src/util.typ @@ -9,10 +9,6 @@ /// Constant to be used as float rounding error #let float-epsilon = 0.000001 -#let typst-measure = measure -#let typst-length = length - - /// Multiplies vectors by a transformation matrix. If multiple vectors are given they are returned as an array, if only one vector is given only one will be returned, if a dictionary is given they will be returned in the dictionary with the same keys. /// /// - transform (matrix,function): The $4 \times 4$ transformation matrix or a function that accepts and returns a vector. @@ -200,7 +196,7 @@ /// - cnt (content): The content to measure. /// -> vector #let measure(ctx, cnt) = { - let size = typst-measure(cnt) + let size = std.measure(cnt) return ( calc.abs(size.width / ctx.length), calc.abs(size.height / ctx.length) @@ -275,11 +271,11 @@ let east = radii.at("east", default: auto) if north != auto or south != auto { - assert(west == auto and east == auto, + assert(ctx, west == auto and east == auto, message: "Corner radius north/south and west/east are mutually exclusive! Use per corner radii: north-west, .. instead.") } if west != auto or east != auto { - assert(north == auto and south == auto, + assert(ctx, north == auto and south == auto, message: "Corner radius north/south and west/east are mutually exclusive! Use per corner radii: north-west, .. instead.") }