Skip to content

Adds Italic, Color, FontSize to CellBuilder, matching the behavior of ParagraphBuilder methods.#35

Open
SlashLight wants to merge 2 commits into
mmonterroca:devfrom
SlashLight:feature/cell-builder-itailc-color-font
Open

Adds Italic, Color, FontSize to CellBuilder, matching the behavior of ParagraphBuilder methods.#35
SlashLight wants to merge 2 commits into
mmonterroca:devfrom
SlashLight:feature/cell-builder-itailc-color-font

Conversation

@SlashLight

Copy link
Copy Markdown

CellBuilder already supports Text() and Bold(), but users cannot set the font size, color or italic through the fluent table API. The underlying run model already supports SetSize, Italic and Color, so this adds a small ergonomic helper.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request adds new formatting methods (Italic, Color, and FontSize) to CellBuilder, supported by a new lastRun helper method, and includes corresponding unit tests. The review feedback recommends introducing a recordError helper to reduce code duplication and prevent potential nil pointer dereferences when accessing nested parent fields, alongside a defensive nil check for cb.cell in lastRun.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread builder.go
Comment on lines +696 to +787
lastRun, err := cb.lastRun()
if err != nil {
cb.err = errors.InvalidState("CellBuilder.Bold", err.Error())
cb.parent.parent.parent.errors = append(cb.parent.parent.parent.errors, cb.err)
return cb
}

runs := paragraphs[len(paragraphs)-1].Runs()
if len(runs) == 0 {
cb.err = errors.InvalidState("CellBuilder.Bold", "no runs in paragraph")
if err := lastRun.SetBold(true); err != nil {
cb.err = err
cb.parent.parent.parent.errors = append(cb.parent.parent.parent.errors, err)
}

return cb
}

// Italic makes the last run in the last paragraph italic.
func (cb *CellBuilder) Italic() *CellBuilder {
if cb.err != nil {
return cb
}

lastRun, err := cb.lastRun()
if err != nil {
cb.err = errors.InvalidState("CellBuilder.Italic", err.Error())
cb.parent.parent.parent.errors = append(cb.parent.parent.parent.errors, cb.err)
return cb
}

if err := runs[len(runs)-1].SetBold(true); err != nil {
if err := lastRun.SetItalic(true); err != nil {
cb.err = err
cb.parent.parent.parent.errors = append(cb.parent.parent.parent.errors, err)
cb.parent.parent.parent.errors = append(cb.parent.parent.parent.errors, cb.err)
}

return cb
}

// Color sets the color of the last run of the last paragraph.
func (cb *CellBuilder) Color(color domain.Color) *CellBuilder {
if cb.err != nil {
return cb
}

lastRun, err := cb.lastRun()
if err != nil {
cb.err = errors.InvalidState("CellBuilder.Color", err.Error())
cb.parent.parent.parent.errors = append(cb.parent.parent.parent.errors, cb.err)
return cb
}

if err := lastRun.SetColor(color); err != nil {
cb.err = err
cb.parent.parent.parent.errors = append(cb.parent.parent.parent.errors, cb.err)
}

return cb
}

// FontSize sets the font size of the last run of the last paragraph.
func (cb *CellBuilder) FontSize(points int) *CellBuilder {
if cb.err != nil {
return cb
}

lastRun, err := cb.lastRun()
if err != nil {
cb.err = errors.InvalidState("CellBuilder.FontSize", err.Error())
cb.parent.parent.parent.errors = append(cb.parent.parent.parent.errors, cb.err)
return cb
}

// Convert points to half-points
halfPoints := points * 2
if err := lastRun.SetSize(halfPoints); err != nil {
cb.err = err
cb.parent.parent.parent.errors = append(cb.parent.parent.parent.errors, cb.err)
}

return cb
}

func (cb *CellBuilder) lastRun() (domain.Run, error) {
paras := cb.cell.Paragraphs()
if len(paras) == 0 {
return nil, fmt.Errorf("no paragraphs in cell")
}
runs := paras[len(paras)-1].Runs()
if len(runs) == 0 {
return nil, fmt.Errorf("no runs in paragraph")
}

return runs[len(runs)-1], nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

To improve safety, maintainability, and reduce code duplication, we can introduce a recordError helper method on CellBuilder. This helper centralizes error assignment and safely appends to the parent document's error slice only if the parent chain is fully initialized (preventing potential nil pointer dereferences in tests or isolated usage). Additionally, we should add a defensive check in lastRun to ensure cb.cell is not nil before calling Paragraphs().

	lastRun, err := cb.lastRun()
	if err != nil {
		cb.recordError(errors.InvalidState("CellBuilder.Bold", err.Error()))
		return cb
	}

	if err := lastRun.SetBold(true); err != nil {
		cb.recordError(err)
	}

	return cb
}

// Italic makes the last run in the last paragraph italic.
func (cb *CellBuilder) Italic() *CellBuilder {
	if cb.err != nil {
		return cb
	}

	lastRun, err := cb.lastRun()
	if err != nil {
		cb.recordError(errors.InvalidState("CellBuilder.Italic", err.Error()))
		return cb
	}

	if err := lastRun.SetItalic(true); err != nil {
		cb.recordError(err)
	}

	return cb
}

// Color sets the color of the last run of the last paragraph.
func (cb *CellBuilder) Color(color domain.Color) *CellBuilder {
	if cb.err != nil {
		return cb
	}

	lastRun, err := cb.lastRun()
	if err != nil {
		cb.recordError(errors.InvalidState("CellBuilder.Color", err.Error()))
		return cb
	}

	if err := lastRun.SetColor(color); err != nil {
		cb.recordError(err)
	}

	return cb
}

// FontSize sets the font size of the last run of the last paragraph.
func (cb *CellBuilder) FontSize(points int) *CellBuilder {
	if cb.err != nil {
		return cb
	}

	lastRun, err := cb.lastRun()
	if err != nil {
		cb.recordError(errors.InvalidState("CellBuilder.FontSize", err.Error()))
		return cb
	}

	// Convert points to half-points
	halfPoints := points * 2
	if err := lastRun.SetSize(halfPoints); err != nil {
		cb.recordError(err)
	}

	return cb
}

func (cb *CellBuilder) lastRun() (domain.Run, error) {
	if cb.cell == nil {
		return nil, fmt.Errorf("cell is nil")
	}
	paras := cb.cell.Paragraphs()
	if len(paras) == 0 {
		return nil, fmt.Errorf("no paragraphs in cell")
	}
	runs := paras[len(paras)-1].Runs()
	if len(runs) == 0 {
		return nil, fmt.Errorf("no runs in paragraph")
	}

	return runs[len(runs)-1], nil
}

func (cb *CellBuilder) recordError(err error) {
	if err == nil {
		return
	}
	if cb.err == nil {
		cb.err = err
	}
	if cb.parent != nil && cb.parent.parent != nil && cb.parent.parent.parent != nil {
		cb.parent.parent.parent.errors = append(cb.parent.parent.parent.errors, err)
	}
}

@SlashLight

Copy link
Copy Markdown
Author

hey @mmonterroca . What do you think? I'd really appreciate to see this feature in the nearest future

@mmonterroca

Copy link
Copy Markdown
Owner

hey @mmonterroca . What do you think? I'd really appreciate to see this feature in the nearest future

Hello! great! let' me check!

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.

2 participants