diff --git a/markdown.go b/markdown.go index b5c2531..3e940e9 100644 --- a/markdown.go +++ b/markdown.go @@ -1,7 +1,6 @@ package termhyo import ( - "fmt" "strings" ) @@ -27,7 +26,7 @@ func hasAutoWidth(table *Table) bool { // AddRow adds a row for markdown rendering (buffered mode for width calculation). func (r *MarkdownRenderer) AddRow(_ *Table, row Row) error { if r.rendered { - return fmt.Errorf("cannot add rows after table is rendered") + return ErrAddAfterRender } // Buffer the row for width calculation @@ -40,7 +39,7 @@ func (r *MarkdownRenderer) AddRow(_ *Table, row Row) error { // Render renders any remaining content (for streaming, this is just cleanup). func (r *MarkdownRenderer) Render(table *Table) error { if r.rendered { - return fmt.Errorf("table already rendered") + return ErrTableAlreadyRendered } // Calculate column widths if needed using all buffered rows diff --git a/renderer.go b/renderer.go index 56da8c4..a9914cc 100644 --- a/renderer.go +++ b/renderer.go @@ -1,7 +1,5 @@ package termhyo -import "fmt" - // Renderer defines the interface for different rendering strategies. type Renderer interface { AddRow(table *Table, row Row) error @@ -39,7 +37,7 @@ type Buffered struct { // AddRow adds a row to the buffered renderer. func (r *Buffered) AddRow(table *Table, row Row) error { if r.rendered { - return fmt.Errorf("cannot add rows after table is rendered") + return ErrAddAfterRender } // Store row for later rendering table.rows = append(table.rows, row) @@ -49,7 +47,7 @@ func (r *Buffered) AddRow(table *Table, row Row) error { // Render renders the buffered content all at once. func (r *Buffered) Render(table *Table) error { if r.rendered { - return fmt.Errorf("table already rendered") + return ErrTableAlreadyRendered } // Calculate column widths for auto-width columns @@ -88,7 +86,7 @@ type Streaming struct { // AddRow adds a row to the streaming renderer. func (r *Streaming) AddRow(table *Table, row Row) error { if r.rendered { - return fmt.Errorf("cannot add rows after table is rendered") + return ErrAddAfterRender } if !r.headerDone { @@ -104,7 +102,7 @@ func (r *Streaming) AddRow(table *Table, row Row) error { // Render renders the streaming content, typically just the footer. func (r *Streaming) Render(table *Table) error { if r.rendered { - return fmt.Errorf("table already rendered") + return ErrTableAlreadyRendered } // For streaming mode, just render footer diff --git a/table.go b/table.go index 1da92b0..3d06d6c 100644 --- a/table.go +++ b/table.go @@ -1,10 +1,24 @@ package termhyo import ( + "errors" "io" "strings" ) +var ( + // ErrNoColumns is returned when trying to render a table with no columns defined. + ErrNoColumns = errors.New("no columns defined") + // ErrNoHeader is returned when trying to render a table without a header. + ErrNoHeader = errors.New("header is required") + // ErrNoMarkdownHeader is returned when trying to render a markdown table without a header. + ErrNoMarkdownHeader = errors.New("markdown table requires at least one non-empty header") + // ErrTableAlreadyRendered is returned when trying to render a table that has already been rendered. + ErrTableAlreadyRendered = errors.New("table has already been rendered") + // ErrAddAfterRender is returned when trying to add a row after rendering. + ErrAddAfterRender = errors.New("cannot add row after table has been rendered") +) + // TableOption is a functional option for configuring Table. type TableOption func(*Table) @@ -59,7 +73,7 @@ func (t *Table) GetAlign() bool { // // Example: // -// table := termhyo.NewTable(os.Stdout, columns, termhyo.Border(termhyo.DoubleStyle), termhyo.Align(false)) +// table := termhyo.NewTable(os.Stdout, columns, termhyo.Border(termhyo.DoubleStyle), termhyo.AutoAlign(false)) // // This is the recommended way to create and configure tables in termhyo. func NewTable(writer io.Writer, columns []Column, opts ...TableOption) *Table { @@ -223,6 +237,9 @@ func (t *Table) CalculateColumnWidths() { // RenderHeader renders the table header. func (t *Table) RenderHeader() error { + if len(t.columns) == 0 { + return ErrNoColumns + } // Top border (only if enabled) if t.borderConfig.Top { if err := t.RenderBorderLine("top"); err != nil {