1use {
2 crate::{
3 Args,
4 col::Col,
5 },
6 lfs_core::*,
7 termimad::{
8 CompoundStyle,
9 MadSkin,
10 ProgressBar,
11 crossterm::style::Color::*,
12 minimad::{
13 self,
14 OwningTemplateExpander,
15 TableBuilder,
16 },
17 },
18};
19
20static USED_COLOR: u8 = 209;
24static AVAI_COLOR: u8 = 65;
25static SIZE_COLOR: u8 = 172;
26
27static BAR_WIDTH: usize = 5;
28static INODES_BAR_WIDTH: usize = 5;
29
30pub fn print(
31 mounts: &[&Mount],
32 color: bool,
33 args: &Args,
34) {
35 if args.cols.is_empty() {
36 return;
37 }
38 let units = args.units;
39 let mut expander = OwningTemplateExpander::new();
40 expander.set_default("");
41 for mount in mounts {
42 let sub = expander
43 .sub("rows")
44 .set(
45 "id",
46 mount
47 .info
48 .id
49 .as_ref()
50 .map_or("".to_string(), |i| i.to_string()),
51 )
52 .set("dev", mount.info.dev)
53 .set("filesystem", &mount.info.fs)
54 .set("disk", mount.disk.as_ref().map_or("", |d| d.disk_type()))
55 .set("type", &mount.info.fs_type)
56 .set("mount-point", mount.info.mount_point.to_string_lossy())
57 .set("mount-options", mount.info.options_string())
58 .set_option("uuid", mount.uuid.as_ref())
59 .set_option("part_uuid", mount.part_uuid.as_ref())
60 .set_option(
61 "compress-level",
62 mount.info.option_value("compress"),
63 );
64 if let Some(label) = &mount.fs_label {
65 sub.set("label", label);
66 }
67 if mount.is_remote() {
68 sub.set("remote", "x");
69 }
70 if let Some(stats) = mount.stats() {
71 let use_share = stats.use_share();
72 let free_share = 1.0 - use_share;
73 sub.set("size", units.fmt(stats.size()))
74 .set("used", units.fmt(stats.used()))
75 .set("use-percents", format!("{:.0}%", 100.0 * use_share))
76 .set_md("bar", progress_bar_md(use_share, BAR_WIDTH, args.ascii))
77 .set("free", units.fmt(stats.available()))
78 .set("free-percents", format!("{:.0}%", 100.0 * free_share));
79 if let Some(inodes) = &stats.inodes {
80 let iuse_share = inodes.use_share();
81 sub.set("inodes", inodes.files)
82 .set("iused", inodes.used())
83 .set("iuse-percents", format!("{:.0}%", 100.0 * iuse_share))
84 .set_md(
85 "ibar",
86 progress_bar_md(iuse_share, INODES_BAR_WIDTH, args.ascii),
87 )
88 .set("ifree", inodes.favail);
89 }
90 } else if mount.is_unreachable() {
91 sub.set("use-error", "unreachable");
92 }
93 }
94 let mut skin = if color {
95 make_colored_skin()
96 } else {
97 MadSkin::no_style()
98 };
99 if args.ascii {
100 skin.limit_to_ascii();
101 }
102
103 let mut tbl = TableBuilder::default();
104 for col in args.cols.cols() {
105 tbl.col(
106 minimad::Col::new(
107 col.title(),
108 match col {
109 Col::Id => "${id}",
110 Col::Dev => "${dev}",
111 Col::Filesystem => "${filesystem}",
112 Col::Label => "${label}",
113 Col::Disk => "${disk}",
114 Col::Type => "${type}",
115 Col::Remote => "${remote}",
116 Col::Used => "~~${used}~~",
117 Col::Use => "~~${use-percents}~~ ${bar}~~${use-error}~~",
118 Col::UsePercent => "~~${use-percents}~~",
119 Col::Free => "*${free}*",
120 Col::FreePercent => "*${free-percents}*",
121 Col::Size => "**${size}**",
122 Col::InodesFree => "*${ifree}*",
123 Col::InodesUsed => "~~${iused}~~",
124 Col::InodesUse => "~~${iuse-percents}~~ ${ibar}",
125 Col::InodesUsePercent => "~~${iuse-percents}~~",
126 Col::InodesCount => "**${inodes}**",
127 Col::MountPoint => "${mount-point}",
128 Col::Uuid => "${uuid}",
129 Col::PartUuid => "${part_uuid}",
130 Col::MountOptions => "${mount-options}",
131 Col::CompressLevel => "${compress-level}",
132 },
133 )
134 .align_content(col.content_align())
135 .align_header(col.header_align()),
136 );
137 }
138
139 skin.print_owning_expander_md(&expander, &tbl);
140}
141
142fn make_colored_skin() -> MadSkin {
143 MadSkin {
144 bold: CompoundStyle::with_fg(AnsiValue(SIZE_COLOR)), inline_code: CompoundStyle::with_fgbg(AnsiValue(USED_COLOR), AnsiValue(AVAI_COLOR)), strikeout: CompoundStyle::with_fg(AnsiValue(USED_COLOR)), italic: CompoundStyle::with_fg(AnsiValue(AVAI_COLOR)), ..Default::default()
149 }
150}
151
152fn progress_bar_md(
153 share: f64,
154 bar_width: usize,
155 ascii: bool,
156) -> String {
157 if ascii {
158 let count = (share * bar_width as f64).round() as usize;
159 let bar: String = "".repeat(count);
160 let no_bar: String = "-".repeat(bar_width - count);
161 format!("~~{}~~*{}*", bar, no_bar)
162 } else {
163 let pb = ProgressBar::new(share as f32, bar_width);
164 format!("`{:<width$}`", pb, width = bar_width)
165 }
166}