2021-12-02 06:59:10 +01:00
|
|
|
use lscolors::{LsColors, Style};
|
2021-12-16 13:17:29 +01:00
|
|
|
use nu_color_config::{get_color_config, style_primitive};
|
2022-01-01 02:39:58 +01:00
|
|
|
use nu_engine::column::get_columns;
|
2021-12-23 22:41:29 +01:00
|
|
|
use nu_engine::{env_to_string, CallExt};
|
2021-09-29 20:25:05 +02:00
|
|
|
use nu_protocol::ast::{Call, PathMember};
|
2021-10-25 18:58:58 +02:00
|
|
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
2021-11-17 05:22:37 +01:00
|
|
|
use nu_protocol::{
|
2021-12-24 08:22:11 +01:00
|
|
|
Category, Config, DataSource, IntoPipelineData, PipelineData, PipelineMetadata, ShellError,
|
|
|
|
Signature, Span, StringStream, SyntaxShape, Value, ValueStream,
|
2021-11-17 05:22:37 +01:00
|
|
|
};
|
2021-11-20 14:12:35 +01:00
|
|
|
use nu_table::{StyledString, TextStyle, Theme};
|
2021-11-09 07:14:00 +01:00
|
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
|
|
use std::sync::Arc;
|
2021-12-03 07:15:23 +01:00
|
|
|
use std::time::Instant;
|
2021-10-08 15:14:32 +02:00
|
|
|
use terminal_size::{Height, Width};
|
2021-09-29 20:25:05 +02:00
|
|
|
|
2021-12-03 07:15:23 +01:00
|
|
|
const STREAM_PAGE_SIZE: usize = 1000;
|
|
|
|
const STREAM_TIMEOUT_CHECK_INTERVAL: usize = 100;
|
|
|
|
|
2021-10-25 06:01:02 +02:00
|
|
|
#[derive(Clone)]
|
2021-09-29 20:25:05 +02:00
|
|
|
pub struct Table;
|
|
|
|
|
|
|
|
//NOTE: this is not a real implementation :D. It's just a simple one to test with until we port the real one.
|
|
|
|
impl Command for Table {
|
|
|
|
fn name(&self) -> &str {
|
|
|
|
"table"
|
|
|
|
}
|
|
|
|
|
|
|
|
fn usage(&self) -> &str {
|
|
|
|
"Render the table."
|
|
|
|
}
|
|
|
|
|
|
|
|
fn signature(&self) -> nu_protocol::Signature {
|
2021-12-23 22:41:29 +01:00
|
|
|
Signature::build("table")
|
|
|
|
.named(
|
|
|
|
"start_number",
|
|
|
|
SyntaxShape::Int,
|
|
|
|
"row number to start viewing from",
|
|
|
|
Some('n'),
|
|
|
|
)
|
|
|
|
.category(Category::Viewers)
|
2021-09-29 20:25:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn run(
|
|
|
|
&self,
|
2021-11-09 07:14:00 +01:00
|
|
|
engine_state: &EngineState,
|
2021-11-14 20:25:57 +01:00
|
|
|
stack: &mut Stack,
|
2021-09-29 20:25:05 +02:00
|
|
|
call: &Call,
|
2021-10-25 06:24:10 +02:00
|
|
|
input: PipelineData,
|
|
|
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
2021-12-24 08:22:11 +01:00
|
|
|
let head = call.head;
|
2021-11-09 07:14:00 +01:00
|
|
|
let ctrlc = engine_state.ctrlc.clone();
|
2021-12-13 04:16:51 +01:00
|
|
|
let config = stack.get_config().unwrap_or_default();
|
2021-11-20 14:12:35 +01:00
|
|
|
let color_hm = get_color_config(&config);
|
2021-12-23 22:41:29 +01:00
|
|
|
let start_num: Option<i64> = call.get_flag(engine_state, stack, "start_number")?;
|
|
|
|
let row_offset = start_num.unwrap_or_default() as usize;
|
2021-11-09 07:14:00 +01:00
|
|
|
|
2021-10-08 15:14:32 +02:00
|
|
|
let term_width = if let Some((Width(w), Height(_h))) = terminal_size::terminal_size() {
|
2021-11-18 06:48:15 +01:00
|
|
|
(w - 1) as usize
|
2021-10-08 15:14:32 +02:00
|
|
|
} else {
|
|
|
|
80usize
|
|
|
|
};
|
|
|
|
|
2021-09-29 20:25:05 +02:00
|
|
|
match input {
|
2021-12-24 08:22:11 +01:00
|
|
|
PipelineData::ByteStream(stream, ..) => Ok(PipelineData::StringStream(
|
|
|
|
StringStream::from_stream(
|
|
|
|
stream.map(move |x| {
|
|
|
|
Ok(if x.iter().all(|x| x.is_ascii()) {
|
2021-12-24 20:24:55 +01:00
|
|
|
format!("{}", String::from_utf8_lossy(&x?))
|
2021-12-24 08:22:11 +01:00
|
|
|
} else {
|
2021-12-24 20:24:55 +01:00
|
|
|
format!("{}\n", nu_pretty_hex::pretty_hex(&x?))
|
2021-12-24 08:22:11 +01:00
|
|
|
})
|
|
|
|
}),
|
|
|
|
ctrlc,
|
|
|
|
),
|
|
|
|
head,
|
|
|
|
None,
|
|
|
|
)),
|
2021-12-24 19:15:01 +01:00
|
|
|
PipelineData::Value(Value::Binary { val, .. }, ..) => Ok(PipelineData::StringStream(
|
|
|
|
StringStream::from_stream(
|
|
|
|
vec![Ok(if val.iter().all(|x| x.is_ascii()) {
|
|
|
|
format!("{}", String::from_utf8_lossy(&val))
|
|
|
|
} else {
|
|
|
|
format!("{}\n", nu_pretty_hex::pretty_hex(&val))
|
|
|
|
})]
|
|
|
|
.into_iter(),
|
|
|
|
ctrlc,
|
|
|
|
),
|
|
|
|
head,
|
|
|
|
None,
|
|
|
|
)),
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(Value::List { vals, .. }, ..) => {
|
2021-12-23 22:41:29 +01:00
|
|
|
let table = convert_to_table(row_offset, &vals, ctrlc, &config, call.head)?;
|
2021-09-29 20:25:05 +02:00
|
|
|
|
|
|
|
if let Some(table) = table {
|
2021-12-01 20:20:23 +01:00
|
|
|
let result = nu_table::draw_table(&table, term_width, &color_hm, &config);
|
2021-09-29 20:25:05 +02:00
|
|
|
|
|
|
|
Ok(Value::String {
|
|
|
|
val: result,
|
|
|
|
span: call.head,
|
2021-10-25 06:24:10 +02:00
|
|
|
}
|
|
|
|
.into_pipeline_data())
|
2021-09-29 20:25:05 +02:00
|
|
|
} else {
|
2021-11-06 06:50:33 +01:00
|
|
|
Ok(PipelineData::new(call.head))
|
2021-09-29 20:25:05 +02:00
|
|
|
}
|
|
|
|
}
|
2021-12-24 08:22:11 +01:00
|
|
|
PipelineData::ListStream(stream, metadata) => {
|
2021-12-02 06:59:10 +01:00
|
|
|
let stream = match metadata {
|
|
|
|
Some(PipelineMetadata {
|
|
|
|
data_source: DataSource::Ls,
|
|
|
|
}) => {
|
|
|
|
let config = config.clone();
|
|
|
|
let ctrlc = ctrlc.clone();
|
|
|
|
|
2022-01-04 23:30:34 +01:00
|
|
|
let ls_colors = match stack.get_env_var(engine_state, "LS_COLORS") {
|
2021-12-17 02:04:54 +01:00
|
|
|
Some(v) => LsColors::from_string(&env_to_string(
|
|
|
|
"LS_COLORS",
|
|
|
|
v,
|
|
|
|
engine_state,
|
|
|
|
stack,
|
|
|
|
&config,
|
|
|
|
)?),
|
2022-01-08 15:30:48 +01:00
|
|
|
None => LsColors::from_string("pi=0;38;2;0;0;0;48;2;102;217;239:so=0;38;2;0;0;0;48;2;249;38;114:*~=0;38;2;122;112;112:ex=1;38;2;249;38;114:ln=0;38;2;249;38;114:fi=0:or=0;38;2;0;0;0;48;2;255;74;68:di=0;38;2;102;217;239:no=0:mi=0;38;2;0;0;0;48;2;255;74;68:*.r=0;38;2;0;255;135:*.o=0;38;2;122;112;112:*.h=0;38;2;0;255;135:*.p=0;38;2;0;255;135:*.t=0;38;2;0;255;135:*.a=1;38;2;249;38;114:*.z=4;38;2;249;38;114:*.m=0;38;2;0;255;135:*.c=0;38;2;0;255;135:*.d=0;38;2;0;255;135:*.pl=0;38;2;0;255;135:*.pm=0;38;2;0;255;135:*.pp=0;38;2;0;255;135:*.ko=1;38;2;249;38;114:*.ui=0;38;2;166;226;46:*.ps=0;38;2;230;219;116:*.di=0;38;2;0;255;135:*.sh=0;38;2;0;255;135:*.rb=0;38;2;0;255;135:*.cc=0;38;2;0;255;135:*.cr=0;38;2;0;255;135:*.hi=0;38;2;122;112;112:*.xz=4;38;2;249;38;114:*.go=0;38;2;0;255;135:*.bz=4;38;2;249;38;114:*.7z=4;38;2;249;38;114:*.rm=0;38;2;253;151;31:*.cp=0;38;2;0;255;135:*.hh=0;38;2;0;255;135:*.cs=0;38;2;0;255;135:*.el=0;38;2;0;255;135:*.kt=0;38;2;0;255;135:*.py=0;38;2;0;255;135:*.mn=0;38;2;0;255;135:*.hs=0;38;2;0;255;135:*.la=0;38;2;122;112;112:*.vb=0;38;2;0;255;135:*.md=0;38;2;226;209;57:*.rs=0;38;2;0;255;135:*.ml=0;38;2;0;255;135:*.so=1;38;2;249;38;114:*.ts=0;38;2;0;255;135:*.as=0;38;2;0;255;135:*.gz=4;38;2;249;38;114:*.ex=0;38;2;0;255;135:*.jl=0;38;2;0;255;135:*css=0;38;2;0;255;135:*.gv=0;38;2;0;255;135:*.js=0;38;2;0;255;135:*.nb=0;38;2;0;255;135:*.fs=0;38;2;0;255;135:*.lo=0;38;2;122;112;112:*.tml=0;38;2;166;226;46:*.pro=0;38;2;166;226;46:*.pas=0;38;2;0;255;135:*.bin=4;38;2;249;38;114:*.xcf=0;38;2;253;151;31:*.ini=0;38;2;166;226;46:*.fsi=0;38;2;0;255;135:*.ics=0;38;2;230;219;116:*.sbt=0;38;2;0;255;135:*.tar=4;38;2;249;38;114:*.deb=4;38;2;249;38;114:*.cgi=0;38;2;0;255;135:*.xmp=0;38;2;166;226;46:*.hxx=0;38;2;0;255;135:*.cfg=0;38;2;166;226;46:*.bag=4;38;2;249;38;114:*.ppt=0;38;2;230;219;116:*.asa=0;38;2;0;255;135:*.xls=0;38;2;230;219;116:*.htm=0;38;2;226;209;57:*.h++=0;38;2;0;255;135:*.hpp=0;38;2;0;255;135:*.tex=0;38;2;0;255;135:*.tmp=0;38;2;122;112;112:*.erl=0;38;2;0;255;135:*.cxx=0;38;2;0;255;135:*.inl=0;38;2;0;255;135:*.elm=0;38;2;0;255;135:*.kts=0;38;2;0;255;135:*.bz2=4;38;2;249;38;114:*.arj=4;38;2;249;38;114:*.dmg=4;38;2;249;38;114:*.vcd=4;38;2;249;38;114:*.ipp=0;38;2;0;255;135:*TODO=1:*.m4v=0;38;2;253;151;31:*.git=0;38;2;122;112;112:*.pod=0;38;2;0;255;135:*.svg=0;38;2;253;151;31:*.log=0;38;2;122;112;112:*.pgm=0;38;2;253;151;31:*.vim=0;38;2;0;255;135:*.bib=0;38;2;166;226;46:*.rpm=4;38;2;249;38;114:*.mpg=0;38;2;253;151;31:*.dpr=0;38;2;0;255;135:*.aux=0;38;2;122;112;112:*.tsx=0;38;2;0;255;135:*.odt=0;38;2;230;219;116:*.mli=0;38;2;0;255;135:*.ps1=0;38;2;0;255;135:*.cpp=0;38;2;0;255;135:*.flv=0;38;2;253;151;31:*.fsx=0;38;2;0;255;135:*.tif=0;38;2;253;151;31:*.blg=0;38;2;122;112;112:*.sty=0;38;2;122;112;112:*.bak=0;38;2;122;112;112:*.zip=4;38;2;249;38;114:*.sxw=0;38;2;230;219;116:*.clj=0;38;2;0;255;135:*.mkv=0;38;2;253;151;31:*.doc=0;38;2;230;219;116:*.dox=0;38;2;166;226;46:*.swf=0;38;2;253;151;31:*.rst=0;38;2;226;209;57:*.png=0;38;2;253;151;31:*.pid=0;38;2;122;112;112:*.nix=0;38;2;166;226;46:*.aif=0;38;2;253;151;31:*.ogg=0;38;2;253;151;31:*.tgz=4;38;2;249;38;114:*.otf=0;38;2;253;151;31:*.img=4;38;2;249;38;114:*.txt=0;38;2;226;209;57:*.epp=0;38;2;0;255;135:*.jpg=0;38;2;253;151;31:*.c++=0;38;2;0;255;135:*.ppm=0;38;2;253;151;31:*.dll=1;38;2;249;38;114:*.tcl=0;38;2;0;255;135:*.sxi=0;38;2;230;219;116:*.bat=1;38;2;249;38;114:*.mid=0;38;2;253;151;31:*.vob=0;38;2;253;151;31:*.csx=0;38;2;0;255;135:*.idx=0;38;2;122;112;112:*.wma=0;38;2;253;151;31:*hgrc=0;38;2;166;226;46:*.fls=0;38;2;122;112;112:*.lua=0;38;2;0;255;135:*.pkg=4;38;2;249;38;114:*.csv=0;38;2;226;209;57:*.wmv=0;38;2;253;151;31:*.fon=0;38;2;253;151;31:*.avi=0;38;2;253;151;31:*.pps=0;38;2;230;219;116:*.swp=0;38;2;122;112;112:*.iso=4;38;2;249;38;114:*.bcf=0;38;2;122;112;112:*.exe=1;38;2;249;38;114:*.bmp=0;38;2;253;151;31:*.pyc=0;38;2;122;112;112:*.apk=4;38;2;249;38;114:*.ttf=0;38;2;253;151;31:*.yml=0;38;2;166;226;46:*.rar=4;38;2;249;38;114:*.zsh=0;38;2;0;255;135:*.xml=0;38;2;226;209;57:*.htc=0;38;2;0;255;135:*.kex=0;38;2;230;219;116:*.com=1;38;2;249;38
|
2021-12-02 06:59:10 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
ValueStream::from_stream(
|
|
|
|
stream.map(move |mut x| match &mut x {
|
|
|
|
Value::Record { cols, vals, .. } => {
|
|
|
|
let mut idx = 0;
|
|
|
|
|
|
|
|
while idx < cols.len() {
|
|
|
|
if cols[idx] == "name" {
|
|
|
|
if let Some(Value::String { val: path, span }) =
|
|
|
|
vals.get(idx)
|
|
|
|
{
|
|
|
|
match std::fs::symlink_metadata(&path) {
|
|
|
|
Ok(metadata) => {
|
|
|
|
let style = ls_colors
|
|
|
|
.style_for_path_with_metadata(
|
|
|
|
path.clone(),
|
|
|
|
Some(&metadata),
|
|
|
|
);
|
|
|
|
let ansi_style = style
|
|
|
|
.map(Style::to_crossterm_style)
|
|
|
|
.unwrap_or_default();
|
|
|
|
let use_ls_colors = config.use_ls_colors;
|
|
|
|
|
|
|
|
if use_ls_colors {
|
|
|
|
vals[idx] = Value::String {
|
|
|
|
val: ansi_style
|
|
|
|
.apply(path)
|
|
|
|
.to_string(),
|
|
|
|
span: *span,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(_) => {
|
|
|
|
let style =
|
|
|
|
ls_colors.style_for_path(path.clone());
|
|
|
|
let ansi_style = style
|
|
|
|
.map(Style::to_crossterm_style)
|
|
|
|
.unwrap_or_default();
|
|
|
|
let use_ls_colors = config.use_ls_colors;
|
|
|
|
|
|
|
|
if use_ls_colors {
|
|
|
|
vals[idx] = Value::String {
|
|
|
|
val: ansi_style
|
|
|
|
.apply(path)
|
|
|
|
.to_string(),
|
|
|
|
span: *span,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
idx += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
x
|
|
|
|
}
|
|
|
|
_ => x,
|
|
|
|
}),
|
|
|
|
ctrlc,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
_ => stream,
|
|
|
|
};
|
|
|
|
|
2021-12-03 07:15:23 +01:00
|
|
|
let head = call.head;
|
2021-09-29 20:25:05 +02:00
|
|
|
|
2021-12-24 08:22:11 +01:00
|
|
|
Ok(PipelineData::StringStream(
|
|
|
|
StringStream::from_stream(
|
|
|
|
PagingTableCreator {
|
|
|
|
row_offset,
|
|
|
|
config,
|
|
|
|
ctrlc: ctrlc.clone(),
|
|
|
|
head,
|
|
|
|
stream,
|
|
|
|
},
|
|
|
|
ctrlc,
|
|
|
|
),
|
2021-12-03 07:15:23 +01:00
|
|
|
head,
|
2021-12-24 08:22:11 +01:00
|
|
|
None,
|
|
|
|
))
|
2021-09-29 20:25:05 +02:00
|
|
|
}
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(Value::Record { cols, vals, .. }, ..) => {
|
2021-10-01 08:01:22 +02:00
|
|
|
let mut output = vec![];
|
|
|
|
|
|
|
|
for (c, v) in cols.into_iter().zip(vals.into_iter()) {
|
|
|
|
output.push(vec![
|
|
|
|
StyledString {
|
|
|
|
contents: c,
|
2021-11-20 14:12:35 +01:00
|
|
|
style: TextStyle::default_field(),
|
2021-10-01 08:01:22 +02:00
|
|
|
},
|
|
|
|
StyledString {
|
2021-12-02 22:07:44 +01:00
|
|
|
contents: v.into_abbreviated_string(&config),
|
2021-11-20 14:12:35 +01:00
|
|
|
style: TextStyle::default(),
|
2021-10-01 08:01:22 +02:00
|
|
|
},
|
|
|
|
])
|
|
|
|
}
|
|
|
|
|
|
|
|
let table = nu_table::Table {
|
|
|
|
headers: vec![],
|
|
|
|
data: output,
|
2021-11-14 20:25:57 +01:00
|
|
|
theme: load_theme_from_config(&config),
|
2021-10-01 08:01:22 +02:00
|
|
|
};
|
|
|
|
|
2021-12-01 20:20:23 +01:00
|
|
|
let result = nu_table::draw_table(&table, term_width, &color_hm, &config);
|
2021-10-01 08:01:22 +02:00
|
|
|
|
|
|
|
Ok(Value::String {
|
|
|
|
val: result,
|
|
|
|
span: call.head,
|
2021-10-25 06:24:10 +02:00
|
|
|
}
|
|
|
|
.into_pipeline_data())
|
2021-10-01 08:01:22 +02:00
|
|
|
}
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(Value::Error { error }, ..) => Err(error),
|
|
|
|
PipelineData::Value(Value::CustomValue { val, span }, ..) => {
|
2021-11-23 09:14:40 +01:00
|
|
|
let base_pipeline = val.to_base_value(span)?.into_pipeline_data();
|
|
|
|
self.run(engine_state, stack, call, base_pipeline)
|
|
|
|
}
|
2021-09-29 20:25:05 +02:00
|
|
|
x => Ok(x),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 19:35:40 +02:00
|
|
|
fn convert_to_table(
|
2021-12-03 07:15:23 +01:00
|
|
|
row_offset: usize,
|
2021-12-20 22:03:47 +01:00
|
|
|
input: &[Value],
|
2021-11-09 07:14:00 +01:00
|
|
|
ctrlc: Option<Arc<AtomicBool>>,
|
2021-11-14 20:25:57 +01:00
|
|
|
config: &Config,
|
2021-12-19 08:46:13 +01:00
|
|
|
head: Span,
|
2021-10-11 19:35:40 +02:00
|
|
|
) -> Result<Option<nu_table::Table>, ShellError> {
|
2021-12-20 22:03:47 +01:00
|
|
|
let mut headers = get_columns(input);
|
|
|
|
let mut input = input.iter().peekable();
|
2021-12-07 21:06:14 +01:00
|
|
|
let color_hm = get_color_config(config);
|
|
|
|
let float_precision = config.float_precision as usize;
|
2021-09-29 20:25:05 +02:00
|
|
|
|
2021-12-20 22:03:47 +01:00
|
|
|
if input.peek().is_some() {
|
2021-09-29 20:25:05 +02:00
|
|
|
if !headers.is_empty() {
|
|
|
|
headers.insert(0, "#".into());
|
|
|
|
}
|
|
|
|
|
2021-11-20 14:12:35 +01:00
|
|
|
// Vec of Vec of String1, String2 where String1 is datatype and String2 is value
|
|
|
|
let mut data: Vec<Vec<(String, String)>> = Vec::new();
|
2021-09-29 20:25:05 +02:00
|
|
|
|
2021-12-20 22:03:47 +01:00
|
|
|
for (row_num, item) in input.enumerate() {
|
2021-11-09 07:14:00 +01:00
|
|
|
if let Some(ctrlc) = &ctrlc {
|
|
|
|
if ctrlc.load(Ordering::SeqCst) {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
}
|
2021-10-11 19:35:40 +02:00
|
|
|
if let Value::Error { error } = item {
|
2021-12-20 22:03:47 +01:00
|
|
|
return Err(error.clone());
|
2021-10-11 19:35:40 +02:00
|
|
|
}
|
2021-11-20 14:12:35 +01:00
|
|
|
// String1 = datatype, String2 = value as string
|
2021-12-03 07:15:23 +01:00
|
|
|
let mut row: Vec<(String, String)> =
|
|
|
|
vec![("string".to_string(), (row_num + row_offset).to_string())];
|
2021-09-29 20:25:05 +02:00
|
|
|
|
2021-12-21 10:05:16 +01:00
|
|
|
if headers.is_empty() {
|
|
|
|
// if header row is empty, this is probably a list so format it that way
|
|
|
|
row.push(("list".to_string(), item.into_abbreviated_string(config)))
|
|
|
|
} else {
|
|
|
|
for header in headers.iter().skip(1) {
|
|
|
|
let result = match item {
|
|
|
|
Value::Record { .. } => {
|
|
|
|
item.clone().follow_cell_path(&[PathMember::String {
|
|
|
|
val: header.into(),
|
|
|
|
span: head,
|
|
|
|
}])
|
|
|
|
}
|
|
|
|
_ => Ok(item.clone()),
|
|
|
|
};
|
|
|
|
|
|
|
|
match result {
|
|
|
|
Ok(value) => row.push((
|
|
|
|
(&value.get_type()).to_string(),
|
|
|
|
value.into_abbreviated_string(config),
|
|
|
|
)),
|
|
|
|
Err(_) => row.push(("empty".to_string(), "❎".into())),
|
|
|
|
}
|
2021-09-29 20:25:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
data.push(row);
|
|
|
|
}
|
|
|
|
|
2021-10-11 19:35:40 +02:00
|
|
|
Ok(Some(nu_table::Table {
|
2021-09-29 20:25:05 +02:00
|
|
|
headers: headers
|
|
|
|
.into_iter()
|
|
|
|
.map(|x| StyledString {
|
|
|
|
contents: x,
|
2021-11-20 14:12:35 +01:00
|
|
|
style: TextStyle {
|
|
|
|
alignment: nu_table::Alignment::Center,
|
|
|
|
color_style: Some(color_hm["header"]),
|
|
|
|
},
|
2021-09-29 20:25:05 +02:00
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
data: data
|
|
|
|
.into_iter()
|
|
|
|
.map(|x| {
|
|
|
|
x.into_iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(col, y)| {
|
|
|
|
if col == 0 {
|
|
|
|
StyledString {
|
2021-11-20 14:12:35 +01:00
|
|
|
contents: y.1,
|
|
|
|
style: TextStyle {
|
2021-12-01 16:17:50 +01:00
|
|
|
alignment: nu_table::Alignment::Right,
|
|
|
|
color_style: Some(color_hm["row_index"]),
|
2021-11-20 14:12:35 +01:00
|
|
|
},
|
2021-09-29 20:25:05 +02:00
|
|
|
}
|
2021-12-07 21:06:14 +01:00
|
|
|
} else if &y.0 == "float" {
|
|
|
|
// set dynamic precision from config
|
|
|
|
let precise_number =
|
|
|
|
match convert_with_precision(&y.1, float_precision) {
|
|
|
|
Ok(num) => num,
|
|
|
|
Err(e) => e.to_string(),
|
|
|
|
};
|
|
|
|
StyledString {
|
|
|
|
contents: precise_number,
|
|
|
|
style: style_primitive(&y.0, &color_hm),
|
|
|
|
}
|
2021-09-29 20:25:05 +02:00
|
|
|
} else {
|
|
|
|
StyledString {
|
2021-11-20 14:12:35 +01:00
|
|
|
contents: y.1,
|
|
|
|
style: style_primitive(&y.0, &color_hm),
|
2021-09-29 20:25:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<Vec<StyledString>>()
|
|
|
|
})
|
|
|
|
.collect(),
|
2021-11-14 20:25:57 +01:00
|
|
|
theme: load_theme_from_config(config),
|
2021-10-11 19:35:40 +02:00
|
|
|
}))
|
2021-09-29 20:25:05 +02:00
|
|
|
} else {
|
2021-10-11 19:35:40 +02:00
|
|
|
Ok(None)
|
2021-09-29 20:25:05 +02:00
|
|
|
}
|
|
|
|
}
|
2021-11-14 20:25:57 +01:00
|
|
|
|
2021-12-07 21:06:14 +01:00
|
|
|
fn convert_with_precision(val: &str, precision: usize) -> Result<String, ShellError> {
|
|
|
|
// vall will always be a f64 so convert it with precision formatting
|
|
|
|
let val_float = match val.trim().parse::<f64>() {
|
|
|
|
Ok(f) => f,
|
|
|
|
Err(e) => {
|
|
|
|
return Err(ShellError::LabeledError(
|
|
|
|
format!("error converting string [{}] to f64", &val),
|
|
|
|
e.to_string(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Ok(format!("{:.prec$}", val_float, prec = precision))
|
|
|
|
}
|
|
|
|
|
2021-12-03 07:15:23 +01:00
|
|
|
struct PagingTableCreator {
|
|
|
|
head: Span,
|
|
|
|
stream: ValueStream,
|
|
|
|
ctrlc: Option<Arc<AtomicBool>>,
|
|
|
|
config: Config,
|
|
|
|
row_offset: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Iterator for PagingTableCreator {
|
2021-12-24 08:22:11 +01:00
|
|
|
type Item = Result<String, ShellError>;
|
2021-12-03 07:15:23 +01:00
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
let mut batch = vec![];
|
|
|
|
|
|
|
|
let start_time = Instant::now();
|
|
|
|
|
|
|
|
let mut idx = 0;
|
|
|
|
|
|
|
|
// Pull from stream until time runs out or we have enough items
|
|
|
|
for item in self.stream.by_ref() {
|
|
|
|
batch.push(item);
|
|
|
|
idx += 1;
|
|
|
|
|
|
|
|
if idx % STREAM_TIMEOUT_CHECK_INTERVAL == 0 {
|
|
|
|
let end_time = Instant::now();
|
|
|
|
|
|
|
|
// If we've been buffering over a second, go ahead and send out what we have so far
|
|
|
|
if (end_time - start_time).as_secs() >= 1 {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if idx == STREAM_PAGE_SIZE {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(ctrlc) = &self.ctrlc {
|
|
|
|
if ctrlc.load(Ordering::SeqCst) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let color_hm = get_color_config(&self.config);
|
|
|
|
|
|
|
|
let term_width = if let Some((Width(w), Height(_h))) = terminal_size::terminal_size() {
|
|
|
|
(w - 1) as usize
|
|
|
|
} else {
|
|
|
|
80usize
|
|
|
|
};
|
|
|
|
|
|
|
|
let table = convert_to_table(
|
|
|
|
self.row_offset,
|
2021-12-20 22:03:47 +01:00
|
|
|
&batch,
|
2021-12-03 07:15:23 +01:00
|
|
|
self.ctrlc.clone(),
|
|
|
|
&self.config,
|
2021-12-19 08:46:13 +01:00
|
|
|
self.head,
|
2021-12-03 07:15:23 +01:00
|
|
|
);
|
|
|
|
self.row_offset += idx;
|
|
|
|
|
|
|
|
match table {
|
|
|
|
Ok(Some(table)) => {
|
|
|
|
let result = nu_table::draw_table(&table, term_width, &color_hm, &self.config);
|
|
|
|
|
2021-12-24 08:22:11 +01:00
|
|
|
Some(Ok(result))
|
2021-12-03 07:15:23 +01:00
|
|
|
}
|
2021-12-24 08:22:11 +01:00
|
|
|
Err(err) => Some(Err(err)),
|
2021-12-03 07:15:23 +01:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-14 20:25:57 +01:00
|
|
|
fn load_theme_from_config(config: &Config) -> Theme {
|
|
|
|
match config.table_mode.as_str() {
|
|
|
|
"basic" => nu_table::Theme::basic(),
|
|
|
|
"compact" => nu_table::Theme::compact(),
|
|
|
|
"compact_double" => nu_table::Theme::compact_double(),
|
|
|
|
"light" => nu_table::Theme::light(),
|
|
|
|
"with_love" => nu_table::Theme::with_love(),
|
|
|
|
"rounded" => nu_table::Theme::rounded(),
|
|
|
|
"reinforced" => nu_table::Theme::reinforced(),
|
|
|
|
"heavy" => nu_table::Theme::heavy(),
|
|
|
|
"none" => nu_table::Theme::none(),
|
|
|
|
_ => nu_table::Theme::rounded(),
|
|
|
|
}
|
|
|
|
}
|