Text formatting library

Browse the source. Ctrl-click or Cmd-click a function to go to its definition. You can also click or tap a linked name.

format/format.np
format (streams, template)

# Builtin shapes and custom formatters share one recursive set.
# Template parts preserve their native scalar types and borrow captured text.
# Actual Template carriers inside aggregates require compiler carrier support.
{Interface*:
    (&self) format() |byte|}

{Class*: Interface | none | bool | byte | int | float | float32 | str | [byte] | Template | Class ? none | [Class] | [Class -> Class] | <Class, *> | <Class | *>}

# Rendering is a borrowed byte stream. Buffer creation is an ordinary consumer.
value*(input &t Class) |byte| from input
    valueStream(input, false)

bytes*(input &t Class) [byte]
    append([byte:], input)

append*(out [byte], input &t Class) [byte]
    when t is
        Template appendTemplate(out, input, 0)
        otherwise appendStream(out, input)

# A template's parts go straight into the buffer, one bulk append each;
# no list of rendered parts is built first.
appendTemplate(out [byte], input &t Any, index int) [byte]
    when template.partAt(input, index) is
        item appendTemplate(appendPart(out, item), input, index + 1)
        absent out

appendPart(out [byte], item template.part) [byte]
    when item is
        <template.part: literal as text> appendText(out, text)
        <template.part: text> appendText(out, text)
        <template.part: bytes as text> appendText(out, text)
        <template.part: integer as number> appendInteger(out, number)
        <template.part: boolean as flag> appendText(out, pick(flag, "true", "false"))
        <template.part: byte as number> appendInteger(out, int(number))
        <template.part: real as number> appendRendered(out, renderedFloat(number, 53, -1074))
        <template.part: real32 as number> appendRendered(out, renderedFloat(float(number), 24, -149))
        # rune, value and nested pieces render in the one C renderer: the
        # operations that walk parts here are replaced by its stubs
        <template.part: rune as ignoredRune> out
        <template.part: value> out
        <template.part: nested> out

appendRendered(out [byte], part renderedPart) [byte]
    update grown = out to [*grown, renderedByte(part, i)] for i in streams.range(0, renderedLength(part))

appendStream(out [byte], input &t Class) [byte]
    update gathered = out to
        [*gathered, item]
    for item in value(input)
    gathered