forked from extern/nushell
add optional footer to table (#392)
* add optional footer to table * missed a draw_table
This commit is contained in:
parent
d2a1564b94
commit
d8c721282b
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1549,6 +1549,7 @@ version = "0.36.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi-cut",
|
"ansi-cut",
|
||||||
"nu-ansi-term 0.39.0",
|
"nu-ansi-term 0.39.0",
|
||||||
|
"nu-protocol",
|
||||||
"regex",
|
"regex",
|
||||||
"strip-ansi-escapes",
|
"strip-ansi-escapes",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use super::color_config::style_primitive;
|
||||||
use crate::viewers::color_config::get_color_config;
|
use crate::viewers::color_config::get_color_config;
|
||||||
use nu_protocol::ast::{Call, PathMember};
|
use nu_protocol::ast::{Call, PathMember};
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
@ -9,8 +10,6 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use terminal_size::{Height, Width};
|
use terminal_size::{Height, Width};
|
||||||
|
|
||||||
use super::color_config::style_primitive;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Table;
|
pub struct Table;
|
||||||
|
|
||||||
@ -50,7 +49,7 @@ impl Command for Table {
|
|||||||
let table = convert_to_table(vals, ctrlc, &config)?;
|
let table = convert_to_table(vals, ctrlc, &config)?;
|
||||||
|
|
||||||
if let Some(table) = table {
|
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 {
|
Ok(Value::String {
|
||||||
val: result,
|
val: result,
|
||||||
@ -65,7 +64,7 @@ impl Command for Table {
|
|||||||
let table = convert_to_table(stream, ctrlc, &config)?;
|
let table = convert_to_table(stream, ctrlc, &config)?;
|
||||||
|
|
||||||
if let Some(table) = table {
|
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 {
|
Ok(Value::String {
|
||||||
val: result,
|
val: result,
|
||||||
@ -98,7 +97,7 @@ impl Command for Table {
|
|||||||
theme: load_theme_from_config(&config),
|
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 {
|
Ok(Value::String {
|
||||||
val: result,
|
val: result,
|
||||||
|
@ -9,6 +9,7 @@ pub struct Config {
|
|||||||
pub use_ls_colors: bool,
|
pub use_ls_colors: bool,
|
||||||
pub color_config: HashMap<String, String>,
|
pub color_config: HashMap<String, String>,
|
||||||
pub use_grid_icons: bool,
|
pub use_grid_icons: bool,
|
||||||
|
pub footer_mode: FooterMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@ -19,10 +20,23 @@ impl Default for Config {
|
|||||||
use_ls_colors: true,
|
use_ls_colors: true,
|
||||||
color_config: HashMap::new(),
|
color_config: HashMap::new(),
|
||||||
use_grid_icons: false,
|
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 {
|
impl Value {
|
||||||
pub fn into_config(self) -> Result<Config, ShellError> {
|
pub fn into_config(self) -> Result<Config, ShellError> {
|
||||||
let v = self.as_record()?;
|
let v = self.as_record()?;
|
||||||
@ -51,6 +65,18 @@ impl Value {
|
|||||||
"use_grid_icons" => {
|
"use_grid_icons" => {
|
||||||
config.use_grid_icons = value.as_bool()?;
|
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]
|
[dependencies]
|
||||||
# nu-ansi-term = "0.39.0"
|
# nu-ansi-term = "0.39.0"
|
||||||
nu-ansi-term = { path = "../nu-ansi-term" }
|
nu-ansi-term = { path = "../nu-ansi-term" }
|
||||||
|
nu-protocol = { path = "../nu-protocol"}
|
||||||
regex = "1.4"
|
regex = "1.4"
|
||||||
unicode-width = "0.1.8"
|
unicode-width = "0.1.8"
|
||||||
strip-ansi-escapes = "0.1.1"
|
strip-ansi-escapes = "0.1.1"
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use nu_protocol::Config;
|
||||||
use nu_table::{draw_table, StyledString, Table, TextStyle, Theme};
|
use nu_table::{draw_table, StyledString, Table, TextStyle, Theme};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@ -25,8 +26,10 @@ fn main() {
|
|||||||
let table = Table::new(headers, vec![rows; 3], Theme::rounded());
|
let table = Table::new(headers, vec![rows; 3], Theme::rounded());
|
||||||
// FIXME: Config isn't available from here so just put these here to compile
|
// 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();
|
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
|
// 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
|
// Draw the table
|
||||||
println!("{}", output_table)
|
println!("{}", output_table)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::wrap::{column_width, split_sublines, wrap, Alignment, Subline, WrappedCell};
|
use crate::wrap::{column_width, split_sublines, wrap, Alignment, Subline, WrappedCell};
|
||||||
use nu_ansi_term::{Color, Style};
|
use nu_ansi_term::{Color, Style};
|
||||||
|
use nu_protocol::{Config, FooterMode};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
@ -629,6 +630,7 @@ pub struct WrappedTable {
|
|||||||
pub headers: Vec<WrappedCell>,
|
pub headers: Vec<WrappedCell>,
|
||||||
pub data: Vec<Vec<WrappedCell>>,
|
pub data: Vec<Vec<WrappedCell>>,
|
||||||
pub theme: Theme,
|
pub theme: Theme,
|
||||||
|
pub footer: Vec<WrappedCell>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WrappedTable {
|
impl WrappedTable {
|
||||||
@ -878,7 +880,7 @@ impl WrappedTable {
|
|||||||
total_output
|
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();
|
let mut output = String::new();
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -890,10 +892,12 @@ impl WrappedTable {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The top border
|
||||||
if self.theme.print_top_border {
|
if self.theme.print_top_border {
|
||||||
output.push_str(&self.print_separator(SeparatorPosition::Top, color_hm));
|
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)
|
let skip_headers = (self.headers.len() == 2 && self.headers[1].max_width == 0)
|
||||||
|| (self.headers.len() == 1 && self.headers[0].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));
|
output.push_str(&self.print_cell_contents(&self.headers, color_hm));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The middle section
|
||||||
let mut first_row = true;
|
let mut first_row = true;
|
||||||
|
|
||||||
for row in &self.data {
|
for row in &self.data {
|
||||||
if !first_row {
|
if !first_row {
|
||||||
if self.theme.separate_rows {
|
if self.theme.separate_rows {
|
||||||
@ -919,6 +923,31 @@ impl WrappedTable {
|
|||||||
output.push_str(&self.print_cell_contents(row, color_hm));
|
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 {
|
if self.theme.print_bottom_border {
|
||||||
output.push_str(&self.print_separator(SeparatorPosition::Bottom, color_hm));
|
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
|
// Remove the edges, if used
|
||||||
let termwidth = if table.theme.print_left_border && table.theme.print_right_border {
|
let termwidth = if table.theme.print_left_border && table.theme.print_right_border {
|
||||||
termwidth - 2
|
termwidth - 2
|
||||||
@ -1073,7 +1107,7 @@ pub fn draw_table(table: &Table, termwidth: usize, color_hm: &HashMap<String, St
|
|||||||
&re_trailing,
|
&re_trailing,
|
||||||
);
|
);
|
||||||
|
|
||||||
wrapped_table.print_table(color_hm)
|
wrapped_table.print_table(color_hm, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_cells(
|
fn wrap_cells(
|
||||||
@ -1151,11 +1185,24 @@ fn wrap_cells(
|
|||||||
output_data.push(output_row);
|
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 {
|
WrappedTable {
|
||||||
column_widths,
|
column_widths,
|
||||||
headers: output_headers,
|
headers: output_headers,
|
||||||
data: output_data,
|
data: output_data,
|
||||||
theme: processed_table.theme,
|
theme: processed_table.theme,
|
||||||
|
footer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,13 +24,13 @@ pub struct Line {
|
|||||||
pub width: usize,
|
pub width: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct WrappedLine {
|
pub struct WrappedLine {
|
||||||
pub line: String,
|
pub line: String,
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct WrappedCell {
|
pub struct WrappedCell {
|
||||||
pub lines: Vec<WrappedLine>,
|
pub lines: Vec<WrappedLine>,
|
||||||
pub max_width: usize,
|
pub max_width: usize,
|
||||||
|
Loading…
Reference in New Issue
Block a user