fig-sys 4.1.0

FFI bindings and native library for fig (the comment-preserving JSON/YAML/TOML/… config engine). Used by the `fig` crate.
Documentation
const nestedtext = @This();
const Document = @import("../../document.zig");
const lang = @import("../manifest.zig");

pub const Parser = @import("parser.zig");
pub const Tokenizer = @import("tokenizer.zig");
pub const Printer = @import("printer.zig");

pub const Type = enum {
    /// NestedText (https://nestedtext.org) — the one dialect this parser
    /// accepts (the format has no versioned spec the way TOML does; recent
    /// releases (3.x) haven't changed the on-disk grammar this reads).
    NESTEDTEXT,
};

pub const Language = struct {
    pub const Type = nestedtext.Type;
    pub const Parser = nestedtext.Parser;
    pub const Printer = nestedtext.Printer;
    pub const default_type: nestedtext.Type = .NESTEDTEXT;
    pub fn parse(parser: *nestedtext.Parser, input: []const u8, format: nestedtext.Type) !Document {
        return nestedtext.Parser.parse(parser.allocator, input, format);
    }
    pub const print = nestedtext.Printer.print;
    pub const printNode = nestedtext.Printer.printNode;

    pub const name = "nestedtext";
    pub const extensions: []const []const u8 = &.{"nt"};
    pub const caps: lang.Caps = .{ .read = true, .edit = true, .serialize = true };

    /// What `languages/harness.zig` round-trips and edits: a dict with a
    /// nested list.
    pub const samples: []const []const u8 = &.{
        "a: 1\nb:\n  - x\n  - y\n",
    };

    /// Nested (dict/list) but deliberately untyped — every leaf is a string.
    pub const dialects: []const lang.Dialect(@This()) = &.{.{
        .name = "nestedtext",
        .abi_value = 13,
        // LAST, after even `.properties` — not because its own grammar is
        // unusually permissive (it isn't: keys/values have real restrictions,
        // unlike `.properties`'s "nearly any text"), but because a huge,
        // ordinary swath of it — plain `key: value` lines and `- item` lists —
        // is ALSO valid YAML, and parses to a MEANINGFULLY DIFFERENT tree there
        // (YAML types `port: 80` as an integer; NestedText's `port` is the
        // untyped string `"80"`). Trying this before YAML would silently change
        // what `detect()` returns for ordinary plain-YAML content already relied
        // upon elsewhere in this codebase — a real regression, not just an
        // academic ambiguity — so NestedText only gets a turn once every
        // stricter-or-equally-plausible format (including YAML) has rejected
        // the input. Its real path to selection is the `.nt` extension (see
        // `cli/args.zig`), exactly like dotenv/`.properties`.
        .sniff_rank = 11,
        .splice = .raw,
        .empty_doc_seed = "",
    }};

    pub fn syntax(t: nestedtext.Type) lang.Syntax {
        _ = t;
        return .{
            // Joins INI: a `#` after a value on the SAME line is literal
            // rest-of-line value text, not a comment (see `parser.zig`,
            // "rest-of-line values are 100% literal"). A trailing comment can
            // only ever be its own `#` line immediately after the entry.
            .comments = .{ .style = .hash, .line = .{ .open = "#" }, .trailing = null },
            // The inline dict form, `{a: 1, b: 2}`, is what the generic
            // flow-entry insert writes; a block entry goes through
            // `renderEntry`.
            .kv_sep = ": ",
            // No literal spelling for an empty nested dict — every value is
            // either rest-of-line text or a nested block — so `set` cannot
            // auto-vivify a missing ancestor.
            .empty_map_literal = null,
            // Four-space nesting; an item is `- value`.
            .indent_unit = "    ",
            .seq_item_marker = "- ",
        };
    }

    // ── Renderers ────────────────────────────────────────────────────────────
    //
    // No hooks. Four renderers say how NestedText spells an entry, an item,
    // what follows a key, and a renamed key; every operation is the generic
    // engine's. The engine dispatches on PRESENCE — `Editor.hasRenderer`,
    // which is `@hasDecl` here — and a renderer it finds is called with the
    // dialect and strings, and returns a string.
    // The logic lives in `editor_helper.zig` (which holds this format's
    // editor tests too), not here: this block is the DECLARATION of what
    // this format supplies.
    const edit = @import("editor_helper.zig");

    /// A value is framed either rest-of-line or as a nested `>`-block, on
    /// a four-space nesting convention, and a key that cannot be spelled
    /// plain takes the `: key` multiline form — none of which `key`,
    /// `kv_sep`, value on one line can write.
    pub const renderEntry = edit.renderEntry;

    /// The item twin: `- value`, or a bare `-` over a nested `>`-block for
    /// an empty or multi-line value.
    pub const renderItem = edit.renderItem;

    /// A value is always a raw scalar (this format has no typed or quoted
    /// literal syntax to splice verbatim) RENDERED same-line or as a nested
    /// `>`-block per its shape, so a replacement is reframed from the key —
    /// `:` and the tail after a plain key, the tail alone after a multiline
    /// `: key`, which has no separator — and the document root is a `>`
    /// block at column 0. The parser records each plain key's `:` so the
    /// engine knows to reframe.
    pub const renderTail = edit.renderTail;

    /// A plain key's span excludes its trailing `:` while a multiline key has
    /// no separator colon at all and starts at its line's indent, so a rename
    /// spells the new key in whichever form it needs, adding or dropping the
    /// colon — and refuses plain-to-multiline, which would also have to move
    /// a same-line value.
    pub const renderKey = edit.renderKey;
};

// Test discovery: importing `nestedtext.zig` (from root.zig) pulls in every
// submodule's tests, so the module owns its own test surface.
test {
    _ = @import("tokenizer.zig");
    _ = @import("parser.zig");
    _ = @import("printer.zig");
    _ = @import("editor_helper.zig");
}