From c22fef7e4cf9d3cb6d7062d248b0cc148dc76137 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Sat, 22 Feb 2020 11:48:26 -0700 Subject: [PATCH] Allow TUI sub-layouts in "new-layout" command The new TUI layout engine has support for "sub-layouts" -- this is a layout that includes another layout as a child. A sub-layout is treated as a unit when allocating space. There's not a very strong reason to use sub-layouts currently. This patch exists to introduce the idea, and to simplify the subsequent patch that adds horizontal layouts -- where sub-layouts are needed. Because this patch won't go in on its own, I chose to defer documenting this change until the subsequent horizontal layout patch. gdb/ChangeLog 2020-02-22 Tom Tromey * tui/tui-layout.h (class tui_layout_split) : Change parameter and return types. (class tui_layout_base) : Add "depth". (class tui_layout_window) : Add "depth". (class tui_layout_split) : Add "depth". * tui/tui-layout.c (tui_layout_split::add_split): Change parameter and return types. (tui_new_layout_command): Parse sub-layouts. (_initialize_tui_layout): Update help string. (tui_layout_window::specification): Add "depth". (add_layout_command): Update. gdb/testsuite/ChangeLog 2020-02-22 Tom Tromey * gdb.tui/new-layout.exp: Add sub-layout tests. Change-Id: Iddf52d067a552c168b8a67f29caf7ac86404b10c --- gdb/ChangeLog | 14 +++++ gdb/testsuite/ChangeLog | 4 ++ gdb/testsuite/gdb.tui/new-layout.exp | 11 ++++ gdb/tui/tui-layout.c | 84 +++++++++++++++++++++------- gdb/tui/tui-layout.h | 11 ++-- 5 files changed, 100 insertions(+), 24 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ed2f3583eba..dc5ed675b87 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +2020-02-22 Tom Tromey + + * tui/tui-layout.h (class tui_layout_split) : Change + parameter and return types. + (class tui_layout_base) : Add "depth". + (class tui_layout_window) : Add "depth". + (class tui_layout_split) : Add "depth". + * tui/tui-layout.c (tui_layout_split::add_split): Change parameter + and return types. + (tui_new_layout_command): Parse sub-layouts. + (_initialize_tui_layout): Update help string. + (tui_layout_window::specification): Add "depth". + (add_layout_command): Update. + 2020-02-22 Tom Tromey * NEWS: Add "tui new-layout" item. diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index c7270b965b6..9e825fbd53c 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2020-02-22 Tom Tromey + + * gdb.tui/new-layout.exp: Add sub-layout tests. + 2020-02-22 Tom Tromey * gdb.tui/new-layout.exp: New file. diff --git a/gdb/testsuite/gdb.tui/new-layout.exp b/gdb/testsuite/gdb.tui/new-layout.exp index 2efc1728bfa..83823229bd4 100644 --- a/gdb/testsuite/gdb.tui/new-layout.exp +++ b/gdb/testsuite/gdb.tui/new-layout.exp @@ -35,12 +35,23 @@ gdb_test "tui new-layout example src 1 src 1" \ "Window \"src\" seen twice in layout" gdb_test "tui new-layout example src 1" \ "New layout does not contain the \"cmd\" window" +gdb_test "tui new-layout example src 1}" \ + "Extra '}' in layout specification" +gdb_test "tui new-layout example {src 1} 1}" \ + "Extra '}' in layout specification" +gdb_test "tui new-layout example {src 1" \ + "Missing '}' in layout specification" gdb_test_no_output "tui new-layout example asm 1 status 0 cmd 1" gdb_test "help layout example" \ "Apply the \"example\" layout.*tui new-layout example asm 1 status 0 cmd 1" +gdb_test_no_output "tui new-layout example2 {asm 1 status 0} 1 cmd 1" + +gdb_test "help layout example2" \ + "Apply the \"example2\" layout.*tui new-layout example2 {asm 1 status 0} 1 cmd 1" + if {![Term::enter_tui]} { unsupported "TUI not supported" } diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c index 8f5dd6ec516..6077a9cc68c 100644 --- a/gdb/tui/tui-layout.c +++ b/gdb/tui/tui-layout.c @@ -400,20 +400,19 @@ tui_layout_window::replace_window (const char *name, const char *new_window) /* See tui-layout.h. */ void -tui_layout_window::specification (ui_file *output) +tui_layout_window::specification (ui_file *output, int depth) { fputs_unfiltered (get_name (), output); } /* See tui-layout.h. */ -tui_layout_split * -tui_layout_split::add_split (int weight) +void +tui_layout_split::add_split (std::unique_ptr &&layout, + int weight) { - tui_layout_split *result = new tui_layout_split (); - split s = {weight, std::unique_ptr (result)}; + split s = {weight, std::move (layout)}; m_splits.push_back (std::move (s)); - return result; } /* See tui-layout.h. */ @@ -711,17 +710,23 @@ tui_layout_split::replace_window (const char *name, const char *new_window) /* See tui-layout.h. */ void -tui_layout_split::specification (ui_file *output) +tui_layout_split::specification (ui_file *output, int depth) { + if (depth > 0) + fputs_unfiltered ("{", output); + bool first = true; for (auto &item : m_splits) { if (!first) fputs_unfiltered (" ", output); first = false; - item.layout->specification (output); + item.layout->specification (output, depth + 1); fprintf_unfiltered (output, " %d", item.weight); } + + if (depth > 0) + fputs_unfiltered ("}", output); } /* Destroy the layout associated with SELF. */ @@ -746,7 +751,7 @@ add_layout_command (const char *name, tui_layout_split *layout) struct cmd_list_element *cmd; string_file spec; - layout->specification (&spec); + layout->specification (&spec, 0); gdb::unique_xmalloc_ptr doc (xstrprintf (_("Apply the \"%s\" layout.\n\ @@ -833,23 +838,60 @@ tui_new_layout_command (const char *spec, int from_tty) if (new_name[0] == '-') error (_("Layout name cannot start with '-'")); - std::unique_ptr new_layout (new tui_layout_split); + std::vector> splits; + splits.emplace_back (new tui_layout_split); std::unordered_set seen_windows; while (true) { - std::string name = extract_arg (&spec); - if (name.empty ()) + spec = skip_spaces (spec); + if (spec[0] == '\0') break; - if (!validate_window_name (name)) - error (_("Unknown window \"%s\""), name.c_str ()); - if (seen_windows.find (name) != seen_windows.end ()) - error (_("Window \"%s\" seen twice in layout"), name.c_str ()); - ULONGEST weight = get_ulongest (&spec); + + if (spec[0] == '{') + { + splits.emplace_back (new tui_layout_split); + ++spec; + continue; + } + + bool is_close = false; + std::string name; + if (spec[0] == '}') + { + is_close = true; + ++spec; + if (splits.size () == 1) + error (_("Extra '}' in layout specification")); + } + else + { + name = extract_arg (&spec); + if (name.empty ()) + break; + if (!validate_window_name (name)) + error (_("Unknown window \"%s\""), name.c_str ()); + if (seen_windows.find (name) != seen_windows.end ()) + error (_("Window \"%s\" seen twice in layout"), name.c_str ()); + } + + ULONGEST weight = get_ulongest (&spec, '}'); if ((int) weight != weight) error (_("Weight out of range: %s"), pulongest (weight)); - new_layout->add_window (name.c_str (), weight); - seen_windows.insert (name); + if (is_close) + { + std::unique_ptr last_split + = std::move (splits.back ()); + splits.pop_back (); + splits.back ()->add_split (std::move (last_split), weight); + } + else + { + splits.back ()->add_window (name.c_str (), weight); + seen_windows.insert (name); + } } + if (splits.size () > 1) + error (_("Missing '}' in layout specification")); if (seen_windows.empty ()) error (_("New layout does not contain any windows")); if (seen_windows.find ("cmd") == seen_windows.end ()) @@ -857,6 +899,7 @@ tui_new_layout_command (const char *spec, int from_tty) gdb::unique_xmalloc_ptr cmd_name = make_unique_xstrdup (new_name.c_str ()); + std::unique_ptr new_layout = std::move (splits.back ()); struct cmd_list_element *cmd = add_layout_command (cmd_name.get (), new_layout.get ()); cmd->name_allocated = 1; @@ -900,6 +943,9 @@ Usage: tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\ Create a new TUI layout. The new layout will be named NAME,\n\ and can be accessed using \"layout NAME\".\n\ The windows will be displayed in the specified order.\n\ +A WINDOW can also be of the form:\n\ + { NAME WEIGHT [NAME WEIGHT]... }\n\ +This form indicates a sub-frame.\n\ Each WEIGHT is an integer, which holds the relative size\n\ to be allocated to the window."), tui_get_cmd_list ()); diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h index c2249a783f8..4351e260720 100644 --- a/gdb/tui/tui-layout.h +++ b/gdb/tui/tui-layout.h @@ -74,8 +74,9 @@ public: NEW_WINDOW. */ virtual void replace_window (const char *name, const char *new_window) = 0; - /* Append the specification to this window to OUTPUT. */ - virtual void specification (ui_file *output) = 0; + /* Append the specification to this window to OUTPUT. DEPTH is the + depth of this layout in the hierarchy (zero-based). */ + virtual void specification (ui_file *output, int depth) = 0; /* The most recent space allocation. */ int x = 0; @@ -125,7 +126,7 @@ public: void replace_window (const char *name, const char *new_window) override; - void specification (ui_file *output) override; + void specification (ui_file *output, int depth) override; protected: @@ -153,7 +154,7 @@ public: /* Add a new split layout to this layout. WEIGHT is the desired size, which is relative to the other weights given in this layout. */ - tui_layout_split *add_split (int weight); + void add_split (std::unique_ptr &&layout, int weight); /* Add a new window to this layout. NAME is the name of the window to add. WEIGHT is the desired size, which is relative to the @@ -174,7 +175,7 @@ public: void replace_window (const char *name, const char *new_window) override; - void specification (ui_file *output) override; + void specification (ui_file *output, int depth) override; protected: -- 2.30.2