Skip to documentation
SLOP

tiny.zen.diagram.ego.svg

Reference tiny.zen diagram ego svg

Defined in diagram.ego.

API (6)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

No direct callersNo direct callsdiagram.egosvg
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsNo direct callersdiagram.ego.svgwritediagram.ego.svgrender
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsprivate sourcelib.zen.src.markdownflushFenceprivate sourcelib.zen.src.diagram.ego.svgcontainsAsciiInsensitiveprivate sourcelib.zen.src.diagram.ego.svgcontainsEventAttributeprivate sourcelib.zen.src.diagram.ego.svgvalidateFragmentLinksprivate sourcelib.zen.src.diagram.ego.svgvalidateFragmentTagsdiagram.ego.svgvalidateDocumentFragment
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsdiagram.ego.svgrenderdiagram.ego.LayoutPlaninspectprivate sourcelib.zen.src.diagram.ego.svgwriteBandprivate sourcelib.zen.src.diagram.ego.svgwriteConnectionsprivate sourcelib.zen.src.diagram.ego.svgwriteEmptyStatesprivate sourcelib.zen.src.diagram.ego.svgwriteHeaders+3 morediagram.ego.svgwrite
Static calls · unresolved targets: 0 · external targets: 1.

Source: lib/zen/src/diagram/ego/root.zig:3

zig
pub const svg = @import("svg.zig");

Source: lib/zen/src/diagram/ego/svg.zig

zig
const std = @import("std");const root = @import("root.zig");const zen = @import("../../root.zig");const html = zen.html;const layout = root.layout;const model = root.model;pub const output_bytes_max: usize = 96 * 1024;pub const document_fragment_bytes_max: usize = output_bytes_max + 1024;const escaped_bytes_max: usize = model.href_bytes_max * 6;pub const FragmentError = error{    InvalidDocumentFragment,    UnsafeDocumentFragment,};const stylesheet =    \\.zen-ego{color:var(--ink,#1a1714);overflow:visible}    \\.zen-ego text{    \\font-family:var(--face-mono,ui-monospace,monospace);    \\pointer-events:none    \\}    \\.zen-ego-edge{    \\fill:none;    \\stroke:var(--rule-bold,rgba(26,23,20,.3));    \\stroke-width:1.5;    \\vector-effect:non-scaling-stroke    \\}    \\.zen-ego-edge-more{stroke-dasharray:4 4}    \\.zen-ego-arrow{fill:var(--ink-mute,#8c8275)}    \\.zen-ego-heading{    \\fill:var(--ink-soft,#564e44);    \\font-weight:700;    \\letter-spacing:.08em;    \\text-transform:uppercase    \\}    \\.zen-ego-empty{fill:var(--ink-mute,#8c8275);font-style:italic}    \\.zen-ego-node>rect{    \\fill:var(--paper,#f4f1ea);    \\stroke:var(--rule-bold,rgba(26,23,20,.3));    \\stroke-width:1.25;    \\vector-effect:non-scaling-stroke    \\}    \\.zen-ego-node .zen-ego-label{fill:var(--ink,#1a1714);font-weight:700}    \\.zen-ego-node .zen-ego-context{fill:var(--ink-soft,#564e44)}    \\.zen-ego .zen-ego-node{text-decoration:none}    \\.zen-ego-subject>rect{    \\fill:var(--paper-sunk,#ece8dd);    \\stroke:var(--accent-ink,#d2371f);    \\stroke-width:2.25    \\}    \\.zen-ego-subject .zen-ego-label{font-weight:900}    \\.zen-ego-more>rect{fill:transparent;stroke-dasharray:4 3}    \\.zen-ego-badge rect{    \\fill:var(--paper-raised,var(--paper,#f4f1ea));    \\stroke:var(--rule-bold,rgba(26,23,20,.3));    \\stroke-width:1    \\}    \\.zen-ego-badge text{    \\fill:var(--ink-soft,#564e44);    \\font-weight:800;    \\letter-spacing:.04em    \\}    \\.zen-ego-self-loop{stroke:var(--accent-ink,#d2371f);stroke-width:2}    \\a.zen-ego-node:is(:hover,:focus-visible)>rect{    \\stroke:var(--accent-ink,#d2371f);    \\stroke-width:2.5    \\}    \\a.zen-ego-node:is(:hover,:focus-visible) .zen-ego-label{    \\fill:var(--accent-ink,#d2371f);    \\text-decoration:underline    \\}    \\a.zen-ego-node:focus-visible{outline:none}    \\a.zen-ego-node:focus-visible .zen-ego-badge rect{    \\stroke:var(--accent-ink,#d2371f)    \\}    \\.zen-ego-node-plain>rect{stroke-dasharray:3 3};/// Renders one call map into caller-owned output storage.pub fn render(    output: []u8,    network: model.Network,    surface: model.Surface,) (model.Error || std.Io.Writer.Error)![]const u8 {    var writer = std.Io.Writer.fixed(output);    try write(&writer, network, surface);    return writer.buffered();}/// Writes one bounded, linked, static SVG call map.pub fn write(    writer: *std.Io.Writer,    network: model.Network,    surface: model.Surface,) (model.Error || std.Io.Writer.Error)!void {    const plan = try layout.Plan.inspect(network, surface);    const leaf = network.callers.total == 0 and network.callees.total == 0;    try writeOpen(writer, network, plan.geometry, leaf);    if (!(leaf and plan.geometry.arrangement == .horizontal)) {        try writeHeaders(writer, &plan);    }    try writeConnections(        writer,        &plan.callers,        plan.subject,        plan.geometry,        .callers,    );    try writeConnections(        writer,        &plan.callees,        plan.subject,        plan.geometry,        .callees,    );    try writeEmptyStates(writer, &plan);    try writeBand(writer, &plan.callers, plan.geometry, .callers);    try writeBand(writer, &plan.callees, plan.geometry, .callees);    if (network.recursive) try writeSelfLoop(writer, plan.subject);    try writeNode(writer, network.subject, plan.subject, plan.geometry, true);    try writer.writeAll("</svg>");}/// Validates the documentation fragment envelope around one rendered call map.pub fn validateDocumentFragment(source: []const u8) FragmentError!void {    const fragment = std.mem.trim(u8, source, " \t\r\n");    if (fragment.len == 0 or fragment.len > document_fragment_bytes_max) {        return error.InvalidDocumentFragment;    }    const wide =        "<figure class=\"docs-call-map docs-call-map-primary zen-role-wide";    const anchored =        "<figure class=\"docs-call-map docs-call-map-anchored zen-role-wide";    if (!std.mem.startsWith(u8, fragment, wide) and        !std.mem.startsWith(u8, fragment, anchored))    {        return error.InvalidDocumentFragment;    }    if (!std.mem.endsWith(u8, fragment, "</figcaption></figure>")) {        return error.InvalidDocumentFragment;    }    if (!std.unicode.utf8ValidateSlice(fragment) or        containsAsciiInsensitive(fragment, "<script") or        containsAsciiInsensitive(fragment, "<foreignobject") or        containsEventAttribute(fragment) or        containsAsciiInsensitive(fragment, " style=") or        containsAsciiInsensitive(fragment, "xlink:href") or        containsAsciiInsensitive(fragment, "javascript:") or        containsAsciiInsensitive(fragment, "data:") or        containsAsciiInsensitive(fragment, "url(") or        containsAsciiInsensitive(fragment, "@import"))    {        return error.UnsafeDocumentFragment;    }    try validateFragmentTags(fragment);    try validateFragmentLinks(fragment);}fn validateFragmentTags(fragment: []const u8) FragmentError!void {    const prefixes = [_][]const u8{        "<figure class=\"docs-call-map docs-call-map-primary zen-role-wide",        "<figure class=\"docs-call-map docs-call-map-anchored zen-role-wide",        "</figure>",        "<svg ",        "</svg>",        "<style>",        "</style>",        "<path ",        "<text ",        "</text>",        "<a ",        "</a>",        "<rect ",        "<g ",        "</g>",        "<figcaption>",        "</figcaption>",    };    var cursor: usize = 0;    while (std.mem.indexOfScalarPos(u8, fragment, cursor, '<')) |start| {        const end = std.mem.indexOfScalarPos(u8, fragment, start, '>') orelse            return error.InvalidDocumentFragment;        var admitted = false;        for (prefixes) |prefix| {            admitted = admitted or std.mem.startsWith(u8, fragment[start..], prefix);        }        if (!admitted) return error.UnsafeDocumentFragment;        cursor = end + 1;    }    if (std.mem.count(u8, fragment, "<svg ") != 1 or        std.mem.count(u8, fragment, "</svg>") != 1)    {        return error.InvalidDocumentFragment;    }}fn validateFragmentLinks(fragment: []const u8) FragmentError!void {    const marker = " href=\"";    var cursor: usize = 0;    while (std.mem.indexOfPos(u8, fragment, cursor, marker)) |start| {        const value_start = start + marker.len;        if (value_start == fragment.len) return error.InvalidDocumentFragment;        const end = std.mem.indexOfScalarPos(u8, fragment, value_start, '"') orelse            return error.InvalidDocumentFragment;        if (end == value_start) return error.InvalidDocumentFragment;        if (!model.safeHref(fragment[value_start..end])) {            return error.UnsafeDocumentFragment;        }        cursor = end + 1;    }}fn containsAsciiInsensitive(haystack: []const u8, needle: []const u8) bool {    if (needle.len == 0 or needle.len > haystack.len) return false;    return std.ascii.findIgnoreCase(haystack, needle) != null;}fn containsEventAttribute(fragment: []const u8) bool {    var tag_start: usize = 0;    while (std.mem.indexOfScalarPos(u8, fragment, tag_start, '<')) |start| {        const end = std.mem.indexOfScalarPos(u8, fragment, start, '>') orelse            return true;        var cursor = start + 1;        while (cursor + 3 < end) : (cursor += 1) {            if (!std.ascii.isWhitespace(fragment[cursor])) continue;            const name_start = cursor + 1;            if (std.ascii.toLower(fragment[name_start]) != 'o' or                std.ascii.toLower(fragment[name_start + 1]) != 'n') continue;            var name_end = name_start + 2;            while (name_end < end and                (std.ascii.isAlphanumeric(fragment[name_end]) or                    fragment[name_end] == '-' or fragment[name_end] == '_'))            {                name_end += 1;            }            while (name_end < end and std.ascii.isWhitespace(fragment[name_end])) {                name_end += 1;            }            if (name_end < end and fragment[name_end] == '=') return true;        }        tag_start = end + 1;    }    return false;}const Direction = enum {    callers,    callees,};fn writeOpen(    writer: *std.Io.Writer,    network: model.Network,    geometry: model.Geometry,    leaf: bool,) std.Io.Writer.Error!void {    try writer.print(        "<svg xmlns=\"http://www.w3.org/2000/svg\" " ++            "class=\"zen-ego{s}\" viewBox=\"0 0 {d} {d}\" " ++            "role=\"group\" aria-label=\"Static call map for ",        .{            if (leaf) " zen-ego-leaf" else "",            geometry.width,            geometry.height,        },    );    try writeAccessibleName(writer, network.subject);    try writer.writeAll(if (leaf and geometry.arrangement == .horizontal)        ". It has no direct callers and no direct calls."    else switch (geometry.arrangement) {        .horizontal => ". Callers flow in from the left. Calls flow out to the right.",        .vertical => ". Callers flow in from above. Calls flow out below.",    });    if (network.recursive) try writer.writeAll(" It calls itself.");    try writer.writeAll("\"><style>");    try writer.writeAll(stylesheet);    try writer.writeAll("</style>");}fn writeHeaders(    writer: *std.Io.Writer,    plan: *const layout.Plan,) std.Io.Writer.Error!void {    try writeHeader(        writer,        plan.callers.heading.x,        plan.callers.heading.y,        plan.geometry.heading_size,        "Called by",    );    try writeHeader(        writer,        plan.callees.heading.x,        plan.callees.heading.y,        plan.geometry.heading_size,        "Calls",    );}fn writeHeader(    writer: *std.Io.Writer,    x: f32,    y: f32,    size: f32,    value: []const u8,) std.Io.Writer.Error!void {    try writer.print(        "<text class=\"zen-ego-heading\" x=\"{d:.2}\" y=\"{d:.2}\" " ++            "font-size=\"{d:.2}\" text-anchor=\"middle\">{s}</text>",        .{ x, y, size, value },    );}fn writeConnections(    writer: *std.Io.Writer,    band: *const layout.Band,    subject: layout.Rect,    geometry: model.Geometry,    direction: Direction,) std.Io.Writer.Error!void {    std.debug.assert(band.count <= model.max_slots_per_band);    for (band.slice()) |item| {        const dashed = switch (item.content) {            .node => false,            .more => true,        };        switch (geometry.arrangement) {            .horizontal => try writeHorizontalConnection(                writer,                item.box,                subject,                direction,                dashed,            ),            .vertical => try writeVerticalConnection(                writer,                item.box,                direction,                dashed,            ),        }    }}fn writeHorizontalConnection(    writer: *std.Io.Writer,    item: layout.Rect,    subject: layout.Rect,    direction: Direction,    dashed: bool,) std.Io.Writer.Error!void {    const start_x = if (direction == .callers)        item.x + item.width + 4    else        subject.x + subject.width + 4;    const end_x = if (direction == .callers) subject.x - 4 else item.x - 4;    const start_y = if (direction == .callers) item.centerY() else subject.centerY();    const end_y = if (direction == .callers) subject.centerY() else item.centerY();    try writeHorizontalEdge(writer, start_x, start_y, end_x, end_y, dashed);}fn writeHorizontalEdge(    writer: *std.Io.Writer,    start_x: f32,    start_y: f32,    end_x: f32,    end_y: f32,    dashed: bool,) std.Io.Writer.Error!void {    const middle = (start_x + end_x) / 2;    try writer.print(        "<path class=\"zen-ego-edge{s}\" d=\"M {d:.2} {d:.2} " ++            "C {d:.2} {d:.2}, {d:.2} {d:.2}, {d:.2} {d:.2}\"/>",        .{            if (dashed) " zen-ego-edge-more" else "",            start_x,            start_y,            middle,            start_y,            middle,            end_y,            end_x,            end_y,        },    );    try writer.print(        "<path class=\"zen-ego-arrow\" d=\"M {d:.2} {d:.2} " ++            "L {d:.2} {d:.2} L {d:.2} {d:.2} Z\"/>",        .{ end_x, end_y, end_x - 7, end_y - 4, end_x - 7, end_y + 4 },    );}fn writeVerticalConnection(    writer: *std.Io.Writer,    item: layout.Rect,    direction: Direction,    dashed: bool,) std.Io.Writer.Error!void {    const start_y = if (direction == .callers)        item.y + item.height + 1    else        item.y - 10;    const end_y = if (direction == .callers) start_y + 8 else item.y - 2;    try writeVerticalStub(writer, item.centerX(), start_y, end_y, dashed);}fn writeVerticalStub(    writer: *std.Io.Writer,    x: f32,    start_y: f32,    end_y: f32,    dashed: bool,) std.Io.Writer.Error!void {    std.debug.assert(start_y < end_y);    try writer.print(        "<path class=\"zen-ego-edge{s}\" d=\"M {d:.2} {d:.2} L {d:.2} {d:.2}\"/>",        .{            if (dashed) " zen-ego-edge-more" else "",            x,            start_y,            x,            end_y,        },    );    try writer.print(        "<path class=\"zen-ego-arrow\" d=\"M {d:.2} {d:.2} " ++            "L {d:.2} {d:.2} L {d:.2} {d:.2} Z\"/>",        .{ x, end_y, x - 4, end_y - 7, x + 4, end_y - 7 },    );}fn writeSelfLoop(    writer: *std.Io.Writer,    subject: layout.Rect,) std.Io.Writer.Error!void {    const start_x = subject.centerX() - 18;    const end_x = subject.centerX() + 18;    const end_y = subject.y - 3;    const top_y = end_y - 22;    try writer.print(        "<path class=\"zen-ego-edge zen-ego-self-loop\" aria-hidden=\"true\" " ++            "d=\"M {d:.2} {d:.2} C {d:.2} {d:.2}, {d:.2} {d:.2}, " ++            "{d:.2} {d:.2}\"/>",        .{ start_x, end_y, start_x, top_y, end_x, top_y, end_x, end_y },    );    try writer.print(        "<path class=\"zen-ego-arrow\" aria-hidden=\"true\" " ++            "d=\"M {d:.2} {d:.2} L {d:.2} {d:.2} L {d:.2} {d:.2} Z\"/>",        .{ end_x, end_y, end_x - 4, end_y - 7, end_x + 4, end_y - 7 },    );}fn writeEmptyStates(    writer: *std.Io.Writer,    plan: *const layout.Plan,) std.Io.Writer.Error!void {    const geometry = plan.geometry;    if (plan.callers.count == 0) {        try writeEmpty(            writer,            plan.callers.empty.x,            plan.callers.empty.y,            geometry.empty_size,            "No direct callers",        );    }    if (plan.callees.count == 0) {        try writeEmpty(            writer,            plan.callees.empty.x,            plan.callees.empty.y,            geometry.empty_size,            "No direct calls",        );    }}fn writeEmpty(    writer: *std.Io.Writer,    x: f32,    y: f32,    size: f32,    value: []const u8,) std.Io.Writer.Error!void {    try writer.print(        "<text class=\"zen-ego-empty\" x=\"{d:.2}\" y=\"{d:.2}\" " ++            "font-size=\"{d:.2}\" text-anchor=\"middle\" " ++            "dominant-baseline=\"middle\">{s}</text>",        .{ x, y, size, value },    );}fn writeBand(    writer: *std.Io.Writer,    band: *const layout.Band,    geometry: model.Geometry,    direction: Direction,) std.Io.Writer.Error!void {    std.debug.assert(band.count <= model.max_slots_per_band);    for (band.slice()) |item| switch (item.content) {        .node => |node| try writeNode(writer, node, item.box, geometry, false),        .more => |more| try writeMore(writer, more, item.box, geometry, direction),    };}fn writeNode(    writer: *std.Io.Writer,    node: model.Node,    box: layout.Rect,    geometry: model.Geometry,    subject: bool,) std.Io.Writer.Error!void {    const linked = node.href.len != 0;    try writer.writeAll(if (linked)        "<a class=\"zen-ego-node"    else        "<g class=\"zen-ego-node zen-ego-node-plain");    if (subject) try writer.writeAll(" zen-ego-subject");    if (linked) {        try writer.writeAll("\" href=\"");        try writeEscaped(writer, node.href);        try writer.writeAll("\" tabindex=\"0");    } else {        try writer.writeAll("\" role=\"img");    }    try writer.writeAll("\" aria-label=\"");    try writeAccessibleName(writer, node);    try writer.writeAll("\">");    try writeBox(writer, box);    const label_size = if (subject) geometry.subject_label_size else geometry.label_size;    if (node.badge.len > 0) try writeBadge(writer, node.badge, box, geometry.badge_size);    try writeNodeText(writer, node, box, label_size, geometry.context_size);    try writer.writeAll(if (linked) "</a>" else "</g>");}fn writeMore(    writer: *std.Io.Writer,    more: layout.More,    box: layout.Rect,    geometry: model.Geometry,    direction: Direction,) std.Io.Writer.Error!void {    try writer.writeAll(        "<a class=\"zen-ego-node zen-ego-more\" href=\"",    );    try writeEscaped(writer, more.href);    try writer.print("\" tabindex=\"0\" aria-label=\"{d} more direct {s}\">", .{        more.count,        if (direction == .callers) "callers" else "calls",    });    try writeBox(writer, box);    try writer.print(        "<text class=\"zen-ego-label\" x=\"{d:.2}\" y=\"{d:.2}\" " ++            "font-size=\"{d:.2}\" text-anchor=\"middle\" " ++            "dominant-baseline=\"middle\">+{d} more</text></a>",        .{ box.centerX(), box.centerY(), geometry.label_size, more.count },    );}fn writeBox(    writer: *std.Io.Writer,    box: layout.Rect,) std.Io.Writer.Error!void {    try writer.print(        "<rect x=\"{d:.2}\" y=\"{d:.2}\" width=\"{d:.2}\" " ++            "height=\"{d:.2}\" rx=\"8\"/>",        .{ box.x, box.y, box.width, box.height },    );}fn writeNodeText(    writer: *std.Io.Writer,    node: model.Node,    box: layout.Rect,    label_size: f32,    context_size: f32,) std.Io.Writer.Error!void {    const center_x = box.centerX();    const center_y = box.centerY();    if (node.context.len == 0) {        try writeText(            writer,            "zen-ego-label",            node.label,            center_x,            center_y + if (node.badge.len > 0) @as(f32, 7) else 0,            label_size,            box.width - 14,        );        return;    }    const context_y = if (node.badge.len > 0) center_y + 2 else center_y - 9;    const label_y = if (node.badge.len > 0) center_y + 15 else center_y + 10;    try writeText(        writer,        "zen-ego-context",        node.context,        center_x,        context_y,        context_size,        box.width - 14,    );    try writeText(        writer,        "zen-ego-label",        node.label,        center_x,        label_y,        label_size,        box.width - 14,    );}fn writeBadge(    writer: *std.Io.Writer,    value: []const u8,    box: layout.Rect,    size: f32,) std.Io.Writer.Error!void {    const glyphs = std.unicode.utf8CountCodepoints(value) catch unreachable;    const desired = @as(f32, @floatFromInt(glyphs)) * size * 0.62 + 12;    const width = @min(box.width - 12, @max(@as(f32, 34), desired));    const x = box.x + box.width - width - 6;    const y = box.y + 5;    try writer.print(        "<g class=\"zen-ego-badge\"><rect x=\"{d:.2}\" y=\"{d:.2}\" " ++            "width=\"{d:.2}\" height=\"14\" rx=\"7\"/>",        .{ x, y, width },    );    try writeText(writer, "zen-ego-badge-label", value, x + width / 2, y + 7, size, width - 8);    try writer.writeAll("</g>");}fn writeText(    writer: *std.Io.Writer,    class: []const u8,    value: []const u8,    x: f32,    y: f32,    size: f32,    width: f32,) std.Io.Writer.Error!void {    try writer.print(        "<text class=\"{s}\" x=\"{d:.2}\" y=\"{d:.2}\" " ++            "font-size=\"{d:.2}\" text-anchor=\"middle\" " ++            "dominant-baseline=\"middle\"",        .{ class, x, y, size },    );    const glyphs = std.unicode.utf8CountCodepoints(value) catch unreachable;    if (@as(f32, @floatFromInt(glyphs)) * size * 0.62 > width) {        try writer.print(            " textLength=\"{d:.2}\" lengthAdjust=\"spacingAndGlyphs\"",            .{width},        );    }    try writer.writeByte('>');    try writeEscaped(writer, value);    try writer.writeAll("</text>");}fn writeAccessibleName(    writer: *std.Io.Writer,    node: model.Node,) std.Io.Writer.Error!void {    if (node.title.len > 0) return writeEscaped(writer, node.title);    if (node.badge.len > 0) {        try writeEscaped(writer, node.badge);        try writer.writeByte('.');    }    if (node.context.len > 0) {        try writeEscaped(writer, node.context);        try writer.writeByte('.');    }    try writeEscaped(writer, node.label);}fn writeEscaped(    writer: *std.Io.Writer,    value: []const u8,) std.Io.Writer.Error!void {    var escaped: [escaped_bytes_max]u8 = undefined;    const length = html.escapedLength(value) catch unreachable;    std.debug.assert(length <= escaped.len);    try writer.writeAll(html.writeEscaped(&escaped, value));}

Complete call list for diagram.ego.svg.write

8 direct calls.

Audit

Definitions7
Public names9
Members2
Version26.7.0
Revisiondaab053ee433