aboutsummaryrefslogtreecommitdiff
path: root/gdb/cli-out.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/cli-out.c')
-rw-r--r--gdb/cli-out.c189
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 */