gcc/gcc/text-art/types.h
David Malcolm 4b02dd48f5 analyzer: respect GCC_COLORS in out-of-bounds diagrams [PR114588]
gcc/analyzer/ChangeLog:
	PR analyzer/114588
	* access-diagram.cc (access_diagram_impl::access_diagram_impl):
	Replace hardcoded colors for valid_style and invalid_style with
	calls to text_art::get_style_from_color_cap_name.

gcc/ChangeLog:
	PR analyzer/114588
	* diagnostic-color.cc (color_dict): Add "valid" and "invalid" as
	color capability names.
	* doc/invoke.texi: Document them in description of GCC_COLORS.
	* text-art/style.cc: Include "diagnostic-color.h".
	(text_art::get_style_from_color_cap_name): New.
	* text-art/types.h (get_style_from_color_cap_name): New decl.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
2024-04-05 14:49:53 -04:00

519 lines
12 KiB
C++

/* Types for drawing 2d "text art".
Copyright (C) 2023-2024 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_TEXT_ART_TYPES_H
#define GCC_TEXT_ART_TYPES_H
/* This header uses std::vector, but <vector> can't be directly
included due to issues with macros. Hence it must be included from
system.h by defining INCLUDE_MEMORY in any source file using it. */
#ifndef INCLUDE_VECTOR
# error "You must define INCLUDE_VECTOR before including system.h to use text-art/types.h"
#endif
#include "cpplib.h"
#include "pretty-print.h"
namespace text_art {
/* Forward decls. */
class canvas;
class table;
class theme;
/* Classes for geometry.
We use templates to avoid mixing up e.g. canvas coordinates
with table coordinates. */
template <typename CoordinateSystem>
struct size
{
size (int w_, int h_) : w (w_), h (h_) {}
int w;
int h;
};
template <typename CoordinateSystem>
struct coord
{
coord (int x_, int y_) : x (x_), y (y_) {}
int x;
int y;
};
template <typename CoordinateSystem>
coord<CoordinateSystem> operator+ (coord<CoordinateSystem> a,
coord<CoordinateSystem> b)
{
return coord<CoordinateSystem> (a.x + b.x, a.y + b.y);
}
/* A half-open range [start, next) of int. */
template <typename CoordinateSystem>
struct range
{
range (int start_, int next_)
: start (start_), next (next_)
{}
int get_min () const { return start; }
int get_max () const { return next - 1; }
int get_next () const { return next; }
int get_size () const { return next - start; }
int get_midpoint () const { return get_min () + get_size () / 2; }
int start;
int next;
};
/* A rectangle area within CoordinateSystem. */
template <typename CoordinateSystem>
struct rect
{
rect (coord<CoordinateSystem> top_left,
size<CoordinateSystem> size)
: m_top_left (top_left),
m_size (size)
{
}
rect (range<CoordinateSystem> x_range,
range<CoordinateSystem> y_range)
: m_top_left (x_range.get_min (), y_range.get_min ()),
m_size (x_range.get_size (), y_range.get_size ())
{
}
int get_min_x () const { return m_top_left.x; }
int get_min_y () const { return m_top_left.y; }
int get_max_x () const { return m_top_left.x + m_size.w - 1; }
int get_max_y () const { return m_top_left.y + m_size.h - 1; }
int get_next_x () const { return m_top_left.x + m_size.w; }
int get_next_y () const { return m_top_left.y + m_size.h; }
range<CoordinateSystem> get_x_range () const
{
return range<CoordinateSystem> (get_min_x (), get_next_x ());
}
range<CoordinateSystem> get_y_range () const
{
return range<CoordinateSystem> (get_min_y (), get_next_y ());
}
int get_width () const { return m_size.w; }
int get_height () const { return m_size.h; }
coord<CoordinateSystem> m_top_left;
size<CoordinateSystem> m_size;
};
template <typename CoordinateSystem>
rect<CoordinateSystem> operator+ (rect<CoordinateSystem> r,
coord<CoordinateSystem> offset)
{
return rect<CoordinateSystem> (r.m_top_left + offset, r.m_size);
}
template <typename ElementType, typename SizeType, typename CoordType>
class array2
{
public:
typedef ElementType element_t;
typedef SizeType size_t;
typedef CoordType coord_t;
array2 (size_t sz)
: m_size (sz),
m_elements (sz.w * sz.h)
{
}
array2 (array2 &&other)
: m_size (other.m_size),
m_elements (std::move (other.m_elements))
{
}
/* Move assignment not implemented or used. */
array2 &operator== (array2 &&other) = delete;
/* No copy ctor or assignment op. */
array2 (const array2 &other) = delete;
array2 &operator= (const array2 &other) = delete;
const size_t &get_size () const { return m_size; }
void add_row (const element_t &element)
{
m_size.h++;
m_elements.insert (m_elements.end (), m_size.w, element);
}
const element_t &get (const coord_t &coord) const
{
::size_t idx = get_idx (coord);
return m_elements[idx];
}
void set (const coord_t &coord, const element_t &element)
{
::size_t idx = get_idx (coord);
m_elements[idx] = element;
}
void fill (element_t element)
{
for (int y = 0; y < m_size.h; y++)
for (int x = 0; x < m_size.w; x++)
set (coord_t (x, y), element);
}
private:
::size_t get_idx (const coord_t &coord) const
{
gcc_assert (coord.x >= 0);
gcc_assert (coord.x < m_size.w);
gcc_assert (coord.y >= 0);
gcc_assert (coord.y < m_size.h);
return (coord.y * m_size.w) + coord.x;
}
size_t m_size;
std::vector<element_t> m_elements;
};
/* A combination of attributes describing how to style a text cell.
We only support those attributes mentioned in invoke.texi:
- bold,
- underscore,
- blink,
- inverse,
- colors for foreground and background:
- default color
- named colors
- 16-color mode colors (the "bright" variants)
- 88-color mode
- 256-color mode
plus URLs. */
struct style
{
typedef unsigned char id_t;
static const id_t id_plain = 0;
/* Colors. */
enum class named_color
{
DEFAULT,
// ANSI order
BLACK,
RED,
GREEN,
YELLOW,
BLUE,
MAGENTA,
CYAN,
WHITE
};
struct color
{
enum class kind
{
NAMED,
BITS_8,
BITS_24,
} m_kind;
union
{
struct {
enum named_color m_name;
bool m_bright;
} m_named;
uint8_t m_8bit;
struct {
uint8_t r;
uint8_t g;
uint8_t b;
} m_24bit;
} u;
/* Constructor for named colors. */
color (enum named_color name = named_color::DEFAULT,
bool bright = false)
: m_kind (kind::NAMED)
{
u.m_named.m_name = name;
u.m_named.m_bright = bright;
}
/* Constructor for 8-bit colors. */
color (uint8_t col_val)
: m_kind (kind::BITS_8)
{
u.m_8bit = col_val;
}
/* Constructor for 24-bit colors. */
color (uint8_t r, uint8_t g, uint8_t b)
: m_kind (kind::BITS_24)
{
u.m_24bit.r = r;
u.m_24bit.g = g;
u.m_24bit.b = b;
}
bool operator== (const color &other) const;
bool operator!= (const color &other) const
{
return !(*this == other);
}
void print_sgr (pretty_printer *pp, bool fg, bool &need_separator) const;
};
style ()
: m_bold (false),
m_underscore (false),
m_blink (false),
m_reverse (false),
m_fg_color (named_color::DEFAULT),
m_bg_color (named_color::DEFAULT),
m_url ()
{}
bool operator== (const style &other) const
{
return (m_bold == other.m_bold
&& m_underscore == other.m_underscore
&& m_blink == other.m_blink
&& m_reverse == other.m_reverse
&& m_fg_color == other.m_fg_color
&& m_bg_color == other.m_bg_color
&& m_url == other.m_url);
}
style &set_style_url (const char *url);
static void print_changes (pretty_printer *pp,
const style &old_style,
const style &new_style);
bool m_bold;
bool m_underscore;
bool m_blink;
bool m_reverse;
color m_fg_color;
color m_bg_color;
std::vector<cppchar_t> m_url; // empty = no URL
};
extern style get_style_from_color_cap_name (const char *name);
/* A class to keep track of all the styles in use in a drawing, so that
we can refer to them via the compact style::id_t type, rather than
via e.g. pointers. */
class style_manager
{
public:
style_manager ();
style::id_t get_or_create_id (const style &style);
const style &get_style (style::id_t id) const
{
return m_styles[id];
}
void print_any_style_changes (pretty_printer *pp,
style::id_t old_id,
style::id_t new_id) const;
unsigned get_num_styles () const { return m_styles.size (); }
private:
std::vector<style> m_styles;
};
class styled_unichar
{
public:
friend class styled_string;
explicit styled_unichar ()
: m_code (0),
m_style_id (style::id_plain)
{}
explicit styled_unichar (cppchar_t ch)
: m_code (ch),
m_emoji_variant_p (false),
m_style_id (style::id_plain)
{}
explicit styled_unichar (cppchar_t ch, bool emoji, style::id_t style_id)
: m_code (ch),
m_emoji_variant_p (emoji),
m_style_id (style_id)
{
gcc_assert (style_id <= 0x7f);
}
cppchar_t get_code () const { return m_code; }
bool emoji_variant_p () const { return m_emoji_variant_p; }
style::id_t get_style_id () const { return m_style_id; }
bool double_width_p () const
{
int width = cpp_wcwidth (get_code ());
gcc_assert (width == 1 || width == 2);
return width == 2;
}
bool operator== (const styled_unichar &other) const
{
return (m_code == other.m_code
&& m_emoji_variant_p == other.m_emoji_variant_p
&& m_style_id == other.m_style_id);
}
void set_emoji_variant () { m_emoji_variant_p = true; }
int get_canvas_width () const
{
return cpp_wcwidth (m_code);
}
void add_combining_char (cppchar_t ch)
{
m_combining_chars.push_back (ch);
}
const std::vector<cppchar_t> get_combining_chars () const
{
return m_combining_chars;
}
private:
cppchar_t m_code : 24;
bool m_emoji_variant_p : 1;
style::id_t m_style_id : 7;
std::vector<cppchar_t> m_combining_chars;
};
class styled_string
{
public:
explicit styled_string () = default;
explicit styled_string (style_manager &sm, const char *str);
explicit styled_string (cppchar_t cppchar, bool emoji = false);
styled_string (styled_string &&) = default;
styled_string &operator= (styled_string &&) = default;
/* No copy ctor or assignment op. */
styled_string (const styled_string &) = delete;
styled_string &operator= (const styled_string &) = delete;
/* For the few cases where copying is required, spell it out explicitly. */
styled_string copy () const
{
styled_string result;
result.m_chars = m_chars;
return result;
}
bool operator== (const styled_string &other) const
{
return m_chars == other.m_chars;
}
static styled_string from_fmt (style_manager &sm,
printer_fn format_decoder,
const char *fmt, ...)
ATTRIBUTE_GCC_PPDIAG(3, 4);
static styled_string from_fmt_va (style_manager &sm,
printer_fn format_decoder,
const char *fmt,
va_list *args)
ATTRIBUTE_GCC_PPDIAG(3, 0);
size_t size () const { return m_chars.size (); }
styled_unichar operator[] (size_t idx) const { return m_chars[idx]; }
std::vector<styled_unichar>::const_iterator begin () const
{
return m_chars.begin ();
}
std::vector<styled_unichar>::const_iterator end () const
{
return m_chars.end ();
}
int calc_canvas_width () const;
void append (const styled_string &suffix);
void set_url (style_manager &sm, const char *url);
private:
std::vector<styled_unichar> m_chars;
};
enum class x_align
{
LEFT,
CENTER,
RIGHT
};
enum class y_align
{
TOP,
CENTER,
BOTTOM
};
/* A set of cardinal directions within a canvas or table. */
struct directions
{
public:
directions (bool up, bool down, bool left, bool right)
: m_up (up), m_down (down), m_left (left), m_right (right)
{
}
size_t as_index () const
{
return (m_up << 3) | (m_down << 2) | (m_left << 1) | m_right;
}
bool m_up: 1;
bool m_down: 1;
bool m_left: 1;
bool m_right: 1;
};
} // namespace text_art
#endif /* GCC_TEXT_ART_TYPES_H */