Skip to content

Commit

Permalink
✨ Add vlines option to text backend
Browse files Browse the repository at this point in the history
This option controls where the vertical lines of the table will be
drawn.

Closes #46
  • Loading branch information
ronisbr committed Mar 20, 2020
1 parent 197d4da commit 986969d
Showing 5 changed files with 211 additions and 24 deletions.
12 changes: 12 additions & 0 deletions docs/src/man/text_backend.md
Original file line number Diff line number Diff line change
@@ -71,6 +71,18 @@ passed as keywords when calling the function `pretty_table`:
row number. (**Default** = `false`)
* `tf`: Table format used to print the table (see the section
[Text table formats](@ref)). (**Default** = `unicode`)
* `vlines`: This variable controls where the vertical lines will be drawn. It
can be `:all` or a vector of integers. In the first case (the

This comment has been minimized.

Copy link
@waldyrious

waldyrious Mar 20, 2020

Would it make sense to also support :none (or some similar symbol) for not showing any lines at all?

This comment has been minimized.

Copy link
@ronisbr

ronisbr Mar 20, 2020

Author Owner

You can do this by just passing [], but, sure, I can do that :)

This comment has been minimized.

Copy link
@ronisbr

ronisbr Mar 20, 2020

Author Owner

Done!

default behavior), all vertical lines will be drawn. In the second
case, the vertical lines will be drawn only after the columns in the
vector. Notice that the left border will be drawn if `0` is in
`vlines`. Furthermore, it is important to mention that the column
number in this variable is related to the **printed columns**. Thus,
it is affected by filters, and by the columns added using the
variables `show_row_number` and `row_names`. Finally, for
convenience, the right border can be drawn by adding the symbol
`:end` to this vector, which will be replaced by the number of the

This comment has been minimized.

Copy link
@waldyrious

waldyrious Mar 20, 2020

@ronisbr would it be possible for the left border to follow the same logic, and use :begin as opposed to 0, for consistency?

This comment has been minimized.

Copy link
@waldyrious

waldyrious Mar 20, 2020

(Inspired by this comment.)

This comment has been minimized.

Copy link
@ronisbr

ronisbr Mar 20, 2020

Author Owner

Sure! I will do that.

This comment has been minimized.

Copy link
@ronisbr

ronisbr Mar 20, 2020

Author Owner

Done! Can you test please?

This comment has been minimized.

Copy link
@waldyrious

waldyrious Mar 20, 2020

Thanks! (For future reference, that was done in cb7cead.)

I tested this locally, seems to work well! Here's what I did:

julia> using Pkg

julia> Pkg.add("PrettyTables")
...

julia> ]

(v1.3) pkg> add PrettyTables#master
...

(v1.3) pkg> ⌫

julia> using PrettyTables
[ Info: Precompiling PrettyTables [08abe8d2-0d0c-5749-adfa-8a2ac140af0d]

julia> data = [1 2 3; 4 5 6];

julia> pretty_table(data, ["Column 1", "Column 2", "Column 3"])
┌──────────┬──────────┬──────────┐
│ Column 1 │ Column 2 │ Column 3 │
├──────────┼──────────┼──────────┤
│        123 │
│        456 │
└──────────┴──────────┴──────────┘

julia> pretty_table(data, ["Column 1", "Column 2", "Column 3"], vlines=:none)
─────────────────────────────────
 Column 1   Column 2   Column 3
─────────────────────────────────
        1          2          3
        4          5          6
─────────────────────────────────

julia> pretty_table(data, ["Column 1", "Column 2", "Column 3"], vlines=[:begin])
┌─────────────────────────────────
│ Column 1   Column 2   Column 3
├─────────────────────────────────
│        1          2          34          5          6
└─────────────────────────────────

julia> pretty_table(data, ["Column 1", "Column 2", "Column 3"], vlines=[:end])
────────────────────────────────┐
 Column 1   Column 2   Column 3 │
────────────────────────────────┤
        1          2          34          5          6 │
────────────────────────────────┘

julia> Pkg.free("PrettyTables")

@ronisbr it would be nice to include these instructions somewhere in the documentation to help people (like me) who want to try out the unreleased features but don't have these invocations memorized. WDYT?

This comment has been minimized.

Copy link
@ronisbr

ronisbr Mar 20, 2020

Author Owner

Sure! Documentation is something I really need to improve.

This comment has been minimized.

Copy link
@ronisbr

ronisbr Mar 20, 2020

Author Owner

Btw, a basic documentation can be found here: https://ronisbr.github.io/PrettyTables.jl/dev

This comment has been minimized.

Copy link
@waldyrious

waldyrious Mar 21, 2020

Yes, I used precisely the code in the Examples section to do the tests above, as you'll surely recognize :)

I thing there could be a "Development", "Testing" or "Contributing" section in the docs, with instructions more focused on setting up PrettyTables for local development (maybe even with examples of using Revise! 😃) or testing of unreleased features, as was the case here.

last printed column. (**Default** = `:all`)

The keywords `header_crayon` and `subheaders_crayon` can be a `Crayon` or a
`Vector{Crayon}`. In the first case, the `Crayon` will be applied to all the
67 changes: 51 additions & 16 deletions src/backends/text/print.jl
Original file line number Diff line number Diff line change
@@ -30,7 +30,8 @@ function _pt_text(io, pinfo;
screen_size::Union{Nothing,Tuple{Int,Int}} = nothing,
show_row_number::Bool = false,
sortkeys::Bool = false,
tf::TextFormat = unicode)
tf::TextFormat = unicode,
vlines::Union{Symbol,AbstractVector} = :all)

@unpack_PrintInfo pinfo

@@ -264,12 +265,38 @@ function _pt_text(io, pinfo;
show_row_names && (all_cols_width = vcat(row_name_width, all_cols_width))
show_row_number && (all_cols_width = vcat(row_number_width, all_cols_width))

# Process `vlines`.
if vlines == :all
vlines = collect(0:1:length(all_cols_width))
elseif !(typeof(vlines) <: AbstractVector)
error("`vlines` must be `:all` or an vector of integers.")
end

# The symbol `:end` is replaced by the last column.
vlines = replace(vlines, :end => length(all_cols_width))

# Auxiliary variables to verify if the vertical line must be drawn in the
# row number and row name.
row_number_vline = 1 vlines
row_name_vline = false

if show_row_names
if show_row_number
row_name_vline = 2 vlines
else
row_name_vline = 1 vlines
end
end

# `Δc` store the number of rows that the user added before that data.
Δc = Int(show_row_number + show_row_names)

# Top table line
# ==========================================================================

tf.top_line && _draw_line!(screen, buf, tf.up_left_corner,
tf.up_intersection, tf.up_right_corner, tf.row,
border_crayon, all_cols_width)
border_crayon, all_cols_width, vlines)

# Header
# ==========================================================================
@@ -279,7 +306,7 @@ function _pt_text(io, pinfo;

if !noheader
@inbounds @views for i = 1:header_num_rows
_p!(screen, buf, border_crayon, tf.left_border)
0 vlines && _p!(screen, buf, border_crayon, tf.left_border)

if show_row_number
# The text "Row" must appear only on the first line.
@@ -290,7 +317,7 @@ function _pt_text(io, pinfo;
_p!(screen, buf, rownum_header_crayon, " "^(row_number_width+2))
end

_p!(screen, buf, border_crayon, tf.column)
_pc!(row_number_vline, screen, buf, border_crayon, tf.column, " ")
end

# If we have row name column, then print in the first line the
@@ -306,7 +333,7 @@ function _pt_text(io, pinfo;
_p!(screen, buf, text_crayon, " "^(row_name_width+2))
end

_p!(screen, buf, border_crayon, tf.column)
_pc!(row_name_vline, screen, buf, border_crayon, tf.column, " ")
end

for j = 1:num_printed_cols
@@ -322,11 +349,15 @@ function _pt_text(io, pinfo;
flp = j == num_printed_cols

_p!(screen, buf, crayon, header_i_str)

if j != num_printed_cols
_p!(screen, buf, border_crayon, tf.column, flp)
_pc!(j + Δc vlines, screen, buf, border_crayon, tf.column,
" " , flp)
else
_p!(screen, buf, border_crayon, tf.right_border, flp)
_pc!(j + Δc vlines, screen, buf, border_crayon,
tf.right_border, " " , flp)
end

_eol(screen) && break
end

@@ -341,7 +372,7 @@ function _pt_text(io, pinfo;
tf.header_line && _draw_line!(screen, buf, tf.left_intersection,
tf.middle_intersection,
tf.right_intersection, tf.row,
border_crayon, all_cols_width)
border_crayon, all_cols_width, vlines)
end

# Data
@@ -351,7 +382,7 @@ function _pt_text(io, pinfo;
ir = id_rows[i]

for l = 1:num_lines_in_row[i]
_p!(screen, buf, border_crayon, tf.left_border)
0 vlines && _p!(screen, buf, border_crayon, tf.left_border)

if show_row_number
if l == 1
@@ -361,15 +392,15 @@ function _pt_text(io, pinfo;
end

_p!(screen, buf, text_crayon, row_number_i_str)
_p!(screen, buf, border_crayon, tf.column)
_pc!(row_number_vline, screen, buf, border_crayon, tf.column, " ")
end

if show_row_names
row_names_i_str = " " * _str_aligned(row_names_str[i],
row_name_alignment,
row_name_width) * " "
_p!(screen, buf, row_name_crayon, row_names_i_str)
_p!(screen, buf, border_crayon, tf.column)
_pc!(row_name_vline, screen, buf, border_crayon, tf.column, " ")
end

for j = 1:num_printed_cols
@@ -407,10 +438,13 @@ function _pt_text(io, pinfo;
flp = j == num_printed_cols

if j != num_printed_cols
_p!(screen, buf, border_crayon, tf.column, flp)
_pc!(j + Δc vlines, screen, buf, border_crayon, tf.column,
" " , flp)
else
_p!(screen, buf, border_crayon, tf.right_border, flp)
_pc!(j + Δc vlines, screen, buf, border_crayon,
tf.right_border, " " , flp)
end

_eol(screen) && break
end

@@ -420,14 +454,15 @@ function _pt_text(io, pinfo;

# Check if we must draw a horizontal line here.
i != num_rows && i in hlines &&
_draw_line!(screen, buf, hlines_format..., border_crayon, all_cols_width)
_draw_line!(screen, buf, hlines_format..., border_crayon,
all_cols_width, vlines)

# Here we must check if the vertical size of the screen has been
# reached. Notice that we must add 4 to account for the command line,
# the continuation line, the bottom table line, and the last blank line.
if (screen.size[1] > 0) && (screen.row + 4 >= screen.size[1])
_draw_continuation_row(screen, buf, tf, text_crayon, border_crayon,
all_cols_width)
all_cols_width, vlines)
break
end
end
@@ -438,7 +473,7 @@ function _pt_text(io, pinfo;
tf.bottom_line && _draw_line!(screen, buf, tf.bottom_left_corner,
tf.bottom_intersection,
tf.bottom_right_corner, tf.row, border_crayon,
all_cols_width)
all_cols_width, vlines)

# Print the buffer
# ==========================================================================
37 changes: 29 additions & 8 deletions src/backends/text/private.jl
Original file line number Diff line number Diff line change
@@ -128,26 +128,26 @@ end
################################################################################

"""
_draw_continuation_row(screen, io, tf, text_crayon, border_crayon, num_printed_cols, cols_width, show_row_number, row_number_width, show_row_names, row_name_width)
_draw_continuation_row(screen, io, tf, text_crayon, border_crayon, cols_width, vlines)
Draw the continuation row when the table has filled the vertical space
available. This function prints in each column the character `⋮` centered.
"""
function _draw_continuation_row(screen, io, tf, text_crayon, border_crayon,
cols_width)
cols_width, vlines)

num_cols = length(cols_width)

_p!(screen, io, border_crayon, tf.column)
0 vlines && _p!(screen, io, border_crayon, tf.column)

@inbounds for j = 1:num_cols
data_ij_str = _str_aligned("", :c, cols_width[j] + 2)
_p!(screen, io, text_crayon, data_ij_str)

flp = j == num_cols

_p!(screen, io, border_crayon, tf.column, flp)
_pc!(j vlines, screen, io, border_crayon, tf.column, " ", flp)
_eol(screen) && break
end

@@ -163,20 +163,21 @@ Draw a vertical line in `io` using the information in `screen`.
"""
function _draw_line!(screen, io, left, intersection, right, row, border_crayon,
cols_width)
cols_width, vlines)

num_cols = length(cols_width)

_p!(screen, io, border_crayon, left)
0 vlines && _p!(screen, io, border_crayon, left)

@inbounds for i = 1:num_cols
# Check the alignment and print.
_p!(screen, io, border_crayon, row^(cols_width[i]+2)) && break

i != num_cols && _p!(screen, io, border_crayon, intersection)
i != num_cols &&
_pc!(i vlines, screen, io, border_crayon, intersection, row)
end

_p!(screen, io, border_crayon, right, true)
_pc!(num_cols vlines, screen, io, border_crayon, right, row, true)
_nl!(screen, io)
end

@@ -297,3 +298,23 @@ function _p!(screen, io, crayon, str, final_line_print = false)
# Return if we reached the end of line.
return _eol(screen)
end

"""
_pc!(cond, screen, io, crayon, str_true, str_false, final_line_print = false)
If `cond == true` then print `str_true`. Otherwise, print `str_false`. Those
strings will be printed into `io` using the Crayon `crayon` with the screen
information in `screen`. The parameter `final_line_print` must be set to `true`
if this is the last string that will be printed in the line. This is necessary
for the algorithm to select whether or not to include the continuation
character.
"""
function _pc!(cond, screen, io, crayon, str_true, str_false,
final_line_print = false)
if cond
return _p!(screen, io, crayon, str_true, final_line_print)
else
return _p!(screen, io, crayon, str_false, final_line_print)
end
end
12 changes: 12 additions & 0 deletions src/print.jl
Original file line number Diff line number Diff line change
@@ -179,6 +179,18 @@ This back-end produces text tables. This back-end can be used by selecting
row number. (**Default** = `false`)
* `tf`: Table format used to print the table (see `TextFormat`).
(**Default** = `unicode`)
* `vlines`: This variable controls where the vertical lines will be drawn. It
can be `:all` or a vector of integers. In the first case (the
default behavior), all vertical lines will be drawn. In the second
case, the vertical lines will be drawn only after the columns in the
vector. Notice that the left border will be drawn if `0` is in
`vlines`. Furthermore, it is important to mention that the column
number in this variable is related to the **printed columns**. Thus,
it is affected by filters, and by the columns added using the
variables `show_row_number` and `row_names`. Finally, for
convenience, the right border can be drawn by adding the symbol
`:end` to this vector, which will be replaced by the number of the
last printed column. (**Default** = `:all`)
The keywords `header_crayon` and `subheaders_crayon` can be a `Crayon` or a
`Vector{Crayon}`. In the first case, the `Crayon` will be applied to all the
Loading

0 comments on commit 986969d

Please sign in to comment.