Add minor theme support (#2449)

* WIP - compiling but not working

* semi-working

* making progress

* working except for table lines

* fmt + clippy

* cleaned up some comments

* working line colors

* fmt, clippy, updated sample config.toml

* removed extra comments
This commit is contained in:
Darren Schroeder
2020-09-01 00:09:55 -05:00
committed by GitHub
parent 860c2a606d
commit adbbcafd30
12 changed files with 904 additions and 384 deletions

View File

@ -1,5 +1,6 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use ansi_term::Color;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
@ -76,60 +77,56 @@ impl WholeStreamCommand for Ansi {
}
}
fn str_to_ansi_color(s: String) -> Option<String> {
pub fn str_to_ansi_color(s: String) -> Option<String> {
match s.as_str() {
"g" | "green" => Some(ansi_term::Color::Green.prefix().to_string()),
"gb" | "green_bold" => Some(ansi_term::Color::Green.bold().prefix().to_string()),
"gu" | "green_underline" => Some(ansi_term::Color::Green.underline().prefix().to_string()),
"gi" | "green_italic" => Some(ansi_term::Color::Green.italic().prefix().to_string()),
"gd" | "green_dimmed" => Some(ansi_term::Color::Green.dimmed().prefix().to_string()),
"gr" | "green_reverse" => Some(ansi_term::Color::Green.reverse().prefix().to_string()),
"r" | "red" => Some(ansi_term::Color::Red.prefix().to_string()),
"rb" | "red_bold" => Some(ansi_term::Color::Red.bold().prefix().to_string()),
"ru" | "red_underline" => Some(ansi_term::Color::Red.underline().prefix().to_string()),
"ri" | "red_italic" => Some(ansi_term::Color::Red.italic().prefix().to_string()),
"rd" | "red_dimmed" => Some(ansi_term::Color::Red.dimmed().prefix().to_string()),
"rr" | "red_reverse" => Some(ansi_term::Color::Red.reverse().prefix().to_string()),
"u" | "blue" => Some(ansi_term::Color::Blue.prefix().to_string()),
"ub" | "blue_bold" => Some(ansi_term::Color::Blue.bold().prefix().to_string()),
"uu" | "blue_underline" => Some(ansi_term::Color::Blue.underline().prefix().to_string()),
"ui" | "blue_italic" => Some(ansi_term::Color::Blue.italic().prefix().to_string()),
"ud" | "blue_dimmed" => Some(ansi_term::Color::Blue.dimmed().prefix().to_string()),
"ur" | "blue_reverse" => Some(ansi_term::Color::Blue.reverse().prefix().to_string()),
"b" | "black" => Some(ansi_term::Color::Black.prefix().to_string()),
"bb" | "black_bold" => Some(ansi_term::Color::Black.bold().prefix().to_string()),
"bu" | "black_underline" => Some(ansi_term::Color::Black.underline().prefix().to_string()),
"bi" | "black_italic" => Some(ansi_term::Color::Black.italic().prefix().to_string()),
"bd" | "black_dimmed" => Some(ansi_term::Color::Black.dimmed().prefix().to_string()),
"br" | "black_reverse" => Some(ansi_term::Color::Black.reverse().prefix().to_string()),
"y" | "yellow" => Some(ansi_term::Color::Yellow.prefix().to_string()),
"yb" | "yellow_bold" => Some(ansi_term::Color::Yellow.bold().prefix().to_string()),
"yu" | "yellow_underline" => {
Some(ansi_term::Color::Yellow.underline().prefix().to_string())
}
"yi" | "yellow_italic" => Some(ansi_term::Color::Yellow.italic().prefix().to_string()),
"yd" | "yellow_dimmed" => Some(ansi_term::Color::Yellow.dimmed().prefix().to_string()),
"yr" | "yellow_reverse" => Some(ansi_term::Color::Yellow.reverse().prefix().to_string()),
"p" | "purple" => Some(ansi_term::Color::Purple.prefix().to_string()),
"pb" | "purple_bold" => Some(ansi_term::Color::Purple.bold().prefix().to_string()),
"pu" | "purple_underline" => {
Some(ansi_term::Color::Purple.underline().prefix().to_string())
}
"pi" | "purple_italic" => Some(ansi_term::Color::Purple.italic().prefix().to_string()),
"pd" | "purple_dimmed" => Some(ansi_term::Color::Purple.dimmed().prefix().to_string()),
"pr" | "purple_reverse" => Some(ansi_term::Color::Purple.reverse().prefix().to_string()),
"c" | "cyan" => Some(ansi_term::Color::Cyan.prefix().to_string()),
"cb" | "cyan_bold" => Some(ansi_term::Color::Cyan.bold().prefix().to_string()),
"cu" | "cyan_underline" => Some(ansi_term::Color::Cyan.underline().prefix().to_string()),
"ci" | "cyan_italic" => Some(ansi_term::Color::Cyan.italic().prefix().to_string()),
"cd" | "cyan_dimmed" => Some(ansi_term::Color::Cyan.dimmed().prefix().to_string()),
"cr" | "cyan_reverse" => Some(ansi_term::Color::Cyan.reverse().prefix().to_string()),
"w" | "white" => Some(ansi_term::Color::White.prefix().to_string()),
"wb" | "white_bold" => Some(ansi_term::Color::White.bold().prefix().to_string()),
"wu" | "white_underline" => Some(ansi_term::Color::White.underline().prefix().to_string()),
"wi" | "white_italic" => Some(ansi_term::Color::White.italic().prefix().to_string()),
"wd" | "white_dimmed" => Some(ansi_term::Color::White.dimmed().prefix().to_string()),
"wr" | "white_reverse" => Some(ansi_term::Color::White.reverse().prefix().to_string()),
"g" | "green" => Some(Color::Green.prefix().to_string()),
"gb" | "green_bold" => Some(Color::Green.bold().prefix().to_string()),
"gu" | "green_underline" => Some(Color::Green.underline().prefix().to_string()),
"gi" | "green_italic" => Some(Color::Green.italic().prefix().to_string()),
"gd" | "green_dimmed" => Some(Color::Green.dimmed().prefix().to_string()),
"gr" | "green_reverse" => Some(Color::Green.reverse().prefix().to_string()),
"r" | "red" => Some(Color::Red.prefix().to_string()),
"rb" | "red_bold" => Some(Color::Red.bold().prefix().to_string()),
"ru" | "red_underline" => Some(Color::Red.underline().prefix().to_string()),
"ri" | "red_italic" => Some(Color::Red.italic().prefix().to_string()),
"rd" | "red_dimmed" => Some(Color::Red.dimmed().prefix().to_string()),
"rr" | "red_reverse" => Some(Color::Red.reverse().prefix().to_string()),
"u" | "blue" => Some(Color::Blue.prefix().to_string()),
"ub" | "blue_bold" => Some(Color::Blue.bold().prefix().to_string()),
"uu" | "blue_underline" => Some(Color::Blue.underline().prefix().to_string()),
"ui" | "blue_italic" => Some(Color::Blue.italic().prefix().to_string()),
"ud" | "blue_dimmed" => Some(Color::Blue.dimmed().prefix().to_string()),
"ur" | "blue_reverse" => Some(Color::Blue.reverse().prefix().to_string()),
"b" | "black" => Some(Color::Black.prefix().to_string()),
"bb" | "black_bold" => Some(Color::Black.bold().prefix().to_string()),
"bu" | "black_underline" => Some(Color::Black.underline().prefix().to_string()),
"bi" | "black_italic" => Some(Color::Black.italic().prefix().to_string()),
"bd" | "black_dimmed" => Some(Color::Black.dimmed().prefix().to_string()),
"br" | "black_reverse" => Some(Color::Black.reverse().prefix().to_string()),
"y" | "yellow" => Some(Color::Yellow.prefix().to_string()),
"yb" | "yellow_bold" => Some(Color::Yellow.bold().prefix().to_string()),
"yu" | "yellow_underline" => Some(Color::Yellow.underline().prefix().to_string()),
"yi" | "yellow_italic" => Some(Color::Yellow.italic().prefix().to_string()),
"yd" | "yellow_dimmed" => Some(Color::Yellow.dimmed().prefix().to_string()),
"yr" | "yellow_reverse" => Some(Color::Yellow.reverse().prefix().to_string()),
"p" | "purple" => Some(Color::Purple.prefix().to_string()),
"pb" | "purple_bold" => Some(Color::Purple.bold().prefix().to_string()),
"pu" | "purple_underline" => Some(Color::Purple.underline().prefix().to_string()),
"pi" | "purple_italic" => Some(Color::Purple.italic().prefix().to_string()),
"pd" | "purple_dimmed" => Some(Color::Purple.dimmed().prefix().to_string()),
"pr" | "purple_reverse" => Some(Color::Purple.reverse().prefix().to_string()),
"c" | "cyan" => Some(Color::Cyan.prefix().to_string()),
"cb" | "cyan_bold" => Some(Color::Cyan.bold().prefix().to_string()),
"cu" | "cyan_underline" => Some(Color::Cyan.underline().prefix().to_string()),
"ci" | "cyan_italic" => Some(Color::Cyan.italic().prefix().to_string()),
"cd" | "cyan_dimmed" => Some(Color::Cyan.dimmed().prefix().to_string()),
"cr" | "cyan_reverse" => Some(Color::Cyan.reverse().prefix().to_string()),
"w" | "white" => Some(Color::White.prefix().to_string()),
"wb" | "white_bold" => Some(Color::White.bold().prefix().to_string()),
"wu" | "white_underline" => Some(Color::White.underline().prefix().to_string()),
"wi" | "white_italic" => Some(Color::White.italic().prefix().to_string()),
"wd" | "white_dimmed" => Some(Color::White.dimmed().prefix().to_string()),
"wr" | "white_reverse" => Some(Color::White.reverse().prefix().to_string()),
"reset" => Some("\x1b[0m".to_owned()),
_ => None,
}

View File

@ -1,10 +1,12 @@
use crate::commands::autoview::options::{ConfigExtensions, NuConfig as AutoViewConfiguration};
use crate::commands::{UnevaluatedCallInfo, WholeStreamCommand};
use crate::prelude::*;
use crate::primitive::get_color_config;
use nu_data::value::format_leaf;
use nu_errors::ShellError;
use nu_protocol::hir::{self, Expression, ExternalRedirection, Literal, SpannedExpression};
use nu_protocol::{Primitive, Scope, Signature, UntaggedValue, Value};
use nu_table::TextStyle;
use parking_lot::Mutex;
use std::sync::atomic::AtomicBool;
@ -92,6 +94,7 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
let (mut input_stream, context) = RunnableContextWithoutInput::convert(context);
let term_width = context.host.lock().width();
let color_hm = get_color_config();
if let Some(x) = input_stream.next().await {
match input_stream.next().await {
@ -256,11 +259,10 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
entries.push(vec![
nu_table::StyledString::new(
key.to_string(),
nu_table::TextStyle {
alignment: nu_table::Alignment::Left,
color: Some(ansi_term::Color::Green),
is_bold: true,
},
TextStyle::new()
.alignment(nu_table::Alignment::Left)
.fg(ansi_term::Color::Green)
.bold(Some(true)),
),
nu_table::StyledString::new(
format_leaf(value).plain_string(100_000),
@ -272,7 +274,7 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
let table =
nu_table::Table::new(vec![], entries, nu_table::Theme::compact());
nu_table::draw_table(&table, term_width);
nu_table::draw_table(&table, term_width, &color_hm);
}
Value {

View File

@ -1,10 +1,12 @@
use crate::commands::table::options::{ConfigExtensions, NuConfig as TableConfiguration};
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use crate::primitive::get_color_config;
use nu_data::value::{format_leaf, style_leaf};
use nu_errors::ShellError;
use nu_protocol::{Primitive, Signature, SyntaxShape, UntaggedValue, Value};
use nu_table::{draw_table, Alignment, StyledString, TextStyle};
use std::collections::HashMap;
use std::time::Instant;
const STREAM_PAGE_SIZE: usize = 1000;
@ -44,19 +46,14 @@ pub fn from_list(
values: &[Value],
configuration: &TableConfiguration,
starting_idx: usize,
color_hm: &HashMap<String, ansi_term::Style>,
) -> nu_table::Table {
let header_style = TextStyle {
is_bold: configuration.header_bold(),
alignment: configuration.header_alignment(),
color: configuration.header_color(),
};
let header_style = configuration.header_style();
let mut headers: Vec<StyledString> = nu_protocol::merge_descriptors(values)
.into_iter()
.map(|x| StyledString::new(x, header_style.clone()))
.map(|x| StyledString::new(x, header_style))
.collect();
let entries = values_to_entries(values, &mut headers, configuration, starting_idx);
let entries = values_to_entries(values, &mut headers, configuration, starting_idx, &color_hm);
nu_table::Table {
headers,
data: entries,
@ -69,9 +66,9 @@ fn values_to_entries(
headers: &mut Vec<StyledString>,
configuration: &TableConfiguration,
starting_idx: usize,
color_hm: &HashMap<String, ansi_term::Style>,
) -> Vec<Vec<StyledString>> {
let disable_indexes = configuration.disabled_indexes();
let mut entries = vec![];
if headers.is_empty() {
@ -89,11 +86,11 @@ fn values_to_entries(
..
} => StyledString::new(
format_leaf(&UntaggedValue::nothing()).plain_string(100_000),
style_leaf(&UntaggedValue::nothing()),
style_leaf(&UntaggedValue::nothing(), &color_hm),
),
_ => StyledString::new(
format_leaf(value).plain_string(100_000),
style_leaf(value),
style_leaf(value, &color_hm),
),
}
} else {
@ -106,12 +103,12 @@ fn values_to_entries(
StyledString::new(
format_leaf(data.borrow()).plain_string(100_000),
style_leaf(data.borrow()),
style_leaf(data.borrow(), &color_hm),
)
}
_ => StyledString::new(
format_leaf(&UntaggedValue::nothing()).plain_string(100_000),
style_leaf(&UntaggedValue::nothing()),
style_leaf(&UntaggedValue::nothing(), &color_hm),
),
}
}
@ -119,16 +116,22 @@ fn values_to_entries(
.collect();
// Indices are green, bold, right-aligned:
// unless we change them :)
if !disable_indexes {
row.insert(
0,
StyledString::new(
(starting_idx + idx).to_string(),
TextStyle {
alignment: Alignment::Right,
color: Some(ansi_term::Color::Green),
is_bold: true,
},
TextStyle::new().alignment(Alignment::Right).style(
color_hm
.get("index_color")
.unwrap_or(
&ansi_term::Style::default()
.bold()
.fg(ansi_term::Color::Green),
)
.to_owned(),
),
),
);
}
@ -141,11 +144,10 @@ fn values_to_entries(
0,
StyledString::new(
"#".to_owned(),
TextStyle {
alignment: Alignment::Center,
color: Some(ansi_term::Color::Green),
is_bold: true,
},
TextStyle::new()
.alignment(Alignment::Center)
.fg(ansi_term::Color::Green)
.bold(Some(true)),
),
);
}
@ -161,8 +163,14 @@ async fn table(
let registry = registry.clone();
let mut args = args.evaluate_once(&registry).await?;
let mut finished = false;
// Ideally, get_color_config would get all the colors configured in the config.toml
// and create a style based on those settings. However, there are few places where
// this just won't work right now, like header styling, because a style needs to know
// more than just color, it needs fg & bg color, bold, dimmed, italic, underline,
// blink, reverse, hidden, strikethrough and most of those aren't available in the
// config.toml.... yet.
let color_hm = get_color_config();
// let host = args.host.clone();
let mut start_number = match args.get("start_number") {
Some(Value {
value: UntaggedValue::Primitive(Primitive::Int(i)),
@ -234,9 +242,9 @@ async fn table(
let input: Vec<Value> = new_input.into();
if !input.is_empty() {
let t = from_list(&input, &configuration, start_number);
let t = from_list(&input, &configuration, start_number, &color_hm);
draw_table(&t, term_width);
draw_table(&t, term_width, &color_hm);
}
start_number += input.len();

View File

@ -1,62 +1,51 @@
pub use nu_data::config::NuConfig;
use nu_data::primitive::lookup_ansi_color_style;
use nu_protocol::{UntaggedValue, Value};
use nu_source::Tag;
use nu_table::TextStyle;
use std::fmt::Debug;
pub trait ConfigExtensions: Debug + Send {
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;
fn text_color(&self) -> Option<ansi_term::Color>;
fn line_color(&self) -> Option<ansi_term::Color>;
fn header_style(&self) -> TextStyle;
}
pub fn header_alignment(config: &NuConfig) -> nu_table::Alignment {
pub fn header_alignment_from_value(align_value: Option<&Value>) -> nu_table::Alignment {
match align_value {
Some(v) => match v
.as_string()
.unwrap_or_else(|_| "none".to_string())
.as_ref()
{
"l" | "left" => nu_table::Alignment::Left,
"c" | "center" => nu_table::Alignment::Center,
"r" | "right" => nu_table::Alignment::Right,
_ => nu_table::Alignment::Center,
},
_ => nu_table::Alignment::Center,
}
}
pub fn get_color_from_key_and_subkey(config: &NuConfig, key: &str, subkey: &str) -> Value {
let vars = config.vars.lock();
let alignment = vars.get("header_align");
if alignment.is_none() {
return nu_table::Alignment::Center;
let mut v: Value =
UntaggedValue::Primitive(nu_protocol::Primitive::String("nocolor".to_string()))
.into_value(Tag::unknown());
if let Some(config_vars) = vars.get(key) {
for (kee, value) in config_vars.row_entries() {
if kee == subkey {
v = value.to_owned();
}
}
}
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,
}
})
})
v
}
pub fn get_color_for_config_key(config: &NuConfig, key: &str) -> Option<ansi_term::Color> {
let vars = config.vars.lock();
Some(match vars.get(key) {
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")
pub fn header_bold_from_value(bold_value: Option<&Value>) -> bool {
bold_value
.map(|x| x.as_bool().unwrap_or(true))
.unwrap_or(true)
}
@ -84,24 +73,25 @@ pub fn disabled_indexes(config: &NuConfig) -> bool {
}
impl ConfigExtensions for NuConfig {
fn header_alignment(&self) -> nu_table::Alignment {
header_alignment(self)
}
fn header_style(&self) -> TextStyle {
// FIXME: I agree, this is the long way around, please suggest and alternative.
let head_color = get_color_from_key_and_subkey(self, "color_config", "header_color");
let head_color_style = lookup_ansi_color_style(
head_color
.as_string()
.unwrap_or_else(|_| "green".to_string()),
);
let head_bold = get_color_from_key_and_subkey(self, "color_config", "header_bold");
let head_bold_bool = header_bold_from_value(Some(&head_bold));
let head_align = get_color_from_key_and_subkey(self, "color_config", "header_align");
let head_alignment = header_alignment_from_value(Some(&head_align));
fn header_color(&self) -> Option<ansi_term::Color> {
get_color_for_config_key(self, "header_color")
}
fn text_color(&self) -> Option<ansi_term::Color> {
get_color_for_config_key(self, "text_color")
}
fn line_color(&self) -> Option<ansi_term::Color> {
get_color_for_config_key(self, "line_color")
}
fn header_bold(&self) -> bool {
header_bold(self)
TextStyle::new()
.alignment(head_alignment)
.bold(Some(head_bold_bool))
.fg(head_color_style
.foreground
.unwrap_or(ansi_term::Color::Green))
}
fn table_mode(&self) -> nu_table::Theme {