• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

KazDragon / munin / 31000645644

05 Aug 2026 11:14AM UTC coverage: 98.216% (-0.1%) from 98.322%
31000645644

push

github

web-flow
Expose more automation with a component ID field and more complete JSON representations (#284)

* Hide composite internals from automation JSON

* Lock button automation JSON as a leaf

* Expose automation ids on Munin components

* Report automation ids on composite Munin widgets

* doc: add CONTEXT.md for AI clarity

* feat: with_id() helper for assigning IDs in flow

* doc: add CONTEXT.md for AI clarity

* Expose button accessible name in JSON

* Expose image accessible name in JSON

* Derive button accessible name from content

* Expose edit text in introspection JSON

* Report edit content in introspection JSON

* Report edit caret in introspection JSON

* Name edit JSON snapshot in tests

* Move focus on tab key in containers

* Move focus on back tab key in containers

* Name container virtual key extraction

* Share container keypress test helper

* Document normal keyboard focus navigation

* Add button JSON coverage

* Cover unfocused button JSON state

* Cover image JSON bounds

* Cover image JSON automation id

* Cover image JSON preferred size

* Cover image JSON focus and cursor state

* Cover image JSON fill changes

* Cover image JSON single-line content changes

* Join image JSON accessible names across lines

* Cover image JSON multi-line constructor names

* Cover image JSON empty name boundary

* Cover focused image JSON state

* Cover cleared image JSON content

* Cover edit JSON type and base fields

* Cover edit JSON preferred size

* Cover unfocused edit JSON state

* Cover focused edit JSON state

* Cover edit JSON cursor state

* Cover edit JSON set text

* Cover container JSON automation id

* Cover container JSON position

* Cover container JSON size

* Refactor container JSON shape assertions

* Cover container JSON current layout

* Refactor container JSON mock layout setup

* Add text area JSON type snapshot

* Report text area text in JSON

* Report text area caret position in JSON

* Cover text area component JSON fiel... (continued)

147 of 151 new or added lines in 14 files covered. (97.35%)

1 existing line in 1 file now uncovered.

2643 of 2691 relevant lines covered (98.22%)

496.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.73
/src/composite_component.cpp
1
#include <munin/composite_component.hpp>
2
#include <munin/container.hpp>
3

4
#include <optional>
5
#include <string>
6

7
namespace munin {
8

9
namespace {
10

11
auto find_accessible_name(nlohmann::json const &json) -> std::optional<std::string>
294 ✔
12
{
13
    if (auto const name = json.find("name");
294 ✔
14
        name != json.end() && name->is_string())
294 ✔
15
    {
16
        return name->get<std::string>();
17 ✔
17
    }
18

19
    if (auto const component = json.find("component");
277 ✔
20
        component != json.end() && component->is_object())
277 ✔
21
    {
22
        if (auto const name = find_accessible_name(*component))
2 ✔
23
        {
NEW
24
            return name;
×
25
        }
2 ✔
26
    }
27

28
    if (auto const subcomponents = json.find("subcomponents");
277 ✔
29
        subcomponents != json.end() && subcomponents->is_array())
277 ✔
30
    {
31
        for (auto const &subcomponent : *subcomponents)
545 ✔
32
        {
33
            if (auto const name = find_accessible_name(subcomponent))
249 ✔
34
            {
35
                return name;
21 ✔
36
            }
249 ✔
37
        }
38
    }
39

40
    return std::nullopt;
256 ✔
41
}
42

43
}  // namespace
44

45
// ==========================================================================
46
// CONSTRUCTOR
47
// ==========================================================================
48
composite_component::composite_component()
229 ✔
49
{
50
    content_.on_redraw.connect(on_redraw);
229 ✔
51
    content_.on_preferred_size_changed.connect(on_preferred_size_changed);
229 ✔
52
    content_.on_focus_set.connect(on_focus_set);
229 ✔
53
    content_.on_focus_lost.connect(on_focus_lost);
229 ✔
54
    content_.on_cursor_state_changed.connect(on_cursor_state_changed);
229 ✔
55
    content_.on_cursor_position_changed.connect(on_cursor_position_changed);
229 ✔
56
}
229 ✔
57

58
// ==========================================================================
59
// SET_LAYOUT
60
// ==========================================================================
61
void composite_component::set_layout(std::unique_ptr<layout> lyt)
207 ✔
62
{
63
    content_.set_layout(std::move(lyt));
207 ✔
64
}
207 ✔
65

66
// ==========================================================================
67
// ADD_COMPONENT
68
// ==========================================================================
69
void composite_component::add_component(
539 ✔
70
    std::shared_ptr<component> const &comp, std::any const &hint)
71
{
72
    content_.add_component(comp, hint);
539 ✔
73
}
539 ✔
74

75
// ==========================================================================
76
// DO_SET_POSITION
77
// ==========================================================================
78
void composite_component::do_set_position(terminalpp::point const &position)
234 ✔
79
{
80
    content_.set_position(position);
234 ✔
81
}
234 ✔
82

83
// ==========================================================================
84
// DO_GET_POSITION
85
// ==========================================================================
86
terminalpp::point composite_component::do_get_position() const
184 ✔
87
{
88
    return content_.get_position();
184 ✔
89
}
90

91
// ==========================================================================
92
// DO_SET_SIZE
93
// ==========================================================================
94
void composite_component::do_set_size(terminalpp::extent const &size)
305 ✔
95
{
96
    content_.set_size(size);
305 ✔
97
}
305 ✔
98

99
// ==========================================================================
100
// DO_GET_SIZE
101
// ==========================================================================
102
terminalpp::extent composite_component::do_get_size() const
144 ✔
103
{
104
    return content_.get_size();
144 ✔
105
}
106

107
// ==========================================================================
108
// DO_GET_PREFERRED_SIZE
109
// ==========================================================================
110
terminalpp::extent composite_component::do_get_preferred_size() const
14 ✔
111
{
112
    return content_.get_preferred_size();
14 ✔
113
}
114

115
// ==========================================================================
116
// DO_HAS_FOCUS
117
// ==========================================================================
118
bool composite_component::do_has_focus() const
107 ✔
119
{
120
    return content_.has_focus();
107 ✔
121
}
122

123
// ==========================================================================
124
// DO_SET_FOCUS
125
// ==========================================================================
126
void composite_component::do_set_focus()
25 ✔
127
{
128
    content_.set_focus();
25 ✔
129
}
25 ✔
130

131
// ==========================================================================
132
// DO_LOSE_FOCUS
133
// ==========================================================================
134
void composite_component::do_lose_focus()
1 ✔
135
{
136
    content_.lose_focus();
1 ✔
137
}
1 ✔
138

139
// ==========================================================================
140
// DO_FOCUS_NEXT
141
// ==========================================================================
142
void composite_component::do_focus_next()
8 ✔
143
{
144
    content_.focus_next();
8 ✔
145
}
8 ✔
146

147
// ==========================================================================
148
// DO_FOCUS_PREVIOUS
149
// ==========================================================================
150
void composite_component::do_focus_previous()
2 ✔
151
{
152
    content_.focus_previous();
2 ✔
153
}
2 ✔
154

155
// ==========================================================================
156
// DO_GET_CURSOR_STATE
157
// ==========================================================================
158
bool composite_component::do_get_cursor_state() const
3 ✔
159
{
160
    return content_.get_cursor_state();
3 ✔
161
}
162

163
// ==========================================================================
164
// DO_GET_CURSOR_POSITION
165
// ==========================================================================
166
terminalpp::point composite_component::do_get_cursor_position() const
3 ✔
167
{
168
    return content_.get_cursor_position();
3 ✔
169
}
170

171
// ==========================================================================
172
// DO_SET_CURSOR_POSITION
173
// ==========================================================================
174
void composite_component::do_set_cursor_position(
1 ✔
175
    terminalpp::point const &position)
176
{
177
    content_.set_cursor_position(position);
1 ✔
178
}
1 ✔
179

180
// ==========================================================================
181
// DO_DRAW
182
// ==========================================================================
183
void composite_component::do_draw(
47 ✔
184
    render_surface &surface, terminalpp::rectangle const &region) const
185
{
186
    content_.draw(surface, region);
47 ✔
187
}
47 ✔
188

189
// ==========================================================================
190
// DO_EVENT
191
// ==========================================================================
192
void composite_component::do_event(std::any const &event)
2 ✔
193
{
194
    content_.event(event);
2 ✔
195
}
2 ✔
196

197
// ==========================================================================
198
// DO_TO_JSON
199
// ==========================================================================
200
nlohmann::json composite_component::do_to_json() const
43 ✔
201
{
202
    nlohmann::json patch = R"([
43 ✔
203
        { "op": "replace", "path": "/type", "value": "composite_component" }
204
    ])"_json;
205

206
    auto json = content_.to_json().patch(patch);
43 ✔
207
    json["id"] = get_id();
43 ✔
208
    if (auto const name = find_accessible_name(json))
43 ✔
209
    {
210
        json["name"] = *name;
17 ✔
211
    }
43 ✔
212
    json.erase("subcomponents");
43 ✔
213
    return json;
86 ✔
214
}
43 ✔
215

216
}  // namespace munin
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc