Files
wehub-resource-sync 8cb1f9f479
Publish SDK (PyPI) / publish (push) Waiting to run
Publish SDK (npm) / publish (@aionui/officecli-sdk) (push) Waiting to run
Publish SDK (npm) / publish (@officecli/officecli-sdk) (push) Waiting to run
Publish SDK (npm) / publish (@officecli/sdk) (push) Waiting to run
Publish SDK (npm) / publish (officecli-sdk) (push) Waiting to run
SDK smoke / smoke (windows-latest) (push) Waiting to run
SDK smoke / smoke (macos-latest) (push) Waiting to run
SDK smoke / smoke (ubuntu-latest) (push) Waiting to run
Skill parity / diff (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:09:29 +08:00

312 lines
12 KiB
Python

#!/usr/bin/env python3
"""
Numbering & List Showcase — generates numbering.docx exercising every supported
`num` / `abstractNum` feature:
• abstractNum top-level props: name, styleLink, numStyleLink, multiLevelType
• Per-level dotted props on all levels: format, text, start, indent, hanging,
justification, suff, font, size, color, bold, italic
• num mode A (auto-create matching abstractNum from format/text/indent)
• num mode B (reuse existing abstractNum via abstractNumId)
• num mode C (startOverride — restart numbering for one instance)
• Two num instances sharing one abstractNum → independent counters
• continue=true opt-in to Word-style continuation
• style-borne numPr (paragraph inherits numbering via pStyle)
• Set on /numbering/abstractNum[@id=N]/level[L] after creation
SDK twin of numbering.sh (officecli CLI). Both produce an equivalent
numbering.docx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started, the `add num` calls go
out via `doc.send(...)` so we can read back each freshly-minted numId, and the
paragraphs that reference those ids ship in `doc.batch(...)` round-trips. Each
item is the same `{"command","parent","type","props"}` dict you'd put in an
`officecli batch` list.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 numbering.py
"""
import os
import re
import sys
# --- locate the SDK: prefer an installed `officecli-sdk`, else the in-repo copy
try:
import officecli # pip install officecli-sdk
except ImportError:
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
"..", "..", "sdk", "python"))
import officecli
FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "numbering.docx")
def para(text, **props):
"""One `add paragraph` item in batch-shape."""
return {"command": "add", "parent": "/body", "type": "paragraph",
"props": {"text": text, **props}}
def _num_id(resp):
"""Pull the numId out of an `add num` envelope ("Added num at
/numbering/num[@id=N]") — the SDK twin of the .sh `sed @id=N` capture."""
text = resp.get("data") or resp.get("message") or "" if isinstance(resp, dict) else str(resp)
m = re.search(r"@id=(\d+)\]", text)
if not m:
raise RuntimeError(f"could not parse numId from add response: {resp!r}")
return m.group(1)
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
def add_num(**props):
"""`add /numbering --type num` via send(), returning the new numId."""
return _num_id(doc.send({"command": "add", "parent": "/numbering",
"type": "num", "props": props}))
# ============================================================
# Title
# ============================================================
doc.batch([
para("Numbering & List Showcase",
align="center", bold="true", size="20"),
para("Generated by officecli — covers abstractNum, num, and style-borne numPr",
align="center", italic="true", color="666666"),
para(""),
# ===== Section 1 heading + abstractNum #100 (custom 3-level template) =====
para("1. Three-level numbered list (custom marker styling)",
bold="true", size="14", spaceBefore="240", spaceAfter="120"),
])
# abstractNum #100 — fully customized 3-level numbered template
doc.send({"command": "add", "parent": "/numbering", "type": "abstractNum", "props": {
"id": "100",
"name": "ShowcaseMultilevel",
"type": "hybridMultilevel",
"level0.format": "decimal",
"level0.text": "%1.",
"level0.indent": "720",
"level0.hanging": "360",
"level0.justification": "left",
"level0.suff": "tab",
"level0.color": "C00000",
"level0.bold": "true",
"level0.size": "14",
"level1.format": "lowerLetter",
"level1.text": "%2)",
"level1.indent": "1440",
"level1.hanging": "360",
"level1.color": "2E74B5",
"level1.italic": "true",
"level2.format": "lowerRoman",
"level2.text": "%3.",
"level2.indent": "2160",
"level2.hanging": "360",
"level2.color": "666666",
}})
# A num instance pointing at #100
num_a = add_num(abstractNumId="100")
print(f" Created num #{num_a} → abstractNum #100")
doc.batch([
para("Project Phoenix kickoff agenda", numId=num_a, ilvl="0"),
para("Stakeholder alignment", numId=num_a, ilvl="1"),
para("identify decision makers", numId=num_a, ilvl="2"),
para("schedule discovery interviews", numId=num_a, ilvl="2"),
para("Architecture review", numId=num_a, ilvl="1"),
para("Sprint planning", numId=num_a, ilvl="0"),
para("Resource allocation", numId=num_a, ilvl="0"),
# ===== Section 2 heading =====
para(""),
para("2. Independent counters (default) and continue=true opt-in",
bold="true", size="14", spaceBefore="240", spaceAfter="120"),
])
# Two new nums on the same abstractNum: by default each gets its own
# auto-injected startOverride.0 → independent counters. The third opts into
# Word's literal continuation via continue=true.
num_b = add_num(abstractNumId="100")
print(f" Created num #{num_b} → independent counter (auto-injected startOverride.0=1)")
num_cont = add_num(abstractNumId="100", **{"continue": "true"})
print(f" Created num #{num_cont} → Word-style continuation (continue=true)")
doc.batch([
para("List B starts fresh at 1 (default behavior)", numId=num_b, ilvl="0"),
para("List B item two (counts 2)", numId=num_b, ilvl="0"),
para("List C continues from List A's count (continue=true)", numId=num_cont, ilvl="0"),
para("List C item two", numId=num_cont, ilvl="0"),
# ===== Section 3 heading =====
para(""),
para("3. Restart numbering with startOverride",
bold="true", size="14", spaceBefore="240", spaceAfter="120"),
])
# Mode C — num with startOverride (restart at 100)
num_c = add_num(abstractNumId="100", start="100")
print(f" Created num #{num_c} → abstractNum #100 with startOverride.0=100")
doc.batch([
para("Numbered starting from 100", numId=num_c, ilvl="0"),
para("Continues from 101", numId=num_c, ilvl="0"),
# ===== Section 4 heading =====
para(""),
para("4. Custom-styled bullet list (★ / ▶ / ●)",
bold="true", size="14", spaceBefore="240", spaceAfter="120"),
])
# abstractNum #200 — bullet list with custom glyphs and font color
doc.send({"command": "add", "parent": "/numbering", "type": "abstractNum", "props": {
"id": "200",
"name": "StarBullet",
"type": "hybridMultilevel",
"level0.format": "bullet",
"level0.text": "★",
"level0.color": "E8B003",
"level0.size": "12",
"level1.format": "bullet",
"level1.text": "▶",
"level1.font": "Arial",
"level1.color": "2E74B5",
"level1.indent": "1440",
"level2.format": "bullet",
"level2.text": "●",
"level2.color": "70AD47",
"level2.indent": "2160",
}})
num_bullet = add_num(abstractNumId="200")
doc.batch([
para("Top-level milestone", numId=num_bullet, ilvl="0"),
para("Sub-milestone with deliverable", numId=num_bullet, ilvl="1"),
para("Nitty-gritty detail", numId=num_bullet, ilvl="2"),
para("Another top-level milestone", numId=num_bullet, ilvl="0"),
# ===== Section 5 heading =====
para(""),
para("5. Mode A — num auto-creates abstractNum",
bold="true", size="14", spaceBefore="240", spaceAfter="120"),
])
# Mode A — num auto-creates a matching abstractNum on the fly
num_auto = add_num(**{
"level0.format": "upperRoman",
"level0.text": "%1.",
"level0.indent": "720",
"level0.size": "12",
"level0.color": "7030A0",
"level0.bold": "true",
})
print(f" Mode A created num #{num_auto} + matching abstractNum")
doc.batch([
para("The first part of the proposal", numId=num_auto, ilvl="0"),
para("The second part", numId=num_auto, ilvl="0"),
para("The third part", numId=num_auto, ilvl="0"),
# ===== Section 6 heading =====
para(""),
para("6. Style-borne numbering (paragraph inherits via pStyle)",
bold="true", size="14", spaceBefore="240", spaceAfter="120"),
])
# Build a dedicated abstractNum + num for the style
doc.send({"command": "add", "parent": "/numbering", "type": "abstractNum", "props": {
"id": "300",
"name": "StyleBorne",
"level0.format": "decimalZero",
"level0.text": "%1.",
"level0.indent": "720",
"level0.color": "C00000",
}})
num_style = add_num(abstractNumId="300")
# Style holds the numPr; paragraphs reference the style without their own numId
doc.send({"command": "add", "parent": "/styles", "type": "style", "props": {
"id": "ShowcaseListItem",
"name": "Showcase List Item",
"type": "paragraph",
"basedOn": "Normal",
"numId": num_style,
"ilvl": "0",
}})
doc.batch([
para("Inherits numbering through style", style="ShowcaseListItem"),
para("Second item, also via style", style="ShowcaseListItem"),
para("Third item — note: paragraphs themselves have no numPr", style="ShowcaseListItem"),
# ===== Section 7 heading =====
para(""),
para("7. Modify abstractNum after creation",
bold="true", size="14", spaceBefore="240", spaceAfter="120"),
])
# Set after create — override abstractNum #100 level 3 with green + larger size
doc.send({"command": "set",
"path": "/numbering/abstractNum[@id=100]/level[3]",
"props": {"format": "decimal", "text": "Step %4 ⇒",
"color": "70AD47", "bold": "true", "size": "12"}})
num_deep = add_num(abstractNumId="100")
doc.batch([
para("Outer step", numId=num_deep, ilvl="0"),
para("Mid step", numId=num_deep, ilvl="1"),
para("Inner step", numId=num_deep, ilvl="2"),
para("Deepest step (modified after creation)", numId=num_deep, ilvl="3"),
# ===== Section 8 heading =====
para(""),
para("8. styleLink, numStyleLink, level<N>.start, direction, isLgl, lvlRestart",
bold="true", size="14", spaceBefore="240", spaceAfter="120"),
])
# abstractNum #400 — styleLink + numStyleLink + per-level start
doc.send({"command": "add", "parent": "/numbering", "type": "abstractNum", "props": {
"id": "400",
"name": "CoverageAbs",
"type": "multilevel",
"styleLink": "CoverageStyle",
"numStyleLink": "OutlineRef",
"level0.format": "decimal",
"level0.text": "%1.",
"level0.start": "1",
"level1.format": "lowerLetter",
"level1.text": "%2)",
"level1.start": "3",
"level2.format": "lowerRoman",
"level2.text": "%3.",
"level2.start": "5",
}})
# Set direction=rtl, isLgl=true, lvlRestart=0 on individual levels via Set
doc.send({"command": "set",
"path": "/numbering/abstractNum[@id=400]/level[1]",
"props": {"direction": "rtl"}})
doc.send({"command": "set",
"path": "/numbering/abstractNum[@id=400]/level[2]",
"props": {"isLgl": "true", "lvlRestart": "0"}})
num_cov = add_num(abstractNumId="400")
print(f" Created num #{num_cov} → abstractNum #400 (coverage)")
doc.batch([
para("Item starting at 1 (level0.start=1)", numId=num_cov, ilvl="0"),
para("Sub-item starting at c (level1.start=3, direction=rtl)", numId=num_cov, ilvl="1"),
para("Deep item starting at v (level2.start=5, isLgl, lvlRestart=0)", numId=num_cov, ilvl="2"),
# ===== Closer =====
para(""),
para("End of showcase. Open in Word/Google Docs to see all numbering rendered.",
italic="true", color="666666", align="center"),
])
print(f"Generated: {FILE}")