refactor: separated json in another file

This commit is contained in:
MartinFillon 2024-03-05 11:44:43 +01:00
parent e5c99f7538
commit e9a29fa662
No known key found for this signature in database
GPG key ID: 16DC898F53F94853
4 changed files with 104 additions and 111 deletions

View file

@ -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

View file

@ -108,21 +108,11 @@ impl<'a> Render<'a> {
// This doesnt 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
View 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}}")
}
}

View file

@ -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.