#include "hecl/MultiProgressPrinter.hpp" #define BOLD "\033[1m" #define NORMAL "\033[0m" #define PREV_LINE "\r\033[%dA" #define HIDE_CURSOR "\033[?25l" #define SHOW_CURSOR "\033[?25h" #if _WIN32 #define FOREGROUND_WHITE FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE #endif namespace hecl { void MultiProgressPrinter::ThreadStat::print(const TermInfo& tinfo) const { bool blocks = m_factor >= 0.f; float factor = std::max(0.f, std::min(1.f, m_factor)); int iFactor = factor * 100.f; int messageLen = m_message.size(); int submessageLen = m_submessage.size(); int half; if (blocks) half = (tinfo.width + 1) / 2 - 2; else if (tinfo.truncate) half = tinfo.width - 4; else half = messageLen; if (half - messageLen < submessageLen-2) submessageLen = 0; if (submessageLen) { if (messageLen > half-submessageLen-1) hecl::Printf(_S(" %.*s... %s "), half-submessageLen-4, m_message.c_str(), m_submessage.c_str()); else { hecl::Printf(_S(" %s"), m_message.c_str()); for (int i=half-messageLen-submessageLen-1 ; i>=0 ; --i) hecl::Printf(_S(" ")); hecl::Printf(_S("%s "), m_submessage.c_str()); } } else { if (messageLen > half) hecl::Printf(_S(" %.*s... "), half-3, m_message.c_str()); else { hecl::Printf(_S(" %s"), m_message.c_str()); for (int i=half-messageLen ; i>=0 ; --i) hecl::Printf(_S(" ")); } } if (blocks) { int rightHalf = tinfo.width - half - 4; int blocks = rightHalf - 7; int filled = blocks * factor; int rem = blocks - filled; if (tinfo.xtermColor) { hecl::Printf(_S("" BOLD "%3d%% ["), iFactor); for (int b=0 ; b= blocks) m_indeterminateCounter = -blocks + 2; int absCounter = std::abs(m_indeterminateCounter); int pre = absCounter; int rem = blocks - pre - 1; if (m_termInfo.xtermColor) { hecl::Printf(_S("" BOLD " [")); for (int b=0 ; b
= 0.f)
            {
                float factor = std::max(0.0f, std::min(1.0f, m_mainFactor));
                int iFactor = factor * 100.0;
                int half = m_termInfo.width - 2;

                int blocks = half - 8;
                int filled = blocks * factor;
                int rem = blocks - filled;

                if (m_termInfo.xtermColor)
                {
                    hecl::Printf(_S("" BOLD "  %3d%% ["), iFactor);
                    for (int b=0 ; b lk(m_logLock);
        DoPrint();
    }
}

MultiProgressPrinter::MultiProgressPrinter(bool activate)
{
    if (activate)
    {
        /* Xterm check */
#if _WIN32
        m_newLineAfter = true;
        m_termInfo.console = GetStdHandle(STD_OUTPUT_HANDLE);
        const char* conemuANSI = getenv("ConEmuANSI");
        if (conemuANSI && !strcmp(conemuANSI, "ON"))
            m_termInfo.xtermColor = true;
#else
        m_newLineAfter = false;
        const char* term = getenv("TERM");
        if (term && !strncmp(term, "xterm", 5))
        {
            m_termInfo.xtermColor = true;
            m_newLineAfter = true;
        }
#endif

        m_running = true;
        m_logThread = std::thread(std::bind(&MultiProgressPrinter::LogProc, this));
    }
}

MultiProgressPrinter::~MultiProgressPrinter()
{
    m_running = false;
    if (m_logThread.joinable())
        m_logThread.join();
}

void MultiProgressPrinter::print(const hecl::SystemChar* message,
                                 const hecl::SystemChar* submessage,
                                 float factor, int threadIdx) const
{
    if (!m_running)
        return;
    std::lock_guard lk(m_logLock);
    if (threadIdx < 0)
        threadIdx = 0;
    if (threadIdx >= m_threadStats.size())
        m_threadStats.resize(threadIdx + 1);
    ThreadStat& stat = m_threadStats[threadIdx];
    if (message)
        stat.m_message = message;
    else
        stat.m_message.clear();
    if (submessage)
        stat.m_submessage = submessage;
    else
        stat.m_submessage.clear();
    stat.m_factor = factor;
    stat.m_active = true;
    m_latestThread = threadIdx;
    m_dirty = true;
}

void MultiProgressPrinter::setMainFactor(float factor) const
{
    if (!m_running)
        return;
    std::lock_guard lk(m_logLock);
    if (!m_mainIndeterminate)
        m_dirty = true;
    m_mainFactor = factor;
}

void MultiProgressPrinter::setMainIndeterminate(bool indeterminate) const
{
    if (!m_running)
        return;
    std::lock_guard lk(m_logLock);
    if (m_mainIndeterminate != indeterminate)
    {
        m_mainIndeterminate = indeterminate;
        m_dirty = true;
    }
}

void MultiProgressPrinter::startNewLine() const
{
    if (!m_running)
        return;
    std::lock_guard lk(m_logLock);
    const_cast(*this).DoPrint();
    m_threadStats.clear();
    m_latestThread = -1;
    m_curThreadLines = 0;
    m_mainFactor = -1.f;
    auto logLk = logvisor::LockLog();
    hecl::Printf(_S("\n"));
}

void MultiProgressPrinter::flush() const
{
    std::lock_guard lk(m_logLock);
    const_cast(*this).DoPrint();
}

}