friend class layout_printer<to_html>;
to_html (xml::printer &xp,
+ const rich_location *richloc,
html_label_writer *html_label_writer)
: m_xp (xp),
+ m_richloc (richloc),
m_html_label_writer (html_label_writer)
{}
// no-op for HTML
}
- void colorize_text_for_range_idx (int)
- {
- // no-op for HTML
- }
-
void colorize_text_for_cfg_edge ()
{
// no-op for HTML
source_policy.get_html_start_span_fn () (loc_policy, *this, exploc);
}
+ const location_range *
+ get_location_range_by_idx (int range_idx)
+ {
+ if (!m_richloc)
+ return nullptr;
+ return m_richloc->get_range (range_idx);
+ }
+
+ const char *
+ get_highlight_color_for_range_idx (int range_idx)
+ {
+ const location_range *const loc_range
+ = get_location_range_by_idx (range_idx);
+ if (!loc_range)
+ return nullptr;
+ return loc_range->m_highlight_color;
+ }
+
xml::printer &m_xp;
+ const rich_location *m_richloc;
private:
html_label_writer *m_html_label_writer;
pretty_printer m_scratch_pp;
xml::printer &xp,
const expanded_location &exploc)
{
- to_html sink (xp, nullptr);
+ to_html sink (xp, nullptr, nullptr);
diagnostic_source_print_policy source_policy (dc);
source_policy.get_html_start_span_fn () (*this, sink, exploc);
}
void end_line ();
void print_annotation_line (linenum_type row, const line_bounds lbounds);
void print_any_labels (linenum_type row);
- void begin_label (const line_label &label);
- void end_label ();
+ void begin_label (int state_idx, bool is_label_text);
+ void end_label (int state_idx, bool is_label_text);
void print_trailing_fixits (linenum_type row);
void
void print_any_right_to_left_edge_lines ();
+ void set_in_range (int range_idx);
+ void set_outside_range ();
+
private:
Sink &m_sink;
const layout &m_layout;
bool m_is_diagnostic_path;
+ bool m_was_in_range_p;
+ int m_last_range_idx;
+
/* Fields for handling links between labels (e.g. for showing CFG edges
in execution paths).
Note that the logic for printing such links makes various simplifying
CU_BYTES,
&state);
if (in_range_p)
- m_sink.colorize_text_for_range_idx (state.range_idx);
+ set_in_range (state.range_idx);
else
- m_sink.colorize_text_ensure_normal ();
+ set_outside_range ();
}
/* Get the display width of the next character to be output, expanding
m_sink.print_decoded_char (m_layout.m_char_policy, cp);
c = dw.next_byte ();
}
+ set_outside_range ();
end_line ();
return lbounds;
}
m_sink.pop_html_tag ("tr");
}
+/* Handle the various transitions between being-in-range and
+ not-being-in-a-range, and between ranges. */
+
+template<typename Sink>
+void
+layout_printer<Sink>::set_in_range (int range_idx)
+{
+ if (m_was_in_range_p)
+ {
+ if (m_last_range_idx != range_idx)
+ {
+ /* transition between ranges. */
+ end_label (m_last_range_idx, false);
+ begin_label (range_idx, false);
+ }
+ }
+ else
+ {
+ /* transition from "not in a range" to "in a range". */
+ begin_label (range_idx, false);
+ m_was_in_range_p = true;
+ }
+ m_last_range_idx = range_idx;
+}
+
+template<typename Sink>
+void
+layout_printer<Sink>::set_outside_range ()
+{
+ if (m_was_in_range_p)
+ /* transition from "in a range" to "not in a range". */
+ end_label (m_last_range_idx, false);
+ m_was_in_range_p = false;
+}
+
/* Print a line consisting of the caret/underlines for the given
source line. */
lbounds.m_last_non_ws_disp_col,
CU_DISPLAY_COLS,
&state);
+ if (in_range_p)
+ set_in_range (state.range_idx);
+ else
+ set_outside_range ();
+
if (in_range_p)
{
/* Within a range. Draw either the caret or an underline. */
- m_sink.colorize_text_for_range_idx (state.range_idx);
if (state.draw_caret_p)
{
/* Draw the caret. */
else
{
/* Not in a range. */
- m_sink.colorize_text_ensure_normal ();
m_sink.add_character (' ');
}
}
+ set_outside_range ();
+
end_line ();
}
bool m_has_out_edge;
};
+/* Implementations of layout_printer::{begin,end}_label for
+ to_text and to_html.
+
+ RANGE_IDX is the index of the range within the rich_location.
+
+ IS_LABEL_TEXT is true for the text of the label,
+ false when quoting the source code, underlining the source
+ code, and for the vertical bars connecting the underlines
+ to the text of the label. */
+
template<>
void
-layout_printer<to_text>::begin_label (const line_label &label)
+layout_printer<to_text>::begin_label (int range_idx,
+ bool is_label_text)
{
- /* Colorize the text, unless it's for events in a
+ /* Colorize the text, unless it's for labels for events in a
diagnostic_path. */
- if (!m_is_diagnostic_path)
- m_sink.colorize_text_for_range_idx (label.m_state_idx);
+ if (is_label_text && m_is_diagnostic_path)
+ return;
+
+ gcc_assert (m_sink.m_colorizer);
+ m_sink.m_colorizer->set_range (range_idx);
}
template<>
void
-layout_printer<to_html>::begin_label (const line_label &)
+layout_printer<to_html>::begin_label (int range_idx,
+ bool is_label_text)
{
- if (m_sink.m_html_label_writer)
+ if (is_label_text && m_sink.m_html_label_writer)
m_sink.m_html_label_writer->begin_label ();
+
+ if (const char *highlight_color
+ = m_sink.get_highlight_color_for_range_idx (range_idx))
+ m_sink.m_xp.push_tag_with_class ("span", highlight_color);
}
template<>
void
-layout_printer<to_text>::end_label ()
+layout_printer<to_text>::end_label (int, bool)
{
m_sink.colorize_text_ensure_normal ();
}
template<>
void
-layout_printer<to_html>::end_label ()
+layout_printer<to_html>::end_label (int range_idx,
+ bool is_label_text)
{
- if (m_sink.m_html_label_writer)
+ if (m_sink.get_highlight_color_for_range_idx (range_idx))
+ m_sink.m_xp.pop_tag ();
+
+ if (is_label_text && m_sink.m_html_label_writer)
m_sink.m_html_label_writer->end_label ();
}
move_to_column (&column, label->m_column, true);
gcc_assert (column == label->m_column);
- begin_label (*label);
+ begin_label (label->m_state_idx, true);
m_sink.add_text (label->m_text.m_buffer);
- end_label ();
+ end_label (label->m_state_idx, true);
column += label->m_display_width;
if (get_options ().show_event_links_p && label->m_has_out_edge)
{
gcc_assert (column <= label->m_column);
move_to_column (&column, label->m_column, true);
- m_sink.colorize_text_for_range_idx (label->m_state_idx);
+ begin_label (label->m_state_idx, false);
m_sink.add_character ('|');
- m_sink.colorize_text_ensure_normal ();
+ end_label (label->m_state_idx, false);
column++;
}
}
: m_sink (sink),
m_layout (layout),
m_is_diagnostic_path (is_diagnostic_path),
+ m_was_in_range_p (false),
+ m_last_range_idx (0),
m_link_lhs_state (link_lhs_state::none),
m_link_rhs_column (-1)
{
const
{
layout layout (*this, richloc, effects);
- to_html sink (xp, label_writer);
+ to_html sink (xp, &richloc, label_writer);
layout_printer<to_html> lp (sink, layout,
diagnostic_kind == DK_DIAGNOSTIC_PATH);
lp.print (*this);
--- /dev/null
+from htmltest import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def html_tree():
+ return html_tree_from_env()
+
+def assert_highlighted_text(element, expected_highlight, expected_text):
+ assert_tag(element, 'span')
+ assert_class(element, expected_highlight)
+ assert element.text == expected_text
+
+def test_message(html_tree):
+ """
+ Verify that the quoted text in the message has the correct
+ highlight colors.
+ """
+ diag = get_diag_by_index(html_tree, 0)
+ msg = get_message_within_diag(diag)
+
+ assert_tag(msg[0], 'span')
+ assert_class(msg[0], 'gcc-quoted-text')
+ assert_highlighted_text(msg[0][0], 'highlight-a', '%i')
+
+ assert_tag(msg[1], 'span')
+ assert_class(msg[1], 'gcc-quoted-text')
+ assert_highlighted_text(msg[1][0], 'highlight-a', 'int')
+
+ assert_tag(msg[2], 'span')
+ assert_class(msg[2], 'gcc-quoted-text')
+ assert_highlighted_text(msg[2][0], 'highlight-b', 'const char *')
+
+def test_annotations(html_tree):
+ """
+ Verify that the labels in the annotations have the correct
+ highlight colors.
+ """
+ diag = get_diag_by_index(html_tree, 0)
+ locus = get_locus_within_diag(diag)
+ tbody = locus.find('xhtml:tbody', ns)
+ assert tbody.attrib['class'] == 'line-span'
+
+ rows = tbody.findall('xhtml:tr', ns)
+
+ # Source row
+ row = rows[0]
+ tds = row.findall('xhtml:td', ns)
+ assert len(tds) == 2
+ assert_class(tds[1], 'source')
+ assert_highlighted_text(tds[1][0], 'highlight-a', '%i')
+ assert_highlighted_text(tds[1][1], 'highlight-b', 'msg')
+
+ # Underline row:
+ row = rows[1]
+ tds = row.findall('xhtml:td', ns)
+ assert len(tds) == 2
+ assert_class(tds[1], 'annotation')
+ assert_highlighted_text(tds[1][0], 'highlight-a', '~^')
+ assert_highlighted_text(tds[1][1], 'highlight-b', '~~~')
+
+ # vline row:
+ row = rows[2]
+ tds = row.findall('xhtml:td', ns)
+ assert len(tds) == 2
+ assert_class(tds[1], 'annotation')
+ assert_highlighted_text(tds[1][0], 'highlight-a', '|')
+ assert_highlighted_text(tds[1][1], 'highlight-b', '|')
+
+ # Label row:
+ row = rows[3]
+ tds = row.findall('xhtml:td', ns)
+ assert len(tds) == 2
+ assert_class(tds[1], 'annotation')
+ assert_highlighted_text(tds[1][0], 'highlight-a', 'int')
+ assert_highlighted_text(tds[1][1], 'highlight-b', 'const char *')
+
+# For reference, here's the generated HTML:
+"""
+ <span class="gcc-message" id="gcc-diag-0-message">format '<span class="gcc-quoted-text"><span class="high
+light-a">%i</span></span>' expects argument of type '<span class="gcc-quoted-text"><span class="highlight-a"
+>int</span></span>', but argument 2 has type '<span class="gcc-quoted-text"><span class="highlight-b">const
+char *</span></span>'</span>
+
+ <span class="gcc-option">[<a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wformat">-Wfo
+rmat=</a>]</span>
+ <table class="locus">
+ <tbody class="line-span">
+ <tr><td class="left-margin"> </td><td class="source"> printf("hello <span class="highlight-a">%i</span>", <span class="highlight-b">msg</span>); /* { dg-warning "format '%i' expects argument of type 'int', but argument 2 has type 'const char \\*' " } */</td></tr>
+ <tr><td class="left-margin"> </td><td class="annotation"> <span class="highlight-a">~^</spa
+n> <span class="highlight-b">~~~</span></td></tr>
+ <tr><td class="left-margin"> </td><td class="annotation"> <span class="highlight-a">|</spa
+n> <span class="highlight-b">|</span></td></tr>
+ <tr><td class="left-margin"> </td><td class="annotation"> <span class="highlight-a">int</s
+pan> <span class="highlight-b">const char *</span></td></tr>
+ <tr><td class="left-margin"> </td><td class="annotation"> %s</td></tr>
+ </tbody>
+ </table>
+"""