mirror of
https://github.com/eza-community/eza.git
synced 2025-08-04 17:08:42 +00:00
refactor: separated json in another file
This commit is contained in:
parent
e5c99f7538
commit
e9a29fa662
4 changed files with 104 additions and 111 deletions
|
@ -81,6 +81,8 @@ use crate::output::table::{Options as TableOptions, Row as TableRow, Table};
|
|||
use crate::output::tree::{TreeDepth, TreeParams, TreeTrunk};
|
||||
use crate::theme::Theme;
|
||||
|
||||
use super::json::JsonRenderer;
|
||||
|
||||
/// With the **Details** view, the output gets formatted into columns, with
|
||||
/// each `Column` object showing some piece of information about the file,
|
||||
/// such as its size, or its permissions.
|
||||
|
@ -222,80 +224,6 @@ impl<'a> Render<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn print_row_contents(
|
||||
&self,
|
||||
w: &mut impl Write,
|
||||
row: &TextCell,
|
||||
header: &Option<TextCell>,
|
||||
) -> io::Result<()> {
|
||||
let mut header_idx: usize = 0;
|
||||
for (i, cell) in row.contents.iter().enumerate() {
|
||||
if cell.is_empty() || cell.trim().is_empty() {
|
||||
continue;
|
||||
};
|
||||
if let Some(ref header) = header {
|
||||
write!(w, "\"{}\": ", header.contents[header_idx])?;
|
||||
header_idx += 1;
|
||||
}
|
||||
write!(w, "\"{cell}\"")?;
|
||||
if (i + 1) < row.contents.len() {
|
||||
writeln!(w, ", ")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_row<W: Write>(
|
||||
&self,
|
||||
w: &mut W,
|
||||
header: &Option<TextCell>,
|
||||
iter: &mut JsonTableIter<'_>,
|
||||
current_depth: usize,
|
||||
idx: &mut usize,
|
||||
len: usize,
|
||||
max: usize,
|
||||
) -> io::Result<Option<TreeParams>> {
|
||||
let (row, depth) = match iter.next() {
|
||||
Some((row, depth)) => (row, depth),
|
||||
None => return Ok(None),
|
||||
};
|
||||
if self.opts.header {
|
||||
writeln!(w, "{{")?;
|
||||
} else {
|
||||
writeln!(w, "[")?;
|
||||
}
|
||||
self.print_row_contents(w, &row, header)?;
|
||||
writeln!(w, ", \"depth\": {}", depth.depth.0)?;
|
||||
*idx += 1;
|
||||
if depth.depth.0 == current_depth && depth.depth.0 < max {
|
||||
writeln!(w, ", \"children\": [")?;
|
||||
let mut d = self.print_row(w, header, iter, depth.depth.0 + 1, idx, len, max)?;
|
||||
while d.is_some() && !d.unwrap().last && d.unwrap().depth.0 > depth.depth.0 {
|
||||
d = self.print_row(w, header, iter, depth.depth.0 + 1, idx, len, max)?;
|
||||
}
|
||||
writeln!(w, "]")?;
|
||||
}
|
||||
if self.opts.header {
|
||||
writeln!(w, "}}")?;
|
||||
} else {
|
||||
writeln!(w, "]")?;
|
||||
}
|
||||
if !depth.last {
|
||||
writeln!(w, ",")?;
|
||||
}
|
||||
Ok(Some(depth))
|
||||
}
|
||||
|
||||
pub fn get_max_depth(&self, iter: &mut JsonTableIter<'_>) -> usize {
|
||||
let mut max_depth = 0;
|
||||
for (_, depth) in iter {
|
||||
if depth.depth.0 > max_depth {
|
||||
max_depth = depth.depth.0;
|
||||
}
|
||||
}
|
||||
max_depth
|
||||
}
|
||||
|
||||
pub fn render_json<W: Write>(self, w: &mut W) -> io::Result<()> {
|
||||
let mut rows = Vec::new();
|
||||
|
||||
|
@ -320,33 +248,15 @@ impl<'a> Render<'a> {
|
|||
None,
|
||||
);
|
||||
|
||||
writeln!(w, "{{")?;
|
||||
let mut row_iter = self.iterate_with_table_json(table.unwrap(), rows);
|
||||
let mut row_iter = self.iterate_with_table(table.unwrap(), rows);
|
||||
let header = if self.opts.header {
|
||||
let (header, _) = row_iter.next().unwrap();
|
||||
let header = row_iter.next().unwrap();
|
||||
Some(header.clean_content())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut i = 0;
|
||||
let len = row_iter.len();
|
||||
writeln!(w, "\"files\":[")?;
|
||||
|
||||
let current_depth = 0;
|
||||
let max_depth = self.get_max_depth(&mut row_iter.clone());
|
||||
|
||||
while row_iter.len() > 0 {
|
||||
self.print_row(
|
||||
w,
|
||||
&(header.clone()),
|
||||
&mut row_iter,
|
||||
current_depth,
|
||||
&mut i,
|
||||
len,
|
||||
max_depth,
|
||||
)?;
|
||||
}
|
||||
writeln!(w, "]\n}}")?;
|
||||
JsonRenderer::new(header, row_iter).render(w)
|
||||
} else {
|
||||
#[rustfmt::skip]
|
||||
self.add_files_to_table(
|
||||
|
@ -364,9 +274,8 @@ impl<'a> Render<'a> {
|
|||
write!(w, ", ")?;
|
||||
}
|
||||
}
|
||||
writeln!(w, "]}}")?;
|
||||
writeln!(w, "]}}")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Whether to show the extended attribute hint
|
||||
|
|
|
@ -108,21 +108,11 @@ impl<'a> Render<'a> {
|
|||
// This doesn’t take an IgnoreCache even though the details one does
|
||||
// because grid-details has no tree view.
|
||||
|
||||
pub fn render_json<W: Write>(self, _w: &mut W) -> io::Result<()> {
|
||||
todo!("Implement json rendering");
|
||||
}
|
||||
|
||||
pub fn render<W: Write>(mut self, w: &mut W) -> io::Result<()> {
|
||||
if let Some((grid, width)) = self.find_fitting_grid() {
|
||||
write!(w, "{}", grid.fit_into_columns(width))
|
||||
} else {
|
||||
self.give_up().render(w)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_json<W: Write>(self, w: &mut W) -> io::Result<()> {
|
||||
// As json is made to be piped we use the Details render method
|
||||
|
||||
self.give_up().render_json(w)
|
||||
}
|
||||
|
||||
pub fn find_fitting_grid(&mut self) -> Option<(grid::Grid, grid::Width)> {
|
||||
let options = self
|
||||
.details
|
||||
.table
|
||||
|
|
93
src/output/json.rs
Normal file
93
src/output/json.rs
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
This file is a special renderer for json
|
||||
*/
|
||||
|
||||
use std::{
|
||||
fmt::Display,
|
||||
io::{self, Write},
|
||||
};
|
||||
|
||||
use super::{details::TableIter, TextCell};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct JsonFile {
|
||||
cell: TextCell,
|
||||
childrens: Option<Vec<JsonFile>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct JsonRenderer {
|
||||
header: Option<TextCell>,
|
||||
files: Vec<JsonFile>,
|
||||
}
|
||||
|
||||
impl JsonFile {
|
||||
pub fn new(cell: TextCell) -> Self {
|
||||
Self {
|
||||
cell,
|
||||
childrens: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display<W: Write>(&self, w: &mut W, header: &Option<TextCell>) -> io::Result<()> {
|
||||
let mut header_idx = 0;
|
||||
|
||||
if header.is_some() {
|
||||
writeln!(w, "{{")?;
|
||||
} else {
|
||||
writeln!(w, "[")?;
|
||||
}
|
||||
for (i, cell) in self.cell.contents.iter().enumerate() {
|
||||
if cell.is_empty() || cell.trim().is_empty() {
|
||||
continue;
|
||||
};
|
||||
if let Some(ref header) = header {
|
||||
write!(w, "\"{}\": ", header.contents[header_idx])?;
|
||||
header_idx += 1;
|
||||
}
|
||||
write!(w, "\"{cell}\"")?;
|
||||
if (i + 1) < self.cell.contents.len() {
|
||||
writeln!(w, ", ")?;
|
||||
}
|
||||
}
|
||||
if self.childrens.is_some() {
|
||||
if header.is_some() {
|
||||
writeln!(w, ", \"childends\": [")
|
||||
} else {
|
||||
writeln!(w, ", [")
|
||||
}?;
|
||||
for (i, f) in self.childrens.as_ref().unwrap().iter().enumerate() {
|
||||
if i != 0 {
|
||||
writeln!(w, ",")?;
|
||||
}
|
||||
f.display(w, header)?;
|
||||
}
|
||||
writeln!(w, "]")?;
|
||||
}
|
||||
if header.is_some() {
|
||||
writeln!(w, "}}")
|
||||
} else {
|
||||
writeln!(w, "]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl JsonRenderer {
|
||||
pub fn new(header: Option<TextCell>, files: TableIter<'_>) -> Self {
|
||||
Self {
|
||||
header,
|
||||
files: files.map(|row| JsonFile::new(row)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
writeln!(w, "{{\n\"files\":[")?;
|
||||
for (i, f) in self.files.iter().enumerate() {
|
||||
if i != 0 {
|
||||
writeln!(w, ",")?;
|
||||
}
|
||||
f.display(w, &self.header)?;
|
||||
}
|
||||
writeln!(w, "]\n}}")
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ pub mod time;
|
|||
|
||||
mod cell;
|
||||
mod escape;
|
||||
mod json;
|
||||
mod tree;
|
||||
|
||||
/// The **view** contains all information about how to format output.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue