Pull out a colored text output interface out of the Console class.
parent
c260aca3f1
commit
b2737e2bed
@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
https://github.com/peterix/dfhack
|
||||||
|
Copyright (c) 2011 Petr Mrázek <peterix@gmail.com>
|
||||||
|
|
||||||
|
A thread-safe logging console with a line editor for windows.
|
||||||
|
|
||||||
|
Based on linenoise win32 port,
|
||||||
|
copyright 2010, Jon Griffiths <jon_p_griffiths at yahoo dot com>.
|
||||||
|
All rights reserved.
|
||||||
|
Based on linenoise, copyright 2010, Salvatore Sanfilippo <antirez at gmail dot com>.
|
||||||
|
The original linenoise can be found at: http://github.com/antirez/linenoise
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of Redis nor the names of its contributors may be used
|
||||||
|
to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <istream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "ColorText.h"
|
||||||
|
#include "MiscUtils.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using namespace DFHack;
|
||||||
|
|
||||||
|
#include "tinythread.h"
|
||||||
|
using namespace tthread;
|
||||||
|
|
||||||
|
void color_ostream::flush_buffer(bool flush)
|
||||||
|
{
|
||||||
|
auto buffer = buf();
|
||||||
|
auto str = buffer->str();
|
||||||
|
|
||||||
|
if (!str.empty()) {
|
||||||
|
add_text(cur_color, buffer->str());
|
||||||
|
buffer->str(std::string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flush)
|
||||||
|
flush_proxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_ostream::begin_batch()
|
||||||
|
{
|
||||||
|
flush_buffer(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_ostream::end_batch()
|
||||||
|
{
|
||||||
|
flush_proxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
color_ostream::color_ostream() : ostream(new buffer(this)), cur_color(COLOR_RESET)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
color_ostream::~color_ostream()
|
||||||
|
{
|
||||||
|
delete buf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_ostream::print(const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
vprint(format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_ostream::vprint(const char *format, va_list args)
|
||||||
|
{
|
||||||
|
std::string str = stl_vsprintf(format, args);
|
||||||
|
|
||||||
|
if (!str.empty()) {
|
||||||
|
flush_buffer(false);
|
||||||
|
add_text(cur_color, str);
|
||||||
|
if (str[str.size()-1] == '\n')
|
||||||
|
flush_proxy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_ostream::printerr(const char * format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
vprinterr(format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_ostream::vprinterr(const char *format, va_list args)
|
||||||
|
{
|
||||||
|
color_value save = cur_color;
|
||||||
|
|
||||||
|
fprintf(stderr, format, args);
|
||||||
|
|
||||||
|
color(COLOR_LIGHTRED);
|
||||||
|
vprint(format, args);
|
||||||
|
color(save);
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_ostream::color(color_value c)
|
||||||
|
{
|
||||||
|
if (c == cur_color)
|
||||||
|
return;
|
||||||
|
|
||||||
|
flush_buffer(false);
|
||||||
|
cur_color = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_ostream::reset_color(void)
|
||||||
|
{
|
||||||
|
color(COLOR_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buffered_color_ostream::add_text(color_value color, const std::string &text)
|
||||||
|
{
|
||||||
|
if (text.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (buffer.empty())
|
||||||
|
{
|
||||||
|
buffer.push_back(fragment_type(color, text));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto &back = buffer.back();
|
||||||
|
|
||||||
|
if (back.first != color || std::max(back.second.size(), text.size()) > 128)
|
||||||
|
buffer.push_back(fragment_type(color, text));
|
||||||
|
else
|
||||||
|
buffer.back().second += text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_ostream_proxy::flush_proxy()
|
||||||
|
{
|
||||||
|
if (!buffer.empty())
|
||||||
|
{
|
||||||
|
target->begin_batch();
|
||||||
|
|
||||||
|
for (auto it = buffer.begin(); it != buffer.end(); ++it)
|
||||||
|
target->add_text(it->first, it->second);
|
||||||
|
|
||||||
|
buffer.clear();
|
||||||
|
|
||||||
|
target->end_batch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
color_ostream_proxy::color_ostream_proxy(color_ostream &target)
|
||||||
|
: target(&target)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
color_ostream_proxy::~color_ostream_proxy()
|
||||||
|
{
|
||||||
|
*this << std::flush;
|
||||||
|
}
|
@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
https://github.com/peterix/dfhack
|
||||||
|
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must
|
||||||
|
not claim that you wrote the original software. If you use this
|
||||||
|
software in a product, an acknowledgment in the product documentation
|
||||||
|
would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "Pragma.h"
|
||||||
|
#include "Export.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <fstream>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace DFHack
|
||||||
|
{
|
||||||
|
class DFHACK_EXPORT color_ostream : public std::ostream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum color_value
|
||||||
|
{
|
||||||
|
COLOR_RESET = -1,
|
||||||
|
COLOR_BLACK = 0,
|
||||||
|
COLOR_BLUE,
|
||||||
|
COLOR_GREEN,
|
||||||
|
COLOR_CYAN,
|
||||||
|
COLOR_RED,
|
||||||
|
COLOR_MAGENTA,
|
||||||
|
COLOR_BROWN,
|
||||||
|
COLOR_GREY,
|
||||||
|
COLOR_DARKGREY,
|
||||||
|
COLOR_LIGHTBLUE,
|
||||||
|
COLOR_LIGHTGREEN,
|
||||||
|
COLOR_LIGHTCYAN,
|
||||||
|
COLOR_LIGHTRED,
|
||||||
|
COLOR_LIGHTMAGENTA,
|
||||||
|
COLOR_YELLOW,
|
||||||
|
COLOR_WHITE,
|
||||||
|
COLOR_MAX = COLOR_WHITE
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
color_value cur_color;
|
||||||
|
|
||||||
|
class buffer : public std::stringbuf
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
color_ostream *owner;
|
||||||
|
|
||||||
|
buffer(color_ostream *owner) : owner(owner) {}
|
||||||
|
virtual ~buffer() { }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int sync() {
|
||||||
|
owner->flush_buffer(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
buffer *buf() { return (buffer*)rdbuf(); }
|
||||||
|
|
||||||
|
void flush_buffer(bool flush);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// These must be strictly balanced, because
|
||||||
|
// they might grab and hold mutexes.
|
||||||
|
virtual void begin_batch();
|
||||||
|
virtual void end_batch();
|
||||||
|
|
||||||
|
virtual void add_text(color_value color, const std::string &text) = 0;
|
||||||
|
|
||||||
|
virtual void flush_proxy() {};
|
||||||
|
|
||||||
|
friend class color_ostream_proxy;
|
||||||
|
public:
|
||||||
|
color_ostream();
|
||||||
|
virtual ~color_ostream();
|
||||||
|
|
||||||
|
/// Print a formatted string, like printf
|
||||||
|
void print(const char *format, ...);
|
||||||
|
void vprint(const char *format, va_list args);
|
||||||
|
|
||||||
|
/// Print a formatted string, like printf, in red
|
||||||
|
void printerr(const char *format, ...);
|
||||||
|
void vprinterr(const char *format, va_list args);
|
||||||
|
|
||||||
|
/// Set color (ANSI color number)
|
||||||
|
void color(color_value c);
|
||||||
|
/// Reset color to default
|
||||||
|
void reset_color(void);
|
||||||
|
|
||||||
|
virtual bool is_console() { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class DFHACK_EXPORT buffered_color_ostream : public color_ostream
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
virtual void add_text(color_value color, const std::string &text);
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef std::pair<color_value,std::string> fragment_type;
|
||||||
|
|
||||||
|
buffered_color_ostream() {}
|
||||||
|
~buffered_color_ostream() {}
|
||||||
|
|
||||||
|
const std::list<fragment_type> &fragments() { return buffer; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::list<fragment_type> buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DFHACK_EXPORT color_ostream_proxy : public buffered_color_ostream
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
color_ostream *target;
|
||||||
|
|
||||||
|
virtual void flush_proxy();
|
||||||
|
|
||||||
|
public:
|
||||||
|
color_ostream_proxy(color_ostream &target);
|
||||||
|
~color_ostream_proxy();
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue