forked from Imagelibrary/binutils-gdb
Move UI out of debuginfod-support and into ui-out and subclasses.
This commit is contained in:
@@ -280,15 +280,14 @@ void
|
||||
cli_ui_out::do_progress_start (const std::string &name, bool should_print)
|
||||
{
|
||||
struct ui_file *stream = m_streams.back ();
|
||||
cli_progress_info meter;
|
||||
cli_progress_info info;
|
||||
|
||||
meter.last_value = 0;
|
||||
meter.name = name;
|
||||
info.name = name;
|
||||
if (!stream->isatty ())
|
||||
{
|
||||
fprintf_unfiltered (stream, "%s...", meter.name.c_str ());
|
||||
fprintf_unfiltered (stream, "%s...", info.name.c_str ());
|
||||
gdb_flush (stream);
|
||||
meter.printing = WORKING;
|
||||
info.state = progress_report::WORKING;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -296,74 +295,120 @@ cli_ui_out::do_progress_start (const std::string &name, bool should_print)
|
||||
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;
|
||||
info.state = should_print ? progress_report::START
|
||||
: progress_report::NO_PRINT;
|
||||
}
|
||||
|
||||
m_meters.push_back (std::move (meter));
|
||||
m_progress_info.push_back (std::move (info));
|
||||
}
|
||||
|
||||
void
|
||||
cli_ui_out::do_progress_notify (double howmuch)
|
||||
{
|
||||
struct ui_file *stream = m_streams.back ();
|
||||
cli_progress_info &meter (m_meters.back ());
|
||||
cli_progress_info &info (m_progress_info.back ());
|
||||
|
||||
if (meter.printing == NO_PRINT)
|
||||
if (info.state == progress_report::NO_PRINT)
|
||||
return;
|
||||
|
||||
if (meter.printing == START)
|
||||
int chars_per_line = get_chars_per_line ();
|
||||
if (info.state == progress_report::START && chars_per_line <= 0)
|
||||
{
|
||||
fprintf_unfiltered (stream, "%s\n", meter.name.c_str ());
|
||||
fprintf_unfiltered (stream, "%s\n", info.name.c_str ());
|
||||
gdb_flush (stream);
|
||||
meter.printing = WORKING;
|
||||
info.state = progress_report::WORKING;
|
||||
}
|
||||
|
||||
if (meter.printing == WORKING && howmuch >= 1.0)
|
||||
if (info.state == progress_report::WORKING && howmuch >= 1.0)
|
||||
return;
|
||||
|
||||
if (!stream->isatty ())
|
||||
return;
|
||||
|
||||
int chars_per_line = get_chars_per_line ();
|
||||
if (chars_per_line > 0)
|
||||
if (chars_per_line <= 0)
|
||||
return;
|
||||
|
||||
if (howmuch <= 0.0)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
seconds diff = duration_cast<seconds>
|
||||
(steady_clock::now () - info.last_update);
|
||||
|
||||
if (diff.count () >= 1.0)
|
||||
{
|
||||
static int spin = 0;
|
||||
|
||||
fprintf_unfiltered (stream, "\r%s %c\b", info.name.c_str (),
|
||||
"-\\|/"[spin++ % 4]);
|
||||
gdb_flush (stream);
|
||||
info.last_update = steady_clock::now ();
|
||||
}
|
||||
info.state = progress_report::SPIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Pick a reasonable limit for the progress bar length. */
|
||||
if (chars_per_line > 3840)
|
||||
chars_per_line = 3840;
|
||||
|
||||
int i, max;
|
||||
int width = chars_per_line - 3;
|
||||
|
||||
max = width * howmuch;
|
||||
|
||||
if (info.state == progress_report::SPIN)
|
||||
{
|
||||
/* Ensure the progress bar prints on its own line so that
|
||||
progress updates don't erase 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);
|
||||
meter.printing = PROGRESS;
|
||||
info.state = progress_report::BAR;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cli_ui_out::update_progress_name (const std::string &name)
|
||||
{
|
||||
cli_progress_info &info = m_progress_info.back ();
|
||||
info.name = name;
|
||||
}
|
||||
|
||||
cli_ui_out::progress_report::state
|
||||
cli_ui_out::get_progress_state ()
|
||||
{
|
||||
cli_progress_info &info = m_progress_info.back ();
|
||||
return info.state;
|
||||
}
|
||||
|
||||
void
|
||||
cli_ui_out::do_progress_end ()
|
||||
{
|
||||
struct ui_file *stream = m_streams.back ();
|
||||
cli_progress_info &meter = m_meters.back ();
|
||||
cli_progress_info &info = m_progress_info.back ();
|
||||
|
||||
if (!stream->isatty ())
|
||||
{
|
||||
fprintf_unfiltered (stream, "\n");
|
||||
gdb_flush (stream);
|
||||
}
|
||||
else if (meter.printing == PROGRESS)
|
||||
if (!stream->isatty () || info.state == progress_report::SPIN)
|
||||
fprintf_unfiltered (stream, " \n");
|
||||
else if (info.state == progress_report::BAR)
|
||||
{
|
||||
int i;
|
||||
int width = get_chars_per_line () - 3;
|
||||
|
||||
this->do_progress_notify (1.0);
|
||||
fprintf_unfiltered (stream, "\r");
|
||||
for (i = 0; i < width + 2; ++i)
|
||||
fprintf_unfiltered (stream, " ");
|
||||
fprintf_unfiltered (stream, "\r");
|
||||
gdb_flush (stream);
|
||||
}
|
||||
|
||||
m_meters.pop_back ();
|
||||
gdb_flush (stream);
|
||||
m_progress_info.pop_back ();
|
||||
}
|
||||
|
||||
/* local functions */
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define CLI_OUT_H
|
||||
|
||||
#include "ui-out.h"
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
|
||||
class cli_ui_out : public ui_out
|
||||
@@ -74,6 +75,8 @@ protected:
|
||||
virtual void do_progress_start (const std::string &, bool) override;
|
||||
virtual void do_progress_notify (double) override;
|
||||
virtual void do_progress_end () override;
|
||||
virtual void update_progress_name (const std::string &) override;
|
||||
virtual progress_report::state get_progress_state () override;
|
||||
|
||||
bool suppress_output ()
|
||||
{ return m_suppress_output; }
|
||||
@@ -85,32 +88,19 @@ private:
|
||||
std::vector<ui_file *> m_streams;
|
||||
bool m_suppress_output;
|
||||
|
||||
/* Represents the printing state of a progress meter. */
|
||||
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. */
|
||||
/* The state of a recent progress report. */
|
||||
struct cli_progress_info
|
||||
{
|
||||
/* The current state. */
|
||||
enum meter_state printing;
|
||||
progress_report::state state;
|
||||
/* The name to print. */
|
||||
std::string name;
|
||||
/* The last notification value. */
|
||||
double last_value;
|
||||
/* Time of last spinner update. */
|
||||
std::chrono::steady_clock::time_point last_update;
|
||||
};
|
||||
|
||||
/* Stack of progress meters. */
|
||||
std::vector<cli_progress_info> m_meters;
|
||||
/* Stack of progress info. */
|
||||
std::vector<cli_progress_info> m_progress_info;
|
||||
};
|
||||
|
||||
extern cli_ui_out *cli_out_new (struct ui_file *stream);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "gdbsupport/gdb_optional.h"
|
||||
#include "cli/cli-cmds.h"
|
||||
#include "cli/cli-style.h"
|
||||
#include "cli-out.h"
|
||||
#include "target.h"
|
||||
|
||||
/* Set/show debuginfod commands. */
|
||||
@@ -82,8 +83,7 @@ struct user_data
|
||||
|
||||
const char * const desc;
|
||||
const char * const fname;
|
||||
gdb::optional<ui_out::progress_meter> meter;
|
||||
bool printed_spin = false;
|
||||
gdb::optional<ui_out::progress_report> report;
|
||||
};
|
||||
|
||||
/* Deleter for a debuginfod_client. */
|
||||
@@ -102,12 +102,14 @@ using debuginfod_client_up
|
||||
static int
|
||||
progressfn (debuginfod_client *c, long cur, long total)
|
||||
{
|
||||
static int spin = 0;
|
||||
user_data *data = static_cast<user_data *> (debuginfod_get_user_data (c));
|
||||
gdb_assert (data != nullptr);
|
||||
|
||||
if (check_quit_flag ())
|
||||
{
|
||||
if (data->report.has_value ())
|
||||
data->report.reset ();
|
||||
|
||||
printf_filtered ("Cancelling download of %s %ps...\n",
|
||||
data->desc,
|
||||
styled_string (file_name_style.style (), data->fname));
|
||||
@@ -122,41 +124,44 @@ progressfn (debuginfod_client *c, long cur, long total)
|
||||
|
||||
if (total > 0)
|
||||
{
|
||||
if (!data->meter.has_value ())
|
||||
/* Transfer size is known, so print it along with the rest of the
|
||||
progress update. */
|
||||
if (!data->report.has_value ()
|
||||
|| data->report->get_state () == ui_out::progress_report::SPIN)
|
||||
{
|
||||
double size = 1.0f * total / 1024;
|
||||
std::string unit = "KB";
|
||||
|
||||
/* Switch to MB if size greater than 0.01 MB. */
|
||||
/* Switch unit to MB if size is greater than 0.01 MB. */
|
||||
if (size > 10.24)
|
||||
{
|
||||
size /= 1024;
|
||||
unit = "MB";
|
||||
}
|
||||
|
||||
/* Overwrite an existing progress update line with no download
|
||||
size information. */
|
||||
if (data->printed_spin)
|
||||
{
|
||||
current_uiout->message ("\r");
|
||||
data->printed_spin = false;
|
||||
}
|
||||
|
||||
std::string message = string_printf ("Downloading %.2f %s %s %s",
|
||||
size, unit.c_str (),
|
||||
data->desc,
|
||||
styled_filename.c_str ());
|
||||
data->meter.emplace (current_uiout, message, 1);
|
||||
|
||||
if (!data->report.has_value ())
|
||||
data->report.emplace (current_uiout, message, 1);
|
||||
else
|
||||
data->report->update_name (message);
|
||||
}
|
||||
|
||||
current_uiout->progress ((double)cur / (double)total);
|
||||
current_uiout->update_progress ((double)cur / (double)total);
|
||||
}
|
||||
else
|
||||
{
|
||||
current_uiout->message (_("\rDownloading %s %s %c"), data->desc,
|
||||
styled_filename.c_str (), "-/|\\"[spin++ % 4]);
|
||||
current_uiout->flush ();
|
||||
data->printed_spin = true;
|
||||
if (!data->report.has_value ())
|
||||
{
|
||||
std::string message = string_printf ("Downloading %s %s", data->desc,
|
||||
styled_filename.c_str ());
|
||||
data->report.emplace (current_uiout, message, 1);
|
||||
}
|
||||
|
||||
current_uiout->update_progress (-1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -230,6 +235,7 @@ debuginfod_source_query (const unsigned char *build_id,
|
||||
if (c == nullptr)
|
||||
return scoped_fd (-ENOMEM);
|
||||
|
||||
char *dname = nullptr;
|
||||
user_data data ("source file", srcpath);
|
||||
|
||||
debuginfod_set_user_data (c, &data);
|
||||
@@ -244,9 +250,7 @@ debuginfod_source_query (const unsigned char *build_id,
|
||||
build_id,
|
||||
build_id_len,
|
||||
srcpath,
|
||||
nullptr));
|
||||
if (data.printed_spin)
|
||||
current_uiout->message ("\b \n");
|
||||
&dname));
|
||||
|
||||
debuginfod_set_user_data (c, nullptr);
|
||||
|
||||
@@ -256,7 +260,7 @@ debuginfod_source_query (const unsigned char *build_id,
|
||||
styled_string (file_name_style.style (), srcpath));
|
||||
|
||||
if (fd.get () >= 0)
|
||||
*destname = make_unique_xstrdup (srcpath);
|
||||
destname->reset (dname);
|
||||
|
||||
return fd;
|
||||
}
|
||||
@@ -290,9 +294,6 @@ debuginfod_debuginfo_query (const unsigned char *build_id,
|
||||
|
||||
scoped_fd fd (debuginfod_find_debuginfo (c, build_id, build_id_len,
|
||||
&dname));
|
||||
if (data.printed_spin)
|
||||
current_uiout->message ("\b \n");
|
||||
|
||||
debuginfod_set_user_data (c, nullptr);
|
||||
|
||||
if (debuginfod_verbose > 0 && fd.get () < 0 && fd.get () != -ENOENT)
|
||||
|
||||
@@ -258,6 +258,25 @@ mi_ui_out::main_stream ()
|
||||
return (string_file *) m_streams.back ();
|
||||
}
|
||||
|
||||
void
|
||||
mi_ui_out::do_progress_start (const std::string &name, bool should_print)
|
||||
{
|
||||
struct ui_file *stream = gdb_stdout;
|
||||
mi_progress_info info;
|
||||
|
||||
fprintf_unfiltered (stream, "%s...\n", name.c_str ());
|
||||
gdb_flush (stream);
|
||||
info.state = progress_report::WORKING;
|
||||
m_progress_info.push_back (std::move (info));
|
||||
}
|
||||
|
||||
mi_ui_out::progress_report::state
|
||||
mi_ui_out::get_progress_state ()
|
||||
{
|
||||
mi_progress_info &info = m_progress_info.back ();
|
||||
return info.state;
|
||||
}
|
||||
|
||||
/* Clear the buffer. */
|
||||
|
||||
void
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
struct ui_out;
|
||||
struct ui_file;
|
||||
|
||||
|
||||
class mi_ui_out : public ui_out
|
||||
{
|
||||
public:
|
||||
@@ -83,9 +82,8 @@ protected:
|
||||
virtual bool do_is_mi_like_p () const override
|
||||
{ return true; }
|
||||
|
||||
virtual void do_progress_start (const std::string &, bool) override
|
||||
{
|
||||
}
|
||||
virtual void do_progress_start (const std::string &, bool) override;
|
||||
virtual progress_report::state get_progress_state () override;
|
||||
|
||||
virtual void do_progress_notify (double) override
|
||||
{
|
||||
@@ -95,12 +93,26 @@ protected:
|
||||
{
|
||||
}
|
||||
|
||||
virtual void update_progress_name (const std::string &) override
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void field_separator ();
|
||||
void open (const char *name, ui_out_type type);
|
||||
void close (ui_out_type type);
|
||||
|
||||
/* The state of a recent progress_report. */
|
||||
struct mi_progress_info
|
||||
{
|
||||
/* The current state. */
|
||||
progress_report::state state;
|
||||
};
|
||||
|
||||
/* Stack of progress info. */
|
||||
std::vector<mi_progress_info> m_progress_info;
|
||||
|
||||
/* Convenience method that returns the MI out's string stream cast
|
||||
to its appropriate type. Assumes/asserts that output was not
|
||||
redirected. */
|
||||
|
||||
46
gdb/ui-out.h
46
gdb/ui-out.h
@@ -280,26 +280,50 @@ class ui_out
|
||||
escapes. */
|
||||
virtual bool can_emit_style_escape () const = 0;
|
||||
|
||||
/* An object that starts and finishes a progress meter. */
|
||||
class progress_meter
|
||||
/* An object that starts and finishes progress reporting. */
|
||||
class progress_report
|
||||
{
|
||||
public:
|
||||
/* Represents the printing state of a progress report. */
|
||||
enum state
|
||||
{
|
||||
/* Printing will start with the next output. */
|
||||
START,
|
||||
/* Printing has already started. */
|
||||
WORKING,
|
||||
/* Progress bar printing has already started. */
|
||||
BAR,
|
||||
/* Spinner printing has already started. */
|
||||
SPIN,
|
||||
/* Printing should not be done. */
|
||||
NO_PRINT
|
||||
};
|
||||
|
||||
/* SHOULD_PRINT indicates whether something should be printed for a tty. */
|
||||
progress_meter (struct ui_out *uiout, const std::string &name,
|
||||
bool should_print)
|
||||
progress_report (struct ui_out *uiout, const std::string &name,
|
||||
bool should_print)
|
||||
: m_uiout (uiout)
|
||||
{
|
||||
m_uiout->do_progress_start (name, should_print);
|
||||
}
|
||||
|
||||
~progress_meter ()
|
||||
~progress_report ()
|
||||
{
|
||||
m_uiout->do_progress_notify (1.0);
|
||||
m_uiout->do_progress_end ();
|
||||
}
|
||||
|
||||
progress_meter (const progress_meter &) = delete;
|
||||
progress_meter &operator= (const progress_meter &) = delete;
|
||||
void update_name (std::string &name)
|
||||
{
|
||||
m_uiout->update_progress_name (name);
|
||||
}
|
||||
|
||||
state get_state ()
|
||||
{
|
||||
return m_uiout->get_progress_state ();
|
||||
}
|
||||
|
||||
progress_report (const progress_report &) = delete;
|
||||
progress_report &operator= (const progress_report &) = delete;
|
||||
|
||||
private:
|
||||
|
||||
@@ -307,8 +331,8 @@ class ui_out
|
||||
};
|
||||
|
||||
/* Emit some progress corresponding to the most recently created
|
||||
progress meter. HOWMUCH may range from 0.0 to 1.0. */
|
||||
void progress (double howmuch)
|
||||
progress_report object. */
|
||||
void update_progress (double howmuch)
|
||||
{
|
||||
do_progress_notify (howmuch);
|
||||
}
|
||||
@@ -350,6 +374,8 @@ class ui_out
|
||||
virtual void do_progress_start (const std::string &, bool) = 0;
|
||||
virtual void do_progress_notify (double) = 0;
|
||||
virtual void do_progress_end () = 0;
|
||||
virtual void update_progress_name (const std::string &) = 0;
|
||||
virtual progress_report::state get_progress_state () = 0;
|
||||
|
||||
/* Set as not MI-like by default. It is overridden in subclasses if
|
||||
necessary. */
|
||||
|
||||
Reference in New Issue
Block a user