1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
use super::{is_too_high, is_too_wide, stringify_text, Coordinates, Text};
use crate::panes::{
terminal_character::{AnsiCode, RESET_STYLES},
CharacterStyles,
};
use std::collections::BTreeMap;
use zellij_utils::{data::Style, shared::ansi_len};
pub fn table(
columns: usize,
_rows: usize,
contents: Vec<Text>,
style: &Style,
coordinates: Option<Coordinates>,
) -> Vec<u8> {
let mut stringified = String::new();
// we first arrange the data by columns so that we can pad them by the widest one
let stringified_columns = stringify_table_columns(contents, columns);
let stringified_rows = stringify_table_rows(stringified_columns, &coordinates);
for (row_index, (_, row)) in stringified_rows.into_iter().enumerate() {
let is_title_row = row_index == 0;
if is_too_high(row_index + 1, &coordinates) {
break;
}
for cell in row {
let declaration = if is_title_row {
style.colors.table_title
} else {
if cell.selected {
style.colors.table_cell_selected
} else {
style.colors.table_cell_unselected
}
};
let text_style = if cell.opaque || cell.selected {
CharacterStyles::from(declaration).background(Some(declaration.background.into()))
} else {
CharacterStyles::from(declaration)
};
// here we intentionally don't pass our coordinates even if we have them, because
// these cells have already been padded and truncated
let (text, _text_width) = stringify_text(
&cell,
None,
&None,
&declaration,
text_style.bold(Some(AnsiCode::On)),
);
stringified.push_str(&format!("{}{} {}", text_style, text, RESET_STYLES));
}
let next_row_instruction = coordinates
.as_ref()
.map(|c| c.stringify_with_y_offset(row_index + 1))
.unwrap_or_else(|| format!("\n\r"));
stringified.push_str(&next_row_instruction);
}
if let Some(coordinates) = coordinates {
format!("{}{}", coordinates, stringified)
.as_bytes()
.to_vec()
} else {
stringified.as_bytes().to_vec()
}
}
fn stringify_table_columns(contents: Vec<Text>, columns: usize) -> BTreeMap<usize, Vec<Text>> {
let mut stringified_columns: BTreeMap<usize, Vec<Text>> = BTreeMap::new();
for (i, cell) in contents.into_iter().enumerate() {
let column_index = i % columns;
stringified_columns
.entry(column_index)
.or_insert_with(Vec::new)
.push(cell);
}
stringified_columns
}
fn max_table_column_width(column: &Vec<Text>) -> usize {
let mut max_column_width = 0;
for cell in column {
let cell_width = ansi_len(&cell.text);
if cell_width > max_column_width {
max_column_width = cell_width;
}
}
max_column_width
}
fn stringify_table_rows(
stringified_columns: BTreeMap<usize, Vec<Text>>,
coordinates: &Option<Coordinates>,
) -> BTreeMap<usize, Vec<Text>> {
let mut stringified_rows: BTreeMap<usize, Vec<Text>> = BTreeMap::new();
let mut row_width = 0;
for (_, column) in stringified_columns.into_iter() {
let max_column_width = max_table_column_width(&column);
if is_too_wide(max_column_width + 1, row_width, &coordinates) {
break;
}
row_width += max_column_width + 1;
for (row_index, mut cell) in column.into_iter().enumerate() {
cell.pad_text(max_column_width);
stringified_rows
.entry(row_index)
.or_insert_with(Vec::new)
.push(cell);
}
}
stringified_rows
}
|