Use some colors in progress reports (where available)

pull/152/head
Nils Maier 2013-11-17 09:42:36 +01:00
parent 87ea4904a0
commit 80528aa9ce
4 changed files with 334 additions and 29 deletions

106
src/ColorizedStream.cc Normal file
View File

@ -0,0 +1,106 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2013 Nils Maier
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#include "ColorizedStream.h"
namespace aria2 {
namespace colors {
const Color black("30");
const Color red("31");
const Color green("32");
const Color yellow("33");
const Color blue("34");
const Color magenta("35");
const Color cyan("36");
const Color white("37");
const Color lightred("1;31");
const Color lightgreen("1;32");
const Color lightyellow("1;33");
const Color lightblue("1;34");
const Color lightmagenta("1;35");
const Color lightcyan("1;36");
const Color lightwhite("1;37");
const Color clear("0");
} // namespace colors
std::string ColorizedStreamBuf::str(bool color) const
{
std::stringstream rv;
for (const auto& e: elems) {
if (color || e.first != eColor) {
rv << e.second;
}
}
if (color) {
rv << colors::clear.str();
}
return rv.str();
}
std::string ColorizedStreamBuf::str(bool color, size_t max) const
{
std::stringstream rv;
for (const auto& e: elems) {
if (e.first == eColor) {
if (color) {
rv << e.second;
}
continue;
}
auto size = e.second.size();
if (size > max) {
auto cut = e.second;
cut.resize(max);
rv << cut;
break;
}
rv << e.second;
max -= size;
if (!max) {
break;
}
}
if (color) {
rv << colors::clear.str();
}
return rv.str();
}
} // namespace aria2

185
src/ColorizedStream.h Normal file
View File

@ -0,0 +1,185 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2013 Nils Maier
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#ifndef D_COLORIZED_STREAM_H
#define D_COLORIZED_STREAM_H
#include <string>
#include <sstream>
#include <deque>
namespace aria2 {
namespace colors {
class Color
{
private:
std::string str_;
public:
explicit Color(const char* str)
: str_(std::string("\033[") + str + "m")
{}
const std::string& str() const {
return str_;
}
};
extern const Color black;
extern const Color red;
extern const Color green;
extern const Color yellow;
extern const Color blue;
extern const Color magenta;
extern const Color cyan;
extern const Color white;
extern const Color lightred;
extern const Color lightgreen;
extern const Color lightyellow;
extern const Color lightblue;
extern const Color lightmagenta;
extern const Color lightcyan;
extern const Color lightwhite;
extern const Color clear;
} // namespace colors
typedef std::char_traits<char> traits_t;
class ColorizedStreamBuf
: public std::basic_streambuf<char, traits_t>
{
enum part_t
{
eColor,
eString
};
typedef std::pair<part_t, std::string> elem_t;
typedef std::deque<elem_t> elems_t;
elems_t elems;
public:
ColorizedStreamBuf()
{
elems.push_back(std::make_pair(eString, ""));
}
void setColor(const colors::Color& color)
{
elems.push_back(std::make_pair(eColor, color.str()));
elems.push_back(std::make_pair(eString, ""));
}
traits_t::int_type overflow(traits_t::int_type c)
{
elems.back().second.push_back((char)c);
return std::char_traits<char>::not_eof(c);
}
void append(const std::string& str)
{
elems.back().second += str;
}
void append(const char* str)
{
elems.back().second += str;
}
std::string str(bool color) const;
std::string str(bool color, size_t max) const;
};
class ColorizedStream: public std::basic_ostream<char, traits_t>
{
public:
ColorizedStream()
: std::basic_ios<char, traits_t>(&buf),
std::basic_ostream<char, traits_t>(&buf)
{
init(&buf);
}
void setColor(const colors::Color& color)
{
buf.setColor(color);
}
void append(const std::string& str) {
buf.append(str);
}
void append(const char* str) {
buf.append(str);
}
std::string str(bool colors) const
{
return buf.str(colors);
}
std::string str(bool colors, size_t max) const
{
return buf.str(colors, max);
}
private:
ColorizedStreamBuf buf;
};
inline
ColorizedStream& operator<<(ColorizedStream& stream, const std::string& str)
{
stream.append(str);
return stream;
}
inline
ColorizedStream& operator<<(ColorizedStream& stream, const char* str)
{
stream.append(str);
return stream;
}
inline
ColorizedStream& operator<<(ColorizedStream& stream, const colors::Color& c)
{
stream.setColor(c);
return stream;
}
} // namespace aria2
#endif // D_COLORIZED_STREAM_H

View File

@ -62,6 +62,8 @@
#include "wallclock.h"
#include "FileEntry.h"
#include "console.h"
#include "ColorizedStream.h"
#ifdef ENABLE_BITTORRENT
# include "bittorrent_helper.h"
# include "PeerStorage.h"
@ -96,7 +98,8 @@ protected:
} // namespace
namespace {
void printSizeProgress(std::ostream& o, const std::shared_ptr<RequestGroup>& rg,
void printSizeProgress(ColorizedStream& o,
const std::shared_ptr<RequestGroup>& rg,
const TransferStat& stat,
const SizeFormatter& sizeFormatter)
{
@ -128,14 +131,18 @@ void printSizeProgress(std::ostream& o, const std::shared_ptr<RequestGroup>& rg,
} // namespace
namespace {
void printProgressCompact(std::ostream& o, const DownloadEngine* e,
void printProgressCompact(ColorizedStream& o, const DownloadEngine* e,
const SizeFormatter& sizeFormatter)
{
if(!e->getRequestGroupMan()->downloadFinished()) {
if (!e->getRequestGroupMan()->downloadFinished()) {
NetStat& netstat = e->getRequestGroupMan()->getNetStat();
int dl = netstat.calculateDownloadSpeed();
int ul = netstat.calculateUploadSpeed();
o << "[DL:" << sizeFormatter(dl) << "B UL:" << sizeFormatter(ul) << "B]";
o << "[DL:" << colors::green << sizeFormatter(dl) << "B" << colors::clear;
if (ul) {
o << " UL:" << colors::cyan << sizeFormatter(ul) << "B" << colors::clear;
}
o << "]";
}
const RequestGroupList& groups =
@ -157,9 +164,8 @@ void printProgressCompact(std::ostream& o, const DownloadEngine* e,
} // namespace
namespace {
void printProgress
(std::ostream& o, const std::shared_ptr<RequestGroup>& rg, const DownloadEngine* e,
const SizeFormatter& sizeFormatter)
void printProgress(ColorizedStream& o, const std::shared_ptr<RequestGroup>& rg,
const DownloadEngine* e, const SizeFormatter& sizeFormatter)
{
TransferStat stat = rg->calculateStat();
int eta = 0;
@ -179,18 +185,18 @@ void printProgress
}
#endif // ENABLE_BITTORRENT
if(!rg->downloadFinished()) {
o << " DL:"
<< sizeFormatter(stat.downloadSpeed) << "B";
if (!rg->downloadFinished()) {
o << " DL:" <<
colors::green << sizeFormatter(stat.downloadSpeed) << "B" <<
colors::clear;
}
if(stat.sessionUploadLength > 0) {
o << " UL:"
<< sizeFormatter(stat.uploadSpeed) << "B"
<< "(" << sizeFormatter(stat.allTimeUploadLength) << "B)";
if (stat.sessionUploadLength > 0) {
o << " UL:" <<
colors::cyan << sizeFormatter(stat.uploadSpeed) << "B" << colors::clear;
o << "(" << sizeFormatter(stat.allTimeUploadLength) << "B)";
}
if(eta > 0) {
o << " ETA:"
<< util::secfmt(eta);
if (eta > 0) {
o << " ETA:" << colors::yellow << util::secfmt(eta) << colors::clear;
}
o << "]";
}
@ -212,7 +218,7 @@ public:
void operator()(const RequestGroupList::value_type& rg)
{
const char SEP_CHAR = '-';
std::stringstream o;
ColorizedStream o;
printProgress(o, rg, e_, sizeFormatter_);
const std::vector<std::shared_ptr<FileEntry> >& fileEntries =
rg->getDownloadContext()->getFileEntries();
@ -221,15 +227,16 @@ public:
o, rg->inMemoryDownload());
o << "\n"
<< std::setfill(SEP_CHAR) << std::setw(cols_) << SEP_CHAR << "\n";
global::cout()->write(o.str().c_str());
auto str = o.str(false);
global::cout()->write(str.c_str());
}
};
} // namespace
namespace {
void printProgressSummary
(const RequestGroupList& groups, size_t cols, const DownloadEngine* e,
const SizeFormatter& sizeFormatter)
void printProgressSummary(const RequestGroupList& groups, size_t cols,
const DownloadEngine* e,
const SizeFormatter& sizeFormatter)
{
const char SEP_CHAR = '=';
time_t now;
@ -304,7 +311,7 @@ ConsoleStatCalc::calculateStat(const DownloadEngine* e)
std::string line(cols, ' ');
global::cout()->printf("\r%s\r", line.c_str());
}
std::ostringstream o;
ColorizedStream o;
if(e->getRequestGroupMan()->countRequestGroup() > 0) {
if((summaryInterval_ > 0) &&
lastSummaryNotified_.differenceInMillis(global::wallclock())+
@ -320,6 +327,7 @@ ConsoleStatCalc::calculateStat(const DownloadEngine* e)
return;
}
size_t numGroup = e->getRequestGroupMan()->countRequestGroup();
const bool color = global::cout()->supportsColor() && isTTY_;
if(numGroup == 1) {
const std::shared_ptr<RequestGroup>& rg =
*e->getRequestGroupMan()->getRequestGroups().begin();
@ -367,15 +375,20 @@ ConsoleStatCalc::calculateStat(const DownloadEngine* e)
}
}
#endif // ENABLE_MESSAGE_DIGEST
std::string readout = o.str();
if(isTTY_) {
if(truncate_ && readout.size() > cols) {
readout[cols] = '\0';
if (truncate_) {
auto str = o.str(color, cols);
global::cout()->write(str.c_str());
}
else {
auto str = o.str(color);
global::cout()->write(str.c_str());
}
global::cout()->write(readout.c_str());
global::cout()->flush();
} else {
global::cout()->write(readout.c_str());
}
else {
auto str = o.str(false);
global::cout()->write(str.c_str());
global::cout()->write("\n");
}
}

View File

@ -226,6 +226,7 @@ SRCS = option_processing.cc\
OutputFile.h\
NullOutputFile.h\
console.cc console.h\
ColorizedStream.cc ColorizedStream.h\
IOFile.cc IOFile.h\
BufferedFile.cc BufferedFile.h\
SegList.h\