diff options
author | Tom Tromey <tom@tromey.com> | 2020-12-16 18:18:40 +0100 |
---|---|---|
committer | Tom de Vries <tdevries@suse.de> | 2020-12-16 18:18:40 +0100 |
commit | 2f2287318b33ddf855a692fcc191f6b25caf4644 (patch) | |
tree | a4ed9af701499455d0eb659a29e912117b565a1e /gdb | |
parent | 1e61189d0ab0905178002120eb0a380858ed6dc0 (diff) | |
download | gdb-2f2287318b33ddf855a692fcc191f6b25caf4644.zip gdb-2f2287318b33ddf855a692fcc191f6b25caf4644.tar.gz gdb-2f2287318b33ddf855a692fcc191f6b25caf4644.tar.bz2 |
[gdb/cli] Add a progress meter
Add a progress meter. It's not used anywhere yet.
gdb/ChangeLog:
2020-12-16 Tom Tromey <tom@tromey.com>
Tom Tromey <tromey@redhat.com>
Tom de Vries <tdevries@suse.de>
* utils.h (get_chars_per_line): Declare.
* utils.c (get_chars_per_line): New function.
(fputs_maybe_filtered): Handle '\r'.
* ui-out.h (ui_out::progress_meter): New class.
(ui_out::progress, ui_out::do_progress_start)
(ui_out::do_progress_notify, ui_out::do_progress_end): New
methods.
* ui-out.c (do_progress_end)
(make_cleanup_ui_out_progress_begin_end, ui_out_progress): New
functions.
* mi/mi-out.h (mi_ui_out::do_progress_start)
(mi_ui_out::do_progress_notify, mi_ui_out::do_progress_end): New
methods.
* cli-out.h (struct cli_ui_out) <do_progress_start,
do_progress_notify, do_progress_end>: New methods.
<enum meter_stat, struct cli_progress_info>: New.
<m_meters>: New member.
* cli-out.c (cli_ui_out::do_progress_start)
(cli_ui_out::do_progress_notify, cli_ui_out::do_progress_end): New
methods.
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 25 | ||||
-rw-r--r-- | gdb/cli-out.c | 101 | ||||
-rw-r--r-- | gdb/cli-out.h | 31 | ||||
-rw-r--r-- | gdb/mi/mi-out.h | 12 | ||||
-rw-r--r-- | gdb/ui-out.h | 37 | ||||
-rw-r--r-- | gdb/utils.c | 14 | ||||
-rw-r--r-- | gdb/utils.h | 4 |
7 files changed, 224 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index d621e22..5dc879b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,28 @@ +2020-12-16 Tom Tromey <tom@tromey.com> + Tom Tromey <tromey@redhat.com> + Tom de Vries <tdevries@suse.de> + + * utils.h (get_chars_per_line): Declare. + * utils.c (get_chars_per_line): New function. + (fputs_maybe_filtered): Handle '\r'. + * ui-out.h (ui_out::progress_meter): New class. + (ui_out::progress, ui_out::do_progress_start) + (ui_out::do_progress_notify, ui_out::do_progress_end): New + methods. + * ui-out.c (do_progress_end) + (make_cleanup_ui_out_progress_begin_end, ui_out_progress): New + functions. + * mi/mi-out.h (mi_ui_out::do_progress_start) + (mi_ui_out::do_progress_notify, mi_ui_out::do_progress_end): New + methods. + * cli-out.h (struct cli_ui_out) <do_progress_start, + do_progress_notify, do_progress_end>: New methods. + <enum meter_stat, struct cli_progress_info>: New. + <m_meters>: New member. + * cli-out.c (cli_ui_out::do_progress_start) + (cli_ui_out::do_progress_notify, cli_ui_out::do_progress_end): New + methods. + 2020-12-16 Luis Machado <luis.machado@linaro.org> * aarch64-tdep.c (aarch64_record_data_proc_simd_fp): Record FPSR. diff --git a/gdb/cli-out.c b/gdb/cli-out.c index e47272a..7722ecc 100644 --- a/gdb/cli-out.c +++ b/gdb/cli-out.c @@ -265,6 +265,107 @@ 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: + <> + - printed for not-a-tty: + <NAME...done. + > +*/ + +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; + + meter.last_value = 0; + meter.name = name; + if (!stream->isatty ()) + { + fprintf_unfiltered (stream, "%s...", meter.name.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; + } + + m_meters.push_back (std::move (meter)); +} + +void +cli_ui_out::do_progress_notify (double howmuch) +{ + struct ui_file *stream = m_streams.back (); + cli_progress_info &meter (m_meters.back ()); + + if (meter.printing == NO_PRINT) + return; + + if (meter.printing == START) + { + fprintf_unfiltered (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 (); + if (chars_per_line > 0) + { + int i, max; + int width = chars_per_line - 3; + + max = width * howmuch; + fprintf_unfiltered (stream, "\r["); + for (i = 0; i < width; ++i) + fprintf_unfiltered (stream, i < max ? "#" : " "); + fprintf_unfiltered (stream, "]"); + gdb_flush (stream); + meter.printing = PROGRESS; + } +} + +void +cli_ui_out::do_progress_end () +{ + struct ui_file *stream = m_streams.back (); + cli_progress_info &meter = m_meters.back (); + + if (!stream->isatty ()) + { + fprintf_unfiltered (stream, "done.\n"); + gdb_flush (stream); + } + else if (meter.printing == PROGRESS) + { + int i; + int width = get_chars_per_line () - 3; + + 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 (); +} + /* local functions */ void diff --git a/gdb/cli-out.h b/gdb/cli-out.h index 84e957c..5f55554 100644 --- a/gdb/cli-out.h +++ b/gdb/cli-out.h @@ -71,6 +71,10 @@ 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) override; + virtual void do_progress_end () override; + bool suppress_output () { return m_suppress_output; } @@ -80,6 +84,33 @@ 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. */ + struct cli_progress_info + { + /* The current state. */ + enum meter_state printing; + /* The name to print. */ + std::string name; + /* The last notification value. */ + double last_value; + }; + + /* Stack of progress meters. */ + std::vector<cli_progress_info> m_meters; }; extern cli_ui_out *cli_out_new (struct ui_file *stream); diff --git a/gdb/mi/mi-out.h b/gdb/mi/mi-out.h index de4b3e0..da8f4e6 100644 --- a/gdb/mi/mi-out.h +++ b/gdb/mi/mi-out.h @@ -83,6 +83,18 @@ 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_notify (double) override + { + } + + virtual void do_progress_end () override + { + } + private: void field_separator (); diff --git a/gdb/ui-out.h b/gdb/ui-out.h index 9fc6061..dfd9679 100644 --- a/gdb/ui-out.h +++ b/gdb/ui-out.h @@ -275,6 +275,39 @@ class ui_out escapes. */ virtual bool can_emit_style_escape () const = 0; + /* An object that starts and finishes a progress meter. */ + class progress_meter + { + public: + /* SHOULD_PRINT indicates whether something should be printed for a tty. */ + progress_meter (struct ui_out *uiout, const std::string &name, + bool should_print) + : m_uiout (uiout) + { + m_uiout->do_progress_start (name, should_print); + } + + ~progress_meter () + { + 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; + + private: + + struct ui_out *m_uiout; + }; + + /* Emit some progress corresponding to the most recently created + progress meter. HOWMUCH may range from 0.0 to 1.0. */ + void progress (double howmuch) + { + do_progress_notify (howmuch); + } + protected: virtual void do_table_begin (int nbrofcols, int nr_rows, const char *tblid) @@ -309,6 +342,10 @@ 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) = 0; + virtual void do_progress_end () = 0; + /* Set as not MI-like by default. It is overridden in subclasses if necessary. */ diff --git a/gdb/utils.c b/gdb/utils.c index 3226656..abcf6e2 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -1579,6 +1579,14 @@ gdb_flush (struct ui_file *stream) stream->flush (); } +/* See utils.h. */ + +int +get_chars_per_line () +{ + return chars_per_line; +} + /* Indicate that if the next sequence of characters overflows the line, a newline should be inserted here rather than when it hits the end. If INDENT is non-null, it is a string to be printed to indent the @@ -1769,6 +1777,12 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream, don't increment chars_printed here. */ lineptr += skip_bytes; } + else if (*lineptr == '\r') + { + wrap_buffer.push_back (*lineptr); + chars_printed = 0; + lineptr++; + } else { wrap_buffer.push_back (*lineptr); diff --git a/gdb/utils.h b/gdb/utils.h index a8c65ed..e87ce11 100644 --- a/gdb/utils.h +++ b/gdb/utils.h @@ -364,6 +364,10 @@ extern void wrap_here (const char *); extern void reinitialize_more_filter (void); +/* Return the number of characters in a line. */ + +extern int get_chars_per_line (); + extern bool pagination_enabled; extern struct ui_file **current_ui_gdb_stdout_ptr (void); |