use serde_json::{Map, Value, json};
use super::{FileEntry, FilesView, Preview};
pub(crate) fn reply(view: &FilesView, preview: Option<&Preview>) -> Value {
let mut map = Map::new();
map.insert("ok".to_owned(), json!(true));
map.insert("kind".to_owned(), json!("files"));
match view {
FilesView::AbsentWorktree => {
map.insert("worktree".to_owned(), json!(false));
}
FilesView::Present { entries, truncated } => {
map.insert("worktree".to_owned(), json!(true));
map.insert(
"rows".to_owned(),
Value::Array(entries.iter().map(entry_row).collect()),
);
map.insert("truncated".to_owned(), json!(truncated));
}
}
if let Some(preview) = preview {
map.insert("preview".to_owned(), preview_value(preview));
}
Value::Object(map)
}
fn entry_row(entry: &FileEntry) -> Value {
json!({ "path": entry.rel_path, "size": entry.size, "dir": entry.is_dir })
}
pub(crate) fn preview_value(preview: &Preview) -> Value {
match preview {
Preview::Text(text) => json!({ "kind": "text", "text": text }),
Preview::Truncated { text, size } => {
json!({ "kind": "truncated", "text": text, "size": size })
}
Preview::Binary { size } => json!({ "kind": "binary", "size": size }),
}
}
pub(crate) fn view_of(obj: &serde_json::Map<String, Value>) -> Result<FilesView, String> {
use crate::boundary::codec::fields::{bool_of, list_of};
if !bool_of(obj, "worktree")? {
return Ok(FilesView::AbsentWorktree);
}
Ok(FilesView::Present {
entries: list_of(obj, "rows", entry_of)?,
truncated: bool_of(obj, "truncated")?,
})
}
fn entry_of(v: &Value) -> Result<FileEntry, String> {
use crate::boundary::codec::fields::{bool_of, str_of, u64_of};
let o = v.as_object().ok_or("file row: not an object")?;
Ok(FileEntry {
rel_path: str_of(o, "path")?,
size: u64_of(o, "size")?,
is_dir: bool_of(o, "dir")?,
})
}
pub(crate) fn preview_of(v: &Value) -> Result<Preview, String> {
use crate::boundary::codec::fields::{str_of, u64_of};
let o = v.as_object().ok_or("preview: not an object")?;
match str_of(o, "kind")?.as_str() {
"text" => Ok(Preview::Text(str_of(o, "text")?)),
"truncated" => Ok(Preview::Truncated {
text: str_of(o, "text")?,
size: u64_of(o, "size")?,
}),
"binary" => Ok(Preview::Binary {
size: u64_of(o, "size")?,
}),
other => Err(format!("preview: unknown kind {other:?}")),
}
}