This commit is contained in:
Maxim Zhiburt 2024-12-03 01:35:08 +03:00
parent 425c3d8380
commit 49318b91f3
4 changed files with 108 additions and 106 deletions

View File

@ -64,6 +64,8 @@ pub fn nu_value_to_string(val: &Value, cfg: &Config, style: &StyleComputer) -> N
make_styled_value(text, val, float_precision, style) make_styled_value(text, val, float_precision, style)
} }
// todo: Expose a method which returns just style
pub fn nu_value_to_string_clean(val: &Value, cfg: &Config, style_comp: &StyleComputer) -> NuText { pub fn nu_value_to_string_clean(val: &Value, cfg: &Config, style_comp: &StyleComputer) -> NuText {
let (text, style) = nu_value_to_string(val, cfg, style_comp); let (text, style) = nu_value_to_string(val, cfg, style_comp);
let mut text = clean_charset(&text); let mut text = clean_charset(&text);

View File

@ -1,3 +1,4 @@
use nu_ansi_term::Style;
use nu_color_config::StyleComputer; use nu_color_config::StyleComputer;
use nu_protocol::{Config, Record, Value}; use nu_protocol::{Config, Record, Value};
use nu_utils::SharedCow; use nu_utils::SharedCow;
@ -46,10 +47,8 @@ fn colorize_value(value: &mut Value, config: &Config, style_computer: &StyleComp
.into_iter() .into_iter()
.map(|(mut header, mut val)| { .map(|(mut header, mut val)| {
colorize_value(&mut val, config, style_computer); colorize_value(&mut val, config, style_computer);
header = colorize_text(&header, style.color_style).unwrap_or(header);
if let Some(color) = style.color_style {
header = color.paint(header).to_string();
}
(header, val) (header, val)
}) })
.collect::<Record>(), .collect::<Record>(),
@ -62,11 +61,19 @@ fn colorize_value(value: &mut Value, config: &Config, style_computer: &StyleComp
} }
value => { value => {
let (text, style) = nu_value_to_string_clean(value, config, style_computer); let (text, style) = nu_value_to_string_clean(value, config, style_computer);
if let Some(color) = style.color_style { if let Some(text) = colorize_text(&text, style.color_style) {
let text = color.paint(text).to_string(); *value = Value::string(text, value.span());
let span = value.span();
*value = Value::string(text, span);
} }
} }
} }
} }
fn colorize_text(text: &str, color: Option<Style>) -> Option<String> {
if let Some(color) = color {
if !color.is_plain() {
return Some(color.paint(text).to_string());
}
}
None
}

View File

@ -2,13 +2,13 @@ use nu_color_config::TextStyle;
use nu_engine::column::get_columns; use nu_engine::column::get_columns;
use nu_protocol::{Config, Record, ShellError, Value}; use nu_protocol::{Config, Record, ShellError, Value};
use super::has_index;
use crate::{ use crate::{
clean_charset, colorize_space, clean_charset, colorize_space,
common::{ common::{
check_value, create_nu_table_config, get_empty_style, get_header_style, get_index_style, check_value, create_nu_table_config, get_empty_style, get_header_style, get_index_style,
get_value_style, nu_value_to_string_colored, NuText, INDEX_COLUMN_NAME, get_value_style, nu_value_to_string_colored, NuText, INDEX_COLUMN_NAME,
}, },
types::has_index,
NuRecordsValue, NuTable, StringResult, TableOpts, TableOutput, TableResult, NuRecordsValue, NuTable, StringResult, TableOpts, TableOutput, TableResult,
}; };

View File

@ -4,10 +4,10 @@ use nu_protocol::{Config, Record, Span, TableIndent, Value};
use tabled::{ use tabled::{
grid::{ grid::{
ansi::ANSIStr, ansi::ANSIStr,
config::{AlignmentHorizontal, Borders, CompactMultilineConfig}, config::{Borders, CompactMultilineConfig},
dimension::{DimensionPriority, PoolTableDimension}, dimension::{DimensionPriority, PoolTableDimension},
}, },
settings::{Color, Padding, TableOption, Theme}, settings::{Alignment, Color, Padding, TableOption},
tables::{PoolTable, TableValue}, tables::{PoolTable, TableValue},
}; };
@ -53,8 +53,8 @@ fn build_table(
theme.set_horizontal_lines(Default::default()); theme.set_horizontal_lines(Default::default());
table.with(Padding::new(indent.left, indent.right, 0, 0)); table.with(Padding::new(indent.left, indent.right, 0, 0));
table.with(SetRawStyle(theme)); table.with(*theme.get_borders());
table.with(SetAlignment(AlignmentHorizontal::Left)); table.with(Alignment::left());
table.with(PoolTableDimension::new( table.with(PoolTableDimension::new(
DimensionPriority::Last, DimensionPriority::Last,
DimensionPriority::Last, DimensionPriority::Last,
@ -72,14 +72,6 @@ fn build_table(
table.to_string() table.to_string()
} }
fn build_table_with_border_color(mut table: PoolTable, color: Color) -> String {
// NOTE: We have this function presizely because of color_into_ansistr internals
// color must be alive why we build table
table.with(SetBorderColor(color_into_ansistr(&color)));
table.to_string()
}
fn convert_nu_value_to_table_value(value: Value, config: &Config) -> TableValue { fn convert_nu_value_to_table_value(value: Value, config: &Config) -> TableValue {
match value { match value {
Value::Record { val, .. } => build_vertical_map(val.into_owned(), config), Value::Record { val, .. } => build_vertical_map(val.into_owned(), config),
@ -91,76 +83,74 @@ fn convert_nu_value_to_table_value(value: Value, config: &Config) -> TableValue
build_vertical_array(vals, config) build_vertical_array(vals, config)
} }
} }
value => { value => build_string_value(value, config),
let mut text = value.to_abbreviated_string(config);
if string_width(&text) > 50 {
text = string_wrap(&text, 30, false);
}
TableValue::Cell(text)
}
} }
} }
fn build_vertical_map(record: Record, config: &Config) -> TableValue { fn build_string_value(value: Value, config: &Config) -> TableValue {
let mut rows = Vec::with_capacity(record.len()); const MAX_STRING_WIDTH: usize = 50;
for (key, value) in record { const WRAP_STRING_WIDTH: usize = 30;
let val = convert_nu_value_to_table_value(value, config);
let row = TableValue::Row(vec![TableValue::Cell(key), val]); let mut text = value.to_abbreviated_string(config);
rows.push(row); if string_width(&text) > MAX_STRING_WIDTH {
text = string_wrap(&text, WRAP_STRING_WIDTH, false);
} }
let max_key_width = rows TableValue::Cell(text)
}
fn build_vertical_map(record: Record, config: &Config) -> TableValue {
let max_key_width = record
.iter() .iter()
.map(|row| match row { .map(|(k, _)| string_width(k))
TableValue::Row(list) => match &list[0] {
TableValue::Cell(key) => string_width(key),
_ => unreachable!(),
},
_ => unreachable!(),
})
.max() .max()
.unwrap_or(0); .unwrap_or(0);
rows.iter_mut().for_each(|row| { let mut rows = Vec::with_capacity(record.len());
match row { for (mut key, value) in record {
TableValue::Row(list) => match &mut list[0] { string_append_to_width(&mut key, max_key_width);
TableValue::Cell(key) => {
let width = string_width(key); let value = convert_nu_value_to_table_value(value, config);
let rest = max_key_width - width;
key.extend(std::iter::repeat(' ').take(rest)); let row = TableValue::Row(vec![TableValue::Cell(key), value]);
} rows.push(row);
_ => unreachable!(), }
},
_ => unreachable!(),
};
});
TableValue::Column(rows) TableValue::Column(rows)
} }
fn string_append_to_width(key: &mut String, max: usize) {
let width = string_width(key);
let rest = max - width;
key.extend(std::iter::repeat(' ').take(rest));
}
fn build_vertical_array(vals: Vec<Value>, config: &Config) -> TableValue { fn build_vertical_array(vals: Vec<Value>, config: &Config) -> TableValue {
let map = vals let map = vals
.into_iter() .into_iter()
.map(|val| convert_nu_value_to_table_value(val, config)) .map(|val| convert_nu_value_to_table_value(val, config))
.collect::<Vec<_>>(); .collect();
TableValue::Column(map) TableValue::Column(map)
} }
fn is_valid_record(vals: &[Value]) -> bool { fn is_valid_record(vals: &[Value]) -> bool {
let mut first_record: Option<&Record> = None; if vals.is_empty() {
for val in vals { return true;
}
let first_value = match &vals[0] {
Value::Record { val, .. } => val,
_ => return false,
};
for val in &vals[1..] {
match val { match val {
Value::Record { val, .. } => { Value::Record { val, .. } => {
if let Some(known) = first_record { let equal = val.columns().eq(first_value.columns());
let equal = known.columns().eq(val.columns()); if !equal {
if !equal { return false;
return false; }
}
} else {
first_record = Some(val)
};
} }
_ => return false, _ => return false,
} }
@ -177,30 +167,41 @@ fn count_columns_in_record(vals: &[Value]) -> usize {
} }
fn build_map_from_record(vals: Vec<Value>, config: &Config) -> TableValue { fn build_map_from_record(vals: Vec<Value>, config: &Config) -> TableValue {
let mut list = vec![]; // assumes that we have a valid record structure (checked by is_valid_record)
let head = get_columns_in_record(&vals); let head = get_columns_in_record(&vals);
let count_columns = head.len(); let mut list = Vec::with_capacity(head.len());
for col in head { for col in head {
list.push(vec![TableValue::Cell(col)]); list.push(TableValue::Column(vec![TableValue::Cell(col)]));
} }
for val in vals { for val in vals {
match val { let val = get_as_record(val);
Value::Record { val, .. } => { for (i, (_, val)) in val.into_owned().into_iter().enumerate() {
for (i, (_key, val)) in val.into_owned().into_iter().take(count_columns).enumerate() let value = convert_nu_value_to_table_value(val, config);
{ let list = get_table_value_column_mut(&mut list[i]);
let cell = convert_nu_value_to_table_value(val, config);
list[i].push(cell); list.push(value);
}
}
_ => unreachable!(),
} }
} }
let columns = list.into_iter().map(TableValue::Column).collect::<Vec<_>>(); TableValue::Row(list)
}
TableValue::Row(columns) fn get_table_value_column_mut(val: &mut TableValue) -> &mut Vec<TableValue> {
match val {
TableValue::Column(row) => row,
_ => {
unreachable!();
}
}
}
fn get_as_record(val: Value) -> nu_utils::SharedCow<Record> {
match val {
Value::Record { val, .. } => val,
_ => unreachable!(),
}
} }
fn get_columns_in_record(vals: &[Value]) -> Vec<String> { fn get_columns_in_record(vals: &[Value]) -> Vec<String> {
@ -210,32 +211,6 @@ fn get_columns_in_record(vals: &[Value]) -> Vec<String> {
} }
} }
struct SetRawStyle(Theme);
impl<R, D> TableOption<R, CompactMultilineConfig, D> for SetRawStyle {
fn change(self, _: &mut R, cfg: &mut CompactMultilineConfig, _: &mut D) {
let borders = *self.0.get_borders();
cfg.set_borders(borders);
}
}
struct SetBorderColor(ANSIStr<'static>);
impl<R, D> TableOption<R, CompactMultilineConfig, D> for SetBorderColor {
fn change(self, _: &mut R, cfg: &mut CompactMultilineConfig, _: &mut D) {
let borders = Borders::filled(self.0);
cfg.set_borders_color(borders);
}
}
struct SetAlignment(AlignmentHorizontal);
impl<R, D> TableOption<R, CompactMultilineConfig, D> for SetAlignment {
fn change(self, _: &mut R, cfg: &mut CompactMultilineConfig, _: &mut D) {
cfg.set_alignment_horizontal(self.0);
}
}
fn truncate_table_value( fn truncate_table_value(
value: &mut TableValue, value: &mut TableValue,
has_vertical: bool, has_vertical: bool,
@ -341,6 +316,15 @@ fn truncate_table_value(
} }
} }
fn build_table_with_border_color(mut table: PoolTable, color: Color) -> String {
// NOTE: We have this function presizely because of color_into_ansistr internals
// color must be alive why we build table
let color = color_into_ansistr(&color);
table.with(SetBorderColor(color));
table.to_string()
}
fn color_into_ansistr(color: &Color) -> ANSIStr<'static> { fn color_into_ansistr(color: &Color) -> ANSIStr<'static> {
// # SAFETY // # SAFETY
// //
@ -355,3 +339,12 @@ fn color_into_ansistr(color: &Color) -> ANSIStr<'static> {
ANSIStr::new(prefix, suffix) ANSIStr::new(prefix, suffix)
} }
struct SetBorderColor(ANSIStr<'static>);
impl<R, D> TableOption<R, CompactMultilineConfig, D> for SetBorderColor {
fn change(self, _: &mut R, cfg: &mut CompactMultilineConfig, _: &mut D) {
let borders = Borders::filled(self.0);
cfg.set_borders_color(borders);
}
}