From: Aaron Merey Date: Thu, 5 May 2022 17:16:59 +0000 (-0400) Subject: change api, progress bar X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b2e0ecaf06242acbbe3c9a02da17c4a1529ca563;p=thirdparty%2Fbinutils-gdb.git change api, progress bar --- diff --git a/gdb/cli-out.c b/gdb/cli-out.c index 3523b074e75..ca1071ac31a 100644 --- a/gdb/cli-out.c +++ b/gdb/cli-out.c @@ -265,134 +265,106 @@ cli_ui_out::do_redirect (ui_file *outstream) m_streams.pop_back (); } -/* The cli_ui_out::do_progress_{start, notify} functions result in - the following: - - - printed for tty, SHOULD_PRINT == true - - next state == PERCENT: - <(XX%) NAME\r> - - next state == SPIN: - <-\|/ NAME\r> - - next state == BAR: - - - printed for tty, SHOULD_PRINT == false: - <> - - printed for not-a-tty: - -*/ - void -cli_ui_out::do_progress_start (const std::string &name, bool should_print) +cli_ui_out::do_progress_start () { - struct ui_file *stream = m_streams.back (); cli_progress_info info; - info.name = name; - if (!stream->isatty ()) - { - fprintf_unfiltered (stream, "%s\n", info.name.c_str ()); - gdb_flush (stream); - info.state = progress_update::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. */ - info.state = should_print ? progress_update::START - : progress_update::NO_PRINT; - } - + info.pos = 0; + info.state = progress_update::START; m_progress_info.push_back (std::move (info)); } /* Pick a reasonable limit for the progress update length. */ #define MAX_CHARS_PER_LINE 4096 +/* Print a progress update. MSG is a string to be printed before + If HOWMUCH is between 0.0 and 1.0, a progress bar is displayed + indicating the percentage of completion. If HOWMUCH is negative, + a progress indicator ticks across the screen. Multiple calls + to this function progressively update the display. + + - printed for tty, HOWMUCH between 0.0 and 1.0: + + - printed for tty, HOWMUCH < 0.0: + + - printed for not-a-tty: + +*/ + void -cli_ui_out::do_progress_notify (double howmuch, - progress_update::state next_state) +cli_ui_out::do_progress_notify (const std::string &msg, double howmuch) { struct ui_file *stream = m_streams.back (); cli_progress_info &info (m_progress_info.back ()); - if (info.state == progress_update::NO_PRINT) - return; - - int chars_per_line = get_chars_per_line (); - if (chars_per_line > MAX_CHARS_PER_LINE) - chars_per_line = MAX_CHARS_PER_LINE; - if (info.state == progress_update::START) { - fprintf_unfiltered (stream, "%s", info.name.c_str ()); - if (chars_per_line <= 0) - fprintf_unfiltered (stream, "\n"); - gdb_flush (stream); - info.state = progress_update::WORKING; + if (!stream->isatty ()) + { + fprintf_unfiltered (stream, "%s...\n", msg.c_str ()); + info.state = progress_update::WORKING; + } + else + { + fprintf_unfiltered (stream, "%s\n", msg.c_str ()); + info.state = progress_update::BAR; + } } - if (chars_per_line <= 0) - return; - - if (info.state == progress_update::WORKING && howmuch >= 1.0) - return; + int chars_per_line = get_chars_per_line (); + if (chars_per_line > MAX_CHARS_PER_LINE) + chars_per_line = MAX_CHARS_PER_LINE; - if (!stream->isatty ()) + if (chars_per_line <= 0 + || info.state == progress_update::WORKING + || !stream->isatty ()) return; - - if (next_state == progress_update::PERCENT) +/* + if (howmuch >= 0) { - fprintf_unfiltered (stream, "\r(%2.0f%%) %s", - howmuch * 100, info.name.c_str ()); + int width = chars_per_line - 3; + int max = width * howmuch; + + fprintf_unfiltered (stream, "\r["); + for (int i = 0; i < width; ++i) + fprintf_unfiltered (stream, i < max ? "#" : " "); + fprintf_unfiltered (stream, "]"); gdb_flush (stream); - info.state = progress_update::PERCENT; } - else if (next_state == progress_update::SPIN) + else { using namespace std::chrono; - seconds diff = duration_cast + milliseconds diff = duration_cast (steady_clock::now () - info.last_update); - /* Advance the spinner no faster than 1 tick per second. */ - if (diff.count () >= 1.0) + * Advance the progress indicator at a rate of 1 tick every + every 0.5 seconds. * + if (diff.count () >= 500) { - static int spin = 0; + int width = chars_per_line - 3; - fprintf_unfiltered (stream, "\r%c %s", "-\\|/"[spin++ % 4], - info.name.c_str ()); + fprintf_unfiltered (stream, "\r["); + + for (int i = 0; i < width; ++i) + { + if (i >= info.pos % width + && i < (info.pos + 3) % width) + fprintf_unfiltered (stream, "#"); + else + fprintf_unfiltered (stream, " "); + } + + fprintf_unfiltered (stream, "]"); gdb_flush (stream); info.last_update = steady_clock::now (); + info.pos++; } - info.state = progress_update::SPIN; - } - else if (next_state == progress_update::BAR) - { - int i, max; - int width = chars_per_line - 3; - max = width * howmuch; - - if (info.state == progress_update::SPIN - || info.state == progress_update::PERCENT) - { - /* Ensure the progress bar prints on its own line so that - progress updates don't overwrite NAME. */ - fprintf_unfiltered (stream, "\r%s\n", info.name.c_str ()); - gdb_flush (stream); - } - - fprintf_unfiltered (stream, "\r["); - - for (i = 0; i < width; ++i) - fprintf_unfiltered (stream, i < max ? "#" : " "); - fprintf_unfiltered (stream, "]"); - gdb_flush (stream); - info.state = progress_update::BAR; } - +*/ return; } @@ -409,40 +381,16 @@ cli_ui_out::clear_current_line () || chars_per_line > MAX_CHARS_PER_LINE) chars_per_line = MAX_CHARS_PER_LINE; - int i; int width = chars_per_line; fprintf_unfiltered (stream, "\r"); - for (i = 0; i < width; ++i) + for (int i = 0; i < width; ++i) fprintf_unfiltered (stream, " "); fprintf_unfiltered (stream, "\r"); gdb_flush (stream); } -/* Set NAME as the new description of the most recent progress update. */ - -void -cli_ui_out::update_progress_name (const std::string &name) -{ - struct ui_file *stream = m_streams.back (); - cli_progress_info &info = m_progress_info.back (); - info.name = name; - - if (stream->isatty ()) - clear_current_line (); -} - -/* Get the current state of the most recent progress update. */ - -cli_ui_out::progress_update::state -cli_ui_out::get_progress_state () -{ - cli_progress_info &info = m_progress_info.back (); - return info.state; -} - - /* Remove the most recent progress update from the stack and overwrite the current line with whitespace. */ diff --git a/gdb/cli-out.h b/gdb/cli-out.h index 2afd5b32706..ae42ff03cf0 100644 --- a/gdb/cli-out.h +++ b/gdb/cli-out.h @@ -72,11 +72,9 @@ protected: virtual void do_flush () override; virtual void do_redirect (struct ui_file *outstream) override; - virtual void do_progress_start (const std::string &, bool) override; - virtual void do_progress_notify (double, progress_update::state) override; + virtual void do_progress_start () override; + virtual void do_progress_notify (const std::string &, double) override; virtual void do_progress_end () override; - virtual void update_progress_name (const std::string &) override; - virtual progress_update::state get_progress_state () override; bool suppress_output () { return m_suppress_output; } @@ -91,10 +89,10 @@ private: /* The state of a recent progress update. */ struct cli_progress_info { + /* Position of indicator. */ + int pos; /* The current state. */ progress_update::state state; - /* The name to print. */ - std::string name; /* Time of last spinner update. */ std::chrono::steady_clock::time_point last_update; }; diff --git a/gdb/debuginfod-support.c b/gdb/debuginfod-support.c index 5a5420c8c03..2d227ba4350 100644 --- a/gdb/debuginfod-support.c +++ b/gdb/debuginfod-support.c @@ -84,7 +84,7 @@ struct user_data const char * const desc; std::string & fname; - gdb::optional progress; + ui_out::progress_update progress; }; /* Deleter for a debuginfod_client. */ @@ -119,200 +119,51 @@ get_size_and_unit (double *size, const char **unit) *unit = "KB"; } -/* Ensure the progress message can fit on a single line. Otherwise - garbled output is possible with \r. - - An example of possible truncations, starting with the original message: - "Downloading XX MB separate debug info for /aa/bb/cc/dd/ee" - "Downloading XX MB separate debug info for /aa/bb/.../ee" - "Downloading XX MB separate debug info for ee" - "Downloading XX MB separate debug info" - "Downloading XX MB" - "Downloading" - */ - -static std::string -build_message (std::string size, std::string unit, std::string desc, std::string fname) -{ - int width = get_chars_per_line (); - std::stringstream message; - - message << "Downloading"; - /* Leave room for spinner and percent indicator. */ - int message_size = message.str ().length () + 6; - - if (!size.empty () && !unit.empty ()) - { - message_size += size.size () + unit.size () + 2; - if (message_size > width) - return message.str (); - - /* "Downloading XX MB" */ - message << " " << size << " " << unit; - } - - /* If FNAME does not fit then message will end with DESC_END. - In case DESC_END is "separate debug info for", remove " for". */ - std::string desc_end = desc; - if (desc.substr (desc.size () - 4) == " for") - desc_end = desc.substr (0, desc.size () - 4); - - if (message_size + desc_end.size () + 1 > width) - return message.str (); - - string_file styled_fname (current_uiout->can_emit_style_escape ()); - if (message_size + desc.size () + fname.size () + 2 <= width) - { - /* Truncation is not necessary. Return untruncated message. - "Downloading XX MB separate debug info for /usr/libxyz.so" */ - fprintf_styled (&styled_fname, file_name_style.style (), "%s", - fname.c_str ()); - - message << " " << desc << " " << styled_fname.c_str (); - return message.str (); - } - - while (fname.back () == '/') - fname.pop_back (); - - /* Find path separators for the first, second and final components. - If FNAME does not have path separators and it does not fit in the - available space, do not include it in message. */ - size_t sep1 = fname.find ('/'); - if (sep1 == std::string::npos) - { - message << " " << desc_end; - return message.str (); - } - - size_t sep2 = fname.find ('/', sep1 + 1); - size_t sep3; - if (sep2 == std::string::npos) - sep3 = std::string::npos; - else - sep3 = fname.find ('/', sep2 + 1); - size_t seplast = fname.find_last_of ('/'); - - /* If the first, second, and final path components are distinct, try to - truncate FNAME so that it fits in the available space. Preserve the - first, second and final path components. For example, - "/aa/bb/cc/dd/ee" becomes "/aa/bb/.../ee" and - "../aa/bb/cc/dd/" becomes "../aa/.../ee" */ - std::stringstream trunc; - if (sep2 != sep3 && sep2 != seplast && sep2 != std::string::npos) - { - std::stringstream fnametmp; - - if (sep1 == 0 && sep3 != seplast && sep3 != std::string::npos) - fnametmp << fname.substr (0, sep3 + 1) - << "..." << fname.substr (seplast); - else if (sep1 != 0) - fnametmp << fname.substr (0, sep2 + 1) - << "..." << fname.substr (seplast); - - if (!fnametmp.str ().empty ()) - { - trunc << " " << desc << " "; - if (message_size + trunc.str ().size () + fnametmp.str ().size () <= width) - { - fprintf_styled (&styled_fname, file_name_style.style (), "%s", - fnametmp.str ().c_str ()); - message << trunc.str () << styled_fname.c_str (); - return message.str (); - } - } - } - - /* The first, second and final components are not distinct or - "/aa/bb/.../ee" does not fit. Try "ee" instead. */ - trunc.str (""); - trunc << " " << desc << " "; - fname = fname.substr (seplast + 1); - if (message_size + trunc.str ().size () + fname.size () <= width) - { - fprintf_styled (&styled_fname, file_name_style.style (), "%s", - fname.c_str ()); - message << trunc.str () << styled_fname.c_str (); - return message.str (); - } - - /* We aren't able to fit anything from FNAME. End message with DESC_END - since we already confirmed it will fit. */ - message << " " << desc_end; - return message.str (); -} - - static int progressfn (debuginfod_client *c, long cur, long total) { user_data *data = static_cast (debuginfod_get_user_data (c)); gdb_assert (data != nullptr); + string_file styled_fname (current_uiout->can_emit_style_escape ()); + fprintf_styled (&styled_fname, file_name_style.style (), "%s", + data->fname.c_str ()); + if (check_quit_flag ()) { - if (data->progress.has_value ()) - data->progress.reset (); - - string_file styled_fname (current_uiout->can_emit_style_escape ()); - fprintf_styled (&styled_fname, file_name_style.style (), "%s", - data->fname.c_str ()); + current_uiout->do_progress_end (); ///? printf_filtered ("Cancelled download of %s %s\n", data->desc, styled_fname.c_str ()); return 1; } - if (debuginfod_verbose == 0 - || (data->progress.has_value () - && data->progress->get_state () == ui_out::progress_update::WORKING)) + if (debuginfod_verbose == 0) return 0; /* Print progress update. Include the transfer size if available. */ if (total > 0) { /* Transfer size is known. */ - double percent = (double)cur / (double)total; + double howmuch = (double) cur / (double) total; - if (percent >= 0.0 && percent <= 1.0) + if (howmuch >= 0.0 && howmuch <= 1.0) { - if (!data->progress.has_value () - || data->progress->get_state () - != ui_out::progress_update::PERCENT) - { - double size = (double)total; - const char *unit = ""; - - get_size_and_unit (&size, &unit); - std::string fsize = string_printf ("%.2f", size); - std::string message = build_message (fsize, unit, data->desc, - data->fname); - if (!data->progress.has_value ()) - data->progress.emplace (current_uiout, message, 1); - else - data->progress->update_name (message); - } - - /* Ensure PERCENT doesn't require three digits to display. */ - if (percent > 0.99 && percent <= 1.0) - percent = .99; - current_uiout->update_progress_percent (percent); - return 0; - } - } - - if (!data->progress.has_value () - || data->progress->get_state () != ui_out::progress_update::SPIN) - { - std::string message = build_message ("", "", data->desc, data->fname); + double size = (double) total; + const char *unit = ""; - if (!data->progress.has_value ()) - data->progress.emplace (current_uiout, message, 1); - else - data->progress->update_name (message); + get_size_and_unit (&size, &unit); + std::string msg = string_printf ("Downloading %0.2f %s %s %s\n", + size, unit, data->desc, + styled_fname.c_str ()); + current_uiout->update_progress (msg, howmuch); + return 0; + } } - current_uiout->update_progress_spin (); + std::string msg = string_printf ("Downloading %s %s\n", + data->desc, styled_fname.c_str ()); + current_uiout->update_progress (msg, -1); return 0; } @@ -374,8 +225,7 @@ static void print_outcome (user_data &data, int fd) { /* Clears the current line of progress output. */ - if (data.progress.has_value ()) - data.progress.reset (); + current_uiout->do_progress_end (); string_file styled_fname (current_uiout->can_emit_style_escape ()); fprintf_styled (&styled_fname, file_name_style.style (), "%s", diff --git a/gdb/mi/mi-out.c b/gdb/mi/mi-out.c index a7f697b4f28..e5c4e3b8534 100644 --- a/gdb/mi/mi-out.c +++ b/gdb/mi/mi-out.c @@ -258,38 +258,28 @@ mi_ui_out::main_stream () return (string_file *) m_streams.back (); } -/* Indicate that a task described by NAME is in progress: - - - SHOULD_PRINT == true: - - - SHOULD_PRINT == false: - <> -*/ - void -mi_ui_out::do_progress_start (const std::string &name, bool should_print) +mi_ui_out::do_progress_start () { - struct ui_file *stream = gdb_stdout; mi_progress_info info; - if (should_print) - { - fprintf_unfiltered (stream, "%s\n", name.c_str ()); - gdb_flush (stream); - } - - info.state = progress_update::WORKING; + info.state = progress_update::START; m_progress_info.push_back (std::move (info)); } -/* Get the state of the most recent progress update. */ +/* Indicate that a task described by NAME is in progress. */ -mi_ui_out::progress_update::state -mi_ui_out::get_progress_state () +void +mi_ui_out::do_progress_notify (const std::string &msg, double howmuch) { - mi_progress_info &info = m_progress_info.back (); - return info.state; + mi_progress_info &info (m_progress_info.back ()); + + if (info.state == progress_update::START) + { + struct ui_file *stream = gdb_stdout; + fprintf_unfiltered (stream, "%s\n", msg.c_str ()); + info.state = progress_update::WORKING; + } } /* Clear the buffer. */ diff --git a/gdb/mi/mi-out.h b/gdb/mi/mi-out.h index d915b35f633..5ce81c94473 100644 --- a/gdb/mi/mi-out.h +++ b/gdb/mi/mi-out.h @@ -82,21 +82,13 @@ protected: virtual bool do_is_mi_like_p () const override { return true; } - virtual void do_progress_start (const std::string &, bool) override; - virtual progress_update::state get_progress_state () override; - - virtual void do_progress_notify (double, progress_update::state) override - { - } + virtual void do_progress_start () override; + virtual void do_progress_notify (const std::string &, double) override; virtual void do_progress_end () override { } - virtual void update_progress_name (const std::string &) override - { - } - private: void field_separator (); diff --git a/gdb/ui-out.h b/gdb/ui-out.h index 4c490c11b82..175ff5fb156 100644 --- a/gdb/ui-out.h +++ b/gdb/ui-out.h @@ -293,35 +293,20 @@ class ui_out WORKING, /* Progress bar printing has already started. */ BAR, - /* Spinner printing has already started. */ - SPIN, - /* Percent printing has already started. */ - PERCENT, /* Printing should not be done. */ NO_PRINT }; /* SHOULD_PRINT indicates whether something should be printed for a tty. */ - progress_update (struct ui_out *uiout, const std::string &name, - bool should_print) - : m_uiout (uiout) + progress_update () { - m_uiout->do_progress_start (name, should_print); + m_uiout = current_uiout; + m_uiout->do_progress_start (); } ~progress_update () { - m_uiout->do_progress_end (); - } - - void update_name (std::string &name) - { - m_uiout->update_progress_name (name); - } - state get_state () - { - return m_uiout->get_progress_state (); } progress_update (const progress_update &) = delete; @@ -334,20 +319,12 @@ class ui_out /* Emit some progress corresponding to the most recently created progress_update object. */ - void update_progress_bar (double howmuch) - { - do_progress_notify (howmuch, progress_update::BAR); - } - - void update_progress_percent (double howmuch) + void update_progress (std::string &msg, double howmuch) { - do_progress_notify (howmuch, progress_update::PERCENT); + do_progress_notify (msg, howmuch); } - void update_progress_spin () - { - do_progress_notify (0, progress_update::SPIN); - } + virtual void do_progress_end () = 0; protected: @@ -383,11 +360,8 @@ class ui_out virtual void do_flush () = 0; virtual void do_redirect (struct ui_file *outstream) = 0; - virtual void do_progress_start (const std::string &, bool) = 0; - virtual void do_progress_notify (double, progress_update::state) = 0; - virtual void do_progress_end () = 0; - virtual void update_progress_name (const std::string &) = 0; - virtual progress_update::state get_progress_state () = 0; + virtual void do_progress_start () = 0; + virtual void do_progress_notify (const std::string &, double) = 0; /* Set as not MI-like by default. It is overridden in subclasses if necessary. */