## Description #############################################################################
#
# Documentation for the text backend.
#
############################################################################################

"""
# PrettyTables.jl Text Backend

The text backend can be selected by passing the keyword `backend = :text` to the function
[`pretty_table`](@ref). In this case, we have the following additional keywords to configure
the output.

# Keywords

- `alignment_anchor_fallback::Symbol`: This keyword controls the line alignment when using
    the regex alignment anchors if a match is not found. If it is `:l`, the left of the line
    will be aligned with the anchor. If it is `:c`, the line center will be aligned with the
    anchor. Otherwise, the end of the line will be aligned with the anchor.
    (**Default** = `:l`)
- `alignment_anchor_regex::Union{Vector{Regex}, Vector{Pair{Int, Vector{Regex}}}}`: This
    keyword can be used to provide regexes to align the data values in the table columns. If
    it is `Vector{Regex}`, the regexes will be used to align all the columns. If it is
    `Vector{Pair{Int, Vector{Regex}}}`, the `Int` element specifies the column to which the
    regexes in `Vector{Regex}` will be applied. The regex match is searched in the same
    order as the regexes appear on the vector. The regex matching is applied after the cell
    conversion to string, which includes the formatters. If no match is found for a specific
    line, the alignment of this line depends on the option `alignment_anchor_fallback`.
    Example: `[2 => [r"\\."]]` aligns the decimal point of the cells in the second column.
    (**Default** = `Regex[]`)
- `apply_alignment_regex_to_summary_rows::Bool`: If `true`, the alignment regexes in
    `alignment_anchor_regex` will also be applied to the summary rows.
    (**Default** = `false`)
- `auto_wrap::Bool`: If `true`, the text will be wrapped on spaces to fit the column. Note
    that this function requires `line_breaks = true` and the column must have a fixed size
    (see `fixed_data_column_widths`).
    (**Default** = `false`)
- `column_label_width_based_on_first_line_only::Bool`: If `true`, the column label width is
    based on the first line of the column. Hence, if the other column labels have text
    width larger than the computed column width, they will be cropped to fit.
    (**Default** = `false`)
- `display_size::Tuple{Int, Int}`: A tuple of two integers that defines the display size
    (num. of rows, num. of columns) that is available to print the table. It is used to crop
    the data depending on the value of the keyword `crop`. Notice that if a dimension is not
    positive, it will be treated as unlimited.
    (**Default** = `displaysize(io)`)
- `equal_data_column_widths::Bool`: If `true`, the data columns will have the same width.
    (**Default** = `false`)
- `fit_table_in_display_horizontally::Bool`: If `true`, the table will be cropped to fit
    the display horizontally.
    (**Default** = `true`)
- `fit_table_in_display_vertically::Bool`: If `true`, the table will be cropped to fit the
    display vertically.
    (**Default** = `true`)
- `fixed_data_column_widths::Union{Int, Vector{Int}}`: If it is a `Vector{Int}`, this vector
    specifies the width of each column. If it is a `Int`, this number will be used as the
    width of all columns. If the width is equal to or lower than 0, it will be automatically
    computed to fit the largest cell in the column.
    (**Default** = 0)
- `highlighters::Vector{TextHighlighter}`: Highlighters to apply to the table. For more
    information, see the section **Text Highlighters** in the **Extended Help**.
- `line_breaks::Bool`: If `true`, a new line character will break the line inside the cells.
    (**Default** = `false`)
- `maximum_data_column_widths::Union{Int, Vector{Int}}`: If it is a `Vector{Int}`, this
    vector specifies the maximum width of each column. If it is an `Int`, this number will
    be used as the maximum width of all columns. If the maximum width is equal to or lower
    than 0, it will be ignored. Notice that the parameter `fixed_data_column_widths` has
    precedence over this one.
    (**Default** = 0)
- `minimum_data_column_widths::Union{Int, Vector{Int}}`: If it is a `Vector{Int}`, this
    vector specifies the minimum width of each column. If it is an `Int`, this number will
    be used as the minimum width of all columns. If the minimum width is equal to or lower
    than 0, it will be ignored. Notice that the parameter `fixed_data_column_widths` has
    precedence over this one.
    (**Default** = 0)
- `overwrite_display::Bool`: If `true`, the same number of lines in the printed table will
    be deleted from the output `io`. This can be used to update the table in the display
    continuously.
    (**Default** = `false`)
- `reserved_display_lines::Int`: Number of lines to be left at the beginning of the printing
    when vertically cropping the output.
    (**Default** = 0)
- `shrinkable_column_minimum_width::Int`: If it is a positive integer (> 0), this is the
    minimum width of the shrinkable column (see `shrinkable_data_column`).
    (**Default** = 0)
- `shrinkable_data_column::Int`: If it is a positive integer, this column will be
    shrinkable. This means that if the table does not fit in the display, this column will
    be shrunk to fit the table in the display. If it is `0` or negative, no column will be
    shrinkable.
    (**Default** = 0)
- `style::TextTableStyle`: Style of the table. For more information, see the section
    **Text Table Style** in the **Extended Help**.
- `table_format::TextTableFormat`: Text table format used to render the table. For more
    information, see the section **Text Table Format** in the **Extended Help**.

# Extended Help

## Text highlighters

A set of highlighters can be passed as a `Vector{TextHighlighter}` to the `highlighters`
keyword. Each highlighter is an instance of the structure [`TextHighlighter`](@ref). It
contains three fields:

- `f::Function`: Function with the signature `f(data, i, j)` which should return `true`
    if the element `(i, j)` in `data` must be highlighted, or `false` otherwise.
- `fd::Function`: Function with the signature `fd(h, data, i, j)` in which `h` is the
    highlighter. This function must return the `Crayon` to be applied to the cell that must
    be highlighted.
- `_decoration::Crayon`: The `Crayon` to be applied to the highlighted cell if the default
    `fd` is used.

The function `f` has the following signature:

```julia
f(data, i, j)
```

in which `data` is a reference to the data that is being printed, and `i` and `j` are the
element coordinates that are being tested. If this function returns `true`, the cell
`(i, j)` will be highlighted.

If the function `f` returns true, the function `fd(h, data, i, j)` will be called and must
return a `Crayon` that will be applied to the cell.

A highlighter can be constructed using three helpers:

```julia
TextHighlighter(f::Function; kwargs...)
```

where it will construct a `Crayon` using the keywords in `kwargs` and apply it to the
highlighted cell,

```julia
TextHighlighter(f::Function, crayon::Crayon)
```

where it will apply the `crayon` to the highlighted cell, and

```julia
TextHighlighter(f::Function, fd::Function)
```

where it will apply the `Crayon` returned by the function `fd` to the highlighted cell.

!!! note

    If multiple highlighters are valid for the element `(i, j)`, the applied style will be
    equal to the first match considering the order in the tuple `highlighters`.

!!! note

    If the highlighters are used together with [Formatters](@ref), the change in the format
    **will not** affect the parameter `data` passed to the highlighter function `f`. It will
    always receive the original, unformatted value.

For example, if we want to highlight the cells with value greater than 5 in red, and
all the cells with value less than 5 in blue, we can define:

```julia
hl_gt5 = TextHighlighter(
    (data, i, j) -> data[i, j] > 5,
    crayon"red"
)

hl_lt5 = TextHighlighter(
    (data, i, j) -> data[i, j] < 5,
    crayon"blue"
)

highlighters = [hl_gt5, hl_lt5]
```

## Text Table Format

The text table format is defined using an object of type [`TextTableFormat`](@ref) that
contains the following fields:

- `borders::TextTableBorders`: Format of the borders.
- `horizontal_line_at_beginning::Bool`: If `true`, a horizontal line will be drawn at the
    beginning of the table.
- `horizontal_lines_at_column_labels::Union{Symbol, Vector{Int}}`: A horizontal line will be
    drawn after each column label row index listed in this vector. If the symbol `:all` is
    passed, a horizontal line will be drawn after every column label. If the symbol `:none`
    is passed, no horizontal lines will be drawn.
- `horizontal_line_at_merged_column_labels::Bool`: If `true`, a horizontal line will be
    drawn at the merged column labels. Notice that the horizontal line drawn using the
    option `horizontal_lines_at_column_labels` has precedence over this one.
- `horizontal_line_after_column_labels::Bool`: If `true`, a horizontal line will be drawn
    after the column labels.
- `horizontal_lines_at_data_rows::Union{Symbol, Vector{Int}}`: A horizontal line will be
    drawn after each data row index listed in this vector. If the symbol `:all` is passed, a
    horizontal line will be drawn after every data row. If the symbol `:none` is passed,
    no horizontal lines will be drawn.
- `horizontal_line_before_row_group_label::Bool`: If `true`, a horizontal line will be
    drawn before the row group label.
- `horizontal_line_after_row_group_label::Bool`: If `true`, a horizontal line will be
    drawn after the row group label.
- `horizontal_line_after_data_rows::Bool`: If `true`, a horizontal line will be drawn
    after the data rows.
- `horizontal_line_before_summary_rows::Bool`: If `true`, a horizontal line will be drawn
    before the summary rows. Notice that this line is the same as the one drawn if
    `horizontal_line_after_data_rows` is `true`. However, in this case, the line is omitted
    if there are no summary rows.
- `horizontal_line_after_summary_rows::Bool`: If `true`, a horizontal line will be drawn
    after the summary rows.
- `vertical_line_at_beginning::Bool`: If `true`, a vertical line will be drawn at the
    beginning of the table.
- `vertical_line_after_row_number_column::Bool`: If `true`, a vertical line will be drawn
    after the row number column.
- `vertical_line_after_row_label_column::Bool`: If `true`, a vertical line will be drawn
    after the row label column.
- `vertical_lines_at_data_columns::Union{Symbol, Vector{Int}}`: A vertical line will be
    drawn after each data column index listed in this vector. If the symbol `:all` is
    passed, a vertical line will be drawn after every data column. If the symbol `:none` is
    passed, no vertical lines will be drawn after the data columns.
- `vertical_line_after_data_columns::Bool`: If `true`, a vertical line will be drawn after
    the data columns.
- `vertical_line_after_continuation_column::Bool`: If `true`, a vertical line will be
    drawn after the continuation column.
- `suppress_vertical_lines_at_column_labels::Bool`: If `true`, the vertical lines inside
    the column label rows will be suppressed.
- `ellipsis_line_skip::Integer`: Number of lines to skip when printing an ellipsis.

We provide a few helpers to configure the table format. For more information, see the
documentation of the following macros:

- [`@text__all_horizontal_lines`](@ref).
- [`@text__all_vertical_lines`](@ref).
- [`@text__no_horizontal_lines`](@ref).
- [`@text__no_vertical_lines`](@ref).

## Text Table Style

The text table style is defined using an object of type [`TextTableStyle`](@ref) that
contains the following fields:

- `title::Crayon`: Crayon with the style for the title.
- `subtitle::Crayon`: Crayon with the style for the subtitle.
- `row_number_label::Crayon`: Crayon with the style for the row number label.
- `row_number::Crayon`: Crayon with the style for the row numbers.
- `stubhead_label::Crayon`:  Crayon with the style for the stubhead label.
- `row_label::Crayon`: Crayon with the style for the row labels.
- `row_group_label::Crayon`: Crayon with the style for the row group label.
- `first_line_column_label::Union{Crayon, Vector{Crayon}}`: Crayon or crayons with the style
    for the first column label lines. If a vector of crayons is passed, it must have the
    same length as the number of columns in the table.
- `column_label::Union{Crayon, Vector{Crayon}}`: Crayon or crayons with the style for the
    rest of the column labels. If a vector of crayons is passed, it must have the same
    length as the number of columns in the table.
- `first_line_merged_column_label::Crayon`: Crayon with the style for the merged cells at
    the first column label line.
- `merged_column_label::Crayon`: Crayon with the style for the merged cells at the rest of
    the column labels.
- `summary_row_cell::Crayon`: Crayon with the style for the summary row cell.
- `summary_row_label::Crayon`: Crayon with the style for the summary row label.
- `footnote::Crayon`: Crayon with the style for the footnotes.
- `source_note::Crayon`: Crayon with the style for the source notes.
- `omitted_cell_summary::Crayon`: Crayon with the style for the omitted cell summary.
- `table_border::Crayon`: Crayon with the style for the table border.

Each field is a `Crayon` describing the style for the corresponding element in the table.

For example, if we want that the stubhead label is bold and red, we must define:

```julia
style = TextTableStyle(
    stubhead_label = crayon"bold red"
)
```
"""
pretty_table_text_backend
