Skip to content

fix(zpl): emit ^CI28, a ^CF default font and ^FH escaping in list labels - #56

Merged
PeteRichardson merged 1 commit into
mainfrom
worktree-issue-53-zpl-encoding
Aug 31, 2026
Merged

PeteRichardson merged 1 commit into
mainfrom
worktree-issue-53-zpl-encoding

Conversation

@PeteRichardson

Copy link
Copy Markdown
Owner

Closes #53.

The three fixes (Sources/LabelKit/Labels/ListLayout.swift)

The prologue becomes ^XA^CI28^PW1200^LH0,0^LS0^CF0,50,50^LL…; item rows drop their font command, headers keep theirs.

Before After
Encoding (none — printer not in UTF-8) ^CI28
Item row ^A0N,50,50^FO100,90^FDeggs^FS ^FO100,90^FH^FDeggs^FS
Header row ^A0N,60,60^FO60,100^FDCostco:^FS ^A0N,60,60^FO60,100^FH^FDCostco:^FS
^ / ~ in text deleted _5E / _7E

^A is scoped to its own field, so a header's ^A0N does not leak into the items below it — that is what makes the ^CF fix safe. Confirmed empirically, not assumed (see Verification).

A fourth escape the issue didn't list

_ is ^FH's own escape introducer. Left alone it silently consumes the next two characters, so it must become _5F. Without this, snake_case_item would have been corrupted by the very fix meant to stop corruption.

ReminderList (Examples/ReminderList/ReminderList.swift)

Pulled into scope. generate_label hand-rolled a second, weaker copy of this layout and never sanitized at all — so a reminder titled pay ^XZ rent emitted a second ^XZ, terminating the label early and dropping every row below it. A live injection bug, worse than the one #53 describes.

Rather than duplicate the fixes it now delegates to ListLayout(itemIndent: 80) — the 80 preserves the historical left margin, and the derived ^PW1200 matches what it hardcoded. Drops ~30 lines of parallel geometry code.

Added a ReminderListTests target (mirroring the existing LabelPrintTests pattern); the example had no coverage before.

Verification

Rendered through Labelary, the reference renderer, with Costco: / café piña jalapeño / bad^XZ and ~JA ok / snake_case_item:

  • accents render correctly (^CI28 working)
  • ^ and ~ print as literal characters, label not truncated
  • underscores preserved
  • header set larger, items smaller — ^CF default holds and the header font does not leak

swift build && swift test — Build complete, 123 tests / 26 suites passed (110 / 25 on main).

Notes

Closes #53.

- ListLayout: emit ^CI28 (UTF-8) in the prologue. Without it the printer
  is not in UTF-8 mode and any non-ASCII input prints as garbage --
  "café piña jalapeño" came out as "caf├® pi▨a jalape▨o". Reachable with
  ordinary input, since labelprint reads arbitrary text on stdin.
- ListLayout: set the item font once with ^CF0,h,h instead of repeating
  ^A0N,h,h on every row. Only headers still carry their own ^A0N, since
  ^A is scoped to its own field and the next item falls back to ^CF.
  Removes one command per item row.
- ListLayout: replace sanitized() -- which deleted ^ and ~ outright,
  silently corrupting the user's text -- with escaped() under ^FH, so
  they print as the real characters via _5E/_7E. Same protection, no
  data loss.

The issue lists three escapes but there are four: _ is ^FH's own escape
introducer, so a literal underscore must become _5F or it silently eats
the next two characters. "snake_case_item" would have been corrupted.

ReminderList.generate_label hand-rolled a second, weaker copy of this
layout: it never sanitized at all, so a reminder titled "pay ^XZ rent"
emitted a second ^XZ and terminated the label early, dropping every row
below it. It now delegates to ListLayout(itemIndent: 80), which keeps
the historical left margin and the derived ^PW1200 it hardcoded, and
picks up all four fixes. Drops ~30 lines of parallel geometry code.

Adds a ReminderListTests target (mirroring LabelPrintTests) -- the
example had no coverage before.

Verified against Labelary, the reference renderer: accents correct,
^ and ~ printed literally without truncating the label, underscores
preserved, and the header's ^A0N does not leak into following items.

swift build && swift test: Build complete!, 123 tests / 26 suites passed
(110 / 25 before).
@PeteRichardson PeteRichardson self-assigned this Aug 31, 2026

@PeteRichardson PeteRichardson left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@PeteRichardson
PeteRichardson merged commit c1eeb44 into main Aug 31, 2026
1 check passed
@PeteRichardson
PeteRichardson deleted the worktree-issue-53-zpl-encoding branch August 31, 2026 16:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Emit leaner, correcter ZPL: ^CF default font, ^CI28 UTF-8, ^FH escaping

1 participant