// F3 numbering part: two fixed definitions — an unordered (bullet) list
// and an ordered (decimal) list, nine levels each — matching what the AST
// can express (`Numbering { is_ordered, level }`). numId 1 = unordered,
// numId 2 = ordered; the reader maps them back through numFmt ("bullet" ⇒
// unordered) and ilvl (+1), so read(write(x)) preserves the numbering.
///|
const UNORDERED_NUM_ID : String = "1"
///|
const ORDERED_NUM_ID : String = "2"
///|
/// The complete `word/numbering.xml` for written documents. CT_Lvl is an
/// enforced sequence: start, numFmt, lvlText, lvlJc, pPr.
fn numbering_xml() -> String {
let children : Array[XmlNode] = [
XmlElement(abstract_num("0", is_ordered=false)),
XmlElement(abstract_num("1", is_ordered=true)),
XmlElement(num_instance(UNORDERED_NUM_ID, "0")),
XmlElement(num_instance(ORDERED_NUM_ID, "1")),
]
@xml.write_xml_string(@xml.xml_element("w:numbering", children~), namespaces={
"w": WORDPROCESSINGML_NAMESPACE,
})
}
///|
fn abstract_num(abstract_id : String, is_ordered~ : Bool) -> XmlElement {
let levels : Array[XmlNode] = []
for index in 0..<9 {
let num_fmt = if is_ordered { "decimal" } else { "bullet" }
let level_text = if is_ordered { "%\{index + 1}." } else { "•" }
// Word's conventional cascade: 720 twips (0.5in) per level, hanging 360.
let indent = ((index + 1) * 720).to_string()
levels.push(
XmlElement(
@xml.xml_element("w:lvl", attributes={ "w:ilvl": index.to_string() }, children=[
XmlElement(@xml.xml_element("w:start", attributes={ "w:val": "1" })),
XmlElement(
@xml.xml_element("w:numFmt", attributes={ "w:val": num_fmt }),
),
XmlElement(
@xml.xml_element("w:lvlText", attributes={ "w:val": level_text }),
),
XmlElement(
@xml.xml_element("w:lvlJc", attributes={ "w:val": "left" }),
),
XmlElement(
@xml.xml_element("w:pPr", children=[
XmlElement(
@xml.xml_element("w:ind", attributes={
"w:left": indent,
"w:hanging": "360",
}),
),
]),
),
]),
),
)
}
@xml.xml_element(
"w:abstractNum",
attributes={ "w:abstractNumId": abstract_id },
children=levels,
)
}
///|
fn num_instance(num_id : String, abstract_id : String) -> XmlElement {
@xml.xml_element("w:num", attributes={ "w:numId": num_id }, children=[
XmlElement(
@xml.xml_element("w:abstractNumId", attributes={ "w:val": abstract_id }),
),
])
}