Closed stefan-mysten closed 1 year ago
Hi @stefan-mysten
You have touched a hard topic :)
In summary:
json
, you can't do changes to the content. (though maybe we shall).My main struggle is that I have a table where my first column is the header for each row, and 2nd column has the values for each row. One row has 360 characters, and I'd like to wrap it (maybe 80 chars per line?), because the table gets really weird.
Could you provide your table?
Cause sounds like it's has relatively simple structure and you might better just really convert it into tables::Table
.
I think we could provide such a function for a not recursive json
(unfortunately yet it's not implemented, but could be a good first issue).
- is there a way to transform a
JsonTable
type into atabled::Table
type?
No.
Though it would be possible to convert it into PoolTable
(it is not yet in implemented; but it also does not support Wrap
).
- how can one taylor the style of a
JsonTable
using the standard methods fromTable
such as Width, Row, Wrap, etc. Doing something like: table.with(Width::wrap(120)); where table is aJsonTable
yields this errorthe trait `TableOption<EmptyRecords, CompleteDimension<'static>, ColoredConfig>` is not implemented for `tabled::settings::width::Wrap`
You can't. The main reason why it was not implemented is because it's not clear how to do that. I mean some people would like to do the width control differently so it was not implemented.
I am not sure if you're aware of https://github.com/nushell/nushell/. But bellow I've provide an example to do something similar.
The example is a bit long and quite complex but.... it does it's job I do think.
You can just copy&paste and try with your json
.
Let me know what do you think.
use serde_json::Value;
use tabled::{
grid::dimension::{DimensionPriority, PoolTableDimension},
grid::util::string::{string_width, string_width_multiline},
settings::style::Style,
settings::width::Wrap,
tables::{PoolTable, TableValue},
Table,
};
fn main() {
let json = serde_json::json!({
"key1": "value1",
"key2": {
"key1": 123,
"key2": [1, 2, 3, 4, 5],
},
"key3": [
{"key": 123.3},
2,
"asd"
],
});
let table = build_table(json, 20);
println!("{table}");
}
fn build_table(json: Value, width: usize) -> PoolTable {
let mut value = json_to_table(json);
truncate_table_value(&mut value, true, width);
let mut table = PoolTable::from(value);
table.with(PoolTableDimension::new(
DimensionPriority::Last,
DimensionPriority::Last,
));
table.with(Style::modern());
table
}
fn json_to_table(json: Value) -> TableValue {
match json {
Value::Array(list) => {
let values = list.into_iter().map(|value| json_to_table(value)).collect();
TableValue::Row(values)
}
Value::Object(map) => {
let values = map
.into_iter()
.map(|(key, value)| {
let key = TableValue::Cell(key);
let value = json_to_table(value);
TableValue::Row(vec![key, value])
})
.collect();
TableValue::Column(values)
}
value => TableValue::Cell(value.to_string()),
}
}
fn truncate_table_value(
value: &mut TableValue,
has_vertical: bool,
available: usize,
) -> Option<usize> {
const MIN_CONTENT_WIDTH: usize = 10;
const TRUNCATE_CELL_WIDTH: usize = 3;
const PAD: usize = 2;
match value {
TableValue::Row(row) => {
if row.is_empty() {
return Some(PAD);
}
if row.len() == 1 {
return truncate_table_value(&mut row[0], has_vertical, available);
}
let count_cells = row.len();
let mut row_width = 0;
let mut i = 0;
let mut last_used_width = 0;
for cell in row.iter_mut() {
let vertical = (has_vertical && i + 1 != count_cells) as usize;
if available < row_width + vertical {
break;
}
let available = available - row_width - vertical;
let width = match truncate_table_value(cell, has_vertical, available) {
Some(width) => width,
None => break,
};
row_width += width + vertical;
last_used_width = row_width;
i += 1;
}
if i == row.len() {
return Some(row_width);
}
if i == 0 {
if available >= PAD + TRUNCATE_CELL_WIDTH {
*value = TableValue::Cell(String::from("..."));
return Some(PAD + TRUNCATE_CELL_WIDTH);
} else {
return None;
}
}
let available = available - row_width;
let has_space_empty_cell = available >= PAD + TRUNCATE_CELL_WIDTH;
if has_space_empty_cell {
row[i] = TableValue::Cell(String::from("..."));
row.truncate(i + 1);
row_width += PAD + TRUNCATE_CELL_WIDTH;
} else if i == 0 {
return None;
} else {
row[i - 1] = TableValue::Cell(String::from("..."));
row.truncate(i);
row_width -= last_used_width;
row_width += PAD + TRUNCATE_CELL_WIDTH;
}
Some(row_width)
}
TableValue::Column(column) => {
let mut max_width = PAD;
for cell in column.iter_mut() {
let width = truncate_table_value(cell, has_vertical, available)?;
max_width = std::cmp::max(max_width, width);
}
Some(max_width)
}
TableValue::Cell(text) => {
if available <= PAD {
return None;
}
let available = available - PAD;
let width = string_width(text);
if width > available {
if available > MIN_CONTENT_WIDTH {
*text = string_wrap(text, available);
Some(available + PAD)
} else if available >= 3 {
*text = String::from("...");
Some(3 + PAD)
} else {
// situation where we have too little space
None
}
} else {
Some(width + PAD)
}
}
}
}
fn increase_width(text: &str, width: usize) -> String {
text.lines()
.map(|line| {
let line_width = string_width(line);
let rest_width = width - line_width;
let mut line = line.to_string();
line.extend((0..rest_width).map(|_| ' '));
line
})
.collect::<Vec<_>>()
.join("\n")
}
fn string_wrap(text: &str, width: usize) -> String {
Wrap::wrap_text(text, width, false)
}
┌──────┬────────────┐
│ key1 │ "value1" │
├──────┼──────┬─────┤
│ key2 │ key1 │ 123 │
│ ├──────┼─────┤
│ │ key2 │ ... │
├──────┼──────┴─────┤
│ key3 │ ... │
└──────┴────────────┘
┌──────┬────────────────────────┐
│ key1 │ "value1" │
├──────┼──────┬─────────────────┤
│ key2 │ key1 │ 123 │
│ ├──────┼───┬───┬───┬─────┤
│ │ key2 │ 1 │ 2 │ 3 │ ... │
├──────┼─────┬┴───┴──┬┴──┬┴─────┤
│ key3 │ key │ 123.3 │ 2 │ ... │
└──────┴─────┴───────┴───┴──────┘
Thanks @zhiburt for the detailed explanation. I know nushell, used to work on it in the past. I know they have a nice nu-table crate, but it feels a bit too complex now and thought I could go with something simpler.
There are structs that have nested structs, so I understand the issue with the recursive json.
Here's my table
Here's an equivalent of that in JSON format.
{
"suiAddress": "0x90f3e6d73b5730f16974f4df1d3441394ebae62186baf83608599f226455afa7",
"rawTxData": "AAACACDIdthIYsGLxKX2T+y/C2wRDyHou3ADyZRHB3GrjKrcyQEAYTnJWTQ4/2sVfz1ZiEQvuZRaXYLm1G2hTxoGQvWpmEUMAAAAAAAAACB1WzYQcNy1l8/25289FS3t42iXEz+84jGDHHdjNxeLbAEBAQEBAAEAAJDz5tc7VzDxaXT03x00QTlOuuYhhrr4NghZnyJkVa+nAWE5yVk0OP9rFX89WYhEL7mUWl2C5tRtoU8aBkL1qZhFDAAAAAAAAAAgdVs2EHDctZfP9udvPRUt7eNolxM/vOIxgxx3YzcXi2yQ8+bXO1cw8Wl09N8dNEE5TrrmIYa6+DYIWZ8iZFWvp+gDAAAAAAAAAMqaOwAAAAAA",
"intent": {
"scope": 0,
"version": 0,
"app_id": 0
},
"rawIntentMsg": "AAAAAAACACDIdthIYsGLxKX2T+y/C2wRDyHou3ADyZRHB3GrjKrcyQEAYTnJWTQ4/2sVfz1ZiEQvuZRaXYLm1G2hTxoGQvWpmEUMAAAAAAAAACB1WzYQcNy1l8/25289FS3t42iXEz+84jGDHHdjNxeLbAEBAQEBAAEAAJDz5tc7VzDxaXT03x00QTlOuuYhhrr4NghZnyJkVa+nAWE5yVk0OP9rFX89WYhEL7mUWl2C5tRtoU8aBkL1qZhFDAAAAAAAAAAgdVs2EHDctZfP9udvPRUt7eNolxM/vOIxgxx3YzcXi2yQ8+bXO1cw8Wl09N8dNEE5TrrmIYa6+DYIWZ8iZFWvp+gDAAAAAAAAAMqaOwAAAAAA",
"digest": "TENCFuVcNXDih1VYx5WsBFiRvCRZpfUvzV9tdoexJwc=",
"suiSignature": "ADIEI66nM+vOJ17ucV+K57PoJSw0D2X2ykptSSnxmjdvshPzQce9Re/3p+DTKeeyGgdkqFL2DTQ9Qpe8Hk3VVQyVTIgDvKm1lnHdsZEu82DvfnF2grmahEY40NJEWv9tpQ=="
}
I've done some steps forward;
You can try either approach you like; must work.
It's not yet published so you need to include tabled from github
.
tabled = { git = "https://github.com/zhiburt/tabled/", rev = "e449317a1c02eb6b29e409ad6617e5d9eb7b3bd4" }
use tabled::settings::{Modify, Style, Width};
fn main() {
let json = serde_json::json!({
"key1": "Some loooooooooooong string",
"key2": {
"key1": 123,
"key2": [1, 2, 3, 4, 5],
},
"key3": [
{"key": 123.3},
2,
"asd"
],
});
let mut table = json_to_table::parse(&json);
table.with(Modify::new((0, 1)).with(Width::wrap(6)));
table.with(Style::ascii_rounded());
println!("{table}");
}
.----------------------------------------.
| key1 | Some l |
| | oooooo |
| | oooooo |
| | ng str |
| | ing |
| key2 | {"key1":123,"key2":[1,2,3,4,5]} |
| key3 | [{"key":123.3},2,"asd"] |
'----------------------------------------'
use json_to_table::Orientation;
use tabled::settings::{Modify, Style, Width};
fn main() {
let json = serde_json::json!({
"key1": "Some loooooooooooong string",
"key2": {
"key1": 123,
"key2": [1, 2, 3, 4, 5],
},
"key3": [
{"key": 123.3},
2,
"asd"
],
});
let mut table = json_to_table::json_to_table(&json)
.with(Style::dots())
.array_orientation(Orientation::Row)
.into_table();
table.with(Style::ascii_rounded());
table.with(Modify::new((0, 1)).with(Width::wrap(6)));
println!("{table}");
}
.---------------------------------------------------.
| key1 | Some l |
| | oooooo |
| | oooooo |
| | ng str |
| | ing |
| key2 | .......................................... |
| | : key1 : 123 : |
| | :......:.................................: |
| | : key2 : ............................... : |
| | : : : 1 : 2 : 3 : 4 : 5 : : |
| | : : :.....:.....:.....:.....:.....: : |
| | :......:.................................: |
| key3 | ................................... |
| | : ................. : 2 : asd : |
| | : : key : 123.3 : : : : |
| | : :.....:.........: : : : |
| | :...................:.....:.......: |
'---------------------------------------------------'
You're amazing @zhiburt, thanks a lot! I will give it a spin asap.
I've been trying to play with this but somehow I don't manage to make it work. Maybe I am doing something wrong, but basically I copy pasted the example and I get an error. @zhiburt Any hints what am I doing wrong?
Toml file
[dependencies]
serde_json = "*"
json_to_table = { git = "https://github.com/zhiburt/tabled/", rev = "e449317a1c02eb6b29e409ad6617e5d9eb7b3bd4"}
tabled = { git = "https://github.com/zhiburt/tabled/", rev = "e449317a1c02eb6b29e409ad6617e5d9eb7b3bd4", features = ["color"] }
Main file
use tabled::settings::{Modify, Style, Width};
fn main() {
let json = serde_json::json!({
"key1": "Some loooooooooooong string",
"key2": {
"key1": 123,
"key2": [1, 2, 3, 4, 5],
},
"key3": [
{"key": 123.3},
2,
"asd"
],
});
let mut table = json_to_table::parse(&json);
table.with(Modify::new((0, 1)).with(Width::wrap(6)));
table.with(Style::ascii_rounded());
println!("{table}");
}
Error:
Compiling tabled-test v0.1.0
error[E0277]: the trait bound `ModifyList<({integer}, {integer}), Wrap>: tabled::settings::table_option::TableOption<VecRecords<CellInfo<std::string::String>>, tabled::grid::dimension::complete_dimension_vec_records::CompleteDimensionVecRecords<'static>, tabled::grid::colored_config::ColoredConfig>` is not satisfied
--> src/main.rs:18:16
|
18 | table.with(Modify::new((0, 1)).with(Width::wrap(6)));
| ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `tabled::settings::table_option::TableOption<VecRecords<CellInfo<std::string::String>>, tabled::grid::dimension::complete_dimension_vec_records::CompleteDimensionVecRecords<'static>, tabled::grid::colored_config::ColoredConfig>` is not implemented for `ModifyList<({integer}, {integer}), Wrap>`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `tabled::settings::table_option::TableOption<R, D, C>`:
<&SpannedConfig as tabled::settings::table_option::TableOption<R, D, tabled::grid::colored_config::ColoredConfig>>
<&[T] as tabled::settings::table_option::TableOption<R, D, C>>
<&tabled::settings::style::raw_style::RawStyle as tabled::settings::table_option::TableOption<R, D, tabled::grid::colored_config::ColoredConfig>>
<CompactConfig as tabled::settings::table_option::TableOption<R, D, CompactConfig>>
<CompactConfig as tabled::settings::table_option::TableOption<R, D, tabled::grid::colored_config::ColoredConfig>>
<SpannedConfig as tabled::settings::table_option::TableOption<R, D, tabled::grid::colored_config::ColoredConfig>>
<Vec<T> as tabled::settings::table_option::TableOption<R, D, C>>
<tabled::grid::colored_config::ColoredConfig as tabled::settings::table_option::TableOption<R, D, tabled::grid::colored_config::ColoredConfig>>
and 61 others
note: required by a bound in `tabled::tables::table::Table::with`
--> /.cargo/registry/src/index.crates.io-6f17d22bba15001f/tabled-0.12.2/src/tables/table.rs:180:12
|
180 | O: TableOption<
| ____________^
181 | | VecRecords<CellInfo<String>>,
182 | | CompleteDimensionVecRecords<'static>,
183 | | ColoredConfig,
184 | | >,
| |_________^ required by this bound in `Table::with`
error[E0277]: the trait bound `Style<On, On, On, On, (), On>: tabled::settings::table_option::TableOption<VecRecords<CellInfo<std::string::String>>, tabled::grid::dimension::complete_dimension_vec_records::CompleteDimensionVecRecords<'static>, tabled::grid::colored_config::ColoredConfig>` is not satisfied
--> src/main.rs:19:16
|
19 | table.with(Style::ascii_rounded());
| ---- ^^^^^^^^^^^^^^^^^^^^^^ the trait `tabled::settings::table_option::TableOption<VecRecords<CellInfo<std::string::String>>, tabled::grid::dimension::complete_dimension_vec_records::CompleteDimensionVecRecords<'static>, tabled::grid::colored_config::ColoredConfig>` is not implemented for `Style<On, On, On, On, (), On>`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `tabled::settings::table_option::TableOption<R, D, C>`:
<&SpannedConfig as tabled::settings::table_option::TableOption<R, D, tabled::grid::colored_config::ColoredConfig>>
<&[T] as tabled::settings::table_option::TableOption<R, D, C>>
<&tabled::settings::style::raw_style::RawStyle as tabled::settings::table_option::TableOption<R, D, tabled::grid::colored_config::ColoredConfig>>
<CompactConfig as tabled::settings::table_option::TableOption<R, D, CompactConfig>>
<CompactConfig as tabled::settings::table_option::TableOption<R, D, tabled::grid::colored_config::ColoredConfig>>
<SpannedConfig as tabled::settings::table_option::TableOption<R, D, tabled::grid::colored_config::ColoredConfig>>
<Vec<T> as tabled::settings::table_option::TableOption<R, D, C>>
<tabled::grid::colored_config::ColoredConfig as tabled::settings::table_option::TableOption<R, D, tabled::grid::colored_config::ColoredConfig>>
and 61 others
note: required by a bound in `tabled::tables::table::Table::with`
--> /.cargo/registry/src/index.crates.io-6f17d22bba15001f/tabled-0.12.2/src/tables/table.rs:180:12
|
180 | O: TableOption<
| ____________^
181 | | VecRecords<CellInfo<String>>,
182 | | CompleteDimensionVecRecords<'static>,
183 | | ColoredConfig,
184 | | >,
| |_________^ required by this bound in `Table::with`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `tabled-test` (bin "tabled-test") due to 2 previous errors
I am not an expert but seems like cargo
treats git dependencies as a different kind compared from the registry (even if they would be on the same commit?).
You just need to include general tabled
.
[dependencies]
serde_json = "*"
json_to_table = { git = "https://github.com/zhiburt/tabled/", rev = "e449317a1c02eb6b29e409ad6617e5d9eb7b3bd4"}
tabled = "0.12"
Works for me
That worked, thanks a lot!
Hi @gngpp
Hmmm, to be honest I don't remember why it was not published. I'll to do it soon.
Take care. Thanks for notion.
Hi @gngpp
Yeeee sorry got distracted quite a bit....
I believe it was released yesterday (version 0.6.0
).
Notice that you shall use tabled 0.12
but not higher.
[dependencies]
json_to_table = "0.6.0"
serde_json = "1"
tabled = "0.12"
PS: I guess we probably shall bump it to the latest 0.14
PS2: I guess it would be WAY better to resolve it completely by relaying on a minumum minor version but... I am not sure whether it's safe.
Hi @zhiburt
Love the library, this is really a fantastic work that you and others have done.
I have a few questions on how to taylor the style of JSON tables using the json-table crate.
JsonTable
type into atabled::Table
type?JsonTable
using the standard methods fromTable
such as Width, Row, Wrap, etc. Doing something like: table.with(Width::wrap(120)); where table is aJsonTable
yields this errorMy main struggle is that I have a table where my first column is the header for each row, and 2nd column has the values for each row. One row has 360 characters, and I'd like to wrap it (maybe 80 chars per line?), because the table gets really weird.
Thanks in advance!