1use f00_core::Entry;
4
5use crate::perms::format_permissions;
6
7pub fn format_csv(entries: &[Entry]) -> String {
9 format_delimited(entries, ',')
10}
11
12pub fn format_tsv(entries: &[Entry]) -> String {
14 format_delimited(entries, '\t')
15}
16
17fn format_delimited(entries: &[Entry], sep: char) -> String {
18 let mut out = String::new();
19 push_row(
21 &mut out,
22 sep,
23 &[
24 "name",
25 "path",
26 "kind",
27 "size",
28 "mode",
29 "permissions",
30 "readonly",
31 "modified",
32 "accessed",
33 "changed",
34 "created",
35 "inode",
36 "nlink",
37 "blocks",
38 "uid",
39 "gid",
40 "owner",
41 "group",
42 "author",
43 "symlink_target",
44 "context",
45 "extension",
46 "git_status",
47 "depth",
48 ],
49 );
50 for e in entries.iter().filter(|e| !e.is_dir_header) {
51 let ts = |d: Option<chrono::DateTime<chrono::Local>>| {
52 d.map(|x| x.to_rfc3339()).unwrap_or_default()
53 };
54 let target = e
55 .symlink_target
56 .as_ref()
57 .map(|p| p.display().to_string())
58 .unwrap_or_default();
59 let ext = e.extension().unwrap_or("").to_string();
60 let fields = [
61 e.name.clone(),
62 e.path.display().to_string(),
63 e.kind.as_str().to_string(),
64 e.size.to_string(),
65 format!("{:o}", e.mode),
66 format_permissions(e),
67 e.readonly.to_string(),
68 ts(e.modified_datetime()),
69 ts(e.accessed_datetime()),
70 ts(e.changed_datetime()),
71 ts(e.created_datetime()),
72 e.inode.to_string(),
73 e.nlink.to_string(),
74 e.blocks.to_string(),
75 e.uid.to_string(),
76 e.gid.to_string(),
77 e.owner.clone(),
78 e.group.clone(),
79 e.author.clone(),
80 target,
81 e.context.clone(),
82 ext,
83 e.git_status.as_str().to_string(),
84 e.depth.to_string(),
85 ];
86 let refs: Vec<&str> = fields.iter().map(|s| s.as_str()).collect();
87 push_row(&mut out, sep, &refs);
88 }
89 out
90}
91
92fn push_row(out: &mut String, sep: char, fields: &[&str]) {
93 for (i, f) in fields.iter().enumerate() {
94 if i > 0 {
95 out.push(sep);
96 }
97 if sep == ',' {
98 push_csv_field(out, f);
99 } else {
100 for c in f.chars() {
102 match c {
103 '\t' => out.push_str("\\t"),
104 '\n' => out.push_str("\\n"),
105 '\r' => out.push_str("\\r"),
106 _ => out.push(c),
107 }
108 }
109 }
110 }
111 out.push('\n');
112}
113
114fn push_csv_field(out: &mut String, f: &str) {
115 if f.contains([',', '"', '\n', '\r']) {
116 out.push('"');
117 for c in f.chars() {
118 if c == '"' {
119 out.push('"');
120 }
121 out.push(c);
122 }
123 out.push('"');
124 } else {
125 out.push_str(f);
126 }
127}