add display-grouped to hover

This commit is contained in:
silverweed 2024-09-12 11:56:12 +02:00
parent 7385210e66
commit fdbfcbc3a6
2 changed files with 156 additions and 59 deletions

View file

@ -14,14 +14,14 @@ template <> u64 bswap_if_needed(u64 x) { return bswap(x); }
template <typename T>
String8_Node *hover_display_val_be(Arena *arena, String8_Node *prev, const char *fmt, T val)
{
static_assert(!std::is_same_v<T, String8>);
val = bswap_if_needed(val);
return push_str8_node_child(arena, prev, fmt, val);
}
template <>
String8_Node *hover_display_val_be(Arena *arena, String8_Node *prev, const char *fmt, String8 val)
String8_Node *hover_display_val_str8(Arena *arena, String8_Node *prev, const char *fmt, String8 val)
{
return push_str8_node_child(arena, prev, fmt, val.c());
return push_str8_node_child(arena, prev, fmt, val.str ? val.c() : "");
}
template <typename T>
@ -86,6 +86,16 @@ String8_Node *display_val_rootzip(Arena *arena, String8_Node *prev, const char *
template <typename T>
using Display_Fn = String8_Node *(*)(Arena *, String8_Node *, const char *, T);
template <typename T>
internal
T read_buf(const void *buf, u64 &off)
{
T val;
memcpy(&val, (u8 *)buf + off, sizeof(val));
off += sizeof(val);
return val;
}
// Functor used by get_section_hover_info to describe the structure of a section and print data about it.
struct Sec_Hover_Fn {
u64 start;
@ -94,6 +104,7 @@ struct Sec_Hover_Fn {
Arena *arena;
Sec_Hover_Info &info;
u64 &cur_field_off;
b8 display_grouped;
template <typename F>
b8 titled_section(const char *title, F &&fn) const
@ -110,6 +121,31 @@ struct Sec_Hover_Fn {
return ok;
}
template <typename T>
T add_to_desc(const char *fmt, Display_Fn<T> display_val = hover_display_val_le<T>) const
{
static_assert(!std::is_same_v<T, String8>, "use add_to_desc_str8 instead.");
T val = read_buf<T>(data + start, cur_field_off);
display_val(arena, info.desc, fmt, val);
return val;
}
template <typename TStrSize>
String8 add_to_desc_str8(const char *fmt, Display_Fn<String8> display_val = hover_display_val_str8) const
{
TStrSize str_size = read_buf<TStrSize>(data + start, cur_field_off);
u8 *buf = nullptr;
if (str_size > 0) {
buf = arena_push_array_nozero<u8>(arena, str_size + 1);
memcpy(buf, data + start + cur_field_off, str_size);
buf[str_size] = 0;
cur_field_off += str_size;
}
String8 s = { buf, str_size };
display_val(arena, info.desc, fmt, s);
return s;
}
template <typename T>
b8 field(const char *desc_fmt, Display_Fn<T> display_val) const
{
@ -117,9 +153,7 @@ struct Sec_Hover_Fn {
u64 field_len = sizeof(T);
if (roff < cur_field_off + field_len) {
info.rng = { start + cur_field_off, field_len };
T val;
memcpy(&val, data + info.rng.start, info.rng.len);
display_val(arena, info.desc, desc_fmt, val);
add_to_desc<T>(desc_fmt, display_val);
return true;
}
cur_field_off += field_len;
@ -139,14 +173,11 @@ struct Sec_Hover_Fn {
}
template <typename TStrSize>
b8 field_str8(const char *desc_fmt, Display_Fn<String8> display_val = hover_display_val_be<String8>) const
b8 field_str8(const char *desc_fmt, Display_Fn<String8> display_val = hover_display_val_str8) const
{
// String size can be stored as different types, like u8 (by ROOT I/O) or u32 (by RNTuple).
TStrSize str_size;
memcpy(&str_size, data + start + cur_field_off, sizeof(TStrSize));
// TEMP DEBUG
if (str_size > 1000)
return false;
if (roff < cur_field_off + sizeof(TStrSize) + str_size) {
info.rng = { start + cur_field_off, sizeof(TStrSize) + (u64)str_size };
u8 *buf = arena_push_array_nozero<u8>(arena, str_size + 1);
@ -279,61 +310,124 @@ struct Sec_Hover_Fn {
static const char *const field_struct_names[] = {
"Leaf", "Collection", "Record", "Variant", "Unsplit"
};
return titled_section("Field", [this] {
u64 flags_off = start + cur_field_off + 22;
u16 flags;
memcpy(&flags, data + flags_off, sizeof(flags));
b8 ok = field_le<i64>("Size: %" PRIi64)
|| field_le<u32>("Field version: %u")
|| field_le<u32>("Type version: %u")
|| field_le<u32>("On-disk parent id: %u")
|| field<u16>("Field structure: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 type) {
if (display_grouped) {
i64 size;
memcpy(&size, data + start + cur_field_off, sizeof(size));
u64 field_desc_len = (u64)std::abs(size);
if (roff < cur_field_off + field_desc_len) {
return titled_section("Field", [this, field_desc_len] {
info.rng = { start + cur_field_off, (u64)field_desc_len };
add_to_desc<i64>("Size: %" PRIi64);
add_to_desc<u32>("Field version: %u");
add_to_desc<u32>("Type version: %u");
add_to_desc<u32>("On-disk parent id: %u");
add_to_desc<u16>("Field structure: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 type) {
const char *name = (type >= countof(field_struct_names)) ? "Unknown" : field_struct_names[type];
return push_str8_node_child(arena, prev, fmt, name);
})
|| field_le<u16>("Flags: 0b%b")
;
if (ok)
return ok;
});
u16 flags = add_to_desc<u16>("Flags: 0b%b");
if ((flags & RNTupleSerializer::kFlagRepetitiveField) && field_le<u64>("N Repetitions: %" PRIu64))
return true;
if ((flags & RNTupleSerializer::kFlagProjectedField) && field_le<u32>("On disk proj.src id: %u"))
return true;
if ((flags & RNTupleSerializer::kFlagHasTypeChecksum) && field_le<u32>("Checksum: %u"))
return true;
if (flags & RNTupleSerializer::kFlagRepetitiveField)
add_to_desc<u64>("N Repetitions: %" PRIu64);
if (flags & RNTupleSerializer::kFlagProjectedField)
add_to_desc<u32>("On disk proj.src id: %u");
if (flags & RNTupleSerializer::kFlagHasTypeChecksum)
add_to_desc<u32>("Checksum: %u");
return field_str8<u32>("Name: %s")
|| field_str8<u32>("Type Name: %s")
|| field_str8<u32>("Type Alias: %s")
|| field_str8<u32>("Description: %s")
;
});
add_to_desc_str8<u32>("Name: %s");
add_to_desc_str8<u32>("Type Name: %s");
add_to_desc_str8<u32>("Type Alias: %s");
add_to_desc_str8<u32>("Description: %s");
return true;
});
}
cur_field_off += field_desc_len;
return false;
} else {
return titled_section("Field", [this] {
u64 flags_off = start + cur_field_off + 22;
u16 flags;
memcpy(&flags, data + flags_off, sizeof(flags));
b8 ok = field_le<i64>("Size: %" PRIi64)
|| field_le<u32>("Field version: %u")
|| field_le<u32>("Type version: %u")
|| field_le<u32>("On-disk parent id: %u")
|| field<u16>("Field structure: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 type) {
const char *name = (type >= countof(field_struct_names)) ? "Unknown" : field_struct_names[type];
return push_str8_node_child(arena, prev, fmt, name);
})
|| field_le<u16>("Flags: 0b%b")
;
if (ok)
return ok;
if ((flags & RNTupleSerializer::kFlagRepetitiveField) && field_le<u64>("N Repetitions: %" PRIu64))
return true;
if ((flags & RNTupleSerializer::kFlagProjectedField) && field_le<u32>("On disk proj.src id: %u"))
return true;
if ((flags & RNTupleSerializer::kFlagHasTypeChecksum) && field_le<u32>("Checksum: %u"))
return true;
return field_str8<u32>("Name: %s")
|| field_str8<u32>("Type Name: %s")
|| field_str8<u32>("Type Alias: %s")
|| field_str8<u32>("Description: %s")
;
});
}
}
b8 column_desc() const
{
return titled_section("Column", [this] {
u64 flags_off = start + cur_field_off + 16;
u16 flags;
memcpy(&flags, data + flags_off, sizeof(flags));
b8 ok = field_le<i64>("Size: %" PRIi64)
|| field_le<u16>("Column Type: 0x%X") // TODO: prettify name
|| field_le<u16>("Bits on storage: %u")
|| field_le<u32>("Field ID: %u")
|| field_le<u16>("Flags: 0b%b")
|| field_le<u16>("Representation idx: %u")
;
if (ok)
return ok;
if ((flags & RNTupleSerializer::kFlagDeferredColumn) && field_le<u64>("First element: %" PRIu64))
return true;
if ((flags & RNTupleSerializer::kFlagHasValueRange) && (field_le<double>("Value Min: %f") || field_le<double>("Value Max: %f")))
return true;
if (display_grouped) {
i64 size;
memcpy(&size, data + start + cur_field_off, sizeof(size));
u64 col_desc_len = (u64)std::abs(size);
if (roff < cur_field_off + col_desc_len) {
return titled_section("Column", [this, col_desc_len] {
info.rng = { start + cur_field_off, col_desc_len };
add_to_desc<i64>("Size: %" PRIi64 " B");
add_to_desc<u16>("Column type: %u"); // TODO: human-readable type
add_to_desc<u16>("Bits on storage: %u");
add_to_desc<u32>("Field ID: %u");
u16 flags = add_to_desc<u16>("Flags: 0b%b");
add_to_desc<u16>("Representation idx: %u");
if (flags & RNTupleSerializer::kFlagDeferredColumn)
add_to_desc<u64>("First element: %" PRIu64);
// if (flags & RNTupleSerializer::kFlagHasValueRange) {
// add_to_desc<double>("Value Min: %f");
// add_to_desc<double>("Value Max: %f");
// }
return true;
});
}
cur_field_off += col_desc_len;
return false;
});
} else {
return titled_section("Column", [this] {
u64 flags_off = start + cur_field_off + 16;
u16 flags;
memcpy(&flags, data + flags_off, sizeof(flags));
b8 ok = field_le<i64>("Size: %" PRIi64)
|| field_le<u16>("Column Type: 0x%X") // TODO: prettify name
|| field_le<u16>("Bits on storage: %u")
|| field_le<u32>("Field ID: %u")
|| field_le<u16>("Flags: 0b%b")
|| field_le<u16>("Representation idx: %u")
;
if (ok)
return ok;
if ((flags & RNTupleSerializer::kFlagDeferredColumn) && field_le<u64>("First element: %" PRIu64))
return true;
// if ((flags & RNTupleSerializer::kFlagHasValueRange) && (field_le<double>("Value Min: %f") || field_le<double>("Value Max: %f")))
// return true;
return false;
});
}
}
b8 schema_description() const
@ -369,7 +463,7 @@ struct Sec_Hover_Fn {
// `off` is the absolute offset into `data`.
internal
Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, const u8 *data)
Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, const u8 *data, b8 display_grouped)
{
Sec_Hover_Info info {};
@ -393,7 +487,7 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co
u64 start = section.range.start - section.pre_size;
u64 roff = off - start; // offset relative to `section`
u64 cur_field_off = 0;
Sec_Hover_Fn hover { start, roff, data, arena, info, cur_field_off };
Sec_Hover_Fn hover { start, roff, data, arena, info, cur_field_off, display_grouped };
switch (section.id) {
case Sec_RNTuple_Anchor: {

View file

@ -387,7 +387,10 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
if (hovered_off)
{
Section hovered_section = find_section(app, hovered_off - 1);
Sec_Hover_Info hover_info = get_section_hover_info(scratch.arena, hovered_section, hovered_off - 1, app.inspected_file.mem);
b8 hover_display_grouped = !(app.user_input.key_state[KEY_ALT] & KEY_STATE_IS_DOWN);
Sec_Hover_Info hover_info = get_section_hover_info(scratch.arena, hovered_section, hovered_off - 1,
app.inspected_file.mem, hover_display_grouped);
ImGui::TextColored(ImColor(0.5f, 0.5f, 0.5f), "(Hint: press Alt for single-field hover information)");
imgui_render_string_tree(scratch.arena, hover_info.desc->head);
app.viewer.hovered_range = hover_info.rng;
} else {