Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow to render "loose" tables as Nushell tables #72

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/config/default.nuon
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
margin: 10, # the number of lines to keep between the cursor and the top / bottom
number: false, # show line numbers
relativenumber: false, # show line numbers, relative to the current one (overrides number)
strict_tables: false, # only render tables when all rows have the same keys with the same types

# "reset" is used instead of "black" in a dark terminal because, when the terminal is actually
# black, "black" is not really black which is ugly, whereas "reset" is really black.
Expand Down
7 changes: 7 additions & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ pub struct Config {
pub number: bool,
pub relativenumber: bool,
pub show_hints: bool,
pub strict_tables: bool,
}

impl Default for Config {
Expand All @@ -164,6 +165,7 @@ impl Default for Config {
number: false,
relativenumber: false,
show_hints: true,
strict_tables: false,
colors: ColorConfig {
normal: TableRowColorConfig {
name: BgFgColorConfig {
Expand Down Expand Up @@ -304,6 +306,11 @@ impl Config {
config.show_hints = val
}
}
"strict_tables" => {
if let Some(val) = try_bool(value, &["strict_tables"])? {
config.strict_tables = val
}
}
"colors" => {
let cell = follow_cell_path(value, &["colors"]).unwrap();
let columns = match &cell {
Expand Down
42 changes: 36 additions & 6 deletions src/nu/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ pub(crate) fn mutate_value_cell(
Some(res)
}

pub(crate) fn is_table(value: &Value) -> Table {
pub(crate) fn is_table(value: &Value, loose: bool) -> Table {
match value {
Value::List { vals, .. } => {
if vals.is_empty() {
Expand Down Expand Up @@ -164,6 +164,9 @@ pub(crate) fn is_table(value: &Value) -> Table {
Some(v) => match ty {
Type::Nothing => ty = v,
_ => {
if loose {
continue;
}
if !matches!(v, Type::Nothing) {
if v.is_numeric() && ty.is_numeric() {
} else if (!v.is_numeric() && ty.is_numeric())
Expand Down Expand Up @@ -227,7 +230,7 @@ pub(crate) fn is_table(value: &Value) -> Table {
/// ```
// WARNING: some _unwraps_ haven't been proven to be safe in this function
pub(crate) fn transpose(value: &Value) -> Value {
if matches!(is_table(value), Table::IsValid) {
if matches!(is_table(value, false), Table::IsValid) {
let value_rows = match value {
Value::List { vals, .. } => vals,
_ => return value.clone(),
Expand Down Expand Up @@ -540,11 +543,18 @@ mod tests {
table_with_number_colum,
] {
assert_eq!(
is_table(&table),
is_table(&table, false),
Table::IsValid,
"{} should be a table",
default_value_repr(&table)
);

assert_eq!(
is_table(&table, true),
Table::IsValid,
"{} should be a loose table",
default_value_repr(&table)
);
}

let not_a_table_missing_field = (
Expand Down Expand Up @@ -607,15 +617,35 @@ mod tests {
not_a_table_row_invalid_key,
] {
assert_eq!(
is_table(&not_a_table),
is_table(&not_a_table, false),
expected,
"{} should not be a table",
default_value_repr(&not_a_table)
);
}

assert_eq!(is_table(&Value::test_int(0)), Table::NotAList);
assert_eq!(is_table(&Value::test_list(vec![])), Table::Empty);
let loosy_table_incompatible_types = Value::test_list(vec![
Value::test_record(record! {
"a" => Value::test_string("a"),
"b" => Value::test_int(1),
}),
Value::test_record(record! {
"a" => Value::test_string("a"),
"b" => Value::test_list(vec![Value::test_int(1)]),
}),
]);

for loosy_table in [loosy_table_incompatible_types] {
assert_eq!(
is_table(&loosy_table, true),
Table::IsValid,
"{} should be a loose table",
default_value_repr(&loosy_table)
);
}

assert_eq!(is_table(&Value::test_int(0), false), Table::NotAList);
assert_eq!(is_table(&Value::test_list(vec![]), false), Table::Empty);
}

#[test]
Expand Down
40 changes: 33 additions & 7 deletions src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,16 @@ fn repr_table(table: &[Record]) -> (Vec<String>, Vec<String>, Vec<Vec<String>>)
let val = row.get(col).unwrap();

let cell_type = val.get_type();
if !matches!(cell_type, Type::Nothing) {
if shapes[j].is_numeric() && cell_type.is_numeric() && (shapes[j] != cell_type) {
shapes[j] = Type::Number;
} else {
shapes[j] = cell_type;
}

if shapes[j].is_numeric() && cell_type.is_numeric() && (shapes[j] != cell_type) {
shapes[j] = Type::Number;
} else if shapes[j] == Type::Nothing && cell_type != Type::Nothing {
shapes[j] = cell_type;
} else if shapes[j] != Type::Nothing && cell_type == Type::Nothing {
} else if shapes[j] != cell_type {
shapes[j] = Type::Any;
} else {
shapes[j] = cell_type;
}

rows[i].push(repr_value(val).data);
Expand Down Expand Up @@ -238,7 +242,7 @@ fn render_data(frame: &mut Frame, app: &mut App) {

let value = app.value_under_cursor(Some(CellPath { members: data_path }));

let table_type = is_table(&value);
let table_type = is_table(&value, !config.strict_tables);
let is_a_table = matches!(table_type, crate::nu::value::Table::IsValid);

let mut data_frame_height = if config.show_cell_path {
Expand Down Expand Up @@ -938,4 +942,26 @@ mod tests {

assert_eq!(repr_table(&table), expected);
}

#[test]
fn repr_loose_table_with_mixed_types() {
let table = vec![
record! {
"a" => Value::test_string("x"),
"b" => Value::test_int(1),
},
record! {
"a" => Value::test_string("y"),
"b" => Value::test_string("z"),
},
];

let expected = (
vec!["a".into(), "b".into()],
vec!["string".into(), "any".into()],
vec![vec!["x".into(), "1".into()], vec!["y".into(), "z".into()]],
);

assert_eq!(repr_table(&table), expected);
}
}
Loading