#ifndef GOOSE_DIAGNOSTICS_RENDERER_H
#define GOOSE_DIAGNOSTICS_RENDERER_H
namespace goose::diagnostics
{
class Renderer
{
public:
Renderer( llvm::raw_ostream& output ) :
m_output( output )
{}
~Renderer()
{
flushContext();
}
enum Style
{
None = 0,
Caret = 1 << 0,
Squiggles = 1 << 1,
Highlight = 1 << 2
};
struct Colors
{
static const char* Reset;
static const char* Location; // File name, line number gutter
static const char* Context; // Squiggles and messages providing contextual informations
static const char* Trace; // Squiggles and messages displayed during tracing
static const char* Error; // Error highlight and "error" keyword
static const char* Source; // Source code
};
// Wrapper around fmt::format that defines named arguments for all the possible colors above
// (in lowercase). If the output isn't a terminal, empty strings will be provided instead of
// color escape sequences.
template< typename S, typename... A >
auto format( S&& str, A&&... args ) const;
template< typename... A >
void addMessage( uint32_t location, const string& message, A&&... args );
template< typename... A >
void addContext( const string& message, A&&... args );
void addContext( uint32_t location, uint8_t styleFlags, const char* color = Colors::Reset );
void addContext( uint32_t location, uint8_t styleFlags, const string& message, const char* color = Colors::Reset );
private:
bool useColors() const;
void addToPendingContext( const optional< Location >& loc, uint8_t styleFlags, const char* pColor, const string& message );
void flushContext();
llvm::raw_ostream& m_output;
struct Item
{
string message;
uint32_t location = 0;
// The following values are only relevant if the location is valid.
bool quoteSource = false;
uint8_t styleFlags = 0;
// Color is only relevant if styleFlags != 0
const char* color = "";
};
void addItem( Item&& item );
void applyColor( const char* pColor );
string m_lastFilename;
uint32_t m_lastLineNumber = 0;
// The pending context line informations.
string m_pendingContextFilename;
uint32_t m_pendingContextOffset = 0;
uint32_t m_pendingContextLineNumber = 0;
// Describe the starting or ending point of a span to be
// highlighted. color = nullptr means it's an ending point.
struct SpanVertex
{
uint32_t column = 0;
uint8_t styleFlags = 0;
const char* color = nullptr;
};
// The pending highlighting vertices.
llvm::SmallVector< SpanVertex, 8 > m_pendingHighlightSpans;
// The pending context message.
string m_pendingContextMessage;
// The color and position of the pending context message.
const char* m_pendingContextMessageColor = nullptr;
uint32_t m_pendingContextMessageXPosStart = 0;
uint32_t m_pendingContextMessageXPosEnd = 0;
// True if there is a pending caret highlighting.
// (we only allow one per displayed context line)
bool m_pendingCaret = false;
};
}
#endif