
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>
519 lines
12 KiB
C++
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 */
|