mirror of
https://github.com/nushell/nushell
synced 2024-12-26 13:03:07 +00:00
add optional footer to table (#392)
* add optional footer to table * missed a draw_table
This commit is contained in:
parent
d2a1564b94
commit
d8c721282b
7 changed files with 89 additions and 12 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1549,6 +1549,7 @@ version = "0.36.0"
|
|||
dependencies = [
|
||||
"ansi-cut",
|
||||
"nu-ansi-term 0.39.0",
|
||||
"nu-protocol",
|
||||
"regex",
|
||||
"strip-ansi-escapes",
|
||||
"unicode-width",
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use super::color_config::style_primitive;
|
||||
use crate::viewers::color_config::get_color_config;
|
||||
use nu_protocol::ast::{Call, PathMember};
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
|
@ -9,8 +10,6 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
|||
use std::sync::Arc;
|
||||
use terminal_size::{Height, Width};
|
||||
|
||||
use super::color_config::style_primitive;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Table;
|
||||
|
||||
|
@ -50,7 +49,7 @@ impl Command for Table {
|
|||
let table = convert_to_table(vals, ctrlc, &config)?;
|
||||
|
||||
if let Some(table) = table {
|
||||
let result = nu_table::draw_table(&table, term_width, &color_hm);
|
||||
let result = nu_table::draw_table(&table, term_width, &color_hm, &config);
|
||||
|
||||
Ok(Value::String {
|
||||
val: result,
|
||||
|
@ -65,7 +64,7 @@ impl Command for Table {
|
|||
let table = convert_to_table(stream, ctrlc, &config)?;
|
||||
|
||||
if let Some(table) = table {
|
||||
let result = nu_table::draw_table(&table, term_width, &color_hm);
|
||||
let result = nu_table::draw_table(&table, term_width, &color_hm, &config);
|
||||
|
||||
Ok(Value::String {
|
||||
val: result,
|
||||
|
@ -98,7 +97,7 @@ impl Command for Table {
|
|||
theme: load_theme_from_config(&config),
|
||||
};
|
||||
|
||||
let result = nu_table::draw_table(&table, term_width, &color_hm);
|
||||
let result = nu_table::draw_table(&table, term_width, &color_hm, &config);
|
||||
|
||||
Ok(Value::String {
|
||||
val: result,
|
||||
|
|
|
@ -9,6 +9,7 @@ pub struct Config {
|
|||
pub use_ls_colors: bool,
|
||||
pub color_config: HashMap<String, String>,
|
||||
pub use_grid_icons: bool,
|
||||
pub footer_mode: FooterMode,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
|
@ -19,10 +20,23 @@ impl Default for Config {
|
|||
use_ls_colors: true,
|
||||
color_config: HashMap::new(),
|
||||
use_grid_icons: false,
|
||||
footer_mode: FooterMode::Never,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub enum FooterMode {
|
||||
/// Never show the footer
|
||||
Never,
|
||||
/// Always show the footer
|
||||
Always,
|
||||
/// Only show the footer if there are more than RowCount rows
|
||||
RowCount(u64),
|
||||
/// Calculate the screen height, calculate row count, if display will be bigger than screen, add the footer
|
||||
Auto,
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn into_config(self) -> Result<Config, ShellError> {
|
||||
let v = self.as_record()?;
|
||||
|
@ -51,6 +65,18 @@ impl Value {
|
|||
"use_grid_icons" => {
|
||||
config.use_grid_icons = value.as_bool()?;
|
||||
}
|
||||
"footer_mode" => {
|
||||
let val_str = value.as_string()?;
|
||||
config.footer_mode = match val_str.as_ref() {
|
||||
"auto" => FooterMode::Auto,
|
||||
"never" => FooterMode::Never,
|
||||
"always" => FooterMode::Always,
|
||||
_ => match &val_str.parse::<u64>() {
|
||||
Ok(number) => FooterMode::RowCount(*number),
|
||||
_ => FooterMode::Never,
|
||||
},
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ path = "src/main.rs"
|
|||
[dependencies]
|
||||
# nu-ansi-term = "0.39.0"
|
||||
nu-ansi-term = { path = "../nu-ansi-term" }
|
||||
nu-protocol = { path = "../nu-protocol"}
|
||||
regex = "1.4"
|
||||
unicode-width = "0.1.8"
|
||||
strip-ansi-escapes = "0.1.1"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use nu_protocol::Config;
|
||||
use nu_table::{draw_table, StyledString, Table, TextStyle, Theme};
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
@ -25,8 +26,10 @@ fn main() {
|
|||
let table = Table::new(headers, vec![rows; 3], Theme::rounded());
|
||||
// FIXME: Config isn't available from here so just put these here to compile
|
||||
let color_hm: HashMap<String, nu_ansi_term::Style> = HashMap::new();
|
||||
// get the default config
|
||||
let config = Config::default();
|
||||
// Capture the table as a string
|
||||
let output_table = draw_table(&table, width, &color_hm);
|
||||
let output_table = draw_table(&table, width, &color_hm, &config);
|
||||
// Draw the table
|
||||
println!("{}", output_table)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::wrap::{column_width, split_sublines, wrap, Alignment, Subline, WrappedCell};
|
||||
use nu_ansi_term::{Color, Style};
|
||||
use nu_protocol::{Config, FooterMode};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
|
||||
|
@ -629,6 +630,7 @@ pub struct WrappedTable {
|
|||
pub headers: Vec<WrappedCell>,
|
||||
pub data: Vec<Vec<WrappedCell>>,
|
||||
pub theme: Theme,
|
||||
pub footer: Vec<WrappedCell>,
|
||||
}
|
||||
|
||||
impl WrappedTable {
|
||||
|
@ -878,7 +880,7 @@ impl WrappedTable {
|
|||
total_output
|
||||
}
|
||||
|
||||
fn print_table(&self, color_hm: &HashMap<String, Style>) -> String {
|
||||
fn print_table(&self, color_hm: &HashMap<String, Style>, config: &Config) -> String {
|
||||
let mut output = String::new();
|
||||
|
||||
#[cfg(windows)]
|
||||
|
@ -890,10 +892,12 @@ impl WrappedTable {
|
|||
return output;
|
||||
}
|
||||
|
||||
// The top border
|
||||
if self.theme.print_top_border {
|
||||
output.push_str(&self.print_separator(SeparatorPosition::Top, color_hm));
|
||||
}
|
||||
|
||||
// The header
|
||||
let skip_headers = (self.headers.len() == 2 && self.headers[1].max_width == 0)
|
||||
|| (self.headers.len() == 1 && self.headers[0].max_width == 0);
|
||||
|
||||
|
@ -901,8 +905,8 @@ impl WrappedTable {
|
|||
output.push_str(&self.print_cell_contents(&self.headers, color_hm));
|
||||
}
|
||||
|
||||
// The middle section
|
||||
let mut first_row = true;
|
||||
|
||||
for row in &self.data {
|
||||
if !first_row {
|
||||
if self.theme.separate_rows {
|
||||
|
@ -919,6 +923,31 @@ impl WrappedTable {
|
|||
output.push_str(&self.print_cell_contents(row, color_hm));
|
||||
}
|
||||
|
||||
match config.footer_mode {
|
||||
FooterMode::Always => {
|
||||
if self.theme.separate_header && !self.headers.is_empty() && !skip_headers {
|
||||
output.push_str(&self.print_separator(SeparatorPosition::Middle, color_hm));
|
||||
}
|
||||
|
||||
if !self.headers.is_empty() && !skip_headers {
|
||||
output.push_str(&self.print_cell_contents(&self.footer, color_hm));
|
||||
}
|
||||
}
|
||||
FooterMode::RowCount(r) => {
|
||||
if self.data.len() as u64 > r {
|
||||
if self.theme.separate_header && !self.headers.is_empty() && !skip_headers {
|
||||
output.push_str(&self.print_separator(SeparatorPosition::Middle, color_hm));
|
||||
}
|
||||
|
||||
if !self.headers.is_empty() && !skip_headers {
|
||||
output.push_str(&self.print_cell_contents(&self.footer, color_hm));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {} // Never and Auto aka auto get eaten and nothing happens
|
||||
}
|
||||
|
||||
// The table finish
|
||||
if self.theme.print_bottom_border {
|
||||
output.push_str(&self.print_separator(SeparatorPosition::Bottom, color_hm));
|
||||
}
|
||||
|
@ -1013,7 +1042,12 @@ pub fn maybe_truncate_columns(termwidth: usize, processed_table: &mut ProcessedT
|
|||
}
|
||||
}
|
||||
|
||||
pub fn draw_table(table: &Table, termwidth: usize, color_hm: &HashMap<String, Style>) -> String {
|
||||
pub fn draw_table(
|
||||
table: &Table,
|
||||
termwidth: usize,
|
||||
color_hm: &HashMap<String, Style>,
|
||||
config: &Config,
|
||||
) -> String {
|
||||
// Remove the edges, if used
|
||||
let termwidth = if table.theme.print_left_border && table.theme.print_right_border {
|
||||
termwidth - 2
|
||||
|
@ -1073,7 +1107,7 @@ pub fn draw_table(table: &Table, termwidth: usize, color_hm: &HashMap<String, St
|
|||
&re_trailing,
|
||||
);
|
||||
|
||||
wrapped_table.print_table(color_hm)
|
||||
wrapped_table.print_table(color_hm, config)
|
||||
}
|
||||
|
||||
fn wrap_cells(
|
||||
|
@ -1151,11 +1185,24 @@ fn wrap_cells(
|
|||
output_data.push(output_row);
|
||||
}
|
||||
|
||||
let mut footer = vec![
|
||||
WrappedCell {
|
||||
lines: vec![],
|
||||
max_width: 0,
|
||||
style: TextStyle {
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
output_headers.len()
|
||||
];
|
||||
footer.clone_from_slice(&output_headers[..]);
|
||||
|
||||
WrappedTable {
|
||||
column_widths,
|
||||
headers: output_headers,
|
||||
data: output_data,
|
||||
theme: processed_table.theme,
|
||||
footer,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,13 +24,13 @@ pub struct Line {
|
|||
pub width: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WrappedLine {
|
||||
pub line: String,
|
||||
pub width: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WrappedCell {
|
||||
pub lines: Vec<WrappedLine>,
|
||||
pub max_width: usize,
|
||||
|
|
Loading…
Reference in a new issue