Skip to content

feat: write rich inline strings (per-run formatting) via Worksheet.inlineString#606

Merged
ochedru merged 1 commit into
dhatim:masterfrom
minkyu725:feat/rich-inline-string
May 19, 2026
Merged

feat: write rich inline strings (per-run formatting) via Worksheet.inlineString#606
ochedru merged 1 commit into
dhatim:masterfrom
minkyu725:feat/rich-inline-string

Conversation

@minkyu725
Copy link
Copy Markdown
Contributor

Add support for writing rich inline strings — a single cell with multiple
font styles (bold/italic/underline, font size/name/color per run).

Use case

Template headers and cells where one fragment must be highlighted relative
to the rest currently can't be expressed: Worksheet.value(r, c, String) /
Worksheet.inlineString(r, c, String) apply one font to the whole cell.
This adds a RichText value type and a Worksheet.inlineString(int, int, RichText) overload.

API

RichText rt = RichText.builder()
    .run("Pickable (A)").end()
    .run("\n*Direct contract only").bold().fontColor("FF70AD47").end()
    .build();
worksheet.inlineString(row, col, rt);

RichText, RichText.Builder, and RichText.RunBuilder are public.
RichText.Run constructor is package-private — runs are produced through
the builder. Unset font properties on a run are omitted from <rPr>,
letting Excel inherit from the cell style.

Wire format

Per OOXML (ECMA-376 §18.4):

<c r="A1" t="inlineStr">
  <is>
    <r><t xml:space="preserve">Pickable (A)</t></r>
    <r><rPr><b/><color rgb="FF70AD47"/></rPr><t xml:space="preserve">
*Direct contract only</t></r>
  </is>
</c>

xml:space="preserve" is always emitted so leading/trailing whitespace and
newlines round-trip correctly.

Tests

Three POI round-trip cases added to PoiCompatibilityTest:

  • per-run formatting (bold + custom color) preserved
  • leading/trailing whitespace preserved
  • runs without any formatting properties produce a bare <r><t>...</t></r>

All 108 existing tests in fastexcel-writer continue to pass.

Scope

This PR touches fastexcel-writer only. Issue #382 requests the
reader module expose rich text formatting when parsing an existing
xlsx — that path is unchanged here. Reader-side work would be a natural
follow-up but is out of scope (theme/indexed color resolution requires
loading theme1.xml, which the reader currently doesn't do — best
designed in a dedicated PR).

…, RichText)

Add a RichText value type and a Worksheet.inlineString(int, int, RichText)
overload so callers can write a single cell with mixed per-run formatting
(bold, italic, underline, font size/name/color).

Output follows OOXML (ECMA-376 §18.4):
<c t="inlineStr"><is><r><rPr>...</rPr><t xml:space="preserve">...</t></r>...</is></c>

API:
  RichText rt = RichText.builder()
      .run("Pickable (A)").end()
      .run("\n*Direct contract only").bold().fontColor("FF70AD47").end()
      .build();
  worksheet.inlineString(row, col, rt);

Notes:
- RichText (and its Builder/RunBuilder) are public; Run constructor is
  package-private so runs are produced through the builder.
- Unset font fields on a run are omitted from <rPr>, letting Excel inherit
  from the cell style — matches the existing inheritance contract for the
  default cell font.
- xml:space="preserve" is always emitted so leading/trailing whitespace
  and newlines round-trip correctly.
- Three POI round-trip tests added to PoiCompatibilityTest covering
  per-run formatting, leading/trailing whitespace, and bare-run output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ochedru ochedru merged commit b616428 into dhatim:master May 19, 2026
1 check passed
@coveralls
Copy link
Copy Markdown

Coverage Status

coverage: 88.885% (-0.01%) from 88.896% — minkyu725:feat/rich-inline-string into dhatim:master

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.

3 participants