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::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::prelude::*;
use nu_errors::ShellError;
@ -82,28 +85,13 @@ impl RunnableContextWithoutInput {
}
pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellError> {
let configuration = Configuration::new();
let binary = context.get_command("binaryview");
let text = context.get_command("textview");
let table = context.get_command("table");
#[derive(PartialEq)]
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 pivot_mode = configuration.pivot_mode();
let (mut input_stream, context) = RunnableContextWithoutInput::convert(context);
let term_width = context.host.lock().width();

View File

@ -1,9 +1,11 @@
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::prelude::*;
use nu_errors::ShellError;
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;
const STREAM_PAGE_SIZE: usize = 1000;
@ -35,102 +37,42 @@ impl WholeStreamCommand for Table {
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
table(args, registry).await
table(TableConfiguration::new(), args, registry).await
}
}
fn str_to_color(s: String) -> Option<ansi_term::Color> {
match s.as_str() {
"g" | "green" => Some(ansi_term::Color::Green),
"r" | "red" => Some(ansi_term::Color::Red),
"u" | "blue" => Some(ansi_term::Color::Blue),
"b" | "black" => Some(ansi_term::Color::Black),
"y" | "yellow" => Some(ansi_term::Color::Yellow),
"p" | "purple" => Some(ansi_term::Color::Purple),
"c" | "cyan" => Some(ansi_term::Color::Cyan),
"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()
pub fn from_list(
values: &[Value],
configuration: &TableConfiguration,
starting_idx: usize,
) -> nu_table::Table {
let header_style = TextStyle {
is_bold: configuration.header_bold(),
alignment: configuration.header_alignment(),
color: configuration.header_color(),
};
let mut headers: Vec<StyledString> = nu_protocol::merge_descriptors(values)
.into_iter()
.map(|x| StyledString::new(x, header_style.clone()))
.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 {
headers,
data: entries,
theme: Theme::compact(),
}
}
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,
theme: configuration.table_mode(),
}
}
fn values_to_entries(
values: &[Value],
headers: &mut Vec<StyledString>,
configuration: &TableConfiguration,
starting_idx: usize,
) -> Vec<Vec<StyledString>> {
let disable_indexes = are_table_indexes_disabled();
let disable_indexes = configuration.disabled_indexes();
let mut entries = vec![];
if headers.is_empty() {
@ -212,7 +154,11 @@ fn values_to_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 mut args = args.evaluate_once(&registry).await?;
let mut finished = false;
@ -289,7 +235,7 @@ async fn table(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
let input: Vec<Value> = new_input.into();
if !input.is_empty() {
let t = from_list(&input, start_number);
let t = from_list(&input, &configuration, start_number);
draw_table(&t, term_width);
}

View File

@ -1,5 +1,6 @@
mod conf;
mod nuconfig;
pub mod table;
#[cfg(test)]
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)
}
}