render

package
v0.4.28 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 19, 2026 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AlignField

func AlignField(f field.Field, col column.Info, opts *options.Options) string

func MinWidth

func MinWidth(rlr ruler.Ruler, col column.Info, opts *options.Options) (chars int, hasHorizontal bool)

MinWidth returns the minimum width of a ruler's field when rendered for a set of column flags and a given layout.

The width 0 will be returned if the column's width is 0 and the layout's CollapseEmpty field is true.

The hasHorizontal flag will be true if at least one horizontal character is included in the minimal ruler. If none of a ruler's fields includes a horizontal character and none of the columns are wider than the minimal ruler, then at least one column should be widened to ensure that the ruler can be parsed properly.

func PaddingWidth

func PaddingWidth(f field.Field, col column.Info) (left, right int)

PaddingWidth calculates the number of spaces to add to the left and/or right of a field's encoded string in order to make the field align with the rest of its column.

Scenarios:

Assumptions:
	- padding = column.Chars - field.Chars

| column  |  field  ||           left           |           right            | description |
| ------- | ------- || ------------------------ | -------------------------- | ----------- |
| number  | number  || padding - right          | column.right - field.right | expected    |
|         | version || padding - right          | column.right - field.right |             |
|         | text    || padding                  | 0                          |             |
| ------- | ------- || ------------------------ | -------------------------- | ----------- |
| version | version || column.left - field.left | padding - left             | expected    |
|         | number  || column.left - field.left | padding - left             |             |
|         | text    || 0                        | padding                    |             |
| ------- | ------- || ------------------------ | -------------------------- | ----------- |
| center  | any     || padding / 2              | padding - left             |             |
| right   | any     || padding                  | 0                          |             |
| left    | any     || 0                        | padding                    |             |

func RenderRulerField

func RenderRulerField(rlr ruler.Ruler, col column.Info, opts *options.Options) string

RenderRulerField returns a single field of a ruler.

  • the field MUST be column.Width.Chars + 2 characters wide, i.e. data + padding
  • exception: profile.CollapseEmpty may reduce the field to "" if the column's width is 0
  • if the ruler's padding character is whitespace, the padding character must be the first and last character of the field
  • if the ruler's padding character is not a whitespace, then the ruler must be fill the whole field
  • alignment and sorting hints must be added if allowed by the layout

Ruler construction:

  • c = column info
  • m = align marker
  • s = sort marker
  • p = padding, if ruler is padded

Layout:

absolute column width |<------------------------- c.Chars ------------------------->|
numeric alignment                        |<----- c.Left ----->|<----- c.Right ----->|
version alignment     |<----- c.Left ----->|<----- c.Right ----->|
column hints          |p m.left ------------- m.middle ----------------- m.right s p|

Invariants / Assumptions:

  • column.Width.Chars must be >= minimum width for ruler
  • either column.Width.Left + column.Width.Right == column.Width.Chars or column.Width.Left + column.Width.Right == 0
  • bit patterns define where markers should be placed, i.e. left|middle|right
  • middle != center: center
  • at least one ruler field MUST contain at least one horizontal character otherwise, the ruler will not be accepted by the ruler parser

func Row

func Row(row row.Row[field.Field], cols []column.Info, opts *options.Options) string

RenderRow returns a row of table data, aligned to the table's column widths

- the number of fields and columns must be identical

func RowCmpFunc

func RowCmpFunc(cols column.Index, localeTag string) func(a, b row.Row[field.Field]) int

func Ruler

func Ruler(rlr ruler.Ruler, cols []column.Info, opts *options.Options) string

func SortIndex

func SortIndex(tableIndex column.Index) column.Index

SortIndex returns a column index of the columns to be used for sorting, in prioritised order.

Goals:

  • do not sort tables which do not have sorting enabled on any of their columns
  • otherwise, sort tables by comparing their data in the order specified by their column's sorting configuration
  • finally, use any trailing columns as a "tie breaker" if necessary
  • sort direction has no effect

Behaviour:

If no columns have sorting enabled then an empty index is returned.

In all other cases:

  • an index is returned with the same number of columns as the provided index
  • the "sorting enabled" columns appear first, in increasing priority order (1, 2, ... 7)
  • followed by the "sorting enabled" columns with priority 0
  • followed by any remaining columns (even if sorting is not enabled)

Types

type CmpFunc

type CmpFunc func(a, b field.Field) int

type Option

type Option func(*Table)

func WithColumns

func WithColumns(cols column.Index) Option

func WithOptions added in v0.4.28

func WithOptions(opts *options.Options) Option

func WithPrefix

func WithPrefix(prefix string) Option

func WithRows

func WithRows(rows [][]string) Option

TODO: 2026-02-22 see ImportRows dependency

func WithRulers

func WithRulers(rulers overlay.Overlay[ruler.Ruler]) Option

func WithTextLines

func WithTextLines(textLines overlay.Overlay[string]) Option

type OverlayLine added in v0.4.18

type OverlayLine interface {
	Line() int // the overlay's position in the overall document (0-based)
	Row() int  // the number of the next table row to appear after this overlay item
}

type RenderCommandAPI added in v0.4.20

type RenderCommandAPI struct {
	*Table
}

RenderCommandAPI provides an indirect API for user command interactions with a Table - without causing cyclic imports :-(

See [command.ConfigAPI]

func (*RenderCommandAPI) FillColumns added in v0.4.20

func (cfg *RenderCommandAPI) FillColumns(cols []*column.Specifier, fillValue string)

func (*RenderCommandAPI) Index added in v0.4.20

func (cfg *RenderCommandAPI) Index() column.Index

func (*RenderCommandAPI) SetIndex added in v0.4.20

func (cfg *RenderCommandAPI) SetIndex(newIndex column.Index)

type RowGroup

type RowGroup struct {
	Start int
	End   int
}

RowGroup contains the start and end indexes for a sub-slice of table rows between two overlay lines. e.g.: rowsInGroup = table.Rows[group.Start:group.End]

func RowGroups

func RowGroups(overlayItems []OverlayLine, rowCount int, skipFirstRow bool) []RowGroup

RowGroups collates the ranges of contiguous table rows between overlay lines

Parameters:

  • overlayLines list of lines to be interleaved between data rows
  • rowCount total number of rows in the table (without overlaid lines)
  • skipFirstRow - if true, always treat the first row as a header row - do not include it in the first row group for sorting! (more accurate: ensure that the first row group has only 1 line)

Given the document: (with line and row numbers)

// Table of Meteor Showers:                     // text  {line:  0, row: 0}
//                                              // text  {line:  1, row: 0}
// +------------+----------+--------------+     // ruler {line:  2, row: 0}
// | Hemisphere |  Dates   |     Name     |     // row 0
// | ========== | ======== | ============ |     // ruler {line:  4, row: 0}
// | both       | 04-23/24 | Lyrids       |     // row 1
// |            | 05-05/06 | Eta Aquarids |     // row 2
// |            | 10-21/22 | Orionids     |     // row 3
// |            | 11-17/18 | Leonids      |     // row 4
// |            | 12-14/15 | Geminids     |     // row 5
// |            | 12-22/23 | Ursids       |     // row 6
// | ---------- | -------- | ------------ |     // ruler {line: 11, row: 7}
// | northern   | 08-12/13 | Perseids     |     // row 7
// |            | 10-08/09 | Draconids    |     // row 8
// +------------+----------+--------------+     // ruler {line: 14, row: 9}
//                                              // text  {line: 15, row: 9}
// Source: the internet                         // text  {line: 16, row: 9}

Here we can see how the overlaid items are interwoven between the table rows.

With the above example we would expect the 3 groups of rows: (written in go's slice format)

rows[0:1]   column header
rows[1:7]   both hemispheres
rows[7:9]   northern hemisphere

type RulerField

type RulerField struct {
	Padding string //   // ---+-------------+
	//                  //    v             v
	//                  //    _?----?----???_
	//                  //     ^ ^  ^  ^ ^^^
	LeftMark     string // ----+ |  |  | |||
	LeftFill     int    // ------+  |  | |||
	LineMark     string // ------+  |  | |||
	MiddleMark   string // ---------+  | |||
	RightFill    int    // ------------+ |||
	RightMark    string // --------------+||
	OrderMark    string // ---------------+|
	PriorityMark string // ----------------+
}

func (*RulerField) HasHorizontal

func (f *RulerField) HasHorizontal() bool

func (*RulerField) MinLeft

func (f *RulerField) MinLeft() int

func (*RulerField) MinRight

func (f *RulerField) MinRight() int

func (*RulerField) MinWidth

func (f *RulerField) MinWidth() int

func (*RulerField) String

func (f *RulerField) String() string

type Table

type Table struct {
	*options.Options
	column.Index
	Prefix     string // prefix discovered by the PrefixMatcher
	Rows       []row.Row[field.Field]
	Rulers     overlay.Overlay[ruler.Ruler]
	TextLines  overlay.Overlay[string]
	HintsRow   int        // where to place the ruler with alignment / sorting hints (typically before row 1)
	StringRows [][]string // temporary - only used to disentable rows from columns
}

render.Table is a derived structure used for rendering psv.Table's

Differences to internal.Table:

  • data is stored as a grid of field.Field structs

Note:

  • go does not allow cyclic module references
  • => cannot reference internal.Table from this package

func NewRenderTable added in v0.4.20

func NewRenderTable(opts ...Option) *Table

func (*Table) ApplyProfile added in v0.4.18

func (t *Table) ApplyProfile()

ApplyProfile modifies a table to comply with the selected profile. Adjustments:

  • ruler placement
  • ruler styles / hints

func (*Table) ApplyRenderCommands added in v0.4.20

func (t *Table) ApplyRenderCommands()

ApplyRenderCommands applies all of the commands provided via the table's Layout

Any errors encountered while parsing the commands are returned as WARNINGS i.e.

  • unparsable commands are ignored / not applied
  • the error(s) should be shown to the user (e.g. via STDERR)

func (*Table) ImportRows

func (t *Table) ImportRows()

ImportRows imports ONLY the fields required AFTER commands have been run on the render.Table

func (*Table) LineCount

func (t *Table) LineCount() int

func (*Table) OverlayItems

func (t *Table) OverlayItems() []OverlayLine

func (*Table) Render

func (t *Table) Render() []byte

Errors should NEVER prevent the table from being rendered. - as of 2026-02-20 the only errors possible are "command parsing" errors

func (*Table) RenderTable

func (t *Table) RenderTable() []byte

func (*Table) RowCount

func (t *Table) RowCount() int

func (*Table) RulerCount

func (t *Table) RulerCount() int

func (*Table) SortRows

func (t *Table) SortRows()

SortRows uses the sorting flags in this table's index to determine how the table's rows should be sorted. Assumptions:

  • the number of rows to be sorted is the same as the number of rows in the table
  • i.e. table.RowGroups() compares the table's overlay positions with the rows in the table

func (*Table) TextlineCount

func (t *Table) TextlineCount() int

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL