diff options
Diffstat (limited to 'gdb/cli-out.c')
-rw-r--r-- | gdb/cli-out.c | 189 |
1 files changed, 121 insertions, 68 deletions
diff --git a/gdb/cli-out.c b/gdb/cli-out.c index fdbed6f..9c2f018 100644 --- a/gdb/cli-out.c +++ b/gdb/cli-out.c @@ -26,6 +26,7 @@ #include "completer.h" #include "readline/readline.h" #include "cli/cli-style.h" +#include "top.h" /* These are the CLI output functions */ @@ -262,105 +263,157 @@ cli_ui_out::do_redirect (ui_file *outstream) m_streams.pop_back (); } -/* The cli_ui_out::do_progress_* functions result in the following: - - printed for tty, SHOULD_PRINT == true: - <NAME - [##### ]\r> - - printed for tty, SHOULD_PRINT == false: - <> +/* Initialize a progress update to be displayed with + cli_ui_out::do_progress_notify. */ + +void +cli_ui_out::do_progress_start () +{ + m_progress_info.emplace_back (); +} + +#define MIN_CHARS_PER_LINE 50 +#define MAX_CHARS_PER_LINE 4096 + +/* Print a progress update. MSG is a string to be printed on the line above + the progress bar. TOTAL is the size of the download whose progress is + being displayed. UNIT should be the unit of TOTAL (ex. "K"). If HOWMUCH + is between 0.0 and 1.0, a progress bar is displayed indicating the percentage + of completion and the download size. If HOWMUCH is negative, a progress + indicator will tick across the screen. If the output stream is not a tty + then only MSG is printed. + + - printed for tty, HOWMUCH between 0.0 and 1.0: + <MSG + [######### ] HOWMUCH*100% (TOTAL UNIT)\r> + - printed for tty, HOWMUCH < 0.0: + <MSG + [ ### ]\r> - printed for not-a-tty: - <NAME... - > + <MSG...\n> */ void -cli_ui_out::do_progress_start (const std::string &name, bool should_print) +cli_ui_out::do_progress_notify (const std::string &msg, + const char *unit, + double howmuch, double total) { + int chars_per_line = get_chars_per_line (); struct ui_file *stream = m_streams.back (); - cli_progress_info meter; + cli_progress_info &info (m_progress_info.back ()); + + if (chars_per_line > MAX_CHARS_PER_LINE) + chars_per_line = MAX_CHARS_PER_LINE; + + if (info.state == progress_update::START) + { + if (stream->isatty () + && current_ui->input_interactive_p () + && chars_per_line >= MIN_CHARS_PER_LINE) + { + gdb_printf (stream, "%s\n", msg.c_str ()); + info.state = progress_update::BAR; + } + else + { + gdb_printf (stream, "%s...\n", msg.c_str ()); + info.state = progress_update::WORKING; + } + } + + if (info.state != progress_update::BAR + || chars_per_line < MIN_CHARS_PER_LINE) + return; - meter.last_value = 0; - meter.name = name; - if (!stream->isatty ()) + if (total > 0 && howmuch >= 0 && howmuch <= 1.0) { - gdb_printf (stream, "%s...", meter.name.c_str ()); + std::string progress = string_printf (" %3.f%% (%.2f %s)", + howmuch * 100, total, + unit); + int width = chars_per_line - progress.size () - 4; + int max = width * howmuch; + + std::string display = "\r["; + + for (int i = 0; i < width; ++i) + if (i < max) + display += "#"; + else + display += " "; + + display += "]" + progress; + gdb_printf (stream, "%s", display.c_str ()); gdb_flush (stream); - meter.printing = WORKING; } else { - /* Don't actually emit anything until the first call notifies us - of progress. This makes it so a second progress message can - be started before the first one has been notified, without - messy output. */ - meter.printing = should_print ? START : NO_PRINT; + using namespace std::chrono; + milliseconds diff = duration_cast<milliseconds> + (steady_clock::now () - info.last_update); + + /* Advance the progress indicator at a rate of 1 tick every + every 0.5 seconds. */ + if (diff.count () >= 500) + { + int width = chars_per_line - 4; + + gdb_printf (stream, "\r["); + for (int i = 0; i < width; ++i) + { + if (i == info.pos % width + || i == (info.pos + 1) % width + || i == (info.pos + 2) % width) + gdb_printf (stream, "#"); + else + gdb_printf (stream, " "); + } + + gdb_printf (stream, "]"); + gdb_flush (stream); + info.last_update = steady_clock::now (); + info.pos++; + } } - m_meters.push_back (std::move (meter)); + return; } +/* Clear the current line of the most recent progress update. Overwrites + the current line with whitespace. */ + void -cli_ui_out::do_progress_notify (double howmuch) +cli_ui_out::clear_current_line () { struct ui_file *stream = m_streams.back (); - cli_progress_info &meter (m_meters.back ()); + int chars_per_line = get_chars_per_line (); - if (meter.printing == NO_PRINT) + if (!stream->isatty () + || !current_ui->input_interactive_p () + || chars_per_line < MIN_CHARS_PER_LINE) return; - if (meter.printing == START) - { - gdb_printf (stream, "%s\n", meter.name.c_str ()); - gdb_flush (stream); - meter.printing = WORKING; - } - - if (meter.printing == WORKING && howmuch >= 1.0) - return; + if (chars_per_line > MAX_CHARS_PER_LINE) + chars_per_line = MAX_CHARS_PER_LINE; - if (!stream->isatty ()) - return; + gdb_printf (stream, "\r"); + for (int i = 0; i < chars_per_line; ++i) + gdb_printf (stream, " "); + gdb_printf (stream, "\r"); - int chars_per_line = get_chars_per_line (); - if (chars_per_line > 0) - { - int i, max; - int width = chars_per_line - 3; - - max = width * howmuch; - gdb_printf (stream, "\r["); - for (i = 0; i < width; ++i) - gdb_printf (stream, i < max ? "#" : " "); - gdb_printf (stream, "]"); - gdb_flush (stream); - meter.printing = PROGRESS; - } + gdb_flush (stream); } +/* Remove the most recent progress update from the progress_info stack + and overwrite the current line with whitespace. */ + void cli_ui_out::do_progress_end () { struct ui_file *stream = m_streams.back (); - cli_progress_info &meter = m_meters.back (); - - if (!stream->isatty ()) - { - gdb_printf (stream, "\n"); - gdb_flush (stream); - } - else if (meter.printing == PROGRESS) - { - int i; - int width = get_chars_per_line () - 3; - - gdb_printf (stream, "\r"); - for (i = 0; i < width + 2; ++i) - gdb_printf (stream, " "); - gdb_printf (stream, "\r"); - gdb_flush (stream); - } + m_progress_info.pop_back (); - m_meters.pop_back (); + if (stream->isatty ()) + clear_current_line (); } /* local functions */ |