Diff
1diff --git a/CHANGELOG.md b/CHANGELOG.md
2index 5ae3994b12141036ae4ee43100aef7bd411c3b43..4354d4ab25254307cff0f168be95c72edeba4b2d 100644
3--- a/CHANGELOG.md
4+++ b/CHANGELOG.md
5@@ -1,5 +1,8 @@
6 # Changelog
7
8+# Upcoming
9+- Added `toggle` to `hy3:makegroup`
10+
11 # hl0.47.0-1 and before
12 - Added focused tab color, to mark selected tabs inside an unfocused container.
13 - Fixed tab rendering on rotated displays.
14diff --git a/README.md b/README.md
15index a31aeace8c514eb951efc5e25a126fd47863dd3c..f3561b37448749873c089ee5cacbae893a0eb8af 100644
16--- a/README.md
17+++ b/README.md
18@@ -336,7 +336,8 @@ plugin {
19 ```
20
21 ### Dispatcher list
22- - `hy3:makegroup, <h | v | opposite | tab>, [ephemeral | force_ephemeral]` - make a vertical / horizontal split or tab group
23+ - `hy3:makegroup, <h | v | opposite | tab>, [toggle], [ephemeral | force_ephemeral]` - make a vertical / horizontal split or tab group
24+ - `toggle` - if the focused node is the only child of its parent, which is of the type specified, the node's parent will be removed.
25 - `ephemeral` - the group will be removed once it contains only one node. does not affect existing groups.
26 - `force_ephemeral` - same as ephemeral, but converts existing single windows groups.
27 - `hy3:changegroup, <h | v | tab | untab | toggletab | opposite>` - change the group the node belongs to, to a different layout
28diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp
29index bc5d85907d5ce342b9b53c8c51f2f063c3621043..8e890090118715e4e7877dcaed745a9da6c05016 100644
30--- a/src/Hy3Layout.cpp
31+++ b/src/Hy3Layout.cpp
32@@ -709,9 +709,29 @@ void Hy3Layout::onDisable() {
33 void Hy3Layout::makeGroupOnWorkspace(
34 const CWorkspace* workspace,
35 Hy3GroupLayout layout,
36- GroupEphemeralityOption ephemeral
37+ GroupEphemeralityOption ephemeral,
38+ bool toggle
39 ) {
40 auto* node = this->getWorkspaceFocusedNode(workspace);
41+
42+ if (node && toggle) {
43+ auto* parent = node->parent;
44+ auto& group = parent->data.as_group();
45+
46+ if (group.children.size() == 1 && group.layout == layout) {
47+ group.children.clear();
48+ Hy3Node::swapData(*node, *parent);
49+ this->nodes.remove(*node); // now the parent
50+
51+ if (auto* pp = node->parent->parent) {
52+ pp->updateTabBarRecursive();
53+ pp->recalcSizePosRecursive();
54+ }
55+
56+ return;
57+ }
58+ }
59+
60 this->makeGroupOn(node, layout, ephemeral);
61 }
62
63diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp
64index eda45791cfcbadc16ad186a1d0756e0d7e3ce092..78316353c8bbb11551a014eba6ab74fea64327a3 100644
65--- a/src/Hy3Layout.hpp
66+++ b/src/Hy3Layout.hpp
67@@ -105,7 +105,7 @@ public:
68 void onDisable() override;
69
70 void insertNode(Hy3Node& node);
71- void makeGroupOnWorkspace(const CWorkspace* workspace, Hy3GroupLayout, GroupEphemeralityOption);
72+ void makeGroupOnWorkspace(const CWorkspace* workspace, Hy3GroupLayout, GroupEphemeralityOption, bool toggle);
73 void makeOppositeGroupOnWorkspace(const CWorkspace* workspace, GroupEphemeralityOption);
74 void changeGroupOnWorkspace(const CWorkspace* workspace, Hy3GroupLayout);
75 void untabGroupOnWorkspace(const CWorkspace* workspace);
76diff --git a/src/dispatchers.cpp b/src/dispatchers.cpp
77index acde155822321431b01153362a528dc46a5e22aa..3344e67947068ec5ff14d9bee089b7e4be3fac59 100644
78--- a/src/dispatchers.cpp
79+++ b/src/dispatchers.cpp
80@@ -14,19 +14,22 @@ void dispatch_makegroup(std::string value) {
81
82 auto args = CVarList(value);
83
84+ auto toggle = args[1] == "toggle";
85+ auto i = toggle ? 2 : 1;
86+
87 GroupEphemeralityOption ephemeral = GroupEphemeralityOption::Standard;
88- if (args[1] == "ephemeral") {
89+ if (args[i] == "ephemeral") {
90 ephemeral = GroupEphemeralityOption::Ephemeral;
91- } else if (args[1] == "force_ephemeral") {
92+ } else if (args[i] == "force_ephemeral") {
93 ephemeral = GroupEphemeralityOption::ForceEphemeral;
94 }
95
96 if (args[0] == "h") {
97- g_Hy3Layout->makeGroupOnWorkspace(workspace.get(), Hy3GroupLayout::SplitH, ephemeral);
98+ g_Hy3Layout->makeGroupOnWorkspace(workspace.get(), Hy3GroupLayout::SplitH, ephemeral, toggle);
99 } else if (args[0] == "v") {
100- g_Hy3Layout->makeGroupOnWorkspace(workspace.get(), Hy3GroupLayout::SplitV, ephemeral);
101+ g_Hy3Layout->makeGroupOnWorkspace(workspace.get(), Hy3GroupLayout::SplitV, ephemeral, toggle);
102 } else if (args[0] == "tab") {
103- g_Hy3Layout->makeGroupOnWorkspace(workspace.get(), Hy3GroupLayout::Tabbed, ephemeral);
104+ g_Hy3Layout->makeGroupOnWorkspace(workspace.get(), Hy3GroupLayout::Tabbed, ephemeral, toggle);
105 } else if (args[0] == "opposite") {
106 g_Hy3Layout->makeOppositeGroupOnWorkspace(workspace.get(), ephemeral);
107 }