mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-17 16:05:56 +08:00
gdb/debuginfod: Improve progress updates
If the download size is known, a progress bar is displayed along with the percentage of completion and the total download size. Downloading separate debug info for /lib/libxyz.so [############ ] 25% (10.01 M) If the download size is not known, a progress indicator is displayed with a ticker ("###") that moves across the screen at a rate of 1 tick every 0.5 seconds. Downloading separate debug info for /lib/libxyz.so [ ### ] If the output stream is not a tty, batch mode is enabled, the screen is too narrow or width has been set to 'unlimited', then only a static description of the download is printed. No bar or ticker is displayed. Downloading separate debug info for /lib/libxyz.so... In any case, if the size of the download is known at the time the description is printed then it will be included in the description. Downloading 10.01 MB separate debug info for /lib/libxyz.so...
This commit is contained in:
195
gdb/cli-out.c
195
gdb/cli-out.c
@ -26,6 +26,7 @@
|
|||||||
#include "completer.h"
|
#include "completer.h"
|
||||||
#include "readline/readline.h"
|
#include "readline/readline.h"
|
||||||
#include "cli/cli-style.h"
|
#include "cli/cli-style.h"
|
||||||
|
#include "top.h"
|
||||||
|
|
||||||
/* These are the CLI output functions */
|
/* These are the CLI output functions */
|
||||||
|
|
||||||
@ -262,105 +263,157 @@ cli_ui_out::do_redirect (ui_file *outstream)
|
|||||||
m_streams.pop_back ();
|
m_streams.pop_back ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The cli_ui_out::do_progress_* functions result in the following:
|
/* Initialize a progress update to be displayed with
|
||||||
- printed for tty, SHOULD_PRINT == true:
|
cli_ui_out::do_progress_notify. */
|
||||||
<NAME
|
|
||||||
[##### ]\r>
|
void
|
||||||
- printed for tty, SHOULD_PRINT == false:
|
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:
|
- printed for not-a-tty:
|
||||||
<NAME...
|
<MSG...\n>
|
||||||
>
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
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 ();
|
struct ui_file *stream = m_streams.back ();
|
||||||
cli_progress_info meter;
|
cli_progress_info &info (m_progress_info.back ());
|
||||||
|
|
||||||
meter.last_value = 0;
|
if (chars_per_line > MAX_CHARS_PER_LINE)
|
||||||
meter.name = name;
|
chars_per_line = MAX_CHARS_PER_LINE;
|
||||||
if (!stream->isatty ())
|
|
||||||
|
if (info.state == progress_update::START)
|
||||||
{
|
{
|
||||||
gdb_printf (stream, "%s...", meter.name.c_str ());
|
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;
|
||||||
|
|
||||||
|
if (total > 0 && howmuch >= 0 && howmuch <= 1.0)
|
||||||
|
{
|
||||||
|
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);
|
gdb_flush (stream);
|
||||||
meter.printing = WORKING;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Don't actually emit anything until the first call notifies us
|
using namespace std::chrono;
|
||||||
of progress. This makes it so a second progress message can
|
milliseconds diff = duration_cast<milliseconds>
|
||||||
be started before the first one has been notified, without
|
(steady_clock::now () - info.last_update);
|
||||||
messy output. */
|
|
||||||
meter.printing = should_print ? START : NO_PRINT;
|
/* 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
|
void
|
||||||
cli_ui_out::do_progress_notify (double howmuch)
|
cli_ui_out::clear_current_line ()
|
||||||
{
|
{
|
||||||
struct ui_file *stream = m_streams.back ();
|
struct ui_file *stream = m_streams.back ();
|
||||||
cli_progress_info &meter (m_meters.back ());
|
|
||||||
|
|
||||||
if (meter.printing == NO_PRINT)
|
|
||||||
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 (!stream->isatty ())
|
|
||||||
return;
|
|
||||||
|
|
||||||
int chars_per_line = get_chars_per_line ();
|
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;
|
if (!stream->isatty ()
|
||||||
gdb_printf (stream, "\r[");
|
|| !current_ui->input_interactive_p ()
|
||||||
for (i = 0; i < width; ++i)
|
|| chars_per_line < MIN_CHARS_PER_LINE)
|
||||||
gdb_printf (stream, i < max ? "#" : " ");
|
return;
|
||||||
gdb_printf (stream, "]");
|
|
||||||
gdb_flush (stream);
|
if (chars_per_line > MAX_CHARS_PER_LINE)
|
||||||
meter.printing = PROGRESS;
|
chars_per_line = MAX_CHARS_PER_LINE;
|
||||||
}
|
|
||||||
|
gdb_printf (stream, "\r");
|
||||||
|
for (int i = 0; i < chars_per_line; ++i)
|
||||||
|
gdb_printf (stream, " ");
|
||||||
|
gdb_printf (stream, "\r");
|
||||||
|
|
||||||
|
gdb_flush (stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove the most recent progress update from the progress_info stack
|
||||||
|
and overwrite the current line with whitespace. */
|
||||||
|
|
||||||
void
|
void
|
||||||
cli_ui_out::do_progress_end ()
|
cli_ui_out::do_progress_end ()
|
||||||
{
|
{
|
||||||
struct ui_file *stream = m_streams.back ();
|
struct ui_file *stream = m_streams.back ();
|
||||||
cli_progress_info &meter = m_meters.back ();
|
m_progress_info.pop_back ();
|
||||||
|
|
||||||
if (!stream->isatty ())
|
if (stream->isatty ())
|
||||||
{
|
clear_current_line ();
|
||||||
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_meters.pop_back ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* local functions */
|
/* local functions */
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#define CLI_OUT_H
|
#define CLI_OUT_H
|
||||||
|
|
||||||
#include "ui-out.h"
|
#include "ui-out.h"
|
||||||
|
#include <chrono>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class cli_ui_out : public ui_out
|
class cli_ui_out : public ui_out
|
||||||
@ -71,8 +72,9 @@ protected:
|
|||||||
virtual void do_flush () override;
|
virtual void do_flush () override;
|
||||||
virtual void do_redirect (struct ui_file *outstream) override;
|
virtual void do_redirect (struct ui_file *outstream) override;
|
||||||
|
|
||||||
virtual void do_progress_start (const std::string &, bool) override;
|
virtual void do_progress_start () override;
|
||||||
virtual void do_progress_notify (double) override;
|
virtual void do_progress_notify (const std::string &, const char *,
|
||||||
|
double, double) override;
|
||||||
virtual void do_progress_end () override;
|
virtual void do_progress_end () override;
|
||||||
|
|
||||||
bool suppress_output ()
|
bool suppress_output ()
|
||||||
@ -85,32 +87,24 @@ private:
|
|||||||
std::vector<ui_file *> m_streams;
|
std::vector<ui_file *> m_streams;
|
||||||
bool m_suppress_output;
|
bool m_suppress_output;
|
||||||
|
|
||||||
/* Represents the printing state of a progress meter. */
|
/* The state of a recent progress update. */
|
||||||
enum meter_state
|
|
||||||
{
|
|
||||||
/* Printing will start with the next output. */
|
|
||||||
START,
|
|
||||||
/* Printing has already started. */
|
|
||||||
WORKING,
|
|
||||||
/* Progress printing has already started. */
|
|
||||||
PROGRESS,
|
|
||||||
/* Printing should not be done. */
|
|
||||||
NO_PRINT
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The state of a recent progress meter. */
|
|
||||||
struct cli_progress_info
|
struct cli_progress_info
|
||||||
{
|
{
|
||||||
|
/* Position of the progress indicator. */
|
||||||
|
int pos;
|
||||||
/* The current state. */
|
/* The current state. */
|
||||||
enum meter_state printing;
|
progress_update::state state;
|
||||||
/* The name to print. */
|
/* Progress indicator's time of last update. */
|
||||||
std::string name;
|
std::chrono::steady_clock::time_point last_update;
|
||||||
/* The last notification value. */
|
|
||||||
double last_value;
|
cli_progress_info ()
|
||||||
|
: pos (0), state (progress_update::START)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Stack of progress meters. */
|
/* Stack of progress info. */
|
||||||
std::vector<cli_progress_info> m_meters;
|
std::vector<cli_progress_info> m_progress_info;
|
||||||
|
void clear_current_line ();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void cli_display_match_list (char **matches, int len, int max);
|
extern void cli_display_match_list (char **matches, int len, int max);
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "gdbsupport/gdb_optional.h"
|
#include "gdbsupport/gdb_optional.h"
|
||||||
#include "cli/cli-cmds.h"
|
#include "cli/cli-cmds.h"
|
||||||
#include "cli/cli-style.h"
|
#include "cli/cli-style.h"
|
||||||
|
#include "cli-out.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
|
||||||
/* Set/show debuginfod commands. */
|
/* Set/show debuginfod commands. */
|
||||||
@ -87,12 +88,12 @@ debuginfod_exec_query (const unsigned char *build_id,
|
|||||||
struct user_data
|
struct user_data
|
||||||
{
|
{
|
||||||
user_data (const char *desc, const char *fname)
|
user_data (const char *desc, const char *fname)
|
||||||
: desc (desc), fname (fname), has_printed (false)
|
: desc (desc), fname (fname)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
const char * const desc;
|
const char * const desc;
|
||||||
const char * const fname;
|
const char * const fname;
|
||||||
bool has_printed;
|
ui_out::progress_update progress;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Deleter for a debuginfod_client. */
|
/* Deleter for a debuginfod_client. */
|
||||||
@ -108,47 +109,74 @@ struct debuginfod_client_deleter
|
|||||||
using debuginfod_client_up
|
using debuginfod_client_up
|
||||||
= std::unique_ptr<debuginfod_client, debuginfod_client_deleter>;
|
= std::unique_ptr<debuginfod_client, debuginfod_client_deleter>;
|
||||||
|
|
||||||
|
|
||||||
|
/* Convert SIZE into a unit suitable for use with progress updates.
|
||||||
|
SIZE should in given in bytes and will be converted into KB, MB, GB
|
||||||
|
or remain unchanged. UNIT will be set to "B", "KB", "MB" or "GB"
|
||||||
|
accordingly. */
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
get_size_and_unit (double &size)
|
||||||
|
{
|
||||||
|
if (size < 1024)
|
||||||
|
/* If size is less than 1 KB then set unit to B. */
|
||||||
|
return "B";
|
||||||
|
|
||||||
|
size /= 1024;
|
||||||
|
if (size < 1024)
|
||||||
|
/* If size is less than 1 MB then set unit to KB. */
|
||||||
|
return "K";
|
||||||
|
|
||||||
|
size /= 1024;
|
||||||
|
if (size < 1024)
|
||||||
|
/* If size is less than 1 GB then set unit to MB. */
|
||||||
|
return "M";
|
||||||
|
|
||||||
|
size /= 1024;
|
||||||
|
return "G";
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
progressfn (debuginfod_client *c, long cur, long total)
|
progressfn (debuginfod_client *c, long cur, long total)
|
||||||
{
|
{
|
||||||
user_data *data = static_cast<user_data *> (debuginfod_get_user_data (c));
|
user_data *data = static_cast<user_data *> (debuginfod_get_user_data (c));
|
||||||
gdb_assert (data != nullptr);
|
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);
|
||||||
|
|
||||||
if (check_quit_flag ())
|
if (check_quit_flag ())
|
||||||
{
|
{
|
||||||
gdb_printf ("Cancelling download of %s %ps...\n",
|
gdb_printf ("Cancelling download of %s %s...\n",
|
||||||
data->desc,
|
data->desc, styled_fname.c_str ());
|
||||||
styled_string (file_name_style.style (), data->fname));
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data->has_printed)
|
if (debuginfod_verbose == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Print progress update. Include the transfer size if available. */
|
||||||
|
if (total > 0)
|
||||||
{
|
{
|
||||||
/* Include the transfer size, if available. */
|
/* Transfer size is known. */
|
||||||
if (total > 0)
|
double howmuch = (double) cur / (double) total;
|
||||||
|
|
||||||
|
if (howmuch >= 0.0 && howmuch <= 1.0)
|
||||||
{
|
{
|
||||||
float size = 1.0f * total / 1024;
|
double d_total = (double) total;
|
||||||
const char *unit = "KB";
|
const char *unit = get_size_and_unit (d_total);
|
||||||
|
std::string msg = string_printf ("Downloading %0.2f %s %s %s",
|
||||||
/* If size is greater than 0.01 MB, set unit to MB. */
|
d_total, unit, data->desc,
|
||||||
if (size > 10.24)
|
styled_fname.c_str ());
|
||||||
{
|
data->progress.update_progress (msg, unit, howmuch, d_total);
|
||||||
size /= 1024;
|
return 0;
|
||||||
unit = "MB";
|
|
||||||
}
|
|
||||||
|
|
||||||
gdb_printf ("Downloading %.2f %s %s %ps...\n",
|
|
||||||
size, unit, data->desc,
|
|
||||||
styled_string (file_name_style.style (),
|
|
||||||
data->fname));
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
gdb_printf ("Downloading %s %ps...\n", data->desc,
|
|
||||||
styled_string (file_name_style.style (), data->fname));
|
|
||||||
|
|
||||||
data->has_printed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string msg = string_printf ("Downloading %s %s",
|
||||||
|
data->desc, styled_fname.c_str ());
|
||||||
|
data->progress.update_progress (msg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,6 +258,21 @@ debuginfod_is_enabled ()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Print the result of the most recent attempted download. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_outcome (user_data &data, int fd)
|
||||||
|
{
|
||||||
|
/* Clears the current line of progress output. */
|
||||||
|
current_uiout->do_progress_end ();
|
||||||
|
|
||||||
|
if (fd < 0 && fd != -ENOENT)
|
||||||
|
gdb_printf (_("Download failed: %s. Continuing without %s %ps.\n"),
|
||||||
|
safe_strerror (-fd),
|
||||||
|
data.desc,
|
||||||
|
styled_string (file_name_style.style (), data.fname));
|
||||||
|
}
|
||||||
|
|
||||||
/* See debuginfod-support.h */
|
/* See debuginfod-support.h */
|
||||||
|
|
||||||
scoped_fd
|
scoped_fd
|
||||||
@ -263,11 +306,7 @@ debuginfod_source_query (const unsigned char *build_id,
|
|||||||
srcpath,
|
srcpath,
|
||||||
&dname));
|
&dname));
|
||||||
debuginfod_set_user_data (c, nullptr);
|
debuginfod_set_user_data (c, nullptr);
|
||||||
|
print_outcome (data, fd.get ());
|
||||||
if (fd.get () < 0 && fd.get () != -ENOENT)
|
|
||||||
gdb_printf (_("Download failed: %s. Continuing without source file %ps.\n"),
|
|
||||||
safe_strerror (-fd.get ()),
|
|
||||||
styled_string (file_name_style.style (), srcpath));
|
|
||||||
|
|
||||||
if (fd.get () >= 0)
|
if (fd.get () >= 0)
|
||||||
destname->reset (dname);
|
destname->reset (dname);
|
||||||
@ -305,11 +344,7 @@ debuginfod_debuginfo_query (const unsigned char *build_id,
|
|||||||
scoped_fd fd (debuginfod_find_debuginfo (c, build_id, build_id_len,
|
scoped_fd fd (debuginfod_find_debuginfo (c, build_id, build_id_len,
|
||||||
&dname));
|
&dname));
|
||||||
debuginfod_set_user_data (c, nullptr);
|
debuginfod_set_user_data (c, nullptr);
|
||||||
|
print_outcome (data, fd.get ());
|
||||||
if (fd.get () < 0 && fd.get () != -ENOENT)
|
|
||||||
gdb_printf (_("Download failed: %s. Continuing without debug info for %ps.\n"),
|
|
||||||
safe_strerror (-fd.get ()),
|
|
||||||
styled_string (file_name_style.style (), filename));
|
|
||||||
|
|
||||||
if (fd.get () >= 0)
|
if (fd.get () >= 0)
|
||||||
destname->reset (dname);
|
destname->reset (dname);
|
||||||
@ -346,12 +381,7 @@ debuginfod_exec_query (const unsigned char *build_id,
|
|||||||
|
|
||||||
scoped_fd fd (debuginfod_find_executable (c, build_id, build_id_len, &dname));
|
scoped_fd fd (debuginfod_find_executable (c, build_id, build_id_len, &dname));
|
||||||
debuginfod_set_user_data (c, nullptr);
|
debuginfod_set_user_data (c, nullptr);
|
||||||
|
print_outcome (data, fd.get ());
|
||||||
if (fd.get () < 0 && fd.get () != -ENOENT)
|
|
||||||
gdb_printf (_("Download failed: %s. " \
|
|
||||||
"Continuing without executable for %ps.\n"),
|
|
||||||
safe_strerror (-fd.get ()),
|
|
||||||
styled_string (file_name_style.style (), filename));
|
|
||||||
|
|
||||||
if (fd.get () >= 0)
|
if (fd.get () >= 0)
|
||||||
destname->reset (dname);
|
destname->reset (dname);
|
||||||
|
@ -259,6 +259,38 @@ mi_ui_out::main_stream ()
|
|||||||
return (string_file *) m_streams.back ();
|
return (string_file *) m_streams.back ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initialize a progress update to be displayed with
|
||||||
|
mi_ui_out::do_progress_notify. */
|
||||||
|
|
||||||
|
void
|
||||||
|
mi_ui_out::do_progress_start ()
|
||||||
|
{
|
||||||
|
m_progress_info.emplace_back ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Indicate that a task described by MSG is in progress. */
|
||||||
|
|
||||||
|
void
|
||||||
|
mi_ui_out::do_progress_notify (const std::string &msg, const char *unit,
|
||||||
|
double cur, double total)
|
||||||
|
{
|
||||||
|
mi_progress_info &info (m_progress_info.back ());
|
||||||
|
|
||||||
|
if (info.state == progress_update::START)
|
||||||
|
{
|
||||||
|
gdb_printf ("%s...\n", msg.c_str ());
|
||||||
|
info.state = progress_update::WORKING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the most recent progress update from the progress_info stack. */
|
||||||
|
|
||||||
|
void
|
||||||
|
mi_ui_out::do_progress_end ()
|
||||||
|
{
|
||||||
|
m_progress_info.pop_back ();
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear the buffer. */
|
/* Clear the buffer. */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -83,17 +83,11 @@ protected:
|
|||||||
virtual bool do_is_mi_like_p () const override
|
virtual bool do_is_mi_like_p () const override
|
||||||
{ return true; }
|
{ return true; }
|
||||||
|
|
||||||
virtual void do_progress_start (const std::string &, bool) override
|
virtual void do_progress_start () override;
|
||||||
{
|
virtual void do_progress_notify (const std::string &, const char *,
|
||||||
}
|
double, double) override;
|
||||||
|
|
||||||
virtual void do_progress_notify (double) override
|
virtual void do_progress_end () override;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void do_progress_end () override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -101,6 +95,20 @@ private:
|
|||||||
void open (const char *name, ui_out_type type);
|
void open (const char *name, ui_out_type type);
|
||||||
void close (ui_out_type type);
|
void close (ui_out_type type);
|
||||||
|
|
||||||
|
/* The state of a recent progress_update. */
|
||||||
|
struct mi_progress_info
|
||||||
|
{
|
||||||
|
/* The current state. */
|
||||||
|
progress_update::state state;
|
||||||
|
|
||||||
|
mi_progress_info ()
|
||||||
|
: state (progress_update::START)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Stack of progress info. */
|
||||||
|
std::vector<mi_progress_info> m_progress_info;
|
||||||
|
|
||||||
/* Convenience method that returns the MI out's string stream cast
|
/* Convenience method that returns the MI out's string stream cast
|
||||||
to its appropriate type. Assumes/asserts that output was not
|
to its appropriate type. Assumes/asserts that output was not
|
||||||
redirected. */
|
redirected. */
|
||||||
|
53
gdb/ui-out.h
53
gdb/ui-out.h
@ -278,39 +278,56 @@ class ui_out
|
|||||||
escapes. */
|
escapes. */
|
||||||
virtual bool can_emit_style_escape () const = 0;
|
virtual bool can_emit_style_escape () const = 0;
|
||||||
|
|
||||||
/* An object that starts and finishes a progress meter. */
|
/* An object that starts and finishes displaying progress updates. */
|
||||||
class progress_meter
|
class progress_update
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/* Represents the printing state of a progress update. */
|
||||||
|
enum state
|
||||||
|
{
|
||||||
|
/* Printing will start with the next update. */
|
||||||
|
START,
|
||||||
|
/* Printing has already started. */
|
||||||
|
WORKING,
|
||||||
|
/* Progress bar printing has already started. */
|
||||||
|
BAR
|
||||||
|
};
|
||||||
|
|
||||||
/* SHOULD_PRINT indicates whether something should be printed for a tty. */
|
/* SHOULD_PRINT indicates whether something should be printed for a tty. */
|
||||||
progress_meter (struct ui_out *uiout, const std::string &name,
|
progress_update ()
|
||||||
bool should_print)
|
|
||||||
: m_uiout (uiout)
|
|
||||||
{
|
{
|
||||||
m_uiout->do_progress_start (name, should_print);
|
m_uiout = current_uiout;
|
||||||
|
m_uiout->do_progress_start ();
|
||||||
}
|
}
|
||||||
|
|
||||||
~progress_meter ()
|
~progress_update ()
|
||||||
{
|
{
|
||||||
m_uiout->do_progress_notify (1.0);
|
|
||||||
m_uiout->do_progress_end ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
progress_meter (const progress_meter &) = delete;
|
progress_update (const progress_update &) = delete;
|
||||||
progress_meter &operator= (const progress_meter &) = delete;
|
progress_update &operator= (const progress_update &) = delete;
|
||||||
|
|
||||||
/* Emit some progress for this progress meter. HOWMUCH may range
|
/* Emit some progress for this progress meter. Includes current
|
||||||
from 0.0 to 1.0. */
|
amount of progress made and total amount in the display. */
|
||||||
void progress (double howmuch)
|
void update_progress (const std::string& msg, const char *unit,
|
||||||
|
double cur, double total)
|
||||||
{
|
{
|
||||||
m_uiout->do_progress_notify (howmuch);
|
m_uiout->do_progress_notify (msg, unit, cur, total);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Emit some progress for this progress meter. */
|
||||||
|
void update_progress (const std::string& msg)
|
||||||
|
{
|
||||||
|
m_uiout->do_progress_notify (msg, "", -1, -1);
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct ui_out *m_uiout;
|
struct ui_out *m_uiout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtual void do_progress_end () = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void do_table_begin (int nbrofcols, int nr_rows, const char *tblid)
|
virtual void do_table_begin (int nbrofcols, int nr_rows, const char *tblid)
|
||||||
@ -345,9 +362,9 @@ class ui_out
|
|||||||
virtual void do_flush () = 0;
|
virtual void do_flush () = 0;
|
||||||
virtual void do_redirect (struct ui_file *outstream) = 0;
|
virtual void do_redirect (struct ui_file *outstream) = 0;
|
||||||
|
|
||||||
virtual void do_progress_start (const std::string &, bool) = 0;
|
virtual void do_progress_start () = 0;
|
||||||
virtual void do_progress_notify (double) = 0;
|
virtual void do_progress_notify (const std::string &, const char *,
|
||||||
virtual void do_progress_end () = 0;
|
double, double) = 0;
|
||||||
|
|
||||||
/* Set as not MI-like by default. It is overridden in subclasses if
|
/* Set as not MI-like by default. It is overridden in subclasses if
|
||||||
necessary. */
|
necessary. */
|
||||||
|
Reference in New Issue
Block a user