https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116792

--- Comment #9 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by David Malcolm <dmalc...@gcc.gnu.org>:

https://gcc.gnu.org/g:04871e748862fc48fac739f0ce9769e566ca7cc3

commit r16-909-g04871e748862fc48fac739f0ce9769e566ca7cc3
Author: David Malcolm <dmalc...@redhat.com>
Date:   Tue May 27 12:22:26 2025 -0400

    diagnostics: rework experimental-html output [PR116792]

    This patch reworks the HTML output from the the option
      -fdiagnostics-add-output=experimental-html
    so that for source quoting and path printing, rather than simply adding
    the textual output inside <pre> elements, it breaks up the output
    into HTML tags reflecting the structure of the output, using CSS, SVG
    and a little javascript to help the user navigate the diagnostics and
    the events within any paths.

    This uses ideas from the patch I posted in:
      https://gcc.gnu.org/pipermail/gcc-patches/2020-November/558603.html
    but reworks the above patch so that:
    * rather than printing source to a pretty_printer, the HTML is created
      by building a DOM tree in memory, using a new xml::printer class.  This
      should be less error-prone than the pretty_printer approach, since it
      ought to solve escaping issues.  Instead of a text vs html boolean,
      the code is generalized via templates with to_text vs to_html sinks.
      This templatization applies both to path-printing and
      diagnostic-show-locus.cc.
    * the HTML output can have multiple diagnostics and multiple paths rather
      than just a single path.  The javascript keyboard controls now cycle
      through all diagnostics and all events within them

    An example of the output can be seen at:
      https://dmalcolm.fedorapeople.org/gcc/2025-05-27/malloc-1.c.html
    where the keys "j" and "k" cycle through diagnostics and events
    within them.

    gcc/ChangeLog:
            PR other/116792
            * diagnostic-format-html.cc: Define INCLUDE_STRING.
            Include "xml.h", "xml-printer.h", and "json.h".
            (html_generation_options::html_generation_options): New.
            (namespace xml): Move decls to xml.h and convert from using
            label_text to std::string.
            (xml::text::write_as_xml): Reimplement indentation so it is done
            by this node, rather than the parent.
            (xml::node_with_children::add_text): Convert from label_text to
            std::string.  Consolidate runs of text into a single node.
            (xml::document::write_as_xml): Reimplement indentation.
            (xml::element::write_as_xml): Reimplement indentation so it is
            done by this node, rather than the parent.  Convert from
            label_text to std::string.  Update attribute-printing to new
            representation to preserve insertion order.
            (xml::element::set_attr): Convert from label_text to std::string.
            Record insertion order.
            (xml::raw::write_as_xml): New.
            (xml::printer::printer): New.
            (xml::printer::push_tag): New.
            (xml::printer::push_tag_with_class): New.
            (xml::printer::pop_tag): New.
            (xml::printer::set_attr): New.
            (xml::printer::add_text): New.
            (xml::printer::add_raw): New.
            (xml::printer::push_element): New.
            (xml::printer::append): New.
            (xml::printer::get_insertion_point): New.
            (html_builder::add_focus_id): New.
            (html_builder::m_html_gen_opts): New field.
            (html_builder::m_head_element): New field.
            (html_builder::m_next_diag_id): New field.
            (html_builder::m_ui_focus_ids): New field.
            (make_div): Convert from label_text to std::string.
            (make_span): Likewise.
            (HTML_STYLE): New.
            (HTML_SCRIPT): New.
            (html_builder::html_builder): Fix indentation.  Add
            "html_gen_opts" param.  Initialize new fields.  Reimplement
            using xml::printer.  Optionally add style and script tags.
            (class html_path_label_writer): New.
            (html_builder::make_element_for_diagnostic): Convert from
            label_text to std::string. Set "id" on "gcc-diagnostic" and
            "gcc-message" <div> elements; add the latter to the focus ids.
            Use diagnostic_context::maybe_show_locus_as_html rather than
            html_builder::make_element_for_source.  Use print_path_as_html
            rather than html_builder::make_element_for_path.
            (html_builder::make_element_for_source): Drop.
            (html_builder::make_element_for_path): Drop.
            (html_builder::make_element_for_patch): Convert from label_text to
            std::string.
            (html_builder::make_metadata_element): Likewise.  Use
            xml::printer.
            (html_builder::make_element_for_metadata): Convert from label_text
            to std::string.
            (html_builder::emit_diagram): Expand comment.
            (html_builder::flush_to_file): Write out initializer for
            "focus_ids" into javascript.
            (html_output_format::html_output_format): Add param
            "html_gen_opts" and use it to initialize m_builder.
            (html_file_output_format::html_file_output_format): Likewise, to
            initialize base class.
            (make_html_sink): Likewise, to pass to ctor.
           
(selftest::test_html_diagnostic_context::test_html_diagnostic_context):
            Set up html_generation_options.
           
(selftest::html_buffered_output_format::html_buffered_output_format):
            Add html_gen_opts param.
            (selftest::test_simple_log): Add id attributes to expected text
            for "gcc-diagnostic" and "gcc-message" elements.  Update
            whitespace for indentation fixes.
            (selftest::test_metadata): Update whitespace for indentation
            fixes.
            (selftest::test_printer): New selftest.
            (selftest::test_attribute_ordering): New selftest.
            (selftest::diagnostic_format_html_cc_tests): Call the new
            selftests.
            * diagnostic-format-html.h (struct html_generation_options): New.
            (make_html_sink): Add "html_gen_opts" param.
            (print_path_as_html): New decl.
            * diagnostic-path-output.cc: Define INCLUDE_MAP.  Add includes of
            "diagnostic-format-html.h", "xml.h", and "xml-printer.h".
            (path_print_policy::path_print_policy): Add ctor.
            (path_print_policy::get_diagram_theme): Fix whitespace.
            (struct stack_frame): New.
            (begin_html_stack_frame): New function.
            (end_html_stack_frame): New function.
            (emit_svg_arrow): New function.
            (event_range::print): Rename to...
            (event_range::print_as_text): ...this.  Update call to
            diagnostic_start_span.
            (event_range::print_as_html): New, based on the above, but ported
            from pretty_printer to xml::printer.
            (thread_event_printer::print_swimlane_for_event_range): Rename
            to...
            (thread_event_printer::print_swimlane_for_event_range_as_text):
            ...this.  Update for renaming of event_range::print to
            event_range::print_as_text.
            (thread_event_printer::print_swimlane_for_event_range_as_html):
            New.
            (print_path_summary_as_text): Update for "_as_text" renaming.
            (print_path_summary_as_html): New.
            (print_path_as_html): New.
            * diagnostic-show-locus.cc: Add defines of INCLUDE_MAP and
            INCLUDE_STRING.  Add includes of "xml.h" and "xml-printer.h".
            (struct char_display_policy): Replace "m_print_cb" with
            "m_print_text_cb" and "m_print_html_cb".
            (struct to_text): New.
            (struct to_html): New.
            (get_printer): New.
            (default_diagnostic_start_span_fn<to_text>): New.
            (default_diagnostic_start_span_fn<to_html>): New.
            (class layout): Update "friend class layout_printer;" for
            template.
            (enum class margin_kind): New.
            (class layout_printer): Convert into a template.
            (layout_printer::m_pp): Replace field with...
            (layout_printer::m_sink): ...this.
            (layout_printer::m_colorizer): Drop field in favor of a pointer
            in the "to_text" sink.
            (default_print_decoded_ch): Convert into a template.
            (escape_as_bytes_print): Likewise.
            (escape_as_unicode_print): Likewise.
            (make_char_policy): Update to use both text and html callbacks.
            (layout_printer::print_gap_in_line_numbering): Replace with...
            (layout_printer<to_text>::print_gap_in_line_numbering): ...this
            (layout_printer<to_html>::print_gap_in_line_numbering): ...and
            this.
            (layout_printer::print_source_line): Convert to template, using
            m_sink.
            (layout_printer::print_leftmost_column): Likewise.
            (layout_printer::start_annotation_line): Likewise.
            (layout_printer<to_text>::end_line): New.
            (layout_printer<to_html>::end_line): New.
            (layout_printer::print_annotation_line): Convert to template,
            using m_sink.
            (class line_label): Add field m_original_range_idx.
            (layout_printer<to_text>::begin_label): New.
            (layout_printer<to_html>::begin_label): New.
            (layout_printer<to_text>::end_label): New.
            (layout_printer<to_html>::end_label): New.
            (layout_printer::print_any_labels): Convert to template, using
            m_sink.
            (layout_printer::print_leading_fixits): Likewise.
            (layout_printer::print_trailing_fixits): Likewise.
            (layout_printer::print_newline): Drop.
            (layout_printer::move_to_column): Convert to template, using
            m_sink.
            (layout_printer::show_ruler): Likewise.
            (layout_printer::print_line): Likewise.
            (layout_printer::print_any_right_to_left_edge_lines): Likewise.
            (layout_printer::layout_printer): Likewise.
            (diagnostic_context::maybe_show_locus_as_html): New.
            (diagnostic_source_print_policy::diagnostic_source_print_policy):
            Update for split of start_span_cb into text vs html variants.
            (diagnostic_source_print_policy::print): Update for use of
            templates; use to_text.
            (diagnostic_source_print_policy::print_as_html): New.
            (layout_printer::print): Convert to template, using m_sink.
            (selftest::make_element_for_locus): New.
            (selftest::make_raw_html_for_locus): New.
            (selftest::test_layout_x_offset_display_utf8): Update for use of
            templates.
            (selftest::test_layout_x_offset_display_tab): Likewise.
            (selftest::test_one_liner_caret_and_range): Add test coverage of
            HTML output.
            (selftest::test_one_liner_labels): Likewise.
            * diagnostic.cc (diagnostic_context::initialize): Update for split
            of start_span_cb into text vs html variants.
            (default_diagnostic_start_span_fn): Move to
            diagnostic-show-locus.cc, converting to template.
            * diagnostic.h (class xml::printer): New forward decl.
            (diagnostic_start_span_fn): Replace typedef with "using",
            converting to a template.
            (struct to_text): New forward decl.
            (struct to_html): New forward decl.
            (get_printer): New decl.
            (diagnostic_location_print_policy::print_text_span_start): New
            decl.
            (diagnostic_location_print_policy::print_html_span_start): New
            decl.
            (class html_label_writer): New.
            (diagnostic_source_print_policy::print_as_html): New decl.
            (diagnostic_source_print_policy::get_start_span_fn): Replace
            with...
            (diagnostic_source_print_policy::get_text_start_span_fn): ...this
            (diagnostic_source_print_policy::get_html_start_span_fn): ...and
            this
            (diagnostic_source_print_policy::m_start_span_cb): Replace with...
            (diagnostic_source_print_policy::m_text_start_span_cb): ...this
            (diagnostic_source_print_policy::m_html_start_span_cb): ...and
            this.
            (diagnostic_context::maybe_show_locus_as_html): New decl.
            (diagnostic_context::m_text_callbacks::m_start_span): Replace
            with...
            (diagnostic_context::m_text_callbacks::m_text_start_span): ...this
            (diagnostic_context::m_text_callbacks::m_html_start_span): ...and
            this.
            (diagnostic_start_span): Update for template change.
            (diagnostic_show_locus_as_html): New inline function.
            (default_diagnostic_start_span_fn): Convert to template.
            * doc/invoke.texi (experimental-html): Add "css" and "javascript"
            keys.
            * opts-diagnostic.cc (html_scheme_handler::make_sink): Likewise.
            * selftest-diagnostic.cc
            (selftest::test_diagnostic_context::start_span_cb): Update for
            template changes.
            * selftest-diagnostic.h
            (selftest::test_diagnostic_context::start_span_cb): Likewise.
            * xml-printer.h: New file.
            * xml.h: New file, based on material in diagnostic-format-html.cc,
            but using std::string rather than label_text.
            (xml::element::m_key_insertion_order): New field.
            (struct xml::raw): New.

    gcc/fortran/ChangeLog
            PR other/116792
            * error.cc (gfc_diagnostic_start_span): Update for diagnostic.h
            changes.

    gcc/testsuite/ChangeLog:
            PR other/116792
            * gcc.dg/html-output/missing-semicolon.c: Add ":javascript=no" to
            html output.
            * gcc.dg/html-output/missing-semicolon.py: Move repeated
            definitions into lib/htmltest.py.
            * gcc.dg/plugin/diagnostic_group_plugin.cc: Update for template
            changes.
            * gcc.dg/plugin/diagnostic-test-metadata-html.c: Add
            ":javascript=no" to html output.  Add
            "-fdiagnostics-show-line-numbers".
            * gcc.dg/plugin/diagnostic-test-metadata-html.py: Move repeated
            definitions into lib/htmltest.py.  Add checks of annotated source.
            * gcc.dg/plugin/diagnostic-test-paths-2.c: Add ":javascript=no" to
            html output.
            * gcc.dg/plugin/diagnostic-test-paths-2.py: Move repeated
            definitions into lib/htmltest.py.  Add checks of execution path.
            * gcc.dg/plugin/diagnostic-test-paths-4.c: Add
            -fdiagnostics-add-output=experimental-html:javascript=no.  Add
            invocation ot diagnostic-test-paths-4.py.
            * gcc.dg/plugin/diagnostic-test-paths-4.py: New test script.
            * gcc.dg/plugin/diagnostic-test-show-locus-bw-line-numbers.c: Add
            -fdiagnostics-add-output=experimental-html:javascript=no.  Add
            invocation of diagnostic-test-show-locus.py.
            * gcc.dg/plugin/diagnostic-test-show-locus.py: New test script.
            * lib/htmltest.py: New test support script.

    Signed-off-by: David Malcolm <dmalc...@redhat.com>

Reply via email to