|
@@ -59,7 +59,8 @@ namespace Usm.Cli {
|
|
|
|
|
|
|
|
private int pulse_position = 0;
|
|
private int pulse_position = 0;
|
|
|
private bool pulse_forward = true;
|
|
private bool pulse_forward = true;
|
|
|
- private uint pulse_timer = 0;
|
|
|
|
|
|
|
+ private Cancellable? pulse_cancel = null;
|
|
|
|
|
+ private Thread<bool>? pulse_thread = null;
|
|
|
|
|
|
|
|
/** Whether the active phase bar is in indeterminate (pulsing) mode. */
|
|
/** Whether the active phase bar is in indeterminate (pulsing) mode. */
|
|
|
public bool phase_is_indeterminate {
|
|
public bool phase_is_indeterminate {
|
|
@@ -73,6 +74,8 @@ namespace Usm.Cli {
|
|
|
private const string COLOUR_BLUE = "\x1b[34m";
|
|
private const string COLOUR_BLUE = "\x1b[34m";
|
|
|
private const string COLOUR_MAGENTA = "\x1b[35m";
|
|
private const string COLOUR_MAGENTA = "\x1b[35m";
|
|
|
private const string COLOUR_CYAN = "\x1b[36m";
|
|
private const string COLOUR_CYAN = "\x1b[36m";
|
|
|
|
|
+ private const string COLOUR_MUTED = "\x1b[90m";
|
|
|
|
|
+ private const string COLOUR_BRIGHT = "\x1b[97m";
|
|
|
|
|
|
|
|
// TIOCGWINSZ request value on Linux; the CLI is already Linux-only
|
|
// TIOCGWINSZ request value on Linux; the CLI is already Linux-only
|
|
|
// (mount/chroot in Cli.vala)
|
|
// (mount/chroot in Cli.vala)
|
|
@@ -277,14 +280,22 @@ namespace Usm.Cli {
|
|
|
pulse_position = 0;
|
|
pulse_position = 0;
|
|
|
if(interactive) {
|
|
if(interactive) {
|
|
|
draw_phase_line();
|
|
draw_phase_line();
|
|
|
- pulse_timer = Timeout.add(120, () => {
|
|
|
|
|
- if(phase_progress < 0.0f) {
|
|
|
|
|
- advance_pulse();
|
|
|
|
|
- draw_phase_line();
|
|
|
|
|
|
|
+ pulse_cancel = new Cancellable();
|
|
|
|
|
+ try {
|
|
|
|
|
+ pulse_thread = new Thread<bool>.try("usm-pulse", () => {
|
|
|
|
|
+ while(!pulse_cancel.is_cancelled()) {
|
|
|
|
|
+ Thread.usleep(120000);
|
|
|
|
|
+ if(pulse_cancel.is_cancelled()) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ advance_pulse();
|
|
|
|
|
+ draw_phase_line();
|
|
|
|
|
+ }
|
|
|
return true;
|
|
return true;
|
|
|
- }
|
|
|
|
|
- return false;
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ catch(ThreadError e) {
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -303,12 +314,16 @@ namespace Usm.Cli {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /** Stops the indeterminate pulse timer if active. */
|
|
|
|
|
|
|
+ /** Stops the indeterminate pulse thread if active. */
|
|
|
private void stop_pulse() {
|
|
private void stop_pulse() {
|
|
|
- if(pulse_timer > 0) {
|
|
|
|
|
- Source.remove(pulse_timer);
|
|
|
|
|
- pulse_timer = 0;
|
|
|
|
|
|
|
+ if(pulse_cancel != null) {
|
|
|
|
|
+ pulse_cancel.cancel();
|
|
|
|
|
+ }
|
|
|
|
|
+ if(pulse_thread != null) {
|
|
|
|
|
+ pulse_thread.join();
|
|
|
|
|
+ pulse_thread = null;
|
|
|
}
|
|
}
|
|
|
|
|
+ pulse_cancel = null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private void advance_pulse() {
|
|
private void advance_pulse() {
|
|
@@ -400,13 +415,33 @@ namespace Usm.Cli {
|
|
|
*/
|
|
*/
|
|
|
private void print_action_log() {
|
|
private void print_action_log() {
|
|
|
var counter = @"[$(current_index + 1)/$current_total]";
|
|
var counter = @"[$(current_index + 1)/$current_total]";
|
|
|
|
|
+ var verb = past_tense(current_task);
|
|
|
|
|
+ var pkg = current_package ?? "transaction";
|
|
|
if(interactive) {
|
|
if(interactive) {
|
|
|
- stderr.printf("\r\033[K%s%s %s %s %s%s\n", colour_for_task(current_task), success_mark,
|
|
|
|
|
- counter, past_tense(current_task), current_package ?? "transaction", COLOUR_RESET);
|
|
|
|
|
|
|
+ var colour = colour_for_task(current_task);
|
|
|
|
|
+ var sb = new StringBuilder();
|
|
|
|
|
+ sb.append("\r\033[K");
|
|
|
|
|
+ sb.append(colour);
|
|
|
|
|
+ sb.append(success_mark);
|
|
|
|
|
+ sb.append(COLOUR_RESET);
|
|
|
|
|
+ sb.append(COLOUR_MUTED);
|
|
|
|
|
+ sb.append(" ");
|
|
|
|
|
+ sb.append(counter);
|
|
|
|
|
+ sb.append(" ");
|
|
|
|
|
+ sb.append(COLOUR_RESET);
|
|
|
|
|
+ sb.append(colour);
|
|
|
|
|
+ sb.append(verb);
|
|
|
|
|
+ sb.append(COLOUR_RESET);
|
|
|
|
|
+ sb.append(COLOUR_BRIGHT);
|
|
|
|
|
+ sb.append(" ");
|
|
|
|
|
+ sb.append(pkg);
|
|
|
|
|
+ sb.append(COLOUR_RESET);
|
|
|
|
|
+ sb.append("\n");
|
|
|
|
|
+ stderr.printf("%s", sb.str);
|
|
|
line_live = false;
|
|
line_live = false;
|
|
|
}
|
|
}
|
|
|
else {
|
|
else {
|
|
|
- stderr.printf("%s %s %s %s\n", success_mark, counter, past_tense(current_task), current_package ?? "transaction");
|
|
|
|
|
|
|
+ stderr.printf("%s %s %s %s\n", success_mark, counter, verb, pkg);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -421,29 +456,64 @@ namespace Usm.Cli {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * One full terminal row: the action text space-padded to the
|
|
|
|
|
- * left third, then the bar zone filling the right two thirds.
|
|
|
|
|
- * The width is re-queried on every call so a resized terminal
|
|
|
|
|
- * re-proportions the layout immediately.
|
|
|
|
|
|
|
+ * One full terminal row: muted counter, coloured verb, bright
|
|
|
|
|
+ * package name (left third), then a white bar on the dim track
|
|
|
|
|
+ * (right two thirds). The width is re-queried on every call so
|
|
|
|
|
+ * a resized terminal re-proportions immediately.
|
|
|
*/
|
|
*/
|
|
|
private string line_text() {
|
|
private string line_text() {
|
|
|
var width = detect_terminal_width();
|
|
var width = detect_terminal_width();
|
|
|
var text_zone = int.max(14, width / 3);
|
|
var text_zone = int.max(14, width / 3);
|
|
|
- var colour = colour_for_task(current_task);
|
|
|
|
|
|
|
|
|
|
- var text = zone_text(text_zone);
|
|
|
|
|
- var padding = text_zone - text.char_count();
|
|
|
|
|
- var padded = new StringBuilder(text);
|
|
|
|
|
- for(var i = 0; i < padding; i++) {
|
|
|
|
|
- padded.append(" ");
|
|
|
|
|
|
|
+ var counter = @"[$(current_index + 1)/$current_total]";
|
|
|
|
|
+ var head = @"$action_mark $counter ";
|
|
|
|
|
+ var verb_colour = colour_for_task(current_task);
|
|
|
|
|
+ var verb = verb_for(current_task);
|
|
|
|
|
+ var pkg = current_package ?? "";
|
|
|
|
|
+
|
|
|
|
|
+ var head_len = head.char_count();
|
|
|
|
|
+ var verb_len = verb.char_count();
|
|
|
|
|
+ var pkg_len = pkg.length > 0 ? pkg.char_count() + 1 : 0;
|
|
|
|
|
+ var visible = head_len + verb_len + pkg_len;
|
|
|
|
|
+ if(visible > text_zone) {
|
|
|
|
|
+ var allowed = text_zone - head_len - verb_len - 1;
|
|
|
|
|
+ if(allowed >= 4) {
|
|
|
|
|
+ pkg = ellipsise(pkg, allowed);
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ var all = ellipsise(@"$head$verb $pkg", text_zone);
|
|
|
|
|
+ var sb0 = new StringBuilder();
|
|
|
|
|
+ sb0.append(COLOUR_MUTED);
|
|
|
|
|
+ sb0.append(all);
|
|
|
|
|
+ sb0.append(COLOUR_RESET);
|
|
|
|
|
+ var pad0 = text_zone - all.char_count();
|
|
|
|
|
+ for(var i = 0; i < pad0; i++) {
|
|
|
|
|
+ sb0.append(" ");
|
|
|
|
|
+ }
|
|
|
|
|
+ sb0.append(bar_text(width - text_zone, overall, null));
|
|
|
|
|
+ return sb0.str;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- var cells = new StringBuilder();
|
|
|
|
|
- cells.append(colour);
|
|
|
|
|
- cells.append(padded.str);
|
|
|
|
|
- cells.append(COLOUR_RESET);
|
|
|
|
|
- cells.append(bar_text(width - text_zone, overall, colour));
|
|
|
|
|
- return cells.str;
|
|
|
|
|
|
|
+ var padding = text_zone - head_len - verb_len - (pkg.length > 0 ? pkg.char_count() + 1 : 0);
|
|
|
|
|
+ var sb = new StringBuilder();
|
|
|
|
|
+ sb.append(COLOUR_MUTED);
|
|
|
|
|
+ sb.append(head);
|
|
|
|
|
+ sb.append(COLOUR_RESET);
|
|
|
|
|
+ sb.append(verb_colour);
|
|
|
|
|
+ sb.append(verb);
|
|
|
|
|
+ sb.append(COLOUR_RESET);
|
|
|
|
|
+ if(pkg.length > 0) {
|
|
|
|
|
+ sb.append(COLOUR_BRIGHT);
|
|
|
|
|
+ sb.append(" ");
|
|
|
|
|
+ sb.append(pkg);
|
|
|
|
|
+ sb.append(COLOUR_RESET);
|
|
|
|
|
+ }
|
|
|
|
|
+ for(var i = 0; i < padding; i++) {
|
|
|
|
|
+ sb.append(" ");
|
|
|
|
|
+ }
|
|
|
|
|
+ sb.append(bar_text(width - text_zone, overall, null));
|
|
|
|
|
+ return sb.str;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -681,6 +751,15 @@ namespace Usm.Cli {
|
|
|
return package_name != null ? @"$capitalised $package_name" : capitalised;
|
|
return package_name != null ? @"$capitalised $package_name" : capitalised;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /** The present-tense verb on its own (for the coloured text zone). */
|
|
|
|
|
+ private string verb_for(TransactionTask task) {
|
|
|
|
|
+ if(task == TransactionTask.STRATEGISING) {
|
|
|
|
|
+ return "Preparing";
|
|
|
|
|
+ }
|
|
|
|
|
+ var verb = task.get_verb();
|
|
|
|
|
+ return verb.substring(0, 1).up() + verb.substring(1);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private string colour_for_task(TransactionTask task) {
|
|
private string colour_for_task(TransactionTask task) {
|
|
|
switch(task) {
|
|
switch(task) {
|
|
|
case TransactionTask.UNPACKING:
|
|
case TransactionTask.UNPACKING:
|