2021-11-29 21:37:09 +01:00
|
|
|
// use super::icons::{icon_for_file, iconify_style_ansi_to_nu};
|
|
|
|
use super::icons::icon_for_file;
|
2021-10-08 16:40:20 +02:00
|
|
|
use lscolors::{LsColors, Style};
|
2021-12-17 02:04:54 +01:00
|
|
|
use nu_engine::env_to_string;
|
2021-10-05 15:43:20 +02:00
|
|
|
use nu_engine::CallExt;
|
|
|
|
use nu_protocol::{
|
|
|
|
ast::{Call, PathMember},
|
2021-10-25 18:58:58 +02:00
|
|
|
engine::{Command, EngineState, Stack},
|
2021-12-04 13:38:21 +01:00
|
|
|
Category, Config, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
|
|
|
Value,
|
2021-10-05 15:43:20 +02:00
|
|
|
};
|
2021-10-07 17:32:39 +02:00
|
|
|
use nu_term_grid::grid::{Alignment, Cell, Direction, Filling, Grid, GridOptions};
|
2021-10-07 18:00:49 +02:00
|
|
|
use terminal_size::{Height, Width};
|
2021-10-05 15:43:20 +02:00
|
|
|
|
2021-10-25 06:01:02 +02:00
|
|
|
#[derive(Clone)]
|
2021-10-05 15:43:20 +02:00
|
|
|
pub struct Griddle;
|
|
|
|
|
|
|
|
impl Command for Griddle {
|
|
|
|
fn name(&self) -> &str {
|
|
|
|
"grid"
|
|
|
|
}
|
|
|
|
|
|
|
|
fn usage(&self) -> &str {
|
2021-10-08 15:14:32 +02:00
|
|
|
"Renders the output to a textual terminal grid."
|
2021-10-05 15:43:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn signature(&self) -> nu_protocol::Signature {
|
2021-10-08 16:53:26 +02:00
|
|
|
Signature::build("grid")
|
|
|
|
.named(
|
|
|
|
"width",
|
|
|
|
SyntaxShape::Int,
|
|
|
|
"number of columns wide",
|
|
|
|
Some('w'),
|
|
|
|
)
|
|
|
|
.switch("color", "draw output with color", Some('c'))
|
2021-10-08 17:15:07 +02:00
|
|
|
.named(
|
|
|
|
"separator",
|
|
|
|
SyntaxShape::String,
|
|
|
|
"character to separate grid with",
|
|
|
|
Some('s'),
|
|
|
|
)
|
2021-11-17 05:22:37 +01:00
|
|
|
.category(Category::Viewers)
|
2021-10-05 15:43:20 +02:00
|
|
|
}
|
|
|
|
|
2021-10-08 15:14:32 +02:00
|
|
|
fn extra_usage(&self) -> &str {
|
|
|
|
r#"grid was built to give a concise gridded layout for ls. however,
|
|
|
|
it determines what to put in the grid by looking for a column named
|
|
|
|
'name'. this works great for tables and records but for lists we
|
|
|
|
need to do something different. such as with '[one two three] | grid'
|
|
|
|
it creates a fake column called 'name' for these values so that it
|
|
|
|
prints out the list properly."#
|
|
|
|
}
|
|
|
|
|
2021-10-05 15:43:20 +02:00
|
|
|
fn run(
|
|
|
|
&self,
|
2021-10-25 08:31:39 +02:00
|
|
|
engine_state: &EngineState,
|
|
|
|
stack: &mut Stack,
|
2021-10-05 15:43:20 +02:00
|
|
|
call: &Call,
|
2021-10-25 06:24:10 +02:00
|
|
|
input: PipelineData,
|
|
|
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
2021-10-25 08:31:39 +02:00
|
|
|
let width_param: Option<String> = call.get_flag(engine_state, stack, "width")?;
|
2021-10-08 16:53:26 +02:00
|
|
|
let color_param: bool = call.has_flag("color");
|
2021-10-25 08:31:39 +02:00
|
|
|
let separator_param: Option<String> = call.get_flag(engine_state, stack, "separator")?;
|
2021-12-13 04:16:51 +01:00
|
|
|
let config = stack.get_config().unwrap_or_default();
|
2022-01-04 23:30:34 +01:00
|
|
|
let env_str = match stack.get_env_var(engine_state, "LS_COLORS") {
|
2021-12-17 02:04:54 +01:00
|
|
|
Some(v) => Some(env_to_string("LS_COLORS", v, engine_state, stack, &config)?),
|
|
|
|
None => None,
|
|
|
|
};
|
2021-11-29 21:37:09 +01:00
|
|
|
let use_grid_icons = config.use_grid_icons;
|
2021-11-21 00:14:42 +01:00
|
|
|
|
2021-10-05 15:43:20 +02:00
|
|
|
match input {
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(Value::List { vals, .. }, ..) => {
|
2021-10-07 18:00:49 +02:00
|
|
|
// dbg!("value::list");
|
2021-12-19 08:46:13 +01:00
|
|
|
let data = convert_to_list(vals, &config, call.head);
|
2021-10-07 18:00:49 +02:00
|
|
|
if let Some(items) = data {
|
2021-11-29 21:37:09 +01:00
|
|
|
Ok(create_grid_output(
|
2021-10-08 17:15:07 +02:00
|
|
|
items,
|
|
|
|
call,
|
|
|
|
width_param,
|
|
|
|
color_param,
|
2021-10-11 16:32:06 +02:00
|
|
|
separator_param,
|
2021-11-21 00:14:42 +01:00
|
|
|
env_str,
|
2021-11-29 21:37:09 +01:00
|
|
|
use_grid_icons,
|
2021-12-04 13:38:21 +01:00
|
|
|
)?)
|
2021-10-07 18:00:49 +02:00
|
|
|
} else {
|
2021-11-06 06:50:33 +01:00
|
|
|
Ok(PipelineData::new(call.head))
|
2021-10-07 18:00:49 +02:00
|
|
|
}
|
2021-10-05 15:43:20 +02:00
|
|
|
}
|
2021-12-24 08:22:11 +01:00
|
|
|
PipelineData::ListStream(stream, ..) => {
|
2021-10-05 15:43:20 +02:00
|
|
|
// dbg!("value::stream");
|
2021-12-19 08:46:13 +01:00
|
|
|
let data = convert_to_list(stream, &config, call.head);
|
2021-10-07 18:00:49 +02:00
|
|
|
if let Some(items) = data {
|
2021-11-29 21:37:09 +01:00
|
|
|
Ok(create_grid_output(
|
2021-10-08 17:15:07 +02:00
|
|
|
items,
|
|
|
|
call,
|
|
|
|
width_param,
|
|
|
|
color_param,
|
2021-10-11 16:32:06 +02:00
|
|
|
separator_param,
|
2021-11-21 00:14:42 +01:00
|
|
|
env_str,
|
2021-11-29 21:37:09 +01:00
|
|
|
use_grid_icons,
|
2021-12-04 13:38:21 +01:00
|
|
|
)?)
|
2021-10-05 15:43:20 +02:00
|
|
|
} else {
|
|
|
|
// dbg!(data);
|
2021-11-06 06:50:33 +01:00
|
|
|
Ok(PipelineData::new(call.head))
|
2021-10-05 15:43:20 +02:00
|
|
|
}
|
|
|
|
}
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(Value::Record { cols, vals, .. }, ..) => {
|
2021-10-07 23:50:27 +02:00
|
|
|
// dbg!("value::record");
|
|
|
|
let mut items = vec![];
|
2021-10-05 15:43:20 +02:00
|
|
|
|
2021-10-07 23:50:27 +02:00
|
|
|
for (i, (c, v)) in cols.into_iter().zip(vals.into_iter()).enumerate() {
|
2021-11-14 20:25:57 +01:00
|
|
|
items.push((i, c, v.into_string(", ", &config)))
|
2021-10-07 23:50:27 +02:00
|
|
|
}
|
2021-10-05 15:43:20 +02:00
|
|
|
|
2021-11-29 21:37:09 +01:00
|
|
|
Ok(create_grid_output(
|
2021-10-08 17:15:07 +02:00
|
|
|
items,
|
|
|
|
call,
|
|
|
|
width_param,
|
|
|
|
color_param,
|
2021-10-11 16:32:06 +02:00
|
|
|
separator_param,
|
2021-11-21 00:14:42 +01:00
|
|
|
env_str,
|
2021-11-29 21:37:09 +01:00
|
|
|
use_grid_icons,
|
2021-12-04 13:38:21 +01:00
|
|
|
)?)
|
2021-10-05 15:43:20 +02:00
|
|
|
}
|
2021-10-07 18:00:49 +02:00
|
|
|
x => {
|
|
|
|
// dbg!("other value");
|
|
|
|
// dbg!(x.get_type());
|
|
|
|
Ok(x)
|
|
|
|
}
|
2021-10-05 15:43:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-29 21:37:09 +01:00
|
|
|
fn strip_ansi(astring: &str) -> String {
|
|
|
|
if let Ok(bytes) = strip_ansi_escapes::strip(astring) {
|
|
|
|
String::from_utf8_lossy(&bytes).to_string()
|
|
|
|
} else {
|
|
|
|
astring.to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn create_grid_output(
|
2021-10-07 23:50:27 +02:00
|
|
|
items: Vec<(usize, String, String)>,
|
|
|
|
call: &Call,
|
2021-10-08 16:53:26 +02:00
|
|
|
width_param: Option<String>,
|
|
|
|
color_param: bool,
|
2021-10-08 17:15:07 +02:00
|
|
|
separator_param: Option<String>,
|
2021-11-21 00:14:42 +01:00
|
|
|
env_str: Option<String>,
|
2021-11-29 21:37:09 +01:00
|
|
|
use_grid_icons: bool,
|
2021-12-04 13:38:21 +01:00
|
|
|
) -> Result<PipelineData, ShellError> {
|
2021-11-21 00:14:42 +01:00
|
|
|
let ls_colors = match env_str {
|
|
|
|
Some(s) => LsColors::from_string(&s),
|
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;114:*.fnt=0;38;2;25
|
2021-11-21 00:14:42 +01:00
|
|
|
};
|
|
|
|
|
2021-10-08 17:15:07 +02:00
|
|
|
let cols = if let Some(col) = width_param {
|
|
|
|
col.parse::<u16>().unwrap_or(80)
|
|
|
|
} else if let Some((Width(w), Height(_h))) = terminal_size::terminal_size() {
|
|
|
|
w
|
|
|
|
} else {
|
|
|
|
80u16
|
|
|
|
};
|
2021-10-11 16:32:06 +02:00
|
|
|
let sep = if let Some(separator) = separator_param {
|
|
|
|
separator
|
2021-10-08 17:15:07 +02:00
|
|
|
} else {
|
|
|
|
" │ ".to_string()
|
|
|
|
};
|
|
|
|
|
2021-10-07 23:50:27 +02:00
|
|
|
let mut grid = Grid::new(GridOptions {
|
|
|
|
direction: Direction::TopToBottom,
|
2021-10-08 17:15:07 +02:00
|
|
|
filling: Filling::Text(sep),
|
2021-10-07 23:50:27 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
for (_row_index, header, value) in items {
|
|
|
|
// only output value if the header name is 'name'
|
|
|
|
if header == "name" {
|
2021-10-08 16:53:26 +02:00
|
|
|
if color_param {
|
2021-11-29 21:37:09 +01:00
|
|
|
if use_grid_icons {
|
|
|
|
let no_ansi = strip_ansi(&value);
|
|
|
|
let path = std::path::Path::new(&no_ansi);
|
2021-12-19 08:46:13 +01:00
|
|
|
let icon = icon_for_file(path, call.head)?;
|
2021-11-29 21:37:09 +01:00
|
|
|
let ls_colors_style = ls_colors.style_for_path(path);
|
|
|
|
// eprintln!("ls_colors_style: {:?}", &ls_colors_style);
|
|
|
|
|
|
|
|
let icon_style = match ls_colors_style {
|
|
|
|
Some(c) => c.to_crossterm_style(),
|
|
|
|
None => crossterm::style::ContentStyle::default(),
|
|
|
|
};
|
|
|
|
// eprintln!("icon_style: {:?}", &icon_style);
|
|
|
|
|
|
|
|
let ansi_style = ls_colors_style
|
|
|
|
.map(Style::to_crossterm_style)
|
|
|
|
.unwrap_or_default();
|
|
|
|
// eprintln!("ansi_style: {:?}", &ansi_style);
|
|
|
|
|
|
|
|
let item = format!(
|
|
|
|
"{} {}",
|
|
|
|
icon_style.apply(icon).to_string(),
|
|
|
|
ansi_style.apply(value).to_string()
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut cell = Cell::from(item);
|
|
|
|
cell.alignment = Alignment::Left;
|
|
|
|
grid.add(cell);
|
|
|
|
} else {
|
|
|
|
let style = ls_colors.style_for_path(value.clone());
|
|
|
|
let ansi_style = style.map(Style::to_crossterm_style).unwrap_or_default();
|
|
|
|
let mut cell = Cell::from(ansi_style.apply(value).to_string());
|
|
|
|
cell.alignment = Alignment::Left;
|
|
|
|
grid.add(cell);
|
|
|
|
}
|
2021-10-08 16:53:26 +02:00
|
|
|
} else {
|
|
|
|
let mut cell = Cell::from(value);
|
2021-11-29 21:37:09 +01:00
|
|
|
cell.alignment = Alignment::Left;
|
2021-10-08 16:53:26 +02:00
|
|
|
grid.add(cell);
|
|
|
|
}
|
2021-10-07 23:50:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-04 13:38:21 +01:00
|
|
|
Ok(
|
|
|
|
if let Some(grid_display) = grid.fit_into_width(cols as usize) {
|
|
|
|
Value::String {
|
|
|
|
val: grid_display.to_string(),
|
|
|
|
span: call.head,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Value::String {
|
|
|
|
val: format!("Couldn't fit grid into {} columns!", cols),
|
|
|
|
span: call.head,
|
|
|
|
}
|
2021-10-07 23:50:27 +02:00
|
|
|
}
|
2021-12-04 13:38:21 +01:00
|
|
|
.into_pipeline_data(),
|
|
|
|
)
|
2021-10-07 23:50:27 +02:00
|
|
|
}
|
|
|
|
|
2021-11-29 21:37:09 +01:00
|
|
|
fn convert_to_list(
|
2021-11-14 20:25:57 +01:00
|
|
|
iter: impl IntoIterator<Item = Value>,
|
|
|
|
config: &Config,
|
2021-12-19 08:46:13 +01:00
|
|
|
head: Span,
|
2021-11-14 20:25:57 +01:00
|
|
|
) -> Option<Vec<(usize, String, String)>> {
|
2021-10-05 15:43:20 +02:00
|
|
|
let mut iter = iter.into_iter().peekable();
|
|
|
|
|
|
|
|
if let Some(first) = iter.peek() {
|
|
|
|
let mut headers = first.columns();
|
|
|
|
|
|
|
|
if !headers.is_empty() {
|
|
|
|
headers.insert(0, "#".into());
|
|
|
|
}
|
|
|
|
|
2021-10-07 23:50:27 +02:00
|
|
|
let mut data = vec![];
|
|
|
|
|
2021-10-05 15:43:20 +02:00
|
|
|
for (row_num, item) in iter.enumerate() {
|
|
|
|
let mut row = vec![row_num.to_string()];
|
|
|
|
|
|
|
|
if headers.is_empty() {
|
2021-11-14 20:25:57 +01:00
|
|
|
row.push(item.into_string(", ", config))
|
2021-10-05 15:43:20 +02:00
|
|
|
} else {
|
|
|
|
for header in headers.iter().skip(1) {
|
|
|
|
let result = match item {
|
|
|
|
Value::Record { .. } => {
|
|
|
|
item.clone().follow_cell_path(&[PathMember::String {
|
|
|
|
val: header.into(),
|
2021-12-19 08:46:13 +01:00
|
|
|
span: head,
|
2021-10-05 15:43:20 +02:00
|
|
|
}])
|
|
|
|
}
|
|
|
|
_ => Ok(item.clone()),
|
|
|
|
};
|
|
|
|
|
|
|
|
match result {
|
2021-11-14 20:25:57 +01:00
|
|
|
Ok(value) => row.push(value.into_string(", ", config)),
|
2021-10-05 15:43:20 +02:00
|
|
|
Err(_) => row.push(String::new()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
data.push(row);
|
|
|
|
}
|
|
|
|
|
2021-10-07 23:50:27 +02:00
|
|
|
let mut h: Vec<String> = headers.into_iter().collect();
|
|
|
|
|
|
|
|
// This is just a list
|
|
|
|
if h.is_empty() {
|
|
|
|
// let's fake the header
|
|
|
|
h.push("#".to_string());
|
|
|
|
h.push("name".to_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
// this tuple is (row_index, header_name, value)
|
|
|
|
let mut interleaved = vec![];
|
2021-10-07 23:59:01 +02:00
|
|
|
for (i, v) in data.into_iter().enumerate() {
|
2021-10-07 23:50:27 +02:00
|
|
|
for (n, s) in v.into_iter().enumerate() {
|
|
|
|
if h.len() == 1 {
|
2021-10-08 15:14:32 +02:00
|
|
|
// always get the 1th element since this is a simple list
|
2021-10-07 23:50:27 +02:00
|
|
|
// and we hacked the header above because it was empty
|
2021-10-08 15:14:32 +02:00
|
|
|
// 0th element is an index, 1th element is the value
|
2021-10-07 23:50:27 +02:00
|
|
|
interleaved.push((i, h[1].clone(), s))
|
|
|
|
} else {
|
|
|
|
interleaved.push((i, h[n].clone(), s))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-08 15:14:32 +02:00
|
|
|
|
2021-10-07 23:50:27 +02:00
|
|
|
Some(interleaved)
|
2021-10-05 15:43:20 +02:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|