pub fn format_bytes(bytes: usize) -> StringExpand description
Format a byte count as a human-readable string.
§Examples
use cli_ui::progress::format_bytes;
assert_eq!(format_bytes(512), "512 B");
assert_eq!(format_bytes(1500), "1.46 KB");
assert_eq!(format_bytes(1_500_000), "1.43 MB");Examples found in repository?
examples/subcommands.rs (line 143)
125fn download(g: &Global, opt: DownloadOpt) {
126 header!(
127 "mytool",
128 env!("CARGO_PKG_VERSION"),
129 "batch file processor",
130 "fast and parallel"
131 );
132 phase!("download", "{}", opt.url);
133 if g.verbose {
134 phase!("debug", "output={} jobs={}", opt.output.display(), opt.jobs);
135 }
136 step!("fetching");
137 ok!(opt.output.join("file.csv").display());
138 summary! {
139 done: "Download complete",
140 "url" => paint(CYAN, &opt.url),
141 "output" => paint(CYAN, &opt.output.display().to_string()),
142 section,
143 "size" => paint(YELLOW, &format_bytes(43_100)),
144 "time" => paint(DIM, "320ms"),
145 }
146}More examples
examples/mytool.rs (line 208)
82fn main() {
83 // parse() handles --help, --version, --completions,
84 // unknown flags, and missing positionals automatically
85 let opt = Opt::parse();
86
87 // resolved_alt_input() generated from conflicts_with = "input"
88 let input = opt.resolved_alt_input();
89 let output = opt.resolved_alt_output();
90 let start = std::time::Instant::now();
91
92 // bail! prints error and exits 1
93 if !input.exists() {
94 bail!("input path does not exist: {}", input.display());
95 }
96
97 header!(
98 "mytool",
99 env!("CARGO_PKG_VERSION"),
100 "batch file processor",
101 "fast and parallel"
102 );
103
104 phase!("init", "scanning {}", input.display());
105 phase!(
106 "scan",
107 "found {} remote · {} local jobs: {}",
108 8,
109 3,
110 opt.jobs
111 );
112
113 if opt.dry_run {
114 phase!("mode", "dry run — nothing will be written");
115 }
116 if !opt.include.is_empty() {
117 phase!("filter", "include: {}", opt.include.join(", "));
118 }
119 if !opt.exclude.is_empty() {
120 phase!("filter", "exclude: {}", opt.exclude.join(", "));
121 }
122
123 // ── remote files ──────────────────────────────────────────────────
124 let remote: &[(&str, &str, usize)] = &[
125 ("https://example.com/data.csv", "./data/data.csv", 43_100),
126 ("https://example.com/ref.json", "./data/ref.json", 8_500),
127 (
128 "https://example.com/schema.json",
129 "./data/schema.json",
130 2_300,
131 ),
132 ("https://cdn.example.com/lib.js", "./js/lib.js", 128_000),
133 (
134 "https://cdn.example.com/style.css",
135 "./css/style.css",
136 12_400,
137 ),
138 ];
139
140 step!("downloading remote files");
141 let pb = Progress::new(remote.len());
142 let mut errors = 0usize;
143 for (url, local, bytes) in remote {
144 // simulate one failure
145 if url.contains("lib.js") {
146 pb.fail("file", url, "connection timeout");
147 errors += 1;
148 } else {
149 pb.ok("file", "remote", url, local, *bytes);
150 }
151 }
152 pb.finish();
153
154 // ── local files ───────────────────────────────────────────────────
155 let local: &[(&str, &str, usize)] = &[
156 ("config.toml", "./cfg/config.toml", 1_200),
157 ("rules.yaml", "./cfg/rules.yaml", 3_400),
158 ("README.md", "./README.md", 8_800),
159 ];
160
161 step!("copying local files");
162 let pb2 = Progress::new(local.len());
163 for (src, dst, bytes) in local {
164 pb2.ok("file", "local", src, dst, *bytes);
165 }
166 pb2.finish();
167
168 // ── nested operations ─────────────────────────────────────────────
169 step!("resolving references in style.css");
170 substep!(
171 "https://fonts.example.com/Inter.woff2",
172 "./fonts/Inter.woff2"
173 );
174 substep!(
175 "https://fonts.example.com/JetBrains.woff2",
176 "./fonts/JetBrains.woff2"
177 );
178
179 // ── write ─────────────────────────────────────────────────────────
180 if !opt.dry_run {
181 step!("writing output");
182 ok!(output.join(format!("result.{}", opt.format)).display());
183 }
184
185 // ── summary ───────────────────────────────────────────────────────
186 let remote_ok = remote.len() - errors;
187 let total_files = remote_ok + local.len();
188 let total_bytes: usize = remote
189 .iter()
190 .filter(|(u, _, _)| !u.contains("lib.js"))
191 .map(|(_, _, b)| b)
192 .chain(local.iter().map(|(_, _, b)| b))
193 .sum();
194
195 let input_val = paint(CYAN, &input.display().to_string());
196 let output_val = paint(
197 BOLD,
198 &output
199 .join(format!("result.{}", opt.format))
200 .display()
201 .to_string(),
202 );
203 let files_val = format!(
204 "{} total · {} errors",
205 paint(OK, &total_files.to_string()),
206 paint(if errors > 0 { ERR } else { DIM }, &errors.to_string())
207 );
208 let size_val = paint(YELLOW, &format_bytes(total_bytes));
209 let time_val = paint(DIM, &format!("{}ms", start.elapsed().as_millis()));
210
211 if errors == 0 {
212 summary! {
213 done: "All files processed",
214 "input" => input_val,
215 "output" => output_val,
216 section,
217 "files" => files_val,
218 "size" => size_val,
219 "time" => time_val,
220 }
221 } else {
222 summary! {
223 warn: "Completed with errors",
224 "input" => input_val,
225 "output" => output_val,
226 section,
227 "files" => files_val,
228 "size" => size_val,
229 "time" => time_val,
230 }
231 }
232}