]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb: Make startup message more user friendly
authorGuinevere Larsen <guinevere@redhat.com>
Mon, 15 Sep 2025 14:56:17 +0000 (11:56 -0300)
committerGuinevere Larsen <guinevere@redhat.com>
Thu, 27 Nov 2025 17:07:16 +0000 (14:07 -0300)
Currently, on startup, GDB prints a lot of licensing information and
then a few hints for new users.  While there is an attempt to separate
the hints from the rest of the text, my user testing showed that it is
not good enough, and most unfamiliar users will just skip the
information.  Especially considering that the documentation link happens
before the separation.

This commit attempts to make the startup message more friendly to new
users by visually separating the most important commands from the
copyright.  If there is enough space available, a box is printed
containing the hints (either using unicode box drawing characters, if
emojis are allowed, or using ascii).  If there isn't space for a box,
a simple line separator is printed.  The code deems "enough space
available" when there is enough space to print the documentation URL
inside the box, since the other hints will be broken into multiple
lines if necessary.
Here are examples of the 2 possible startups, with enough space:

+-----------------------------------------------------------------+
| Find the GDB manual online at:                                  |
| http://www.gnu.org/software/gdb/documentation/                  |
| For help, type "help".                                          |
| Type "apropos <word>" to search for commands related to "word". |
+-----------------------------------------------------------------+

And with limited space:

---------------------------------------------
Find the GDB manual documentation resources o
nline at:
    <http://www.gnu.org/software/gdb/document
ation/>.
For help, type "help".
Type "apropos word" to search for commands re
lated to "word".

Approved-By: Tom Tromey <tom@tromey.com>
gdb/main.c
gdb/top.c
gdb/top.h

index 58a744bb2b7b6bd43e73c149dbf2bf9149be268f..0fa2b0ecbe432bb911c052705873ee2223328160 100644 (file)
@@ -1200,6 +1200,8 @@ captured_main_1 (struct captured_main_args *context)
       /* Print all the junk at the top, with trailing "..." if we are
         about to read a symbol file (possibly slowly).  */
       print_gdb_version (gdb_stdout, true);
+      gdb_printf ("\n");
+      print_gdb_hints (gdb_stdout);
       if (symarg)
        gdb_printf ("..");
       gdb_printf ("\n");
index dc22a3f58fbf2086ad858e1dce35d6d7880e1659..2e3b373d5e2f150ba0a6ec9e29d0172729e46a9b 100644 (file)
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -1357,17 +1357,114 @@ There is NO WARRANTY, to the extent permitted by law.",
                  styled_string (file_name_style.style (),
                                 REPORT_BUGS_TO));
     }
-  gdb_printf (stream,
-             _("Find the GDB manual and other documentation \
-resources online at:\n    <%ps>."),
-             styled_string (file_name_style.style (),
-                            "http://www.gnu.org/software/gdb/documentation/"));
-  gdb_printf (stream, "\n\n");
-  gdb_printf (stream, _("For help, type \"%ps\".\n"),
+}
+
+/* Print MESSAGE to STREAM in lines of maximum size WIDTH, so that it fits
+   in an ascii art box of width WIDTH+4.  Messages may be broken on
+   spaces.  */
+static void
+box_one_message (ui_file *stream, std::string message, int width)
+{
+  const char *wall = emojis_ok () ? u8"\u2503" : "|";
+  while (!message.empty ())
+    {
+      std::string line;
+      int n_escape_chars = 0;
+      const char *escape = message.c_str ();
+      while ((escape = strchr (escape, '\033')) != nullptr)
+       {
+         int tmp;
+         if (skip_ansi_escape (escape, &tmp))
+           n_escape_chars += tmp;
+         else
+           break;
+         escape += tmp;
+       }
+      if ((message.length () - n_escape_chars) > width)
+       {
+         line = message.substr (0, message.rfind (" ", width));
+         message = message.substr (line.length ());
+       }
+      else
+       {
+         line = message;
+         message = "";
+       }
+
+      if ((line.length () - n_escape_chars) < width)
+       line.append (width - line.length () + n_escape_chars, ' ');
+
+      gdb_printf (stream, "%s %s %s\n", wall, line.c_str (), wall);
+    }
+}
+
+/* Print some hints about how to use GDB in a very visible manner.  */
+void
+print_gdb_hints (struct ui_file *stream)
+{
+  int width = get_chars_per_line ();
+
+  /* Arbitrarily setting maximum width to 80 characters, so that
+     things are big and visible but not overwhelming.  */
+  if (80 < width)
+    width = 80;
+
+  std::string docs_url = "http://www.gnu.org/software/gdb/documentation/";
+  std::array<string_file, 4> styled_msg {
+    string_file (true),
+    string_file (true),
+    string_file (true),
+    string_file (true)
+  };
+
+  gdb_printf (&styled_msg[0], _("Find the GDB manual online at:"));
+  gdb_printf (&styled_msg[1], _("%ps."),
+             styled_string (file_name_style.style (), docs_url.c_str ()));
+  gdb_printf (&styled_msg[2], _("For help, type \"%ps\"."),
              styled_string (command_style.style (), "help"));
-  gdb_printf (stream,
-             _("Type \"%ps\" to search for commands related to \"word\"."),
-             styled_string (command_style.style (), "apropos word"));
+  gdb_printf (&styled_msg[3],
+             _("Type \"%ps\" to search for commands related to <word>"),
+             styled_string (command_style.style (), "apropos <word>"));
+
+  /* If there isn't enough space to display the longest URL in a boxed
+     style, use the simple styling of a singular visual break.  The longest
+     URL is used because the other messages may be broken into multiple
+     lines, but URLs can't.  */
+  if (width - 3 <= docs_url.length ())
+    {
+      std::string sep (width, '-');
+      for (string_file &msg : styled_msg)
+       gdb_printf (stream, "%s\n", msg.c_str ());
+
+      return;
+    }
+  else
+    {
+      std::string sep (width-2, '-');
+
+      if (emojis_ok ())
+       {
+         gdb_printf (stream, u8"\u250f");
+         for (int i = 0; i < (width - 2); i++)
+           gdb_printf (stream, u8"\u2501");
+         gdb_printf (stream, u8"\u2513\n");
+       }
+      else
+       gdb_printf (stream, "+%s+\n", sep.c_str ());
+
+      for (string_file &msg : styled_msg)
+       box_one_message (stream, msg.release (), width - 4);
+
+      if (emojis_ok ())
+       {
+         gdb_printf (stream, u8"\u2517");
+         for (int i = 0; i < (width - 2); i++)
+           gdb_printf (stream, u8"\u2501");
+         gdb_printf (stream, u8"\u251b\n");
+       }
+      else
+       gdb_printf (stream, "+%s+\n", sep.c_str ());
+    }
 }
 
 /* Print the details of GDB build-time configuration.  */
index 41af51acecf93ab3c0273268e731b01276bb19e5..f90515ea7400f791dff87e43ff1bfc76e1a68eec 100644 (file)
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -36,6 +36,10 @@ extern auto_boolean interactive_mode;
    mentioned.  */
 extern void print_gdb_version (struct ui_file *stream, bool interactive);
 
+/* Print some hints for an inexperienced user on how to get more
+   information about using GDB.  */
+extern void print_gdb_hints (struct ui_file *stream);
+
 extern void print_gdb_configuration (struct ui_file *);
 
 extern void read_command_file (FILE *);