progress.v

2.2 KB · raw

1//! The line a long action draws while it works (§4, "never leave the person2//! wondering"): one line on stderr, redrawn in place and cleared when the step3//! ends, and only when stderr is a terminal, so pipes, logs and `--json` never4//! see it.56module cli78import os9import src.fmt10import src.remote11import src.view1213fn working(text string) {14	if os.is_atty(2) == 0 {15		return16	}17	width := line_width()18	shown := fmt.fit('  ${text}', width)19	// Padded with spaces, not cleared with an escape code, so a plain terminal20	// and NO_COLOR stay free of control sequences.21	eprint('\r${fmt.dim(shown)}${' '.repeat(width - fmt.visible_width(shown))}')22	flush_stderr()23}2425fn done_working() {26	if os.is_atty(2) != 0 {27		eprint('\r${' '.repeat(line_width())}\r')28		flush_stderr()29	}30}3132// line_width stays one column short of the terminal, so the line never wraps.33fn line_width() int {34	_, columns := view.terminal_size()35	return if columns > 1 { columns - 1 } else { 79 }36}3738// Watched counts what an offer, steal or strip moves through a backend, so the39// line moves with the transfer. Exchange stays unaware of it.40struct Watched {41	label string42mut:43	inner    remote.Backend44	received int45	sent     int46}4748// watched_backend is this machine's backend, counted on the line under `label`.49fn watched_backend(label string) !remote.Backend {50	return remote.Backend(watch(label, this_machine_backend()!))51}5253fn watch(label string, backend remote.Backend) Watched {54	return Watched{55		label: label56		inner: backend57	}58}5960fn (mut w Watched) show() {61	mut text := w.label62	if w.sent > 0 {63		text += ' · ${w.sent} sent'64	}65	if w.received > 0 {66		text += ' · ${w.received} received'67	}68	working(text)69}7071fn (mut w Watched) get(key string) !remote.Object {72	object := w.inner.get(key)!73	w.received++74	w.show()75	return object76}7778fn (mut w Watched) list(prefix string) ![]string {79	return w.inner.list(prefix)!80}8182fn (mut w Watched) put_if_absent(key string, body []u8) !bool {83	put := w.inner.put_if_absent(key, body)!84	w.sent++85	w.show()86	return put87}8889fn (mut w Watched) put_if_match(key string, body []u8, tag string) !bool {90	put := w.inner.put_if_match(key, body, tag)!91	w.sent++92	w.show()93	return put94}9596fn (mut w Watched) delete(key string) ! {97	w.inner.delete(key)!98	w.sent++99	w.show()100}