monotone-commits-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Monotone-commits-diffs] net.venge.monotone.colored-diff: 90a61d2166a6c


From: code
Subject: [Monotone-commits-diffs] net.venge.monotone.colored-diff: 90a61d2166a6c30e950a0d02f590b83ca9b6b39d
Date: Sun, 10 Apr 2011 11:22:44 +0200 (CEST)

revision:            90a61d2166a6c30e950a0d02f590b83ca9b6b39d
date:                2011-04-09T23:38:14
author:              Richard Hopkins <address@hidden>
branch:              net.venge.monotone.colored-diff
changelog:
propagate from branch 'net.venge.monotone' (head 
239d3d013399793455ccc3f42246163591e35631)
            to branch 'net.venge.monotone.colored-diff' (head 
bf94eb3b34add43865cfe4dc8c5c59934efa48da)

manifest:
format_version "1"

new_manifest [c015cbb5dbe8d45415528b6e146a5b474d6a1953]

old_revision [239d3d013399793455ccc3f42246163591e35631]

add_file "src/colorizer.cc"
 content [96964884a83e4d7d638c146821a554d033f396eb]

add_file "src/colorizer.hh"
 content [eb3d0e3dad8d447e270e0c6264bf1a4ea139013f]

patch "Makefile.am"
 from [d8bebdb36192f09f35b5737b9975fce92b11eeb9]
   to [45e7b8adf59d3c5227c340937bd27a20267e3aeb]

patch "NEWS"
 from [710b0adc68789d90faf583d85b094f93295ac19e]
   to [fbd21978307072241795228e418ee6dc2dd19db7]

patch "doc/monotone.texi"
 from [0e40017dfe8ba652e6af4585a2ac176c8bd12dcc]
   to [73c733d069b4ff2fbd203a396c7cadd7aed8f78b]

patch "src/asciik.cc"
 from [cf946f9a14ad309615704bc960255c50e12b636a]
   to [64600c9969226fa55cd05982364147342d3b734e]

patch "src/asciik.hh"
 from [592aa966af256f50be9784bfd01c543f54d3447b]
   to [3e0dcd90804053a5e558b0ddfa6e5f3dcc462d50]

patch "src/cmd_diff_log.cc"
 from [b24dffb0470d057fa1e91ccc5a81627b40252e78]
   to [66d959146c432421ca24988535a9b250aa860a36]

patch "src/cmd_files.cc"
 from [f15378efd25e597762776ad6e9c6f78c1a4ff191]
   to [3bb32dddf14bd79e630069837220aeb2e67d9346]

patch "src/cmd_ws_commit.cc"
 from [d9dbacb820c6d070c4952ee2b0f143e61e85631e]
   to [b22c4c8871fe38e55da487318326755c699d4873]

patch "src/diff_output.cc"
 from [8df7c0bec2e64275f6c8e8b6ccb035c8fd0f684f]
   to [db19431f96f35ca8c6b89c129c2a805ddd418f15]

patch "src/diff_output.hh"
 from [9125ccd0d0fa725782c9910b5f34e844048d2da8]
   to [168281addd27cdade1dc1320ee4814b28070feb8]

patch "src/lua_hooks.cc"
 from [1c178085332c73dcefb4681d205d17b059e52080]
   to [81dd3985d253ac62743df0341e60a74d5b93b755]

patch "src/lua_hooks.hh"
 from [66412b9fa5db97cd3b3ec01cadf036fb346ac161]
   to [51a2842d22554cba640dcea416103f5e70c63c3b]

patch "src/options_list.hh"
 from [0462e302b89179f4acb28ecb91f4255140d4a4a7]
   to [9bb72269e07a2b32e6c5db912731564cf9bbe62e]

patch "src/rev_output.cc"
 from [a2c70b893b31296917d1a2b974faa1da46c13f1e]
   to [fec6728d80bca2d8d13ab49bb4ecd03310879fe5]

patch "src/rev_output.hh"
 from [666dd3ed35e16d8b122b4932c2aad05a21a22e25]
   to [5879a8268a59545c946583b65f66eda4491b979e]

patch "src/std_hooks.lua"
 from [ada658bd275399032411e0f520d9900bad966dc4]
   to [c8cd84c99c2b34b1ed32a0c5b58c9ab415f1be48]

old_revision [bf94eb3b34add43865cfe4dc8c5c59934efa48da]

patch "test/func/db_opt_fallback_mechanisms/__driver__.lua"
 from [09354a970b921effa2850aa4ad722ce95a433ea8]
   to [0b0da944f19f7a0be42165069fdc1bb8862fd6ee]

patch "test/func/serve-automate/__driver__.lua"
 from [d41f819fd49060c45bb154dde614699b0cb938e7]
   to [ae4b03baf16d8401f31a32c8377021f879788d01]
============================================================
--- Makefile.am	d8bebdb36192f09f35b5737b9975fce92b11eeb9
+++ Makefile.am	45e7b8adf59d3c5227c340937bd27a20267e3aeb
@@ -47,6 +47,7 @@ MOST_SOURCES = 								\
 	src/automate_reader.cc src/automate_stdio_helpers.hh		\
 	src/botan_pipe_cache.hh	src/cache_logger.hh src/cache_logger.cc	\
 	src/commands.cc src/commands.hh $(CMD_SOURCES)			\
+	src/colorizer.cc src/colorizer.hh				\
 	src/diff_output.cc src/diff_output.hh				\
 	src/lua_hooks.cc src/lua_hooks.hh 				\
 	src/transforms.cc src/transforms.hh				\
============================================================
--- NEWS	710b0adc68789d90faf583d85b094f93295ac19e
+++ NEWS	fbd21978307072241795228e418ee6dc2dd19db7
@@ -400,6 +400,11 @@ Thu Oct 28 21:07:18 UTC 2010
         - New 'k:' selector type to query revisions where at least one
           certificate was signed with the given key.
 
+        - Monotone has a new global '--colorize' option which colors the
+          output of commands like 'diff', 'fdiff' or 'log' for better
+          readability in terminals that support output coloring and
+          formatting.
+
         - New automate command 'log' which behaves identical to the
           normal 'log' command, except that it only outputs the
           revision ids.
============================================================
--- src/diff_output.cc	8df7c0bec2e64275f6c8e8b6ccb035c8fd0f684f
+++ src/diff_output.cc	db19431f96f35ca8c6b89c129c2a805ddd418f15
@@ -17,6 +17,7 @@
 #include "simplestring_xform.hh"
 
 #include <ostream>
+#include <sstream>
 #include <iterator>
 #include <boost/scoped_ptr.hpp>
 
@@ -25,6 +26,7 @@ using std::string;
 using std::ostream;
 using std::ostream_iterator;
 using std::string;
+using std::stringstream;
 using std::vector;
 using boost::scoped_ptr;
 
@@ -45,6 +47,8 @@ struct hunk_consumer
   vector<string>::const_reverse_iterator encloser_last_match;
   vector<string>::const_reverse_iterator encloser_last_search;
 
+  colorizer color;
+
   virtual void flush_hunk(size_t pos) = 0;
   virtual void advance_to(size_t newpos) = 0;
   virtual void insert_at(size_t b_pos) = 0;
@@ -55,10 +59,12 @@ struct hunk_consumer
                 vector<string> const & b,
                 size_t ctx,
                 ostream & ost,
-                string const & encloser_pattern)
+                string const & encloser_pattern,
+                colorizer const & color)
     : a(a), b(b), ctx(ctx), ost(ost), encloser_re(0),
       a_begin(0), b_begin(0), a_len(0), b_len(0), skew(0),
-      encloser_last_match(a.rend()), encloser_last_search(a.rend())
+      encloser_last_match(a.rend()), encloser_last_search(a.rend()),
+      color(color)
   {
     if (encloser_pattern != "")
       encloser_re.reset(new pcre::regex(encloser_pattern, origin::user));
@@ -170,21 +176,24 @@ struct unidiff_hunk_writer : public hunk
                       vector<string> const & b,
                       size_t ctx,
                       ostream & ost,
-                      string const & encloser_pattern)
-  : hunk_consumer(a, b, ctx, ost, encloser_pattern)
+                      string const & encloser_pattern,
+                      colorizer const & color)
+  : hunk_consumer(a, b, ctx, ost, encloser_pattern, color)
   {}
 };
 
 void unidiff_hunk_writer::insert_at(size_t b_pos)
 {
   b_len++;
-  hunk.push_back(string("+") + b[b_pos]);
+  hunk.push_back(color.colorize(string("+") + b[b_pos],
+                                    colorizer::add));
 }
 
 void unidiff_hunk_writer::delete_at(size_t a_pos)
 {
   a_len++;
-  hunk.push_back(string("-") + a[a_pos]);
+  hunk.push_back(color.colorize(string("-") + a[a_pos],
+                                    colorizer::remove));
 }
 
 void unidiff_hunk_writer::flush_hunk(size_t pos)
@@ -201,22 +210,23 @@ void unidiff_hunk_writer::flush_hunk(siz
         }
 
       // write hunk to stream
+      stringstream ss;
       if (a_len == 0)
-        ost << "@@ -0,0";
+        ss << "@@ -0,0";
       else
         {
-          ost << "@@ -" << a_begin+1;
+          ss << "@@ -" << a_begin+1;
           if (a_len > 1)
-            ost << ',' << a_len;
+            ss << ',' << a_len;
         }
-
+ 
       if (b_len == 0)
-        ost << " +0,0";
+        ss << " +0,0";
       else
         {
-          ost << " +" << b_begin+1;
+          ss << " +" << b_begin+1;
           if (b_len > 1)
-            ost << ',' << b_len;
+            ss << ',' << b_len;
         }
 
       {
@@ -231,7 +241,11 @@ void unidiff_hunk_writer::flush_hunk(siz
             }
 
         find_encloser(a_begin + first_mod, encloser);
-        ost << " @@" << encloser << '\n';
+        ss << " @@";
+
+        ost << color.colorize(ss.str(), colorizer::separator);
+        ost << color.colorize(encloser, colorizer::encloser);
+        ost << '\n';
       }
       copy(hunk.begin(), hunk.end(), ostream_iterator<string>(ost, "\n"));
     }
@@ -297,8 +311,9 @@ struct cxtdiff_hunk_writer : public hunk
                       vector<string> const & b,
                       size_t ctx,
                       ostream & ost,
-                      string const & encloser_pattern)
-  : hunk_consumer(a, b, ctx, ost, encloser_pattern),
+                      string const & encloser_pattern,
+                      colorizer const & colorizer)
+  : hunk_consumer(a, b, ctx, ost, encloser_pattern, colorizer),
     have_insertions(false), have_deletions(false)
   {}
 };
@@ -360,7 +375,8 @@ void cxtdiff_hunk_writer::flush_hunk(siz
         find_encloser(a_begin + min(first_insert, first_delete),
                       encloser);
 
-        ost << "***************" << encloser << '\n';
+        ost << color.colorize("***************", colorizer::separator)
+            << color.colorize(encloser, colorizer::encloser) << '\n';
       }
 
       ost << "*** " << (a_begin + 1) << ',' << (a_begin + a_len) << " ****\n";
@@ -394,23 +410,33 @@ void cxtdiff_hunk_writer::flush_pending_
 
   // if we have just insertions to flush, prefix them with "+"; if
   // just deletions, prefix with "-"; if both, prefix with "!"
+  colorizer::purpose p = colorizer::normal;
   if (inserts.empty() && !deletes.empty())
+  {
     prefix = "-";
+    p = colorizer::remove;
+  }
   else if (deletes.empty() && !inserts.empty())
+  {
     prefix = "+";
+    p = colorizer::add;
+  }
   else
+  {
     prefix = "!";
+    p = colorizer::change;
+  }
 
   for (vector<size_t>::const_iterator i = deletes.begin();
        i != deletes.end(); ++i)
     {
-      from_file.push_back(prefix + string(" ") + a[*i]);
+      from_file.push_back(color.colorize(prefix + string(" ") + a[*i], p));
       a_len++;
     }
   for (vector<size_t>::const_iterator i = inserts.begin();
        i != inserts.end(); ++i)
     {
-      to_file.push_back(prefix + string(" ") + b[*i]);
+      to_file.push_back(color.colorize(prefix + string(" ") + b[*i], p));
       b_len++;
     }
 
@@ -471,16 +497,19 @@ make_diff(string const & filename1,
           data const & data2,
           ostream & ost,
           diff_type type,
-          string const & pattern)
+          string const & pattern,
+          colorizer const & color)
 {
   if (guess_binary(data1()) || guess_binary(data2()))
     {
       // If a file has been removed, filename2 will be "/dev/null".
       // It doesn't make sense to output that.
       if (filename2 == "/dev/null")
-        ost << "# " << filename1 << " is binary\n";
+        ost << color.colorize(string("# ") + filename1 + " is binary",
+                              colorizer::comment) << "\n";
       else
-        ost << "# " << filename2 << " is binary\n";
+        ost << color.colorize(string("# ") + filename2 + " is binary",
+                              colorizer::comment) << "\n";
       return;
     }
 
@@ -569,23 +598,27 @@ make_diff(string const & filename1,
     {
       case unified_diff:
       {
-        ost << "--- " << filename1 << '\t'
-            << id1 << '\n';
-        ost << "+++ " << filename2 << '\t'
-            << id2 << '\n';
+        ost << color.colorize(string("--- ") + filename1,
+                              colorizer::remove)
+            << '\t' << id1 << '\n';
+        ost << color.colorize(string("+++ ") + filename2,
+                              colorizer::add)
+            << '\t' << id2 << '\n';
 
-        unidiff_hunk_writer hunks(lines1, lines2, 3, ost, pattern);
+        unidiff_hunk_writer hunks(lines1, lines2, 3, ost, pattern, color);
         walk_hunk_consumer(lcs, left_interned, right_interned, hunks);
         break;
       }
       case context_diff:
       {
-        ost << "*** " << filename1 << '\t'
-            << id1 << '\n';
-        ost << "--- " << filename2 << '\t'
-            << id2 << '\n';
+        ost << color.colorize(string("*** ") + filename1,
+                              colorizer::remove)
+            << '\t' << id1 << '\n';
+        ost << color.colorize(string("--- ") + filename2,
+                              colorizer::add)
+            << '\t' << id2 << '\n';
 
-        cxtdiff_hunk_writer hunks(lines1, lines2, 3, ost, pattern);
+        cxtdiff_hunk_writer hunks(lines1, lines2, 3, ost, pattern, color);
         walk_hunk_consumer(lcs, left_interned, right_interned, hunks);
         break;
       }
============================================================
--- src/diff_output.hh	9125ccd0d0fa725782c9910b5f34e844048d2da8
+++ src/diff_output.hh	168281addd27cdade1dc1320ee4814b28070feb8
@@ -15,6 +15,7 @@
 // of GNU-diffutils-like things (diff, diff3, maybe patch..)
 
 #include "vocab.hh"
+#include "colorizer.hh"
 
 void make_diff(std::string const & filename1,
                std::string const & filename2,
@@ -24,7 +25,8 @@ void make_diff(std::string const & filen
                data const & data2,
                std::ostream & ost,
                diff_type type,
-               std::string const & pattern);
+               std::string const & pattern,
+               colorizer const & colorizer);
 
 #endif // __DIFF_PATCH_HH__
 
============================================================
--- src/lua_hooks.cc	1c178085332c73dcefb4681d205d17b059e52080
+++ src/lua_hooks.cc	81dd3985d253ac62743df0341e60a74d5b93b755
@@ -770,6 +770,21 @@ bool
 }
 
 bool
+lua_hooks::hook_get_output_color(string const purpose, string & fg,
+                                 string & bg, string & style)
+{
+  Lua ll = Lua(st);
+
+  return ll.func("get_output_color")
+    .push_str(purpose)
+    .call(1, 3)
+    .extract_str(style).pop()
+    .extract_str(bg).pop()
+    .extract_str(fg)
+    .ok();
+}
+
+bool
 lua_hooks::hook_use_inodeprints()
 {
   bool use = false, exec_ok = false;
============================================================
--- src/lua_hooks.hh	66412b9fa5db97cd3b3ec01cadf036fb346ac161
+++ src/lua_hooks.hh	51a2842d22554cba640dcea416103f5e70c63c3b
@@ -173,6 +173,9 @@ public:
 
   bool hook_get_man_page_formatter_command(string & command);
 
+  bool hook_get_output_color(string const purpose, string & fg,
+                             string & bg, string & style);
+
   // notification hooks
   bool hook_note_commit(revision_id const & new_id,
                         revision_data const & rdat,
============================================================
--- doc/monotone.texi	0e40017dfe8ba652e6af4585a2ac176c8bd12dcc
+++ doc/monotone.texi	73c733d069b4ff2fbd203a396c7cadd7aed8f78b
@@ -5878,7 +5878,7 @@ @section Informative
 @code{fa36}. This command is intended to be used by programmable
 completion systems, such as those in @command{bash} and @command{zsh}.
 
address@hidden address@hidden mtn diff [--unified] [--[no-]show-encloser]
address@hidden address@hidden mtn diff [--unified] [--[no-]show-encloser] [--[no-]colorize]
 @itemx mtn diff --context [--[no-]show-encloser]
 @itemx mtn diff --external address@hidden
 @itemx mtn diff @var{pathname...}
@@ -5920,7 +5920,7 @@ @section Informative
 changed within the current subdirectory of the workspace.
 
 The output format of @command{diff} is controlled by the options
address@hidden, @option{--context}, @option{--no-show-encloser}, and
address@hidden, @option{--context}, @option{--no-show-encloser}, @option{--colorize}, and
 @option{--external}.  By default, monotone uses its built-in diff
 algorithm to produce a listing in ``unified diff'' format (analogous
 to running the program @command{diff @option{-u}}); you can also explicitly
@@ -5942,6 +5942,10 @@ @section Informative
 @ref{get_encloser_pattern}.  For the regular _expression_ syntax, see
 @ref{Regexps}.
 
+Furthermore, when @option{--colorize} is given, monotone tries to print 
+colored diff output if the underlying terminal supports it.  This works
+in both modes as well.
+
 Sometimes, you may want more flexibility in output formats; for these
 cases, you can use @option{--external}, which causes monotone to
 invoke an external program to generate the actual output.  By default,
@@ -6169,7 +6173,7 @@ @section Informative
 within this list.  See @ref{Managed Databases} for more information.
 
 @anchor{mtn address@hidden mtn log
address@hidden mtn log address@hidden address@hidden address@hidden [...]] [--clear-from] address@hidden [...]] [--clear-to] address@hidden [...]] [--[no-]brief] [--[no-]merges] [--[no-]files] [--[no-]graph] [--[no-]diffs] address@hidden
address@hidden mtn log address@hidden address@hidden address@hidden [...]] [--clear-from] address@hidden [...]] [--clear-to] address@hidden [...]] [--[no-]brief] [--[no-]merges] [--[no-]files] [--[no-]graph] [--[no-]diffs] [--[no-]colorize] address@hidden
 See the online help for more options.
 
 This command prints out a log, in forward ancestry order by default
@@ -6240,8 +6244,11 @@ @section Informative
 prefix on log output lines.
 
 Specifying @option{--diffs} causes the log output to include a unified
-diff of the changes in each revision.
+diff of the changes in each revision. If @option{--colorize} is given
+additionally, the diff output is colored if the underlying terminal
+supports that.
 
+
 If one or more files are given, the command will only log the revisions
 where those files are changed.
 
============================================================
--- src/std_hooks.lua	ada658bd275399032411e0f520d9900bad966dc4
+++ src/std_hooks.lua	c8cd84c99c2b34b1ed32a0c5b58c9ab415f1be48
@@ -1540,3 +1540,41 @@ end
    end
 end
 
+function get_output_color(purpose)
+	-- Returns a triple containing the fore color, background color and
+	-- style to use for formatting the output.
+	-- The fore color and background color can be any of the following
+	-- red, green, blue, yellow, cyan, magenta, black, white
+	-- Alternatively, they can be the empty string and Monotone will
+	-- decide.
+	-- Valid values for style are
+	-- none, bold, italic, underline
+	-- Alternatively, it can be the empty string and Monotone will
+	-- decide.
+
+	local default_color = { fg = "", bg = "", style = "" }
+	local color_table = 
+	{
+		normal = default_color,
+		
+                add = { fg = "green", bg = "", style = "" },
+                change = { fg = "blue", bg = "", style = "" },
+                comment = { fg = "yellow", bg = "", style = "" },
+                encloser = { fg = "magenta", bg = "", style = "" },
+                log_revision = { fg = "", bg = "", style = "bold" },
+                remove = { fg = "red", bg = "", style = "" },
+                rename = { fg = "yellow", bg = "", style = "" },
+                rev_header = { fg = "", bg = "", style = "bold" },
+                separator = { fg = "", bg = "", style = "bold" },
+                set = { fg = "cyan", bg = "", style = "" },
+                unset = { fg = "magenta", bg = "", style = "" }
+	}
+
+	local chosen_color = color_table[purpose]
+	
+	if chosen_color == nil then
+		return default_color
+	else
+		return chosen_color.fg, chosen_color.bg, chosen_color.style
+	end
+end
============================================================
--- src/cmd_diff_log.cc	b24dffb0470d057fa1e91ccc5a81627b40252e78
+++ src/cmd_diff_log.cc	66d959146c432421ca24988535a9b250aa860a36
@@ -17,6 +17,7 @@
 #include "asciik.hh"
 #include "charset.hh"
 #include "cmd.hh"
+#include "colorizer.hh"
 #include "date_format.hh"
 #include "diff_output.hh"
 #include "file_io.hh"
@@ -70,6 +71,7 @@ dump_diff(lua_hooks & lua,
           bool external_diff_args_given,
           string external_diff_args,
           string const & encloser,
+          colorizer const & colorizer,
           ostream & output)
 {
   if (diff_format == external_diff)
@@ -111,7 +113,8 @@ dump_diff(lua_hooks & lua,
       make_diff(left, right,
                 left_id, right_id,
                 left_data, right_data,
-                output, diff_format, encloser);
+                output, diff_format,
+                encloser, colorizer);
     }
 
 }
@@ -134,7 +137,8 @@ dump_diffs(lua_hooks & lua,
            string external_diff_args,
            bool left_from_db,
            bool right_from_db,
-           bool show_encloser)
+           bool show_encloser,
+           colorizer const & colorizer)
 {
   // Put all node data in a multimap with the file path of the node as key
   // which gets automatically sorted. For removed nodes the file path is
@@ -220,7 +224,7 @@ dump_diffs(lua_hooks & lua,
                 dat.left_id, dat.right_id,
                 left_data, right_data,
                 diff_format, external_diff_args_given, external_diff_args,
-                encloser, output);
+                encloser, colorizer, output);
     }
 }
 
@@ -382,6 +386,7 @@ void dump_header(std::string const & rev
                  roster_t const & old_roster,
                  roster_t const & new_roster,
                  std::ostream & out,
+                 colorizer const & colorizer,
                  bool show_if_empty)
 {
   cset changes;
@@ -394,19 +399,23 @@ void dump_header(std::string const & rev
 
   vector<string> lines;
   split_into_lines(summary(), lines);
-  out << "#\n";
+  out << colorizer.colorize("#", colorizer::comment) << "\n";
   if (!summary().empty())
     {
-      out << revs << "#\n";
+      out << colorizer.colorize(revs, colorizer::comment);
+      out << colorizer.colorize("#", colorizer::comment) << "\n";
+
       for (vector<string>::iterator i = lines.begin();
            i != lines.end(); ++i)
-        out << "# " << *i << '\n';
+        out << colorizer.colorize(string("# ") + *i,
+                                  colorizer::comment) << "\n";
     }
   else
     {
-      out << "# " << _("no changes") << '\n';
+      out << colorizer.colorize(string("# ") + _("no changes"),
+                                colorizer::comment) << "\n";
     }
-  out << "#\n";
+  out << colorizer.colorize("#", colorizer::comment) << "\n";
 }
 
 CMD_PRESET_OPTIONS(diff)
@@ -436,9 +445,11 @@ CMD(diff, "diff", "di", CMD_REF(informat
 
   prepare_diff(app, db, old_roster, new_roster, args, old_from_db, new_from_db, revs);
 
+  colorizer colorizer(app.opts.colorize, app.lua);
+
   if (app.opts.with_header)
     {
-      dump_header(revs, old_roster, new_roster, cout, true);
+      dump_header(revs, old_roster, new_roster, cout, colorizer, true);
     }
 
   dump_diffs(app.lua, db, old_roster, new_roster, cout,
@@ -446,7 +457,8 @@ CMD(diff, "diff", "di", CMD_REF(informat
              app.opts.external_diff_args_given,
              app.opts.external_diff_args,
              old_from_db, new_from_db,
-             !app.opts.no_show_encloser);
+             !app.opts.no_show_encloser,
+             colorizer);
 }
 
 
@@ -475,16 +487,20 @@ CMD_AUTOMATE(content_diff, N_("[FILE [..
   prepare_diff(app, db, old_roster, new_roster, args, old_from_db, new_from_db,
                dummy_header);
 
+  // never colorize the diff output
+  colorizer colorizer(false, app.lua);
 
   if (app.opts.with_header)
     {
-      dump_header(dummy_header, old_roster, new_roster, output, false);
+      dump_header(dummy_header, old_roster, new_roster, output, colorizer, false);
     }
 
   dump_diffs(app.lua, db, old_roster, new_roster, output,
              app.opts.diff_format,
              app.opts.external_diff_args_given, app.opts.external_diff_args,
-             old_from_db, new_from_db, !app.opts.no_show_encloser);
+             old_from_db, new_from_db,
+             !app.opts.no_show_encloser,
+             colorizer);
 }
 
 
@@ -549,6 +565,7 @@ log_print_rev (app_state &      app,
                revision_t &     rev,
                string           date_fmt,
                node_restriction mask,
+               colorizer const & color,
                ostream &        out)
 {
   cert_name const author_name(author_cert_name);
@@ -562,7 +579,8 @@ log_print_rev (app_state &      app,
 
   if (app.opts.brief)
     {
-      out << rid;
+      out << color.colorize(encode_hexenc(rid.inner()(), rid.inner().made_from),
+                            colorizer::log_revision);
       log_certs(certs, out, author_name);
       if (app.opts.no_graph)
         log_certs(certs, out, date_name, date_fmt);
@@ -577,7 +595,7 @@ log_print_rev (app_state &      app,
   else
     {
       utf8 header;
-      revision_header(rid, rev, certs, date_fmt, header);
+      revision_header(rid, rev, certs, date_fmt, color, header);
 
       external header_external;
       utf8_to_system_best_effort(header, header_external);
@@ -586,7 +604,7 @@ log_print_rev (app_state &      app,
       if (!app.opts.no_files)
         {
           utf8 summary;
-          revision_summary(rev, summary);
+          revision_summary(rev, color, summary);
           external summary_external;
           utf8_to_system_best_effort(summary, summary_external);
           out << summary_external;
@@ -618,7 +636,8 @@ log_print_rev (app_state &      app,
                      app.opts.external_diff_args_given,
                      app.opts.external_diff_args,
                      true, true,
-                     !app.opts.no_show_encloser);
+                     !app.opts.no_show_encloser,
+                     color);
         }
     }
 }
@@ -841,8 +860,11 @@ log_common (app_state & app,
 
   set<revision_id> seen;
   revision_t rev;
+
+  colorizer color(app.opts.colorize && !automate, app.lua);
   // this is instantiated even when not used, but it's lightweight
-  asciik graph(output);
+  asciik graph(output, color);
+
   while(!frontier.empty() && last != 0 && next != 0)
     {
       revision_id const & rid = frontier.top().second;
@@ -938,7 +960,7 @@ log_common (app_state & app,
           else
             {
               ostringstream out;
-              log_print_rev (app, db, project, rid, rev, date_fmt, mask_diff, out);
+              log_print_rev(app, db, project, rid, rev, date_fmt, mask_diff, color, out);
 
               string out_system;
               utf8_to_system_best_effort(utf8(out.str(), origin::internal), out_system);
@@ -986,7 +1008,7 @@ CMD(log, "log", "", CMD_REF(informative)
     options::opts::brief | options::opts::diffs |
     options::opts::depth | options::opts::exclude |
     options::opts::no_merges | options::opts::no_files |
-    options::opts::no_graph)
+    options::opts::no_graph )
 {
   log_common (app, args, false, cout);
 }
============================================================
--- src/cmd_files.cc	f15378efd25e597762776ad6e9c6f78c1a4ff191
+++ src/cmd_files.cc	3bb32dddf14bd79e630069837220aeb2e67d9346
@@ -14,6 +14,7 @@
 #include "annotate.hh"
 #include "revision.hh"
 #include "cmd.hh"
+#include "colorizer.hh"
 #include "diff_output.hh"
 #include "merge_content.hh"
 #include "file_io.hh"
@@ -132,7 +133,8 @@ CMD(fdiff, "fdiff", "", CMD_REF(debug), 
   make_diff(src_name, dst_name,
             src_id, dst_id,
             src.inner(), dst.inner(),
-            cout, app.opts.diff_format, pattern);
+            cout, app.opts.diff_format, 
+            pattern, colorizer(app.opts.colorize, app.lua));
 }
 
 CMD(annotate, "annotate", "", CMD_REF(informative), N_("PATH"),
============================================================
--- src/cmd_ws_commit.cc	d9dbacb820c6d070c4952ee2b0f143e61e85631e
+++ src/cmd_ws_commit.cc	b22c4c8871fe38e55da487318326755c699d4873
@@ -259,7 +259,8 @@ get_log_message_interactively(lua_hooks 
   }
 
   utf8 summary;
-  revision_summary(rev, summary);
+  colorizer color(false, lua);
+  revision_summary(rev, color, summary);
 
   utf8 full_message(changelog() + cancel() + instructions() + editable() + ignored() +
                     notes() + summary(),
@@ -965,10 +966,11 @@ CMD(status, "status", "", CMD_REF(inform
 
   utf8 header;
   utf8 summary;
+  colorizer color(app.opts.colorize, app.lua);
 
   revision_header(rid, rev, author, date_t::now(), app.opts.branch, changelog,
-                  date_fmt, header);
-  revision_summary(rev, summary);
+                  date_fmt, color, header);
+  revision_summary(rev, color, summary);
 
   external header_external;
   external summary_external;
============================================================
--- src/options_list.hh	0462e302b89179f4acb28ecb91f4255140d4a4a7
+++ src/options_list.hh	9bb72269e07a2b32e6c5db912731564cf9bbe62e
@@ -285,7 +285,8 @@ GROUPED_SIMPLE_OPTION(date_formats, no_f
                       "no-format-dates", bool,
                       gettext_noop("print date certs exactly as stored in the database"))
 
-
+GROUPED_SIMPLE_OPTION(globals, colorize, "colorize/no-colorize", bool,
+                      gettext_noop("colorize output"))                     
 OPTVAR(globals, db_type, dbname_type, )
 OPTVAR(globals, std::string, dbname_alias, )
 OPTVAR(globals, system_path, dbname, )
============================================================
--- src/asciik.cc	cf946f9a14ad309615704bc960255c50e12b636a
+++ src/asciik.cc	64600c9969226fa55cd05982364147342d3b734e
@@ -135,8 +135,8 @@ static revision_id ghost; // valid but e
 
 static revision_id ghost; // valid but empty revision_id to be used as ghost value
 
-asciik::asciik(ostream & os, size_t min_width)
-  : width(min_width), output(os)
+asciik::asciik(ostream & os, colorizer const & color, size_t min_width)
+  : width(min_width), output(os), color(color)
 {
 }
 
@@ -250,10 +250,13 @@ asciik::draw(size_t const curr_items,
 
   // prints it out
   //TODO convert line/interline/interline2 from ASCII to system charset
-  output << line << "  " << lines[0] << '\n';
-  output << interline << "  " << lines[1] << '\n';
+  output << color.colorize(line, colorizer::log_revision)
+         << "  " << lines[0] << '\n';
+  output << color.colorize(interline, colorizer::log_revision)
+         << "  " << lines[1] << '\n';
   for (int i = 2; i < num_lines; ++i)
-    output << interline2 << "  " << lines[i] << '\n';
+    output << color.colorize(interline2, colorizer::log_revision)
+           << "  " << lines[i] << '\n';
 }
 
 bool
@@ -387,7 +390,7 @@ CMD(asciik, "asciik", "", CMD_REF(debug)
   toposort(db, revs, sorted);
   reverse(sorted.begin(), sorted.end());
 
-  asciik graph(std::cout, 10);
+  asciik graph(std::cout, colorizer(app.opts.colorize, app.lua), 10);
 
   for (vector<revision_id>::const_iterator rev = sorted.begin();
        rev != sorted.end(); ++rev)
============================================================
--- src/asciik.hh	592aa966af256f50be9784bfd01c543f54d3447b
+++ src/asciik.hh	3e0dcd90804053a5e558b0ddfa6e5f3dcc462d50
@@ -11,13 +11,14 @@
 #define __ASCIIK_HH__
 
 #include <set>
+#include "colorizer.hh"
 #include "vector.hh"
 #include "vocab.hh"
 
 class asciik
 {
 public:
-  asciik(std::ostream & os, size_t min_width = 0);
+  asciik(std::ostream & os, colorizer const & color, size_t min_width = 0);
   // Prints an ASCII-k chunk using the given revisions.
   // Multiple lines are supported in annotation (the graph will stretch
   // accordingly); empty newlines at the end will be removed.
@@ -41,6 +42,7 @@ private:
   // internal state
   size_t width;
   std::ostream & output;
+  colorizer const & color;
   std::vector<revision_id> curr_row;
 };
 
============================================================
--- src/rev_output.cc	a2c70b893b31296917d1a2b974faa1da46c13f1e
+++ src/rev_output.cc	fec6728d80bca2d8d13ab49bb4ecd03310879fe5
@@ -31,40 +31,40 @@ revision_header(revision_id const rid, r
 revision_header(revision_id const rid, revision_t const & rev,
                 string const & author, date_t const date,
                 branch_name const & branch, utf8 const & changelog,
-                string const & date_fmt, utf8 & header)
+                string const & date_fmt, colorizer const & color, utf8 & header)
 {
   vector<cert> certs;
   key_id empty_key;
-  certs.push_back(cert(rid, author_cert_name, 
+  certs.push_back(cert(rid, author_cert_name,
                        cert_value(author, origin::user), empty_key));
-  certs.push_back(cert(rid, date_cert_name, 
+  certs.push_back(cert(rid, date_cert_name,
                        cert_value(date.as_iso_8601_extended(), origin::user),
                        empty_key));
-  certs.push_back(cert(rid, branch_cert_name, 
+  certs.push_back(cert(rid, branch_cert_name,
                        cert_value(branch(), origin::user), empty_key));
 
   if (!changelog().empty())
-    certs.push_back(cert(rid, changelog_cert_name, 
+    certs.push_back(cert(rid, changelog_cert_name,
                          cert_value(changelog(), origin::user), empty_key));
 
-  revision_header(rid, rev, certs, date_fmt, header);
+  revision_header(rid, rev, certs, date_fmt, color, header);
 }
 
 void
 revision_header(revision_id const rid, revision_t const & rev,
                 vector<cert> const & certs, string const & date_fmt,
-                utf8 & header)
+                colorizer const & color, utf8 & header)
 {
   ostringstream out;
 
-  out << string(70, '-') << '\n'
-      << _("Revision: ") << rid << '\n';
+  out << color.colorize(string(70, '-'), colorizer::log_revision) << '\n'
+      << color.colorize(_("Revision: "), colorizer::rev_header) << rid << '\n';
 
   for (edge_map::const_iterator i = rev.edges.begin(); i != rev.edges.end(); ++i)
     {
       revision_id parent = edge_old_revision(*i);
       if (!null_id(parent))
-        out << _("Parent:   ") << parent << '\n';
+        out << color.colorize(_("Parent:   "), colorizer::rev_header) << parent << '\n';
     }
 
   cert_name const author(author_cert_name);
@@ -76,34 +76,40 @@ revision_header(revision_id const rid, r
 
   for (vector<cert>::const_iterator i = certs.begin(); i != certs.end(); ++i)
     if (i->name == author)
-      out << _("Author:   ") << i->value << '\n';
+      out << color.colorize(_("Author:   "), colorizer::rev_header)
+          << i->value << '\n';
 
   for (vector<cert>::const_iterator i = certs.begin(); i != certs.end(); ++i)
     if (i->name == date)
       {
         if (date_fmt.empty())
-          out << _("Date:     ") << i->value << '\n';
+          out << color.colorize(_("Date:     "), colorizer::rev_header)
+              << i->value << '\n';
         else
           {
             date_t date(i->value());
-            out << _("Date:     ") << date.as_formatted_localtime(date_fmt) << '\n';
+            out << color.colorize(_("Date:     "), colorizer::rev_header)
+                << date.as_formatted_localtime(date_fmt) << '\n';
           }
       }
 
   for (vector<cert>::const_iterator i = certs.begin(); i != certs.end(); ++i)
     if (i->name == branch)
-      out << _("Branch:   ") << i->value << '\n';
+      out << color.colorize(_("Branch:   "), colorizer::rev_header)
+          << i->value << '\n';
 
   for (vector<cert>::const_iterator i = certs.begin(); i != certs.end(); ++i)
     if (i->name == tag)
-      out << _("Tag:      ") << i->value << '\n';
+      out << color.colorize(_("Tag:      "), colorizer::rev_header)
+          << i->value << '\n';
 
   out << "\n";
 
   for (vector<cert>::const_iterator i = certs.begin(); i != certs.end(); ++i)
     if (i->name == changelog)
       {
-        out << _("Changelog: ") << "\n\n" << i->value << '\n';
+        out << color.colorize(_("Changelog: "), colorizer::rev_header) << "\n\n"
+            << i->value << '\n';
         if (!i->value().empty() && i->value()[i->value().length()-1] != '\n')
           out << '\n';
       }
@@ -111,7 +117,8 @@ revision_header(revision_id const rid, r
   for (vector<cert>::const_iterator i = certs.begin(); i != certs.end(); ++i)
     if (i->name == comment)
       {
-        out << _("Comments: ") << "\n\n" << i->value << '\n';
+        out << color.colorize(_("Comments: "), colorizer::rev_header) << "\n\n"
+            << i->value << '\n';
         if (!i->value().empty() && i->value()[i->value().length()-1] != '\n')
           out << '\n';
       }
@@ -120,7 +127,7 @@ void
 }
 
 void
-revision_summary(revision_t const & rev, utf8 & summary)
+revision_summary(revision_t const & rev, colorizer const & color, utf8 & summary)
 {
   // We intentionally do not collapse the final \n into the format
   // strings here, for consistency with newline conventions used by most
@@ -138,9 +145,9 @@ revision_summary(revision_t const & rev,
       // A colon at the end of this string looked nicer, but it made
       // double-click copying from terminals annoying.
       if (null_id(parent))
-        out << _("Changes") << "\n\n";
+        out << color.colorize(_("Changes"), colorizer::rev_header) << "\n\n";
       else
-        out << _("Changes against parent ") << parent << "\n\n";
+        out << color.colorize(_("Changes against parent "), colorizer::rev_header) << parent << "\n\n";
 
       // presumably a merge rev could have an empty edge if one side won
       if (cs.empty())
@@ -148,43 +155,53 @@ revision_summary(revision_t const & rev,
 
       for (set<file_path>::const_iterator i = cs.nodes_deleted.begin();
             i != cs.nodes_deleted.end(); ++i)
-        out << (F("  dropped  %s") %*i) << '\n';
+        out << color.colorize((F("  dropped  %s") %*i).str(),
+                              colorizer::remove) << '\n';
 
       for (map<file_path, file_path>::const_iterator
             i = cs.nodes_renamed.begin();
             i != cs.nodes_renamed.end(); ++i)
-        out << (F("  renamed  %s\n"
-                  "       to  %s") % i->first % i->second) << '\n';
+        out << color.colorize((F("  renamed  %s\n"
+                                 "       to  %s") % i->first
+                                 % i->second).str(),
+                              colorizer::rename) << '\n';
 
       for (set<file_path>::const_iterator i = cs.dirs_added.begin();
             i != cs.dirs_added.end(); ++i)
-        out << (F("  added    %s") % *i) << '\n';
+        out << color.colorize((F("  added    %s") % *i).str(),
+                              colorizer::add) << '\n';
 
       for (map<file_path, file_id>::const_iterator i = cs.files_added.begin();
             i != cs.files_added.end(); ++i)
-        out << (F("  added    %s") % i->first) << '\n';
+        out << color.colorize((F("  added    %s") % i->first).str(),
+                              colorizer::add) << '\n';
 
       for (map<file_path, pair<file_id, file_id> >::const_iterator
               i = cs.deltas_applied.begin(); i != cs.deltas_applied.end(); ++i)
-        out << (F("  patched  %s") % i->first) << '\n';
+        out << color.colorize((F("  patched  %s") % i->first).str(),
+                              colorizer::change) << '\n';
 
       for (map<pair<file_path, attr_key>, attr_value >::const_iterator
              i = cs.attrs_set.begin(); i != cs.attrs_set.end(); ++i)
-        out << (F("  attr on  %s\n"
-                  "      set  %s\n"
-                  "       to  %s")
-                % i->first.first % i->first.second % i->second) << '\n';
+        out << color.colorize((F("  attr on  %s\n"
+                                 "      set  %s\n"
+                                 "       to  %s")
+                               % i->first.first % i->first.second
+                               % i->second).str(),
+                              colorizer::set) << '\n';
 
       // FIXME: naming here could not be more inconsistent
       // the cset calls it attrs_cleared
       // the command is attr drop
       // here it is called unset
-      // the revision text uses attr clear 
+      // the revision text uses attr clear
 
       for (set<pair<file_path, attr_key> >::const_iterator
              i = cs.attrs_cleared.begin(); i != cs.attrs_cleared.end(); ++i)
-        out << (F("  attr on  %s\n"
-                  "    unset  %s") % i->first % i->second) << '\n';
+        out << color.colorize((F("  attr on  %s\n"
+                                 "    unset  %s") % i->first
+                                 % i->second).str(),
+                              colorizer::unset) << '\n';
 
       out << '\n';
     }
============================================================
--- src/rev_output.hh	666dd3ed35e16d8b122b4932c2aad05a21a22e25
+++ src/rev_output.hh	5879a8268a59545c946583b65f66eda4491b979e
@@ -10,6 +10,7 @@
 #ifndef __REV_SUMMARY_HH__
 #define __REV_SUMMARY_HH__
 
+#include "colorizer.hh"
 #include "rev_types.hh"
 #include "vocab.hh"
 
@@ -17,18 +18,19 @@ void
 struct cert;
 
 void
-revision_header(revision_id const rid, revision_t const & rev, 
+revision_header(revision_id const rid, revision_t const & rev,
                 std::string const & author, date_t const date,
                 branch_name const & branch, utf8 const & changelog,
-                std::string const & date_fmt, utf8 & header);
+                std::string const & date_fmt, colorizer const & color,
+                utf8 & header);
 
 void
-revision_header(revision_id const rid, revision_t const & rev, 
+revision_header(revision_id const rid, revision_t const & rev,
                 std::vector<cert> const & certs, std::string const & date_fmt,
-                utf8 & header);
+                colorizer const & color, utf8 & header);
 
 void
-revision_summary(revision_t const & rev, utf8 & summary);
+revision_summary(revision_t const & rev, colorizer const & color, utf8 & summary);
 
 #endif  // header guard
 
============================================================
--- /dev/null	
+++ src/colorizer.cc	96964884a83e4d7d638c146821a554d033f396eb
@@ -0,0 +1,184 @@
+// Copyright (C) 2010 Thomas Keller <address@hidden>
+//
+// This program is made available under the GNU GPL version 2.0 or
+// greater. See the accompanying file COPYING for details.
+//
+// This program is distributed WITHOUT ANY WARRANTY; without even the
+// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+// PURPOSE.
+
+#include "base.hh"
+#include "colorizer.hh"
+#include "platform.hh"
+
+using std::string;
+using std::map;
+using std::make_pair;
+
+
+string colorizer::purpose_to_name(colorizer::purpose const p) const
+{
+  switch (p)
+  {
+    case normal:
+      return "normal";
+    case reset:
+      return "reset";
+
+    case add:
+      return "add";
+    case change:
+      return "change";
+    case comment:
+      return "comment";
+    case encloser:
+      return "encloser";
+    case log_revision:
+      return "log_revision";
+    case remove:
+      return "remove";
+    case rename:
+      return "rename";
+    case rev_header:
+      return "rev_header";
+    case separator:
+      return "separator";
+    case set:
+      return "set";
+    case unset:
+      return "unset";
+
+    default:
+      I(false); // should never get here
+  }
+}
+
+std::pair<colorizer::purpose, boost::tuple<string, string, string> > colorizer::map_output_color(
+  purpose const p)
+{
+  string fg, bg, style;
+  string purpose_name = purpose_to_name(p);
+
+  if (p == reset)
+    {
+      // the user doesn't need to know about reset - it's an implementation
+      // detail for us to handle
+      fg = bg = style = "";
+    }
+  else
+    {
+      lua.hook_get_output_color(purpose_name, fg, bg, style);
+    }
+
+  return std::make_pair(p, boost::make_tuple(fg_to_code(fg),
+                                             bg_to_code(bg),
+                                             style_to_code(style)));
+}
+
+string colorizer::fg_to_code(string const color) const
+{
+  if (color == "black")
+    return "\033[30m";
+  else if (color == "red")
+    return "\033[31m";
+  else if (color == "green")
+    return "\033[32m";
+  else if (color == "yellow")
+    return "\033[33m";
+  else if (color == "blue")
+    return "\033[34m";
+  else if (color == "magenta")
+    return "\033[35m";
+  else if (color == "cyan")
+    return "\033[36m";
+  else if (color == "white")
+    return "\033[37m";
+  else
+    return "\033[39m"; // default
+}
+
+string colorizer::bg_to_code(string const color) const
+{
+  if (color == "black")
+    return "\033[40m";
+  else if (color == "red")
+    return "\033[41m";
+  else if (color == "green")
+    return "\033[42m";
+  else if (color == "yellow")
+    return "\033[43m";
+  else if (color == "blue")
+    return "\033[44m";
+  else if (color == "magenta")
+    return "\033[45m";
+  else if (color == "cyan")
+    return "\033[46m";
+  else if (color == "white")
+    return "\033[47m";
+  else
+    return "\033[49m"; // default
+}
+
+string colorizer::style_to_code(string const style) const
+{
+  if (style == "none")
+    return "\033[22m\033[23m\033[24m";
+  else if (style == "bold")
+    return "\033[1m";
+  else if (style == "italic")
+    return "\033[3m";
+  else if (style == "underline")
+    return "\033[4m";
+  else
+    return "\033[22m\033[23m\033[24m"; // all off
+}
+
+colorizer::colorizer(bool enable, lua_hooks & lh) 
+  : lua(lh)
+{
+  if (!have_smart_terminal())
+    enable = false;
+
+  if (enable)
+    {
+      colormap.insert(map_output_color(normal));
+      colormap.insert(map_output_color(reset));
+
+      colormap.insert(map_output_color(add));
+      colormap.insert(map_output_color(change));
+      colormap.insert(map_output_color(comment));
+      colormap.insert(map_output_color(encloser));
+      colormap.insert(map_output_color(log_revision));
+      colormap.insert(map_output_color(remove));
+      colormap.insert(map_output_color(rename));
+      colormap.insert(map_output_color(rev_header));
+      colormap.insert(map_output_color(separator));
+      colormap.insert(map_output_color(set));
+      colormap.insert(map_output_color(unset));
+    }
+}
+
+string
+colorizer::colorize(string const & in, purpose p) const
+{
+  if (colormap.find(p) == colormap.end())
+    return in;
+
+   return get_format(p) + in + get_format(reset);
+}
+
+string
+colorizer::get_format(purpose const p) const
+{
+  boost::tuple<string, string, string> format = colormap.find(p)->second;
+
+  return format.get<0>() + format.get<1>() + format.get<2>();
+}
+
+// Local Variables:
+// mode: C++
+// fill-column: 76
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:
============================================================
--- /dev/null	
+++ src/colorizer.hh	eb3d0e3dad8d447e270e0c6264bf1a4ea139013f
@@ -0,0 +1,66 @@
+// Copyright (C) 2010 Thomas Keller <address@hidden>
+//
+// This program is made available under the GNU GPL version 2.0 or
+// greater. See the accompanying file COPYING for details.
+//
+// This program is distributed WITHOUT ANY WARRANTY; without even the
+// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+// PURPOSE.
+
+#ifndef __COLORIZER_HH__
+#define __COLORIZER_HH__
+
+#include "lua_hooks.hh"
+#include "vocab.hh"
+#include <map>
+#include <boost/tuple/tuple.hpp>
+
+struct colorizer {
+
+  typedef enum { normal = 0,
+                 reset,
+
+                 add,
+                 change,
+                 comment,
+                 encloser,
+                 log_revision,
+                 remove,
+                 rename,
+                 rev_header,
+                 separator,
+                 set,
+                 unset
+                } purpose;
+
+  colorizer(bool enable, lua_hooks & lh);
+
+  std::string
+  colorize(std::string const & in, purpose p = normal) const;
+
+private:
+  std::map<purpose, boost::tuple<std::string, std::string, std::string> >
+    colormap;
+  lua_hooks & lua;
+
+  std::pair<purpose, boost::tuple<std::string, std::string, std::string> >
+  map_output_color(purpose const p);
+
+  std::string fg_to_code(std::string const color) const;
+  std::string bg_to_code(std::string const color) const;
+  std::string style_to_code(std::string const style) const;
+
+  std::string get_format(purpose const p) const;
+
+  std::string purpose_to_name(purpose const p) const;
+};
+
+#endif // __COLORIZER_HH__
+
+// Local Variables:
+// mode: C++
+// fill-column: 76
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:
============================================================
--- test/func/serve-automate/__driver__.lua	d41f819fd49060c45bb154dde614699b0cb938e7
+++ test/func/serve-automate/__driver__.lua	ae4b03baf16d8401f31a32c8377021f879788d01
@@ -15,7 +15,7 @@ check(
 local errors = run_remote_stdio(server, "l17:interface_versione", 1, 0, "e")
 check(
     table.maxn(errors) == 1 and
-    errors[1] == "misuse: Sorry, you aren't allowed to do that."
+    errors[1] == "misuse: sorry, you aren't allowed to do that."
 )
 
 server:stop()
============================================================
--- test/func/db_opt_fallback_mechanisms/__driver__.lua	09354a970b921effa2850aa4ad722ce95a433ea8
+++ test/func/db_opt_fallback_mechanisms/__driver__.lua	0b0da944f19f7a0be42165069fdc1bb8862fd6ee
@@ -14,4 +14,4 @@ check(raw_mtn("au", "remote", "interface
 -- and some commands should use :memory: as default because they
 -- just need a temporary throw-away database to work properly
 check(raw_mtn("au", "remote", "interface_version", "--remote-stdio-host", "http://code.monotone.ca/monotone", "--key="), 0, false, true)
-check(qgrep("No database given; assuming ':memory:' database", "stderr"))
+check(qgrep("no database given; assuming ':memory:' database", "stderr"))

reply via email to

[Prev in Thread] Current Thread [Next in Thread]