mirror of
https://github.com/nushell/nushell
synced 2025-01-14 06:04:09 +00:00
Bump tabled to 0.17
With this comes a new unicode-width. And a bit of refactorings Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
This commit is contained in:
parent
671640b0a9
commit
7226ac35eb
7 changed files with 292 additions and 344 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -4168,15 +4168,15 @@ checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56"
|
|||
|
||||
[[package]]
|
||||
name = "papergrid"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7419ad52a7de9b60d33e11085a0fe3df1fbd5926aa3f93d3dd53afbc9e86725"
|
||||
checksum = "d2b0f8def1f117e13c895f3eda65a7b5650688da29d6ad04635f61bc7b92eebd"
|
||||
dependencies = [
|
||||
"ansi-str",
|
||||
"ansitok",
|
||||
"bytecount",
|
||||
"fnv",
|
||||
"unicode-width 0.1.11",
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6317,9 +6317,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tabled"
|
||||
version = "0.16.0"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77c9303ee60b9bedf722012ea29ae3711ba13a67c9b9ae28993838b63057cb1b"
|
||||
checksum = "c6709222f3973137427ce50559cd564dc187a95b9cfe01613d2f4e93610e510a"
|
||||
dependencies = [
|
||||
"ansi-str",
|
||||
"ansitok",
|
||||
|
|
|
@ -154,7 +154,7 @@ sha2 = "0.10"
|
|||
strip-ansi-escapes = "0.2.0"
|
||||
syn = "2.0"
|
||||
sysinfo = "0.32"
|
||||
tabled = { version = "0.16.0", default-features = false }
|
||||
tabled = { version = "0.17.0", default-features = false }
|
||||
tempfile = "3.14"
|
||||
terminal_size = "0.4"
|
||||
titlecase = "2.0"
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
use crate::debug::inspect_table::{
|
||||
global_horizontal_char::SetHorizontalChar, set_widths::SetWidths,
|
||||
};
|
||||
// note: Seems like could be simplified
|
||||
// IMHO: it shall not take 300+ lines :)
|
||||
|
||||
use nu_protocol::Value;
|
||||
use nu_table::{string_width, string_wrap};
|
||||
|
||||
use tabled::{
|
||||
grid::config::ColoredConfig,
|
||||
settings::{peaker::PriorityMax, width::Wrap, Settings, Style},
|
||||
settings::{peaker::Priority, width::Wrap, Settings, Style},
|
||||
Table,
|
||||
};
|
||||
|
||||
use self::{global_horizontal_char::SetHorizontalChar, set_widths::SetWidths};
|
||||
|
||||
pub fn build_table(value: Value, description: String, termsize: usize) -> String {
|
||||
let (head, mut data) = util::collect_input(value);
|
||||
let count_columns = head.len();
|
||||
|
@ -57,7 +60,7 @@ pub fn build_table(value: Value, description: String, termsize: usize) -> String
|
|||
Settings::default()
|
||||
.with(Style::rounded().corner_top_left('├').corner_top_right('┤'))
|
||||
.with(SetWidths(widths))
|
||||
.with(Wrap::new(width).priority(PriorityMax))
|
||||
.with(Wrap::new(width).priority(Priority::max(true)))
|
||||
.with(SetHorizontalChar::new('┼', '┴', 11 + 2 + 1)),
|
||||
);
|
||||
|
||||
|
|
|
@ -1,32 +1,36 @@
|
|||
use crate::{convert_style, table_theme::TableTheme};
|
||||
use std::{cmp::min, collections::HashMap};
|
||||
|
||||
use nu_ansi_term::Style;
|
||||
use nu_color_config::TextStyle;
|
||||
use nu_protocol::TrimStrategy;
|
||||
use nu_utils::strip_ansi_unlikely;
|
||||
use std::{cmp::min, collections::HashMap};
|
||||
|
||||
use tabled::{
|
||||
builder::Builder,
|
||||
grid::{
|
||||
ansi::ANSIBuf,
|
||||
colors::Colors,
|
||||
config::{AlignmentHorizontal, ColoredConfig, Entity, EntityMap, Position},
|
||||
config::{AlignmentHorizontal, ColoredConfig, Entity, Position},
|
||||
dimension::CompleteDimensionVecRecords,
|
||||
records::{
|
||||
vec_records::{Cell, Text, VecRecords},
|
||||
ExactRecords, PeekableRecords, Records, Resizable,
|
||||
ExactRecords, Records, Resizable,
|
||||
},
|
||||
},
|
||||
settings::{
|
||||
format::FormatContent,
|
||||
formatting::AlignmentStrategy,
|
||||
object::{Columns, Segment},
|
||||
peaker::Peaker,
|
||||
object::{Columns, Row, Rows},
|
||||
peaker::Priority,
|
||||
themes::ColumnNames,
|
||||
width::Truncate,
|
||||
Alignment, Color, Modify, Padding, Settings, TableOption, Width,
|
||||
Alignment, Color, Format, Modify, ModifyList, Padding, Settings, TableOption, Width,
|
||||
},
|
||||
Table,
|
||||
};
|
||||
|
||||
use crate::{convert_style, table_theme::TableTheme};
|
||||
|
||||
/// NuTable is a table rendering implementation.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NuTable {
|
||||
|
@ -41,12 +45,14 @@ pub type NuTableCell = Text<String>;
|
|||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
struct Styles {
|
||||
index: ANSIBuf,
|
||||
header: ANSIBuf,
|
||||
data: EntityMap<ANSIBuf>,
|
||||
data_is_set: bool,
|
||||
data: Color,
|
||||
index: Color,
|
||||
header: Color,
|
||||
columns: HashMap<usize, Color>,
|
||||
cells: HashMap<Position, Color>,
|
||||
}
|
||||
|
||||
// todo: generic
|
||||
#[derive(Debug, Clone)]
|
||||
struct Alignments {
|
||||
data: AlignmentHorizontal,
|
||||
|
@ -89,9 +95,8 @@ impl NuTable {
|
|||
|
||||
pub fn set_column_style(&mut self, column: usize, style: TextStyle) {
|
||||
if let Some(style) = style.color_style {
|
||||
let style = ANSIBuf::from(convert_style(style));
|
||||
self.styles.data.insert(Entity::Column(column), style);
|
||||
self.styles.data_is_set = true;
|
||||
let style = convert_style(style);
|
||||
self.styles.columns.insert(column, style);
|
||||
}
|
||||
|
||||
let alignment = convert_alignment(style.alignment);
|
||||
|
@ -102,9 +107,8 @@ impl NuTable {
|
|||
|
||||
pub fn insert_style(&mut self, pos: Position, style: TextStyle) {
|
||||
if let Some(style) = style.color_style {
|
||||
let style = ANSIBuf::from(convert_style(style));
|
||||
self.styles.data.insert(Entity::Cell(pos.0, pos.1), style);
|
||||
self.styles.data_is_set = true;
|
||||
let style = convert_style(style);
|
||||
self.styles.cells.insert(pos, style);
|
||||
}
|
||||
|
||||
let alignment = convert_alignment(style.alignment);
|
||||
|
@ -115,7 +119,7 @@ impl NuTable {
|
|||
|
||||
pub fn set_header_style(&mut self, style: TextStyle) {
|
||||
if let Some(style) = style.color_style {
|
||||
let style = ANSIBuf::from(convert_style(style));
|
||||
let style = convert_style(style);
|
||||
self.styles.header = style;
|
||||
}
|
||||
|
||||
|
@ -124,7 +128,7 @@ impl NuTable {
|
|||
|
||||
pub fn set_index_style(&mut self, style: TextStyle) {
|
||||
if let Some(style) = style.color_style {
|
||||
let style = ANSIBuf::from(convert_style(style));
|
||||
let style = convert_style(style);
|
||||
self.styles.index = style;
|
||||
}
|
||||
|
||||
|
@ -133,9 +137,8 @@ impl NuTable {
|
|||
|
||||
pub fn set_data_style(&mut self, style: TextStyle) {
|
||||
if let Some(style) = style.color_style {
|
||||
let style = ANSIBuf::from(convert_style(style));
|
||||
self.styles.data.insert(Entity::Global, style);
|
||||
self.styles.data_is_set = true;
|
||||
let style = convert_style(style);
|
||||
self.styles.data = style;
|
||||
}
|
||||
|
||||
self.alignments.data = convert_alignment(style.alignment);
|
||||
|
@ -207,6 +210,22 @@ impl Default for NuTableConfig {
|
|||
}
|
||||
}
|
||||
|
||||
struct TableStructure {
|
||||
with_index: bool,
|
||||
with_header: bool,
|
||||
with_footer: bool,
|
||||
}
|
||||
|
||||
impl TableStructure {
|
||||
fn new(with_index: bool, with_header: bool, with_footer: bool) -> Self {
|
||||
Self {
|
||||
with_index,
|
||||
with_header,
|
||||
with_footer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_table(
|
||||
mut data: NuRecords,
|
||||
cfg: NuTableConfig,
|
||||
|
@ -241,9 +260,7 @@ fn draw_table(
|
|||
termwidth: usize,
|
||||
indent: (usize, usize),
|
||||
) -> Option<String> {
|
||||
let with_index = cfg.with_index;
|
||||
let with_header = cfg.with_header && data.count_rows() > 1;
|
||||
let with_footer = with_header && cfg.with_footer;
|
||||
let structure = get_table_structure(&data, &cfg);
|
||||
let sep_color = cfg.split_color;
|
||||
let border_header = cfg.header_on_border;
|
||||
|
||||
|
@ -251,77 +268,99 @@ fn draw_table(
|
|||
let mut table = Builder::from(data).build();
|
||||
|
||||
set_indent(&mut table, indent.0, indent.1);
|
||||
load_theme(&mut table, &cfg.theme, with_footer, with_header, sep_color);
|
||||
align_table(&mut table, alignments, with_index, with_header, with_footer);
|
||||
colorize_table(&mut table, styles, with_index, with_header, with_footer);
|
||||
load_theme(&mut table, &cfg.theme, &structure, sep_color);
|
||||
align_table(&mut table, alignments, &structure);
|
||||
colorize_table(&mut table, styles, &structure);
|
||||
|
||||
let pad = indent.0 + indent.1;
|
||||
let width_ctrl = TableWidthCtrl::new(widths, cfg, termwidth, pad);
|
||||
let width_ctrl = WidthCtrl::new(widths, cfg, termwidth, pad);
|
||||
|
||||
if with_header && border_header {
|
||||
set_border_head(&mut table, with_footer, width_ctrl);
|
||||
let need_border_header = structure.with_header && border_header;
|
||||
adjust_table(
|
||||
&mut table,
|
||||
width_ctrl,
|
||||
need_border_header,
|
||||
structure.with_footer,
|
||||
);
|
||||
|
||||
table_to_string(table, termwidth)
|
||||
}
|
||||
|
||||
fn get_table_structure(data: &VecRecords<Text<String>>, cfg: &NuTableConfig) -> TableStructure {
|
||||
let with_index = cfg.with_index;
|
||||
let with_header = cfg.with_header && data.count_rows() > 1;
|
||||
let with_footer = with_header && cfg.with_footer;
|
||||
|
||||
TableStructure::new(with_index, with_header, with_footer)
|
||||
}
|
||||
|
||||
fn adjust_table(table: &mut Table, width_ctrl: WidthCtrl, border_header: bool, with_footer: bool) {
|
||||
if border_header {
|
||||
if with_footer {
|
||||
set_border_head_with_footer(table, width_ctrl);
|
||||
} else {
|
||||
set_border_head(table, width_ctrl);
|
||||
}
|
||||
} else {
|
||||
table.with(width_ctrl);
|
||||
}
|
||||
|
||||
table_to_string(table, termwidth)
|
||||
}
|
||||
|
||||
fn set_indent(table: &mut Table, left: usize, right: usize) {
|
||||
table.with(Padding::new(left, right, 0, 0));
|
||||
}
|
||||
|
||||
fn set_border_head(table: &mut Table, with_footer: bool, wctrl: TableWidthCtrl) {
|
||||
if with_footer {
|
||||
let count_rows = table.count_rows();
|
||||
let last_row_index = count_rows - 1;
|
||||
fn set_border_head(table: &mut Table, wctrl: WidthCtrl) {
|
||||
let mut row = GetRow(0, Vec::new());
|
||||
let mut row_opts = GetRowSettings(0, AlignmentHorizontal::Left, None);
|
||||
|
||||
// note: funnily last and row must be equal at this point but we do not rely on it just in case.
|
||||
table.with(&mut row);
|
||||
table.with(&mut row_opts);
|
||||
|
||||
let mut first_row = GetRow(0, Vec::new());
|
||||
let mut head_settings = GetRowSettings(0, AlignmentHorizontal::Left, None);
|
||||
let mut last_row = GetRow(last_row_index, Vec::new());
|
||||
table.with(
|
||||
Settings::default()
|
||||
.with(strip_color_from_row(0))
|
||||
.with(wctrl)
|
||||
.with(MoveRowNext::new(0, 0))
|
||||
.with(SetLineHeaders::new(0, row.1, row_opts.1, row_opts.2)),
|
||||
);
|
||||
}
|
||||
|
||||
table.with(&mut first_row);
|
||||
table.with(&mut head_settings);
|
||||
table.with(&mut last_row);
|
||||
fn set_border_head_with_footer(table: &mut Table, wctrl: WidthCtrl) {
|
||||
// note: funnily last and row must be equal at this point but we do not rely on it just in case.
|
||||
|
||||
let head = first_row.1;
|
||||
let footer = last_row.1;
|
||||
let alignment = head_settings.1;
|
||||
let head_color = head_settings.2.clone();
|
||||
let footer_color = head_settings.2;
|
||||
let count_rows = table.count_rows();
|
||||
let last_row_index = count_rows - 1;
|
||||
|
||||
table.with(
|
||||
Settings::default()
|
||||
.with(StripColorFromRow(0))
|
||||
.with(StripColorFromRow(count_rows - 1))
|
||||
.with(wctrl)
|
||||
.with(MoveRowNext::new(0, 0))
|
||||
.with(MoveRowPrev::new(last_row_index - 1, last_row_index))
|
||||
.with(SetLineHeaders::new(0, head, alignment, head_color))
|
||||
.with(SetLineHeaders::new(
|
||||
last_row_index - 1,
|
||||
footer,
|
||||
alignment,
|
||||
footer_color,
|
||||
)),
|
||||
);
|
||||
} else {
|
||||
let mut row = GetRow(0, Vec::new());
|
||||
let mut row_opts = GetRowSettings(0, AlignmentHorizontal::Left, None);
|
||||
let mut first_row = GetRow(0, Vec::new());
|
||||
let mut head_settings = GetRowSettings(0, AlignmentHorizontal::Left, None);
|
||||
let mut last_row = GetRow(last_row_index, Vec::new());
|
||||
|
||||
table.with(&mut row);
|
||||
table.with(&mut row_opts);
|
||||
table.with(&mut first_row);
|
||||
table.with(&mut head_settings);
|
||||
table.with(&mut last_row);
|
||||
|
||||
table.with(
|
||||
Settings::default()
|
||||
.with(StripColorFromRow(0))
|
||||
.with(wctrl)
|
||||
.with(MoveRowNext::new(0, 0))
|
||||
.with(SetLineHeaders::new(0, row.1, row_opts.1, row_opts.2)),
|
||||
);
|
||||
}
|
||||
let head = first_row.1;
|
||||
let footer = last_row.1;
|
||||
let alignment = head_settings.1;
|
||||
let head_color = head_settings.2.clone();
|
||||
let footer_color = head_settings.2;
|
||||
|
||||
table.with(
|
||||
Settings::default()
|
||||
.with(strip_color_from_row(0))
|
||||
.with(strip_color_from_row(count_rows - 1))
|
||||
.with(wctrl)
|
||||
.with(MoveRowNext::new(0, 0))
|
||||
.with(MoveRowPrev::new(last_row_index - 1, last_row_index))
|
||||
.with(SetLineHeaders::new(0, head, alignment, head_color))
|
||||
.with(SetLineHeaders::new(
|
||||
last_row_index - 1,
|
||||
footer,
|
||||
alignment,
|
||||
footer_color,
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
fn table_to_string(table: Table, termwidth: usize) -> Option<String> {
|
||||
|
@ -335,14 +374,14 @@ fn table_to_string(table: Table, termwidth: usize) -> Option<String> {
|
|||
}
|
||||
}
|
||||
|
||||
struct TableWidthCtrl {
|
||||
struct WidthCtrl {
|
||||
width: Vec<usize>,
|
||||
cfg: NuTableConfig,
|
||||
width_max: usize,
|
||||
pad: usize,
|
||||
}
|
||||
|
||||
impl TableWidthCtrl {
|
||||
impl WidthCtrl {
|
||||
fn new(width: Vec<usize>, cfg: NuTableConfig, max: usize, pad: usize) -> Self {
|
||||
Self {
|
||||
width,
|
||||
|
@ -353,7 +392,7 @@ impl TableWidthCtrl {
|
|||
}
|
||||
}
|
||||
|
||||
impl TableOption<NuRecords, ColoredConfig, CompleteDimensionVecRecords<'_>> for TableWidthCtrl {
|
||||
impl TableOption<NuRecords, ColoredConfig, CompleteDimensionVecRecords<'_>> for WidthCtrl {
|
||||
fn change(
|
||||
self,
|
||||
rec: &mut NuRecords,
|
||||
|
@ -362,24 +401,24 @@ impl TableOption<NuRecords, ColoredConfig, CompleteDimensionVecRecords<'_>> for
|
|||
) {
|
||||
let total_width = get_total_width2(&self.width, cfg);
|
||||
|
||||
if total_width > self.width_max {
|
||||
let need_truncation = total_width > self.width_max;
|
||||
if need_truncation {
|
||||
let has_header = self.cfg.with_header && rec.count_rows() > 1;
|
||||
let trim_as_head = has_header && self.cfg.header_on_border;
|
||||
let as_head = has_header && self.cfg.header_on_border;
|
||||
|
||||
TableTrim::new(
|
||||
self.width,
|
||||
self.width_max,
|
||||
self.cfg.trim,
|
||||
trim_as_head,
|
||||
self.pad,
|
||||
)
|
||||
.change(rec, cfg, dim);
|
||||
} else if self.cfg.expand && self.width_max > total_width {
|
||||
let opt = (SetDimensions(self.width), Width::increase(self.width_max));
|
||||
TableOption::<VecRecords<_>, _, _>::change(opt, rec, cfg, dim)
|
||||
} else {
|
||||
SetDimensions(self.width).change(rec, cfg, dim);
|
||||
let trim = TableTrim::new(self.width, self.width_max, self.cfg.trim, as_head, self.pad);
|
||||
trim.change(rec, cfg, dim);
|
||||
return;
|
||||
}
|
||||
|
||||
let need_expantion = self.cfg.expand && self.width_max > total_width;
|
||||
if need_expantion {
|
||||
let opt = (SetDimensions(self.width), Width::increase(self.width_max));
|
||||
TableOption::<VecRecords<_>, _, _>::change(opt, rec, cfg, dim);
|
||||
return;
|
||||
}
|
||||
|
||||
SetDimensions(self.width).change(rec, cfg, dim);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -427,13 +466,13 @@ impl TableOption<NuRecords, ColoredConfig, CompleteDimensionVecRecords<'_>> for
|
|||
TrimStrategy::Wrap { try_to_keep_words } => {
|
||||
let wrap = Width::wrap(self.width_max)
|
||||
.keep_words(try_to_keep_words)
|
||||
.priority(PriorityMax);
|
||||
.priority(Priority::max(false));
|
||||
|
||||
let opt = (SetDimensions(self.width), wrap);
|
||||
TableOption::<NuRecords, _, _>::change(opt, recs, cfg, dims);
|
||||
}
|
||||
TrimStrategy::Truncate { suffix } => {
|
||||
let mut truncate = Width::truncate(self.width_max).priority(PriorityMax);
|
||||
let mut truncate = Width::truncate(self.width_max).priority(Priority::max(false));
|
||||
if let Some(suffix) = suffix {
|
||||
truncate = truncate.suffix(suffix).suffix_try_color(true);
|
||||
}
|
||||
|
@ -515,7 +554,7 @@ fn trim_as_header(
|
|||
let wrap = Width::wrap(width).keep_words(*try_to_keep_words);
|
||||
|
||||
let opt = Modify::new(Columns::single(i)).with(wrap);
|
||||
TableOption::<VecRecords<Text<String>>, _, _>::change(opt, recs, cfg, dims);
|
||||
TableOption::<VecRecords<_>, _, _>::change(opt, recs, cfg, dims);
|
||||
}
|
||||
TrimStrategy::Truncate { suffix } => {
|
||||
let mut truncate = Width::truncate(width);
|
||||
|
@ -524,7 +563,7 @@ fn trim_as_header(
|
|||
}
|
||||
|
||||
let opt = Modify::new(Columns::single(i)).with(truncate);
|
||||
TableOption::<VecRecords<Text<String>>, _, _>::change(opt, recs, cfg, dims);
|
||||
TableOption::<VecRecords<_>, _, _>::change(opt, recs, cfg, dims);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -532,82 +571,74 @@ fn trim_as_header(
|
|||
TableOption::change(SetDimensions(widths), recs, cfg, dims);
|
||||
}
|
||||
|
||||
fn align_table(
|
||||
table: &mut Table,
|
||||
alignments: Alignments,
|
||||
with_index: bool,
|
||||
with_header: bool,
|
||||
with_footer: bool,
|
||||
) {
|
||||
table
|
||||
.with(Modify::new(Segment::all()).with(AlignmentStrategy::PerLine))
|
||||
.with(SetAlignment(alignments.data, Entity::Global));
|
||||
fn align_table(table: &mut Table, alignments: Alignments, structure: &TableStructure) {
|
||||
table.with(AlignmentStrategy::PerLine);
|
||||
table.with(Alignment::from(alignments.data));
|
||||
|
||||
for (column, alignment) in alignments.columns {
|
||||
table.with(SetAlignment(alignment, Entity::Column(column)));
|
||||
table.modify(Columns::single(column), Alignment::from(alignment));
|
||||
}
|
||||
|
||||
for (pos, alignment) in alignments.cells {
|
||||
table.with(SetAlignment(alignment, Entity::Cell(pos.0, pos.1)));
|
||||
table.modify(pos, Alignment::from(alignment));
|
||||
}
|
||||
|
||||
if with_header {
|
||||
table.with(SetAlignment(alignments.header, Entity::Row(0)));
|
||||
if structure.with_header {
|
||||
table.modify(Rows::first(), Alignment::from(alignments.header));
|
||||
|
||||
if with_footer {
|
||||
table.with(SetAlignment(
|
||||
alignments.header,
|
||||
Entity::Row(table.count_rows() - 1),
|
||||
));
|
||||
if structure.with_footer {
|
||||
table.modify(Rows::last(), Alignment::from(alignments.header));
|
||||
}
|
||||
}
|
||||
|
||||
if with_index {
|
||||
table.with(SetAlignment(alignments.index, Entity::Column(0)));
|
||||
if structure.with_index {
|
||||
table.modify(Columns::first(), Alignment::from(alignments.index));
|
||||
}
|
||||
}
|
||||
|
||||
fn colorize_table(
|
||||
table: &mut Table,
|
||||
mut styles: Styles,
|
||||
with_index: bool,
|
||||
with_header: bool,
|
||||
with_footer: bool,
|
||||
) {
|
||||
if with_index {
|
||||
styles.data.insert(Entity::Column(0), styles.index);
|
||||
styles.data_is_set = true;
|
||||
fn colorize_table(table: &mut Table, styles: Styles, structure: &TableStructure) {
|
||||
if !is_color_empty(&styles.data) {
|
||||
table.with(styles.data);
|
||||
}
|
||||
|
||||
if with_header {
|
||||
styles.data.insert(Entity::Row(0), styles.header.clone());
|
||||
styles.data_is_set = true;
|
||||
|
||||
if with_footer {
|
||||
let count_rows = table.count_rows();
|
||||
if count_rows > 1 {
|
||||
let last_row = count_rows - 1;
|
||||
styles.data.insert(Entity::Row(last_row), styles.header);
|
||||
}
|
||||
for (column, color) in styles.columns {
|
||||
if !is_color_empty(&color) {
|
||||
table.modify(Columns::single(column), color);
|
||||
}
|
||||
}
|
||||
|
||||
if styles.data_is_set {
|
||||
table.get_config_mut().set_colors(styles.data);
|
||||
for (pos, color) in styles.cells {
|
||||
if !is_color_empty(&color) {
|
||||
table.modify(pos, color);
|
||||
}
|
||||
}
|
||||
|
||||
if structure.with_index && !is_color_empty(&styles.index) {
|
||||
table.modify(Columns::first(), styles.index);
|
||||
}
|
||||
|
||||
if structure.with_header && !is_color_empty(&styles.header) {
|
||||
table.modify(Rows::first(), styles.header.clone());
|
||||
}
|
||||
|
||||
if structure.with_footer && !is_color_empty(&styles.header) {
|
||||
table.modify(Rows::last(), styles.header);
|
||||
}
|
||||
}
|
||||
|
||||
fn load_theme(
|
||||
table: &mut Table,
|
||||
theme: &TableTheme,
|
||||
with_footer: bool,
|
||||
with_header: bool,
|
||||
structure: &TableStructure,
|
||||
sep_color: Option<Style>,
|
||||
) {
|
||||
let mut theme = theme.get_theme();
|
||||
let mut theme = theme.as_base().clone();
|
||||
|
||||
if !with_header {
|
||||
if !structure.with_header {
|
||||
theme.set_horizontal_lines(Default::default());
|
||||
theme.remove_horizontal_lines();
|
||||
} else if structure.with_footer {
|
||||
theme_copy_horizontal_line(&mut theme, 1, table.count_rows() - 1);
|
||||
}
|
||||
|
||||
table.with(theme);
|
||||
|
@ -615,17 +646,8 @@ fn load_theme(
|
|||
if let Some(style) = sep_color {
|
||||
let color = convert_style(style);
|
||||
let color = ANSIBuf::from(color);
|
||||
// todo: use .modify(Segment::all(), color) --> it has this optimization
|
||||
table.get_config_mut().set_border_color_default(color);
|
||||
}
|
||||
|
||||
if !with_header {
|
||||
// todo: remove and use theme.remove_horizontal_lines();
|
||||
table.with(RemoveHorizontalLine);
|
||||
} else if with_footer {
|
||||
// todo: remove and set it on theme rather then here...
|
||||
table.with(CopyFirstHorizontalLineAtLast);
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_truncate_columns(
|
||||
|
@ -880,18 +902,6 @@ fn truncate_columns_by_head(
|
|||
widths
|
||||
}
|
||||
|
||||
/// The same as [`tabled::settings::peaker::PriorityMax`] but prioritizes left columns first in case
|
||||
/// of equal width.
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct PriorityMax;
|
||||
|
||||
impl Peaker for PriorityMax {
|
||||
fn peak(&mut self, _: &[usize], widths: &[usize]) -> Option<usize> {
|
||||
let col = (0..widths.len()).rev().max_by_key(|&i| widths[i]);
|
||||
col.filter(|&col| widths[col] != 0)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_total_width2(widths: &[usize], cfg: &ColoredConfig) -> usize {
|
||||
let total = widths.iter().sum::<usize>();
|
||||
let countv = cfg.count_vertical(widths.len());
|
||||
|
@ -901,8 +911,9 @@ fn get_total_width2(widths: &[usize], cfg: &ColoredConfig) -> usize {
|
|||
}
|
||||
|
||||
fn get_config(theme: &TableTheme, with_header: bool, color: Option<Style>) -> ColoredConfig {
|
||||
let structure = TableStructure::new(false, with_header, false);
|
||||
let mut table = Table::new([[""]]);
|
||||
load_theme(&mut table, theme, false, with_header, color);
|
||||
load_theme(&mut table, theme, &structure, color);
|
||||
table.get_config().clone()
|
||||
}
|
||||
|
||||
|
@ -947,14 +958,6 @@ fn convert_alignment(alignment: nu_color_config::Alignment) -> AlignmentHorizont
|
|||
}
|
||||
}
|
||||
|
||||
struct SetAlignment(AlignmentHorizontal, Entity);
|
||||
|
||||
impl<R, D> TableOption<R, ColoredConfig, D> for SetAlignment {
|
||||
fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
|
||||
cfg.set_alignment_horizontal(self.1, self.0);
|
||||
}
|
||||
}
|
||||
|
||||
struct SetDimensions(Vec<usize>);
|
||||
|
||||
impl<R> TableOption<R, ColoredConfig, CompleteDimensionVecRecords<'_>> for SetDimensions {
|
||||
|
@ -1045,16 +1048,8 @@ impl TableOption<NuRecords, ColoredConfig, CompleteDimensionVecRecords<'_>> for
|
|||
cfg: &mut ColoredConfig,
|
||||
dims: &mut CompleteDimensionVecRecords<'_>,
|
||||
) {
|
||||
let mut columns = self.columns;
|
||||
|
||||
match dims.get_widths() {
|
||||
Some(widths) => {
|
||||
columns = columns
|
||||
.into_iter()
|
||||
.zip(widths.iter().cloned()) // it must be always safe to do
|
||||
.map(|(s, width)| Truncate::truncate(&s, width).into_owned())
|
||||
.collect();
|
||||
}
|
||||
let widths = match dims.get_widths() {
|
||||
Some(widths) => widths,
|
||||
None => {
|
||||
// we don't have widths cached; which means that NO width adjustments were done
|
||||
// which means we are OK to leave columns as they are.
|
||||
|
@ -1065,15 +1060,21 @@ impl TableOption<NuRecords, ColoredConfig, CompleteDimensionVecRecords<'_>> for
|
|||
}
|
||||
};
|
||||
|
||||
set_column_names(
|
||||
recs,
|
||||
cfg,
|
||||
dims,
|
||||
columns,
|
||||
self.line,
|
||||
self.alignment,
|
||||
self.color,
|
||||
)
|
||||
let columns: Vec<_> = self
|
||||
.columns
|
||||
.into_iter()
|
||||
.zip(widths.iter().cloned()) // it must be always safe to do
|
||||
.map(|(s, width)| Truncate::truncate(&s, width).into_owned())
|
||||
.collect();
|
||||
|
||||
let mut names = ColumnNames::new(columns)
|
||||
.line(self.line)
|
||||
.alignment(Alignment::from(self.alignment));
|
||||
if let Some(color) = self.color {
|
||||
names = names.color(color);
|
||||
}
|
||||
|
||||
names.change(recs, cfg, dims);
|
||||
}
|
||||
|
||||
fn hint_change(&self) -> Option<Entity> {
|
||||
|
@ -1142,26 +1143,23 @@ fn row_shift_next(recs: &mut NuRecords, cfg: &mut ColoredConfig, row: usize, lin
|
|||
return;
|
||||
}
|
||||
|
||||
if !has_line {
|
||||
let _ = remove_row(recs, row);
|
||||
let count_rows = recs.count_rows();
|
||||
shift_alignments_down(cfg, row, count_rows, count_columns);
|
||||
shift_colors_down(cfg, row, count_rows, count_columns);
|
||||
shift_lines_up(cfg, count_rows, &[line + 1]);
|
||||
shift_lines_up(cfg, count_rows, &[count_rows]);
|
||||
return;
|
||||
}
|
||||
|
||||
let _ = remove_row(recs, row);
|
||||
recs.remove_row(row);
|
||||
let count_rows = recs.count_rows();
|
||||
|
||||
shift_alignments_down(cfg, row, count_rows, count_columns);
|
||||
shift_colors_down(cfg, row, count_rows, count_columns);
|
||||
remove_lines(cfg, count_rows, &[line + 1]);
|
||||
|
||||
if !has_line {
|
||||
shift_lines_up(cfg, count_rows, &[line + 1]);
|
||||
} else {
|
||||
remove_lines(cfg, count_rows, &[line + 1]);
|
||||
}
|
||||
|
||||
shift_lines_up(cfg, count_rows, &[count_rows]);
|
||||
}
|
||||
|
||||
fn row_shift_prev(recs: &mut NuRecords, cfg: &mut ColoredConfig, row: usize, line: usize) {
|
||||
let count_rows = recs.count_rows();
|
||||
let mut count_rows = recs.count_rows();
|
||||
let count_columns = recs.count_columns();
|
||||
let has_line = cfg.has_horizontal(line, count_rows);
|
||||
let has_prev_line = cfg.has_horizontal(line - 1, count_rows);
|
||||
|
@ -1169,14 +1167,14 @@ fn row_shift_prev(recs: &mut NuRecords, cfg: &mut ColoredConfig, row: usize, lin
|
|||
return;
|
||||
}
|
||||
|
||||
recs.remove_row(row);
|
||||
|
||||
if !has_line {
|
||||
let _ = remove_row(recs, row);
|
||||
// shift_lines_down(table, &[line - 1]);
|
||||
return;
|
||||
}
|
||||
|
||||
let _ = remove_row(recs, row);
|
||||
let count_rows = count_rows - 1;
|
||||
count_rows -= 1;
|
||||
|
||||
shift_alignments_down(cfg, row, count_rows, count_columns);
|
||||
shift_colors_down(cfg, row, count_rows, count_columns);
|
||||
remove_lines(cfg, count_rows, &[line - 1]);
|
||||
|
@ -1230,73 +1228,21 @@ fn shift_lines_up(cfg: &mut ColoredConfig, count_rows: usize, lines: &[usize]) {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_column_names(
|
||||
records: &mut NuRecords,
|
||||
cfg: &mut ColoredConfig,
|
||||
dims: &mut CompleteDimensionVecRecords<'_>,
|
||||
head: Vec<String>,
|
||||
line: usize,
|
||||
align: AlignmentHorizontal,
|
||||
color: Option<Color>,
|
||||
) {
|
||||
let mut names = ColumnNames::new(head)
|
||||
.line(line)
|
||||
.alignment(Alignment::from(align));
|
||||
if let Some(color) = color {
|
||||
names = names.color(color);
|
||||
}
|
||||
|
||||
ColumnNames::change(names, records, cfg, dims)
|
||||
}
|
||||
|
||||
fn remove_row(recs: &mut NuRecords, row: usize) -> Vec<String> {
|
||||
let count_columns = recs.count_columns();
|
||||
let columns = (0..count_columns)
|
||||
.map(|column| recs.get_text((row, column)).to_owned())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
recs.remove_row(row);
|
||||
|
||||
columns
|
||||
}
|
||||
|
||||
// todo; use Format?
|
||||
struct StripColorFromRow(usize);
|
||||
|
||||
impl TableOption<NuRecords, ColoredConfig, CompleteDimensionVecRecords<'_>> for StripColorFromRow {
|
||||
fn change(
|
||||
self,
|
||||
recs: &mut NuRecords,
|
||||
_: &mut ColoredConfig,
|
||||
_: &mut CompleteDimensionVecRecords<'_>,
|
||||
) {
|
||||
for cell in &mut recs[self.0] {
|
||||
*cell = Text::new(strip_ansi_unlikely(cell.as_ref()).into_owned());
|
||||
}
|
||||
fn theme_copy_horizontal_line(theme: &mut tabled::settings::Theme, from: usize, to: usize) {
|
||||
if let Some(line) = theme.get_horizontal_line(from) {
|
||||
theme.insert_horizontal_line(to, *line);
|
||||
}
|
||||
}
|
||||
|
||||
struct RemoveHorizontalLine;
|
||||
|
||||
impl<D> TableOption<NuRecords, ColoredConfig, D> for RemoveHorizontalLine {
|
||||
fn change(self, recs: &mut NuRecords, cfg: &mut ColoredConfig, _: &mut D) {
|
||||
cfg.remove_horizontal_line(1, recs.count_rows());
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn strip_color_from_row(row: usize) -> ModifyList<Row, FormatContent<fn(&str) -> String>> {
|
||||
fn foo(s: &str) -> String {
|
||||
strip_ansi_unlikely(s).into_owned()
|
||||
}
|
||||
|
||||
Modify::new(Rows::single(row)).with(Format::content(foo))
|
||||
}
|
||||
|
||||
struct CopyFirstHorizontalLineAtLast;
|
||||
|
||||
impl<D> TableOption<NuRecords, ColoredConfig, D> for CopyFirstHorizontalLineAtLast {
|
||||
fn change(self, recs: &mut NuRecords, cfg: &mut ColoredConfig, _: &mut D) {
|
||||
if recs.count_rows() <= 2 {
|
||||
return;
|
||||
}
|
||||
|
||||
let line = match cfg.get_horizontal_line(1) {
|
||||
Some(line) => *line,
|
||||
None => return,
|
||||
};
|
||||
|
||||
cfg.insert_horizontal_line(recs.count_rows() - 1, line);
|
||||
}
|
||||
fn is_color_empty(c: &Color) -> bool {
|
||||
c.get_prefix().is_empty() && c.get_suffix().is_empty()
|
||||
}
|
||||
|
|
|
@ -1,67 +1,63 @@
|
|||
use tabled::settings::style::{HorizontalLine, Style};
|
||||
use tabled::settings::themes::Theme;
|
||||
use tabled::settings::{
|
||||
style::{HorizontalLine, Style},
|
||||
themes::Theme,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TableTheme {
|
||||
theme: Theme,
|
||||
full_theme: Theme,
|
||||
has_inner: bool,
|
||||
base: Theme,
|
||||
full: Theme,
|
||||
}
|
||||
|
||||
impl TableTheme {
|
||||
pub fn new(theme: impl Into<Theme>, full_theme: impl Into<Theme>, has_inner: bool) -> Self {
|
||||
pub fn new(base: impl Into<Theme>, full: impl Into<Theme>) -> Self {
|
||||
Self {
|
||||
theme: theme.into(),
|
||||
full_theme: full_theme.into(),
|
||||
has_inner,
|
||||
base: base.into(),
|
||||
full: full.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn basic() -> TableTheme {
|
||||
Self::new(Style::ascii(), Style::ascii(), true)
|
||||
Self::new(Style::ascii(), Style::ascii())
|
||||
}
|
||||
|
||||
pub fn thin() -> TableTheme {
|
||||
Self::new(Style::modern(), Style::modern(), true)
|
||||
Self::new(Style::modern(), Style::modern())
|
||||
}
|
||||
|
||||
pub fn light() -> TableTheme {
|
||||
let mut theme = Theme::from_style(Style::blank());
|
||||
theme.insert_horizontal_line(1, HorizontalLine::new('─').intersection('─'));
|
||||
|
||||
Self::new(theme, Style::modern(), true)
|
||||
Self::new(theme, Style::modern())
|
||||
}
|
||||
|
||||
pub fn psql() -> TableTheme {
|
||||
Self::new(Style::psql(), Style::psql(), true)
|
||||
Self::new(Style::psql(), Style::psql())
|
||||
}
|
||||
|
||||
pub fn markdown() -> TableTheme {
|
||||
Self::new(Style::markdown(), Style::markdown(), true)
|
||||
Self::new(Style::markdown(), Style::markdown())
|
||||
}
|
||||
|
||||
pub fn dots() -> TableTheme {
|
||||
let theme = Style::dots().remove_horizontal();
|
||||
|
||||
Self::new(theme, Style::dots(), true)
|
||||
Self::new(theme, Style::dots())
|
||||
}
|
||||
|
||||
pub fn restructured() -> TableTheme {
|
||||
Self::new(
|
||||
Style::re_structured_text(),
|
||||
Style::re_structured_text(),
|
||||
true,
|
||||
)
|
||||
Self::new(Style::re_structured_text(), Style::re_structured_text())
|
||||
}
|
||||
|
||||
pub fn ascii_rounded() -> TableTheme {
|
||||
Self::new(Style::ascii_rounded(), Style::ascii_rounded(), true)
|
||||
Self::new(Style::ascii_rounded(), Style::ascii_rounded())
|
||||
}
|
||||
|
||||
pub fn basic_compact() -> TableTheme {
|
||||
let theme = Style::ascii().remove_horizontal();
|
||||
|
||||
Self::new(theme, Style::ascii(), true)
|
||||
Self::new(theme, Style::ascii())
|
||||
}
|
||||
|
||||
pub fn compact() -> TableTheme {
|
||||
|
@ -72,7 +68,7 @@ impl TableTheme {
|
|||
.remove_horizontal()
|
||||
.horizontals([(1, hline)]);
|
||||
|
||||
Self::new(theme, Style::modern(), true)
|
||||
Self::new(theme, Style::modern())
|
||||
}
|
||||
|
||||
pub fn with_love() -> TableTheme {
|
||||
|
@ -99,7 +95,7 @@ impl TableTheme {
|
|||
.intersection_left('❤')
|
||||
.intersection('❤');
|
||||
|
||||
Self::new(theme, full_theme, true)
|
||||
Self::new(theme, full_theme)
|
||||
}
|
||||
|
||||
pub fn compact_double() -> TableTheme {
|
||||
|
@ -112,7 +108,7 @@ impl TableTheme {
|
|||
.remove_horizontal()
|
||||
.horizontals([(1, hline)]);
|
||||
|
||||
Self::new(theme, Style::extended(), true)
|
||||
Self::new(theme, Style::extended())
|
||||
}
|
||||
|
||||
pub fn rounded() -> TableTheme {
|
||||
|
@ -122,7 +118,7 @@ impl TableTheme {
|
|||
.corner_bottom_left('╰')
|
||||
.corner_bottom_right('╯');
|
||||
|
||||
Self::new(Style::rounded(), full, true)
|
||||
Self::new(Style::rounded(), full)
|
||||
}
|
||||
|
||||
pub fn reinforced() -> TableTheme {
|
||||
|
@ -132,7 +128,7 @@ impl TableTheme {
|
|||
.corner_bottom_left('┗')
|
||||
.corner_bottom_right('┛');
|
||||
|
||||
Self::new(full.clone().remove_horizontal(), full, true)
|
||||
Self::new(full.clone().remove_horizontal(), full)
|
||||
}
|
||||
|
||||
pub fn heavy() -> TableTheme {
|
||||
|
@ -157,38 +153,38 @@ impl TableTheme {
|
|||
.intersection_right('┫')
|
||||
.intersection('╋');
|
||||
|
||||
Self::new(theme, full, true)
|
||||
Self::new(theme, full)
|
||||
}
|
||||
|
||||
pub fn none() -> TableTheme {
|
||||
Self::new(Style::blank(), Style::blank(), true)
|
||||
Self::new(Style::blank(), Style::blank())
|
||||
}
|
||||
|
||||
pub fn has_top(&self) -> bool {
|
||||
self.theme.borders_has_top()
|
||||
// pub fn has_top(&self) -> bool {
|
||||
// self.theme.borders_has_top()
|
||||
// }
|
||||
|
||||
// pub fn has_left(&self) -> bool {
|
||||
// self.theme.borders_has_left()
|
||||
// }
|
||||
|
||||
// pub fn has_right(&self) -> bool {
|
||||
// self.theme.borders_has_right()
|
||||
// }
|
||||
|
||||
// pub fn has_inner(&self) -> bool {
|
||||
// self.has_inner
|
||||
// }
|
||||
|
||||
// pub fn has_horizontals(&self) -> bool {
|
||||
// self.full_theme.get_borders().has_horizontal()
|
||||
// }
|
||||
|
||||
pub fn as_full(&self) -> &Theme {
|
||||
&self.full
|
||||
}
|
||||
|
||||
pub fn has_left(&self) -> bool {
|
||||
self.theme.borders_has_left()
|
||||
}
|
||||
|
||||
pub fn has_right(&self) -> bool {
|
||||
self.theme.borders_has_right()
|
||||
}
|
||||
|
||||
pub fn has_inner(&self) -> bool {
|
||||
self.has_inner
|
||||
}
|
||||
|
||||
pub fn has_horizontals(&self) -> bool {
|
||||
self.full_theme.get_borders().has_horizontal()
|
||||
}
|
||||
|
||||
pub fn get_theme_full(&self) -> Theme {
|
||||
self.full_theme.clone()
|
||||
}
|
||||
|
||||
pub fn get_theme(&self) -> Theme {
|
||||
self.theme.clone()
|
||||
pub fn as_base(&self) -> &Theme {
|
||||
&self.base
|
||||
}
|
||||
}
|
||||
|
|
|
@ -374,13 +374,15 @@ fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
|
|||
|
||||
fn expanded_table_kv(record: &Record, cfg: Cfg<'_>) -> CellResult {
|
||||
let theme = load_theme(cfg.opts.mode);
|
||||
let theme = theme.as_base();
|
||||
let key_width = record
|
||||
.columns()
|
||||
.map(|col| string_width(col))
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
let count_borders =
|
||||
theme.has_inner() as usize + theme.has_right() as usize + theme.has_left() as usize;
|
||||
let count_borders = theme.borders_has_vertical() as usize
|
||||
+ theme.borders_has_right() as usize
|
||||
+ theme.borders_has_left() as usize;
|
||||
let padding = 2;
|
||||
if key_width + count_borders + padding + padding > cfg.opts.width {
|
||||
return Ok(None);
|
||||
|
@ -403,7 +405,8 @@ fn expanded_table_kv(record: &Record, cfg: Cfg<'_>) -> CellResult {
|
|||
// we could use Padding for it but,
|
||||
// the easiest way to do so is just push a new_line char before
|
||||
let mut key = key.to_owned();
|
||||
if !key.is_empty() && cell.is_expanded && theme.has_top() {
|
||||
let is_key_on_next_line = !key.is_empty() && cell.is_expanded && theme.borders_has_top();
|
||||
if is_key_on_next_line {
|
||||
key.insert(0, '\n');
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ impl UnstructuredTable {
|
|||
|
||||
pub fn truncate(&mut self, theme: &TableTheme, width: usize) -> bool {
|
||||
let mut available = width;
|
||||
let has_vertical = theme.has_left();
|
||||
let has_vertical = theme.as_base().borders_has_left();
|
||||
if has_vertical {
|
||||
available = available.saturating_sub(2);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ fn build_table(
|
|||
) -> String {
|
||||
let mut table = PoolTable::from(val);
|
||||
|
||||
let mut theme = theme.get_theme_full();
|
||||
let mut theme = theme.as_full().clone();
|
||||
theme.set_horizontal_lines(Default::default());
|
||||
|
||||
table.with(Padding::new(indent.0, indent.1, 0, 0));
|
||||
|
|
Loading…
Reference in a new issue