Skip to content

Commit 0148a4c

Browse files
clamp text that gets rendered in data table (#268)
1 parent 6b08683 commit 0148a4c

File tree

1 file changed

+57
-5
lines changed

1 file changed

+57
-5
lines changed

src/components/data.rs

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::{
2323
};
2424

2525
const MAX_COLUMN_WIDTH: u16 = 36;
26+
const TITLE_CELL_PREVIEW_MAX_CHARS: usize = 96;
2627

2728
#[allow(clippy::large_enum_variant)]
2829
#[derive(Default)]
@@ -202,7 +203,37 @@ impl Data<'_> {
202203
}
203204

204205
fn cell_display_width(value: &str) -> usize {
205-
value.chars().count()
206+
value.chars().take(MAX_COLUMN_WIDTH as usize).count()
207+
}
208+
209+
fn clamp_render_text(value: &str, max_chars: usize) -> String {
210+
if max_chars == 0 || value.is_empty() {
211+
return String::new();
212+
}
213+
let mut chars_seen = 0_usize;
214+
for (idx, _) in value.char_indices() {
215+
if chars_seen == max_chars {
216+
return value[..idx].to_owned();
217+
}
218+
chars_seen = chars_seen.saturating_add(1);
219+
}
220+
value.to_owned()
221+
}
222+
223+
fn preview_text(value: &str, max_chars: usize) -> String {
224+
if max_chars == 0 || value.is_empty() {
225+
return String::new();
226+
}
227+
let mut chars_seen = 0_usize;
228+
for (idx, _) in value.char_indices() {
229+
if chars_seen == max_chars {
230+
let mut preview = value[..idx].to_owned();
231+
preview.push_str("...");
232+
return preview;
233+
}
234+
chars_seen = chars_seen.saturating_add(1);
235+
}
236+
value.to_owned()
206237
}
207238
}
208239

@@ -235,13 +266,34 @@ impl<'a> SettableDataTable<'a> for Data<'a> {
235266
let row_bottom_margin: u16 = if row_spacing_enabled { 1 } else { 0 };
236267
let header_height: u16 = 2;
237268
let data_row_offset = header_height.saturating_add(row_bottom_margin);
269+
let column_widths = self.column_widths(&rows);
238270
let header_row = Row::new(
239-
rows.headers.iter().map(|h| Cell::from(format!("{}\n{}", h.name, h.type_name))).collect::<Vec<Cell>>(),
271+
rows
272+
.headers
273+
.iter()
274+
.enumerate()
275+
.map(|(index, h)| {
276+
let col_width = column_widths.get(index).copied().unwrap_or(MAX_COLUMN_WIDTH) as usize;
277+
let header_name = Self::clamp_render_text(&h.name, col_width);
278+
let header_type = Self::clamp_render_text(&h.type_name, col_width);
279+
Cell::from(format!("{header_name}\n{header_type}"))
280+
})
281+
.collect::<Vec<Cell>>(),
240282
)
241283
.height(header_height)
242284
.bottom_margin(row_bottom_margin);
243-
let value_rows = rows.rows.iter().map(|r| Row::new(r.clone()).bottom_margin(row_bottom_margin));
244-
let column_widths = self.column_widths(&rows);
285+
let value_rows = rows.rows.iter().map(|r| {
286+
Row::new(
287+
r.iter()
288+
.enumerate()
289+
.map(|(index, value)| {
290+
let col_width = column_widths.get(index).copied().unwrap_or(MAX_COLUMN_WIDTH) as usize;
291+
Self::clamp_render_text(value, col_width)
292+
})
293+
.collect::<Vec<String>>(),
294+
)
295+
.bottom_margin(row_bottom_margin)
296+
});
245297
let buf_table = Table::new(value_rows, column_widths.clone())
246298
.header(header_row)
247299
.style(Style::default())
@@ -479,7 +531,7 @@ impl Component for Data<'_> {
479531
format!(" 󰆼 results <alt+3> (row {} of {})", y.saturating_add(1), rows.len())
480532
},
481533
Some(SelectionMode::Cell) => {
482-
let cell = row.get(x).cloned().unwrap_or_default();
534+
let cell = row.get(x).map(|c| Self::preview_text(c, TITLE_CELL_PREVIEW_MAX_CHARS)).unwrap_or_default();
483535
format!(" 󰆼 results <alt+3> (row {} of {}) - {} ", y.saturating_add(1), rows.len(), cell)
484536
},
485537
Some(SelectionMode::Copied) => {

0 commit comments

Comments
 (0)