Skip to documentation
SLOP

tiny.termtex.alphabet

Reference tiny.termtex alphabet

Defined in tiny.termtex.

API (3)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callstiny.termtexalphabet
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallstest sourcelib.termtex.src.alphabettest: alphabet maps common mathematic...test sourcelib.termtex.src.alphabettest: alphabet maps script exceptions...test sourcelib.termtex.src.alphabettest: alphabet maps unicode math alia...private sourcelib.termtex.src.parse.ParsermakeAlphabetprivate sourcelib.termtex.src.alphabetmapTextastnodeastspacealphabetapply
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callstest sourcelib.termtex.src.alphabettest: alphabet maps unicode math alia...private sourcelib.termtex.src.parse.ParsercommandExpralphabetcommand
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/termtex/src/alphabet.zig

zig
const std = @import("std");const ast = @import("ast.zig");pub const Mode = enum {    bold,    italic,    bold_italic,    script,    bold_script,    fraktur,    bold_fraktur,    double_struck,    double_struck_italic,    sans,    sans_bold,    sans_italic,    sans_bold_italic,    monospace,    small_caps,};const Command = struct {    name: []const u8,    mode: Mode,};pub fn command(name: []const u8) ?Mode {    inline for (commands) |entry| {        if (std.mem.eql(u8, name, entry.name)) return entry.mode;    }    return null;}pub fn apply(arena: std.mem.Allocator, mode: Mode, expr: *const ast.Expr) std.mem.Allocator.Error!*ast.Expr {    return switch (expr.*) {        .row => |items| block: {            const out = try arena.alloc(*ast.Expr, items.len);            for (items, 0..) |item, index| out[index] = try apply(arena, mode, item);            break :block ast.node(arena, .{ .row = out });        },        .text => |value| mapText(arena, mode, value),        .operator => |value| ast.node(arena, .{ .operator = .{            .body = try apply(arena, mode, value.body),            .limit_policy = value.limit_policy,        } }),        .space => |value| ast.space(arena, value),        .fraction => |value| ast.node(arena, .{ .fraction = .{            .numerator = try apply(arena, mode, value.numerator),            .denominator = try apply(arena, mode, value.denominator),            .style = value.style,        } }),        .sqrt => |value| ast.node(arena, .{ .sqrt = .{            .index = if (value.index) |index| try apply(arena, mode, index) else null,            .body = try apply(arena, mode, value.body),        } }),        .scripts => |value| ast.node(arena, .{ .scripts = .{            .base = try apply(arena, mode, value.base),            .sub = if (value.sub) |sub| try apply(arena, mode, sub) else null,            .sup = if (value.sup) |sup| try apply(arena, mode, sup) else null,        } }),        .accent => |value| ast.node(arena, .{ .accent = .{            .mark = value.mark,            .body = try apply(arena, mode, value.body),        } }),        .grid => |value| block: {            const rows = try arena.alloc(ast.GridRow, value.rows.len);            for (value.rows, 0..) |row, row_index| {                const cells = try arena.alloc(*ast.Expr, row.cells.len);                for (row.cells, 0..) |cell, cell_index| cells[cell_index] = try apply(arena, mode, cell);                rows[row_index] = .{ .cells = cells };            }            break :block ast.node(arena, .{ .grid = .{                .rows = rows,                .fence = value.fence,                .alignment = value.alignment,            } });        },        .annotation => |value| ast.node(arena, .{ .annotation = .{            .base = try apply(arena, mode, value.base),            .over = if (value.over) |over| try apply(arena, mode, over) else null,            .under = if (value.under) |under| try apply(arena, mode, under) else null,            .kind = value.kind,        } }),        .delimited => |value| ast.node(arena, .{ .delimited = .{            .left = value.left,            .body = try apply(arena, mode, value.body),            .right = value.right,        } }),    };}fn mapText(arena: std.mem.Allocator, mode: Mode, value: []const u8) std.mem.Allocator.Error!*ast.Expr {    var out: std.ArrayListUnmanaged(u8) = .empty;    errdefer out.deinit(arena);    var index: usize = 0;    while (index < value.len) {        const len = std.unicode.utf8ByteSequenceLength(value[index]) catch 1;        const end = index + @min(len, value.len - index);        const glyph = value[index..end];        if (mappedGlyph(mode, glyph)) |mapped| {            switch (mapped) {                .scalar => |scalar| try appendScalar(arena, &out, scalar),                .text => |text| try out.appendSlice(arena, text),            }        } else {            try out.appendSlice(arena, glyph);        }        index = end;    }    return ast.node(arena, .{ .text = try out.toOwnedSlice(arena) });}const Glyph = union(enum) {    scalar: u21,    text: []const u8,};fn mappedGlyph(mode: Mode, glyph: []const u8) ?Glyph {    if (glyph.len == 1) {        if (asciiGlyph(mode, glyph[0])) |scalar| return .{ .scalar = scalar };    }    if (greekGlyph(mode, glyph)) |scalar| return .{ .scalar = scalar };    return null;}fn asciiGlyph(mode: Mode, char: u8) ?u21 {    return switch (mode) {        .bold => rangedAscii(char, 0x1D400, 0x1D41A, 0x1D7CE),        .italic => italicAscii(char),        .bold_italic => rangedAscii(char, 0x1D468, 0x1D482, null),        .script => scriptAscii(char),        .bold_script => rangedAscii(char, 0x1D4D0, 0x1D4EA, null),        .fraktur => frakturAscii(char),        .bold_fraktur => rangedAscii(char, 0x1D56C, 0x1D586, null),        .double_struck => doubleStruckAscii(char),        .double_struck_italic => doubleStruckItalicAscii(char),        .sans => rangedAscii(char, 0x1D5A0, 0x1D5BA, 0x1D7E2),        .sans_bold => rangedAscii(char, 0x1D5D4, 0x1D5EE, 0x1D7EC),        .sans_italic => rangedAscii(char, 0x1D608, 0x1D622, null),        .sans_bold_italic => rangedAscii(char, 0x1D63C, 0x1D656, null),        .monospace => rangedAscii(char, 0x1D670, 0x1D68A, 0x1D7F6),        .small_caps => smallCapsAscii(char),    };}fn rangedAscii(char: u8, upper: ?u21, lower: ?u21, digit: ?u21) ?u21 {    if (char >= 'A' and char <= 'Z') {        if (upper) |base| return base + offset(char, 'A');    }    if (char >= 'a' and char <= 'z') {        if (lower) |base| return base + offset(char, 'a');    }    if (char >= '0' and char <= '9') {        if (digit) |base| return base + offset(char, '0');    }    return null;}fn italicAscii(char: u8) ?u21 {    if (char == 'h') return 0x210E;    return rangedAscii(char, 0x1D434, 0x1D44E, null);}fn scriptAscii(char: u8) ?u21 {    return switch (char) {        'B' => 0x212C,        'E' => 0x2130,        'F' => 0x2131,        'H' => 0x210B,        'I' => 0x2110,        'L' => 0x2112,        'M' => 0x2133,        'R' => 0x211B,        'e' => 0x212F,        'g' => 0x210A,        'o' => 0x2134,        else => rangedAscii(char, 0x1D49C, 0x1D4B6, null),    };}fn frakturAscii(char: u8) ?u21 {    return switch (char) {        'C' => 0x212D,        'H' => 0x210C,        'I' => 0x2111,        'R' => 0x211C,        'Z' => 0x2128,        else => rangedAscii(char, 0x1D504, 0x1D51E, null),    };}fn doubleStruckAscii(char: u8) ?u21 {    return switch (char) {        'C' => 0x2102,        'H' => 0x210D,        'N' => 0x2115,        'P' => 0x2119,        'Q' => 0x211A,        'R' => 0x211D,        'Z' => 0x2124,        else => rangedAscii(char, 0x1D538, 0x1D552, 0x1D7D8),    };}fn doubleStruckItalicAscii(char: u8) ?u21 {    return switch (char) {        'D' => 0x2145,        'd' => 0x2146,        'e' => 0x2147,        'i' => 0x2148,        'j' => 0x2149,        else => null,    };}fn smallCapsAscii(char: u8) ?u21 {    return switch (std.ascii.toUpper(char)) {        'A' => 0x1D00,        'B' => 0x0299,        'C' => 0x1D04,        'D' => 0x1D05,        'E' => 0x1D07,        'F' => 0xA730,        'G' => 0x0262,        'H' => 0x029C,        'I' => 0x026A,        'J' => 0x1D0A,        'K' => 0x1D0B,        'L' => 0x029F,        'M' => 0x1D0D,        'N' => 0x0274,        'O' => 0x1D0F,        'P' => 0x1D18,        'Q' => 0xA7AF,        'R' => 0x0280,        'S' => 0xA731,        'T' => 0x1D1B,        'U' => 0x1D1C,        'V' => 0x1D20,        'W' => 0x1D21,        'X' => 'x',        'Y' => 0x028F,        'Z' => 0x1D22,        else => null,    };}fn greekGlyph(mode: Mode, glyph: []const u8) ?u21 {    const set = switch (mode) {        .bold => GreekSet{ .upper = 0x1D6A8, .nabla = 0x1D6C1, .lower = 0x1D6C2, .partial = 0x1D6DB, .symbol = 0x1D6DC },        .italic => GreekSet{ .upper = 0x1D6E2, .nabla = 0x1D6FB, .lower = 0x1D6FC, .partial = 0x1D715, .symbol = 0x1D716 },        .bold_italic => GreekSet{ .upper = 0x1D71C, .nabla = 0x1D735, .lower = 0x1D736, .partial = 0x1D74F, .symbol = 0x1D750 },        else => return null,    };    inline for (greekUpper, 0..) |value, index| {        if (std.mem.eql(u8, glyph, value)) return set.upper + @as(u21, @intCast(index));    }    if (std.mem.eql(u8, glyph, "∇")) return set.nabla;    inline for (greekLower, 0..) |value, index| {        if (std.mem.eql(u8, glyph, value)) return set.lower + @as(u21, @intCast(index));    }    if (std.mem.eql(u8, glyph, "∂")) return set.partial;    inline for (greekSymbols, 0..) |value, index| {        if (std.mem.eql(u8, glyph, value)) return set.symbol + @as(u21, @intCast(index));    }    return null;}const GreekSet = struct {    upper: u21,    nabla: u21,    lower: u21,    partial: u21,    symbol: u21,};fn appendScalar(arena: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8), scalar: u21) std.mem.Allocator.Error!void {    var buffer: [4]u8 = undefined;    const len = std.unicode.utf8Encode(scalar, &buffer) catch unreachable;    try out.appendSlice(arena, buffer[0..len]);}fn offset(char: u8, base: u8) u21 {    return @intCast(char - base);}const commands = [_]Command{    .{ .name = "mathbf", .mode = .bold },    .{ .name = "textbf", .mode = .bold },    .{ .name = "mathbold", .mode = .bold },    .{ .name = "mathbfup", .mode = .bold },    .{ .name = "symbf", .mode = .bold },    .{ .name = "symbfup", .mode = .bold },    .{ .name = "mathit", .mode = .italic },    .{ .name = "textit", .mode = .italic },    .{ .name = "emph", .mode = .italic },    .{ .name = "symit", .mode = .italic },    .{ .name = "mathbfit", .mode = .bold_italic },    .{ .name = "boldsymbol", .mode = .bold_italic },    .{ .name = "bm", .mode = .bold_italic },    .{ .name = "symbfit", .mode = .bold_italic },    .{ .name = "mathcal", .mode = .script },    .{ .name = "mathscr", .mode = .script },    .{ .name = "symcal", .mode = .script },    .{ .name = "symscr", .mode = .script },    .{ .name = "mathbcal", .mode = .bold_script },    .{ .name = "mathbfcal", .mode = .bold_script },    .{ .name = "mathbfscr", .mode = .bold_script },    .{ .name = "symbfcal", .mode = .bold_script },    .{ .name = "symbfscr", .mode = .bold_script },    .{ .name = "mathfrak", .mode = .fraktur },    .{ .name = "symfrak", .mode = .fraktur },    .{ .name = "mathbffrak", .mode = .bold_fraktur },    .{ .name = "symbffrak", .mode = .bold_fraktur },    .{ .name = "mathbb", .mode = .double_struck },    .{ .name = "mathds", .mode = .double_struck },    .{ .name = "symbb", .mode = .double_struck },    .{ .name = "mathbbit", .mode = .double_struck_italic },    .{ .name = "symbbit", .mode = .double_struck_italic },    .{ .name = "mathsf", .mode = .sans },    .{ .name = "mathsfup", .mode = .sans },    .{ .name = "textsf", .mode = .sans },    .{ .name = "symsf", .mode = .sans },    .{ .name = "symsfup", .mode = .sans },    .{ .name = "mathbfsf", .mode = .sans_bold },    .{ .name = "mathbfsfup", .mode = .sans_bold },    .{ .name = "mathsfbf", .mode = .sans_bold },    .{ .name = "symbfsf", .mode = .sans_bold },    .{ .name = "symbfsfup", .mode = .sans_bold },    .{ .name = "symsfbf", .mode = .sans_bold },    .{ .name = "mathsfit", .mode = .sans_italic },    .{ .name = "symsfit", .mode = .sans_italic },    .{ .name = "mathbfsfit", .mode = .sans_bold_italic },    .{ .name = "mathsfbfit", .mode = .sans_bold_italic },    .{ .name = "symbfsfit", .mode = .sans_bold_italic },    .{ .name = "symsfbfit", .mode = .sans_bold_italic },    .{ .name = "mathtt", .mode = .monospace },    .{ .name = "texttt", .mode = .monospace },    .{ .name = "symtt", .mode = .monospace },    .{ .name = "textsc", .mode = .small_caps },};const greekUpper = [_][]const u8{    "Α",    "Β",    "Γ",    "Δ",    "Ε",    "Ζ",    "Η",    "Θ",    "Ι",    "Κ",    "Λ",    "Μ",    "Ν",    "Ξ",    "Ο",    "Π",    "Ρ",    "ϴ",    "Σ",    "Τ",    "Υ",    "Φ",    "Χ",    "Ψ",    "Ω",};const greekLower = [_][]const u8{    "α",    "β",    "γ",    "δ",    "ε",    "ζ",    "η",    "θ",    "ι",    "κ",    "λ",    "μ",    "ν",    "ξ",    "ο",    "π",    "ρ",    "ς",    "σ",    "τ",    "υ",    "φ",    "χ",    "ψ",    "ω",};const greekSymbols = [_][]const u8{    "ϵ",    "ϑ",    "ϰ",    "ϕ",    "ϱ",    "ϖ",};test "alphabet maps common mathematical alphabets" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const expr = try ast.text(arena.allocator(), "Az09");    const bold = try apply(arena.allocator(), .bold, expr);    try std.testing.expectEqualStrings("𝐀𝐳𝟎𝟗", bold.text);    const blackboard = try apply(arena.allocator(), .double_struck, expr);    try std.testing.expectEqualStrings("𝔸𝕫𝟘𝟡", blackboard.text);}test "alphabet maps unicode math aliases" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const bold = try apply(arena.allocator(), command("symbfup").?, try ast.text(arena.allocator(), "A"));    try std.testing.expectEqualStrings("𝐀", bold.text);    const sans = try apply(arena.allocator(), command("symsfup").?, try ast.text(arena.allocator(), "B"));    try std.testing.expectEqualStrings("𝖡", sans.text);    const bold_sans = try apply(arena.allocator(), command("symbfsfup").?, try ast.text(arena.allocator(), "C"));    try std.testing.expectEqualStrings("𝗖", bold_sans.text);    const bold_sans_italic = try apply(arena.allocator(), command("symbfsfit").?, try ast.text(arena.allocator(), "D"));    try std.testing.expectEqualStrings("𝘿", bold_sans_italic.text);    const blackboard_italic = try apply(arena.allocator(), command("symbbit").?, try ast.text(arena.allocator(), "Ddeijx"));    try std.testing.expectEqualStrings("ⅅⅆⅇⅈⅉx", blackboard_italic.text);}test "alphabet maps script exceptions and bold Greek" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const script = try apply(arena.allocator(), .script, try ast.text(arena.allocator(), "BFeo"));    try std.testing.expectEqualStrings("ℬℱℯℴ", script.text);    const greek = try apply(arena.allocator(), .bold_italic, try ast.text(arena.allocator(), "αϕ∂"));    try std.testing.expectEqualStrings("𝜶𝝓𝝏", greek.text);    const small_caps = try apply(arena.allocator(), .small_caps, try ast.text(arena.allocator(), "E-App"));    try std.testing.expectEqualStrings("ᴇ-ᴀᴘᴘ", small_caps.text);}

Source: lib/termtex/src/root.zig:9

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

Audit

Definitions4
Public names4
Members15
Version26.7.0
Revisiondaab053ee433