Config refactoring baseline.

The initial configuration refactoring already gave significant benefits
with my use case. On another note, Commands should know and ask for
configuration variables. We could, as we refactor, add the ability
for commands to tell what configuration variables knows about and
their types.

This way, completers can be used too when using `config` command if we
also add a sub command that config could set variables to.

Commands stating the config variables they know about will allow us
to implement it in `help` and display them.
This commit is contained in:
Andrés N. Robalino 2020-08-17 02:00:04 -05:00
parent 8d269f62dd
commit 05aca1c157
4 changed files with 159 additions and 96 deletions

View File

@ -1,5 +1,8 @@
use crate::commands::UnevaluatedCallInfo; use crate::commands::UnevaluatedCallInfo;
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::data::config::table::AutoPivotMode;
use crate::data::config::table::HasTableProperties;
use crate::data::config::NuConfig as Configuration;
use crate::data::value::format_leaf; use crate::data::value::format_leaf;
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
@ -82,28 +85,13 @@ impl RunnableContextWithoutInput {
} }
pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellError> { pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellError> {
let configuration = Configuration::new();
let binary = context.get_command("binaryview"); let binary = context.get_command("binaryview");
let text = context.get_command("textview"); let text = context.get_command("textview");
let table = context.get_command("table"); let table = context.get_command("table");
#[derive(PartialEq)] let pivot_mode = configuration.pivot_mode();
enum AutoPivotMode {
Auto,
Always,
Never,
}
let pivot_mode = crate::data::config::config(Tag::unknown());
let pivot_mode = if let Some(v) = pivot_mode?.get("pivot_mode") {
match v.as_string() {
Ok(m) if m.to_lowercase() == "auto" => AutoPivotMode::Auto,
Ok(m) if m.to_lowercase() == "always" => AutoPivotMode::Always,
Ok(m) if m.to_lowercase() == "never" => AutoPivotMode::Never,
_ => AutoPivotMode::Always,
}
} else {
AutoPivotMode::Always
};
let (mut input_stream, context) = RunnableContextWithoutInput::convert(context); let (mut input_stream, context) = RunnableContextWithoutInput::convert(context);
let term_width = context.host.lock().width(); let term_width = context.host.lock().width();

View File

@ -1,9 +1,11 @@
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::data::config::table::HasTableProperties;
use crate::data::config::NuConfig as TableConfiguration;
use crate::data::value::{format_leaf, style_leaf}; use crate::data::value::{format_leaf, style_leaf};
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{Primitive, Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{Primitive, Signature, SyntaxShape, UntaggedValue, Value};
use nu_table::{draw_table, Alignment, StyledString, TextStyle, Theme}; use nu_table::{draw_table, Alignment, StyledString, TextStyle};
use std::time::Instant; use std::time::Instant;
const STREAM_PAGE_SIZE: usize = 1000; const STREAM_PAGE_SIZE: usize = 1000;
@ -35,102 +37,42 @@ impl WholeStreamCommand for Table {
args: CommandArgs, args: CommandArgs,
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
table(args, registry).await table(TableConfiguration::new(), args, registry).await
} }
} }
fn str_to_color(s: String) -> Option<ansi_term::Color> { pub fn from_list(
match s.as_str() { values: &[Value],
"g" | "green" => Some(ansi_term::Color::Green), configuration: &TableConfiguration,
"r" | "red" => Some(ansi_term::Color::Red), starting_idx: usize,
"u" | "blue" => Some(ansi_term::Color::Blue), ) -> nu_table::Table {
"b" | "black" => Some(ansi_term::Color::Black), let header_style = TextStyle {
"y" | "yellow" => Some(ansi_term::Color::Yellow), is_bold: configuration.header_bold(),
"p" | "purple" => Some(ansi_term::Color::Purple), alignment: configuration.header_alignment(),
"c" | "cyan" => Some(ansi_term::Color::Cyan), color: configuration.header_color(),
"w" | "white" => Some(ansi_term::Color::White),
_ => None,
}
}
pub fn from_list(values: &[Value], starting_idx: usize) -> nu_table::Table {
let config = crate::data::config::config(Tag::unknown());
let header_style = if let Ok(config) = &config {
let header_align = config.get("header_align").map_or(Alignment::Left, |a| {
a.as_string()
.map_or(Alignment::Center, |a| match a.to_lowercase().as_str() {
"center" | "c" => Alignment::Center,
"right" | "r" => Alignment::Right,
_ => Alignment::Center,
})
});
let header_color = match config.get("header_color") {
Some(c) => match c.as_string() {
Ok(color) => str_to_color(color.to_lowercase()).unwrap_or(ansi_term::Color::Green),
_ => ansi_term::Color::Green,
},
_ => ansi_term::Color::Green,
};
let header_bold = config
.get("header_bold")
.map(|x| x.as_bool().unwrap_or(true))
.unwrap_or(true);
TextStyle {
alignment: header_align,
color: Some(header_color),
is_bold: header_bold,
}
} else {
TextStyle::default_header()
}; };
let mut headers: Vec<StyledString> = nu_protocol::merge_descriptors(values) let mut headers: Vec<StyledString> = nu_protocol::merge_descriptors(values)
.into_iter() .into_iter()
.map(|x| StyledString::new(x, header_style.clone())) .map(|x| StyledString::new(x, header_style.clone()))
.collect(); .collect();
let entries = values_to_entries(values, &mut headers, starting_idx); let entries = values_to_entries(values, &mut headers, configuration, starting_idx);
if let Ok(config) = config {
if let Some(style) = config.get("table_mode") {
if let Ok(table_mode) = style.as_string() {
if table_mode == "light" {
return nu_table::Table {
headers,
data: entries,
theme: Theme::light(),
};
}
}
}
}
nu_table::Table { nu_table::Table {
headers, headers,
data: entries, data: entries,
theme: Theme::compact(), theme: configuration.table_mode(),
}
}
fn are_table_indexes_disabled() -> bool {
let config = crate::data::config::config(Tag::unknown());
match config {
Ok(config) => {
let disable_indexes = config.get("disable_table_indexes");
disable_indexes.map_or(false, |x| x.as_bool().unwrap_or(false))
}
_ => false,
} }
} }
fn values_to_entries( fn values_to_entries(
values: &[Value], values: &[Value],
headers: &mut Vec<StyledString>, headers: &mut Vec<StyledString>,
configuration: &TableConfiguration,
starting_idx: usize, starting_idx: usize,
) -> Vec<Vec<StyledString>> { ) -> Vec<Vec<StyledString>> {
let disable_indexes = are_table_indexes_disabled(); let disable_indexes = configuration.disabled_indexes();
let mut entries = vec![]; let mut entries = vec![];
if headers.is_empty() { if headers.is_empty() {
@ -212,7 +154,11 @@ fn values_to_entries(
entries entries
} }
async fn table(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> { async fn table(
configuration: TableConfiguration,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone(); let registry = registry.clone();
let mut args = args.evaluate_once(&registry).await?; let mut args = args.evaluate_once(&registry).await?;
let mut finished = false; let mut finished = false;
@ -289,7 +235,7 @@ async fn table(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
let input: Vec<Value> = new_input.into(); let input: Vec<Value> = new_input.into();
if !input.is_empty() { if !input.is_empty() {
let t = from_list(&input, start_number); let t = from_list(&input, &configuration, start_number);
draw_table(&t, term_width); draw_table(&t, term_width);
} }

View File

@ -1,5 +1,6 @@
mod conf; mod conf;
mod nuconfig; mod nuconfig;
pub mod table;
#[cfg(test)] #[cfg(test)]
pub mod tests; pub mod tests;

View File

@ -0,0 +1,128 @@
use crate::data::config::nuconfig::NuConfig;
use std::fmt::Debug;
#[derive(PartialEq, Debug)]
pub enum AutoPivotMode {
Auto,
Always,
Never,
}
pub trait HasTableProperties: Debug + Send {
fn pivot_mode(&self) -> AutoPivotMode;
fn header_alignment(&self) -> nu_table::Alignment;
fn header_color(&self) -> Option<ansi_term::Color>;
fn header_bold(&self) -> bool;
fn table_mode(&self) -> nu_table::Theme;
fn disabled_indexes(&self) -> bool;
}
pub fn pivot_mode(config: &NuConfig) -> AutoPivotMode {
let vars = config.vars.lock();
if let Some(mode) = vars.get("pivot_mode") {
let mode = match mode.as_string() {
Ok(m) if m.to_lowercase() == "auto" => AutoPivotMode::Auto,
Ok(m) if m.to_lowercase() == "always" => AutoPivotMode::Always,
Ok(m) if m.to_lowercase() == "never" => AutoPivotMode::Never,
_ => AutoPivotMode::Always,
};
return mode;
}
AutoPivotMode::Always
}
pub fn header_alignment(config: &NuConfig) -> nu_table::Alignment {
let vars = config.vars.lock();
let alignment = vars.get("header_align");
if alignment.is_none() {
return nu_table::Alignment::Center;
}
alignment.map_or(nu_table::Alignment::Left, |a| {
a.as_string().map_or(nu_table::Alignment::Center, |a| {
match a.to_lowercase().as_str() {
"center" | "c" => nu_table::Alignment::Center,
"right" | "r" => nu_table::Alignment::Right,
_ => nu_table::Alignment::Center,
}
})
})
}
pub fn header_color(config: &NuConfig) -> Option<ansi_term::Color> {
let vars = config.vars.lock();
Some(match vars.get("header_color") {
Some(c) => match c.as_string() {
Ok(color) => match color.to_lowercase().as_str() {
"g" | "green" => ansi_term::Color::Green,
"r" | "red" => ansi_term::Color::Red,
"u" | "blue" => ansi_term::Color::Blue,
"b" | "black" => ansi_term::Color::Black,
"y" | "yellow" => ansi_term::Color::Yellow,
"p" | "purple" => ansi_term::Color::Purple,
"c" | "cyan" => ansi_term::Color::Cyan,
"w" | "white" => ansi_term::Color::White,
_ => ansi_term::Color::Green,
},
_ => ansi_term::Color::Green,
},
_ => ansi_term::Color::Green,
})
}
pub fn header_bold(config: &NuConfig) -> bool {
let vars = config.vars.lock();
vars.get("header_bold")
.map(|x| x.as_bool().unwrap_or(true))
.unwrap_or(true)
}
pub fn table_mode(config: &NuConfig) -> nu_table::Theme {
let vars = config.vars.lock();
vars.get("table_mode")
.map_or(nu_table::Theme::compact(), |mode| match mode.as_string() {
Ok(m) if m == "light" => nu_table::Theme::light(),
_ => nu_table::Theme::compact(),
})
}
pub fn disabled_indexes(config: &NuConfig) -> bool {
let vars = config.vars.lock();
vars.get("disable_table_indexes")
.map_or(false, |x| x.as_bool().unwrap_or(false))
}
impl HasTableProperties for NuConfig {
fn pivot_mode(&self) -> AutoPivotMode {
pivot_mode(self)
}
fn header_alignment(&self) -> nu_table::Alignment {
header_alignment(self)
}
fn header_color(&self) -> Option<ansi_term::Color> {
header_color(self)
}
fn header_bold(&self) -> bool {
header_bold(self)
}
fn table_mode(&self) -> nu_table::Theme {
table_mode(self)
}
fn disabled_indexes(&self) -> bool {
disabled_indexes(self)
}
}