Browse Source

Use some colors in progress reports (where available)

Nils Maier 12 years ago
parent
commit
80528aa9ce
4 changed files with 334 additions and 29 deletions
  1. 106 0
      src/ColorizedStream.cc
  2. 185 0
      src/ColorizedStream.h
  3. 42 29
      src/ConsoleStatCalc.cc
  4. 1 0
      src/Makefile.am

+ 106 - 0
src/ColorizedStream.cc

@@ -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 - 0
src/ColorizedStream.h

@@ -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

+ 42 - 29
src/ConsoleStatCalc.cc

@@ -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");
   }
 }

+ 1 - 0
src/Makefile.am

@@ -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\