GNU Binutils with patches for OS216
Revision | c22fef7e4cf9d3cb6d7062d248b0cc148dc76137 (tree) |
---|---|
Time | 2020-02-23 03:48:32 |
Author | Tom Tromey <tom@trom...> |
Commiter | Tom Tromey |
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 <tom@tromey.com>
* tui/tui-layout.h (class tui_layout_split) <add_split>: Change
parameter and return types.
(class tui_layout_base) <specification>: Add "depth".
(class tui_layout_window) <specification>: Add "depth".
(class tui_layout_split) <specification>: 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 <tom@tromey.com>
* gdb.tui/new-layout.exp: Add sub-layout tests.
Change-Id: Iddf52d067a552c168b8a67f29caf7ac86404b10c
@@ -1,5 +1,19 @@ | ||
1 | 1 | 2020-02-22 Tom Tromey <tom@tromey.com> |
2 | 2 | |
3 | + * tui/tui-layout.h (class tui_layout_split) <add_split>: Change | |
4 | + parameter and return types. | |
5 | + (class tui_layout_base) <specification>: Add "depth". | |
6 | + (class tui_layout_window) <specification>: Add "depth". | |
7 | + (class tui_layout_split) <specification>: Add "depth". | |
8 | + * tui/tui-layout.c (tui_layout_split::add_split): Change parameter | |
9 | + and return types. | |
10 | + (tui_new_layout_command): Parse sub-layouts. | |
11 | + (_initialize_tui_layout): Update help string. | |
12 | + (tui_layout_window::specification): Add "depth". | |
13 | + (add_layout_command): Update. | |
14 | + | |
15 | +2020-02-22 Tom Tromey <tom@tromey.com> | |
16 | + | |
3 | 17 | * NEWS: Add "tui new-layout" item. |
4 | 18 | * tui/tui-layout.c (add_layout_command): Return cmd_list_element. |
5 | 19 | Add new-layout command to help text. |
@@ -1,5 +1,9 @@ | ||
1 | 1 | 2020-02-22 Tom Tromey <tom@tromey.com> |
2 | 2 | |
3 | + * gdb.tui/new-layout.exp: Add sub-layout tests. | |
4 | + | |
5 | +2020-02-22 Tom Tromey <tom@tromey.com> | |
6 | + | |
3 | 7 | * gdb.tui/new-layout.exp: New file. |
4 | 8 | |
5 | 9 | 2020-02-22 Tom Tromey <tom@tromey.com> |
@@ -35,12 +35,23 @@ gdb_test "tui new-layout example src 1 src 1" \ | ||
35 | 35 | "Window \"src\" seen twice in layout" |
36 | 36 | gdb_test "tui new-layout example src 1" \ |
37 | 37 | "New layout does not contain the \"cmd\" window" |
38 | +gdb_test "tui new-layout example src 1}" \ | |
39 | + "Extra '}' in layout specification" | |
40 | +gdb_test "tui new-layout example {src 1} 1}" \ | |
41 | + "Extra '}' in layout specification" | |
42 | +gdb_test "tui new-layout example {src 1" \ | |
43 | + "Missing '}' in layout specification" | |
38 | 44 | |
39 | 45 | gdb_test_no_output "tui new-layout example asm 1 status 0 cmd 1" |
40 | 46 | |
41 | 47 | gdb_test "help layout example" \ |
42 | 48 | "Apply the \"example\" layout.*tui new-layout example asm 1 status 0 cmd 1" |
43 | 49 | |
50 | +gdb_test_no_output "tui new-layout example2 {asm 1 status 0} 1 cmd 1" | |
51 | + | |
52 | +gdb_test "help layout example2" \ | |
53 | + "Apply the \"example2\" layout.*tui new-layout example2 {asm 1 status 0} 1 cmd 1" | |
54 | + | |
44 | 55 | if {![Term::enter_tui]} { |
45 | 56 | unsupported "TUI not supported" |
46 | 57 | } |
@@ -400,20 +400,19 @@ tui_layout_window::replace_window (const char *name, const char *new_window) | ||
400 | 400 | /* See tui-layout.h. */ |
401 | 401 | |
402 | 402 | void |
403 | -tui_layout_window::specification (ui_file *output) | |
403 | +tui_layout_window::specification (ui_file *output, int depth) | |
404 | 404 | { |
405 | 405 | fputs_unfiltered (get_name (), output); |
406 | 406 | } |
407 | 407 | |
408 | 408 | /* See tui-layout.h. */ |
409 | 409 | |
410 | -tui_layout_split * | |
411 | -tui_layout_split::add_split (int weight) | |
410 | +void | |
411 | +tui_layout_split::add_split (std::unique_ptr<tui_layout_split> &&layout, | |
412 | + int weight) | |
412 | 413 | { |
413 | - tui_layout_split *result = new tui_layout_split (); | |
414 | - split s = {weight, std::unique_ptr<tui_layout_base> (result)}; | |
414 | + split s = {weight, std::move (layout)}; | |
415 | 415 | m_splits.push_back (std::move (s)); |
416 | - return result; | |
417 | 416 | } |
418 | 417 | |
419 | 418 | /* See tui-layout.h. */ |
@@ -711,17 +710,23 @@ tui_layout_split::replace_window (const char *name, const char *new_window) | ||
711 | 710 | /* See tui-layout.h. */ |
712 | 711 | |
713 | 712 | void |
714 | -tui_layout_split::specification (ui_file *output) | |
713 | +tui_layout_split::specification (ui_file *output, int depth) | |
715 | 714 | { |
715 | + if (depth > 0) | |
716 | + fputs_unfiltered ("{", output); | |
717 | + | |
716 | 718 | bool first = true; |
717 | 719 | for (auto &item : m_splits) |
718 | 720 | { |
719 | 721 | if (!first) |
720 | 722 | fputs_unfiltered (" ", output); |
721 | 723 | first = false; |
722 | - item.layout->specification (output); | |
724 | + item.layout->specification (output, depth + 1); | |
723 | 725 | fprintf_unfiltered (output, " %d", item.weight); |
724 | 726 | } |
727 | + | |
728 | + if (depth > 0) | |
729 | + fputs_unfiltered ("}", output); | |
725 | 730 | } |
726 | 731 | |
727 | 732 | /* Destroy the layout associated with SELF. */ |
@@ -746,7 +751,7 @@ add_layout_command (const char *name, tui_layout_split *layout) | ||
746 | 751 | struct cmd_list_element *cmd; |
747 | 752 | |
748 | 753 | string_file spec; |
749 | - layout->specification (&spec); | |
754 | + layout->specification (&spec, 0); | |
750 | 755 | |
751 | 756 | gdb::unique_xmalloc_ptr<char> doc |
752 | 757 | (xstrprintf (_("Apply the \"%s\" layout.\n\ |
@@ -833,23 +838,60 @@ tui_new_layout_command (const char *spec, int from_tty) | ||
833 | 838 | if (new_name[0] == '-') |
834 | 839 | error (_("Layout name cannot start with '-'")); |
835 | 840 | |
836 | - std::unique_ptr<tui_layout_split> new_layout (new tui_layout_split); | |
841 | + std::vector<std::unique_ptr<tui_layout_split>> splits; | |
842 | + splits.emplace_back (new tui_layout_split); | |
837 | 843 | std::unordered_set<std::string> seen_windows; |
838 | 844 | while (true) |
839 | 845 | { |
840 | - std::string name = extract_arg (&spec); | |
841 | - if (name.empty ()) | |
846 | + spec = skip_spaces (spec); | |
847 | + if (spec[0] == '\0') | |
842 | 848 | break; |
843 | - if (!validate_window_name (name)) | |
844 | - error (_("Unknown window \"%s\""), name.c_str ()); | |
845 | - if (seen_windows.find (name) != seen_windows.end ()) | |
846 | - error (_("Window \"%s\" seen twice in layout"), name.c_str ()); | |
847 | - ULONGEST weight = get_ulongest (&spec); | |
849 | + | |
850 | + if (spec[0] == '{') | |
851 | + { | |
852 | + splits.emplace_back (new tui_layout_split); | |
853 | + ++spec; | |
854 | + continue; | |
855 | + } | |
856 | + | |
857 | + bool is_close = false; | |
858 | + std::string name; | |
859 | + if (spec[0] == '}') | |
860 | + { | |
861 | + is_close = true; | |
862 | + ++spec; | |
863 | + if (splits.size () == 1) | |
864 | + error (_("Extra '}' in layout specification")); | |
865 | + } | |
866 | + else | |
867 | + { | |
868 | + name = extract_arg (&spec); | |
869 | + if (name.empty ()) | |
870 | + break; | |
871 | + if (!validate_window_name (name)) | |
872 | + error (_("Unknown window \"%s\""), name.c_str ()); | |
873 | + if (seen_windows.find (name) != seen_windows.end ()) | |
874 | + error (_("Window \"%s\" seen twice in layout"), name.c_str ()); | |
875 | + } | |
876 | + | |
877 | + ULONGEST weight = get_ulongest (&spec, '}'); | |
848 | 878 | if ((int) weight != weight) |
849 | 879 | error (_("Weight out of range: %s"), pulongest (weight)); |
850 | - new_layout->add_window (name.c_str (), weight); | |
851 | - seen_windows.insert (name); | |
880 | + if (is_close) | |
881 | + { | |
882 | + std::unique_ptr<tui_layout_split> last_split | |
883 | + = std::move (splits.back ()); | |
884 | + splits.pop_back (); | |
885 | + splits.back ()->add_split (std::move (last_split), weight); | |
886 | + } | |
887 | + else | |
888 | + { | |
889 | + splits.back ()->add_window (name.c_str (), weight); | |
890 | + seen_windows.insert (name); | |
891 | + } | |
852 | 892 | } |
893 | + if (splits.size () > 1) | |
894 | + error (_("Missing '}' in layout specification")); | |
853 | 895 | if (seen_windows.empty ()) |
854 | 896 | error (_("New layout does not contain any windows")); |
855 | 897 | if (seen_windows.find ("cmd") == seen_windows.end ()) |
@@ -857,6 +899,7 @@ tui_new_layout_command (const char *spec, int from_tty) | ||
857 | 899 | |
858 | 900 | gdb::unique_xmalloc_ptr<char> cmd_name |
859 | 901 | = make_unique_xstrdup (new_name.c_str ()); |
902 | + std::unique_ptr<tui_layout_split> new_layout = std::move (splits.back ()); | |
860 | 903 | struct cmd_list_element *cmd |
861 | 904 | = add_layout_command (cmd_name.get (), new_layout.get ()); |
862 | 905 | cmd->name_allocated = 1; |
@@ -900,6 +943,9 @@ Usage: tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\ | ||
900 | 943 | Create a new TUI layout. The new layout will be named NAME,\n\ |
901 | 944 | and can be accessed using \"layout NAME\".\n\ |
902 | 945 | The windows will be displayed in the specified order.\n\ |
946 | +A WINDOW can also be of the form:\n\ | |
947 | + { NAME WEIGHT [NAME WEIGHT]... }\n\ | |
948 | +This form indicates a sub-frame.\n\ | |
903 | 949 | Each WEIGHT is an integer, which holds the relative size\n\ |
904 | 950 | to be allocated to the window."), |
905 | 951 | tui_get_cmd_list ()); |
@@ -74,8 +74,9 @@ public: | ||
74 | 74 | NEW_WINDOW. */ |
75 | 75 | virtual void replace_window (const char *name, const char *new_window) = 0; |
76 | 76 | |
77 | - /* Append the specification to this window to OUTPUT. */ | |
78 | - virtual void specification (ui_file *output) = 0; | |
77 | + /* Append the specification to this window to OUTPUT. DEPTH is the | |
78 | + depth of this layout in the hierarchy (zero-based). */ | |
79 | + virtual void specification (ui_file *output, int depth) = 0; | |
79 | 80 | |
80 | 81 | /* The most recent space allocation. */ |
81 | 82 | int x = 0; |
@@ -125,7 +126,7 @@ public: | ||
125 | 126 | |
126 | 127 | void replace_window (const char *name, const char *new_window) override; |
127 | 128 | |
128 | - void specification (ui_file *output) override; | |
129 | + void specification (ui_file *output, int depth) override; | |
129 | 130 | |
130 | 131 | protected: |
131 | 132 |
@@ -153,7 +154,7 @@ public: | ||
153 | 154 | /* Add a new split layout to this layout. WEIGHT is the desired |
154 | 155 | size, which is relative to the other weights given in this |
155 | 156 | layout. */ |
156 | - tui_layout_split *add_split (int weight); | |
157 | + void add_split (std::unique_ptr<tui_layout_split> &&layout, int weight); | |
157 | 158 | |
158 | 159 | /* Add a new window to this layout. NAME is the name of the window |
159 | 160 | to add. WEIGHT is the desired size, which is relative to the |
@@ -174,7 +175,7 @@ public: | ||
174 | 175 | |
175 | 176 | void replace_window (const char *name, const char *new_window) override; |
176 | 177 | |
177 | - void specification (ui_file *output) override; | |
178 | + void specification (ui_file *output, int depth) override; | |
178 | 179 | |
179 | 180 | protected: |
180 | 181 |