From 921a20722cab989cfc4df02826b42e379709c4e6 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 11 Feb 2026 17:14:17 -0500 Subject: [PATCH] diagnostics: add disclosure widgets to HTML output [PR116792] Examples: https://dmalcolm.fedorapeople.org/gcc/2026-02-11/bad-fndef-1.C.html https://dmalcolm.fedorapeople.org/gcc/2026-02-11/nested-diagnostics-1.C.html https://dmalcolm.fedorapeople.org/gcc/2026-02-11/malloc-ipa-8-double-free.c.html TODO: blurb TODO: Maybe we want to add a boolean hint when pushing nesting levels about whether the child diagnostics should be shown by default??? gcc/ChangeLog: PR diagnostics/116792 * diagnostics/html-sink.cc (HTML_STYLE): Add styling for . (html_builder::push_nesting_level): For nesting levels not at the top-level, add a "
Details
" to get a disclosure widget. Open the top two levels of disclosure widget by default. (html_builder::make_element_for_diagnostic): Add details and summary to execution path, to get a disclosure widget. This hides the execution path until expanded. --- gcc/diagnostics/html-sink.cc | 63 +++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/gcc/diagnostics/html-sink.cc b/gcc/diagnostics/html-sink.cc index 33cbb8c2413..6f3721ff776 100644 --- a/gcc/diagnostics/html-sink.cc +++ b/gcc/diagnostics/html-sink.cc @@ -331,6 +331,9 @@ static const char * const HTML_STYLE " font-weight: bold; }\n" " .gcc-quoted-text { font-weight: bold;\n" " font-family: mono; }\n" + " summary { display: list-item;\n" + " color: #0088ce; }\n" + " summary:hover { text-decoration: underline; }\n" " \n"); /* A little JavaScript for ease of navigation. @@ -602,17 +605,49 @@ void html_builder::push_nesting_level () { gcc_assert (m_cur_diagnostic_element); - auto new_nesting_level = std::make_unique ("ul", false); - add_nesting_level_attr (*new_nesting_level, - m_cur_nesting_levels.size () + 1); - xml::element *current_nesting_level = nullptr; - if (!m_cur_nesting_levels.empty ()) - current_nesting_level = m_cur_nesting_levels.back (); - m_cur_nesting_levels.push_back (new_nesting_level.get ()); - if (current_nesting_level) - current_nesting_level->add_child (std::move (new_nesting_level)); + + if (m_cur_nesting_levels.empty ()) + { + /* At the top level, add a
    to hold elements, with + no
    or . */ + auto new_ul = std::make_unique ("ul", false); + add_nesting_level_attr (*new_ul, + m_cur_nesting_levels.size () + 1); + m_cur_nesting_levels.push_back (new_ul.get ()); + m_cur_diagnostic_element->add_child (std::move (new_ul)); + } else - m_cur_diagnostic_element->add_child (std::move (new_nesting_level)); + { + /* Within nested levels, add +
    Details
      + to the current nesting level, and push the nesting level + so that child elements appear within the
        . */ + + xml::element *current_nesting_level = m_cur_nesting_levels.back (); + + auto details = std::make_unique ("details", false); + add_nesting_level_attr (*details, + m_cur_nesting_levels.size () + 1); + + /* Open the top two levels by default. */ + if (m_cur_nesting_levels.size () < 3) + details->set_attr ("open", "true"); + + { + auto summary = std::make_unique ("summary", false); + summary->add_text ("Details"); + details->add_child (std::move (summary)); + } + { + auto new_ul = std::make_unique ("ul", false); + add_nesting_level_attr (*new_ul, + m_cur_nesting_levels.size () + 1); + m_cur_nesting_levels.push_back (new_ul.get ()); + details->add_child (std::move (new_ul)); + } + + current_nesting_level->add_child (std::move (details)); + } } void @@ -1146,7 +1181,9 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, xp.push_tag ("div"); xp.set_attr ("id", "execution-path"); - xp.push_tag ("label", true); + xp.push_tag ("details"); + + xp.push_tag ("summary", true); const int num_events = path->num_events (); pretty_printer pp; pp_printf_n (&pp, num_events, @@ -1154,7 +1191,7 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, "Execution path with %i events", num_events); xp.add_text_from_pp (pp); - xp.pop_tag ("label"); + xp.pop_tag ("summary"); std::string event_id_prefix (diag_id + "-event-"); html_path_label_writer event_label_writer (xp, *this, *path, @@ -1164,6 +1201,8 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, print_path_as_html (xp, *path, m_context, &event_label_writer, dspp); + xp.pop_tag ("details"); + xp.pop_tag ("div"); } -- 2.49.0