add display-grouped to hover
This commit is contained in:
parent
7385210e66
commit
fdbfcbc3a6
2 changed files with 156 additions and 59 deletions
210
src/hover.cpp
210
src/hover.cpp
|
@ -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: {
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue