use serde_json::{Map, Value};
use super::fields;
pub(crate) const KIND: &str = "files";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Files {
pub listing: Option<Listing>,
pub preview: Option<Preview>,
pub working_dir: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Listing {
pub rows: Vec<FileRow>,
pub truncated: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FileRow {
pub path: String,
pub size: u64,
pub dir: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Preview {
Text(String),
Truncated { text: String, size: u64 },
Binary { size: u64 },
Unknown(String),
}
pub(crate) fn files(obj: &Map<String, Value>) -> Result<Files, String> {
let listing = if fields::flag(obj, "worktree")? {
Some(Listing {
rows: fields::rows(obj, row)?,
truncated: fields::flag(obj, "truncated")?,
})
} else {
None
};
let preview = match obj.get("preview") {
None => None,
Some(value) => Some(preview(value)?),
};
Ok(Files {
listing,
preview,
working_dir: fields::opt_text(obj, "working_dir")?,
})
}
fn row(value: &Value) -> Result<FileRow, String> {
let obj: &Map<String, Value> = value.as_object().ok_or("file row: not an object")?;
Ok(FileRow {
path: fields::text(obj, "path")?,
size: fields::count(obj, "size")?,
dir: fields::flag(obj, "dir")?,
})
}
fn preview(value: &Value) -> Result<Preview, String> {
let obj: &Map<String, Value> = value.as_object().ok_or("preview: not an object")?;
Ok(match fields::text(obj, "kind")?.as_str() {
"text" => Preview::Text(fields::text(obj, "text")?),
"truncated" => Preview::Truncated {
text: fields::text(obj, "text")?,
size: fields::count(obj, "size")?,
},
"binary" => Preview::Binary {
size: fields::count(obj, "size")?,
},
other => Preview::Unknown(other.to_owned()),
})
}
#[cfg(test)]
mod tests;