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: 3fd6dbdf43313


From: code
Subject: [Monotone-commits-diffs] net.venge.monotone.colored-diff: 3fd6dbdf433136f25a57a9043d02020cc4e044ba
Date: Fri, 14 Jan 2011 23:04:19 GMT

revision:            3fd6dbdf433136f25a57a9043d02020cc4e044ba
date:                2011-01-13T19:39:21
author:              Richard Hopkins
branch:              net.venge.monotone.colored-diff
changelog:
propagate from branch 'net.venge.monotone' (head 
c21a8d05f9dc8d7444416cc47ecf36a3a273c061)
            to branch 'net.venge.monotone.colored-diff' (head 
86c803294d687290901ebbf1cf2f2196c2faf83d)

manifest:
format_version "1"

new_manifest [d781b37cf34aee864fcd7030b7948cf1799663b9]

old_revision [86c803294d687290901ebbf1cf2f2196c2faf83d]

patch "monotone.texi"
 from [be1dd907f6f06074b2c0b4a71fc9f7bca0f345e6]
   to [9174c3285ed2ed4b68615cc1e21a041d9e426fb9]

old_revision [c21a8d05f9dc8d7444416cc47ecf36a3a273c061]

add_file "colorizer.cc"
 content [c219975b61f0749de94fd6e9a6491022acbde7e3]

add_file "colorizer.hh"
 content [acac5ffcef7270972ccd94aa0a671ab27c892450]

patch "Makefile.am"
 from [0c1e48ef9dfb72bc9f3ada23437e17c7fca73c18]
   to [442ce438b934c521906098ab2e934027a08b0461]

patch "NEWS"
 from [f9ce17392993af31e59748c969baa33ab5296c42]
   to [d005b48d90eb3b71b743e4696e7625b078660537]

patch "asciik.cc"
 from [cf946f9a14ad309615704bc960255c50e12b636a]
   to [bdb2253549ec477bf725e9f5ae43c0fa7dff564f]

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

patch "cmd_diff_log.cc"
 from [a3014082674ecb9c3b0617a9603b03452723fec9]
   to [9152df5398b88e5d29fc7af0941011c1137e169e]

patch "cmd_files.cc"
 from [7e9ffd4a06daeb0ef7ab7557d3a656c6b99ab2ad]
   to [8193666bb289537ceb8ce3fd05d85577dada5fe4]

patch "cmd_ws_commit.cc"
 from [7b91a53d8eec4e78b062092f85c945bbaaefe23a]
   to [cbcbf79937b6a299324b93357770b225d0e6cde2]

patch "diff_output.cc"
 from [1e537406208bd9ff6afd2a728389d1c4f34acaf2]
   to [9aab77314ce27866f7fee966936480d03fa13220]

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

patch "monotone.texi"
 from [23a45f966060f1b164dd0f7003af4449be8fdb4a]
   to [9174c3285ed2ed4b68615cc1e21a041d9e426fb9]

patch "options_list.hh"
 from [1985a3326ea833595edf84b75ae5ab9fde487709]
   to [6e5020c38127f3e043602673b0c8b12a0dccc9e5]

patch "rev_output.cc"
 from [a2c70b893b31296917d1a2b974faa1da46c13f1e]
   to [90f5ca2ff78f91bdf512231482d00a2eee37875b]

patch "rev_output.hh"
 from [666dd3ed35e16d8b122b4932c2aad05a21a22e25]
   to [5879a8268a59545c946583b65f66eda4491b979e]
============================================================
--- monotone.texi	be1dd907f6f06074b2c0b4a71fc9f7bca0f345e6
+++ monotone.texi	9174c3285ed2ed4b68615cc1e21a041d9e426fb9
@@ -5263,7 +5263,7 @@ @section Tree
 This may be needed when upgrading to a new version of monotone.
 
 @item mtn propagate @var{sourcebranch} @var{destbranch} [--message @var{string}] [--message-file @var{filename}]
-See online help for more options.
+See online help for more options. See @ref{Common Options}.
 
 This command takes a unique head from @var{sourcebranch} and merges it
 with a unique head of @var{destbranch}, using the least common
@@ -6635,16 +6635,14 @@ @section Variables
 @command{list databases} to work; see @ref{Managed Databases}).
 
 @item mtn set @var{domain} @var{name} @var{value}
-Associates the value @var{value} to @var{name} in domain @var{domain}.
+Associates @var{value} to @var{name} in domain @var{domain}.
 See @ref{Vars} for more information.
 
 @item mtn unregister_workspace address@hidden
-Unregisters the given workspace from the current database, so that it
-will no longer show up in the output of @ref{mtn list databases}.
+Unregisters the given workspace (default the current workspace) from
+the current database, so that it will no longer show up in the output
+of @ref{mtn list databases}.
 
-If no @var{workspace_path} is given, this command defaults to the
-current workspace.
-
 @item mtn unset @var{domain} @var{name}
 Deletes any value associated with @var{name} in @var{domain}.  See
 @ref{Vars} for more information.
@@ -6656,21 +6654,18 @@ @section Key and Cert
 @section Key and Cert
 
 @ftable @command
address@hidden mtn cert @var{selector} @var{certname}
address@hidden mtn cert @var{selector} @var{certname} @var{certval}
address@hidden mtn cert @var{selector} @var{certname} address@hidden
 
-These commands create a new certificate with name @var{certname}, for all
-revisions matching @var{selector}. The @var{selector} argument can
-use certs already on the revision, such as @code{h:@var{branchname}}.
+Create a new certificate with name @var{certname}, for all
+revisions matching @var{selector}.
 
 If @var{certval} is provided, it is the value of the certificate.
 Otherwise the certificate value is read from @code{stdin}.
 
 @item mtn dropkey @var{keyid}
-This command drops the public and/or private key. If both exist, both
-are dropped, if only one exists, it is dropped. This command should
-be used with caution as changes are irreversible without a backup of
-the key(s) that were dropped.
+Drop the public and/or private key. This command should be used with
+caution as changes are irreversible without a backup of the key(s)
+that were dropped.
 
 @item mtn genkey @var{keyid}
 This command generates an @sc{rsa} public/private key pair, using a
@@ -6678,32 +6673,37 @@ @section Key and Cert
 the key name @var{keyid.keyhash}.  The key's hash is printed out after
 the key has been created.
 
-The private half of the key is stored in an encrypted form, so that anyone
-who can read your keystore cannot extract your private key and use it.
-You must provide a passphrase for your key when it is generated, which is used
-to determine the encryption key. In the future you will need to enter this
-passphrase again each time you sign a certificate, which happens every
-time you @command{commit} to your database. You can tell monotone to
-automatically use a certain passphrase for a given key using the
address@hidden(@var{key_identity})}, but this significantly
-increases the risk of a key compromise on your local computer. Be
-careful using this hook.
+The private half of the key is stored in an encrypted form, so that
+anyone who can read your keystore cannot extract your private key and
+use it.  You must provide a passphrase for your key when it is
+generated, which is used to determine the encryption key. In the
+future you will need to enter this passphrase again each time you sign
+a certificate, which happens every time you @command{commit} to your
+database. You can tell monotone to automatically use a certain
+passphrase for a given key using the
address@hidden(@var{key_identity})} (see @ref{get_passphrase}),
+but this significantly increases the risk of a key compromise on your
+local computer. Be careful using this hook.
 
+Another way to avoid entering the private key passphrase each time it
+is needed is to export it to ssh-agent; see @ref{mtn
+ssh_agent_export}, @ref{mtn ssh_agent_add}.
+
 The public key is stored in the database; the public and private keys
 are stored in the keystore. This allows copying the database without
 copying the private key.
 
-The location of the keystore is specified by the @option{--keydir}
-option; it defaults to the value stored in @file{_MTN/options} for
-commands executed in a workspace, or to
-the system default (@file{$HOME/.monotone/keys} on Unix and Cygwin,
+The location of the keystore is specified by @option{--keydir}; it
+defaults to the value stored in @file{_MTN/options} for commands
+executed in a workspace, or to the system default
+(@file{$HOME/.monotone/keys} on Unix and Cygwin,
 @file{%APPDATA%/monotone/keys} on native Win32).
 
 @item mtn passphrase @var{keyid}
 This command lets you change the passphrase of the private half of the
 key @var{id}.
 
address@hidden mtn ssh_agent_add
address@hidden address@hidden mtn ssh_agent_add
 This command will add your monotone keys to your current ssh-agent session.
 You will be asked for the passphrase for each of your monotone private keys
 and they will be added to the ssh-agent. Once this is done you should be able
@@ -6711,6 +6711,10 @@ @section Key and Cert
 subsequently use these keys through monotone it will use ssh-agent for signing
 without asking your for your passphrase.
 
+On Windows native, monotone only supports the PuTTY ssh-agent
+implementation. On Windows Cygwin and Unix, any standard ssh-agent
+implementation can be used.
+
 This command is mainly for use in a session script as monotone will automatically
 add your keys to ssh-agent on first use if it is available. For example the
 following two examples are equivalent:
@@ -6735,13 +6739,15 @@ @section Key and Cert
 In the second example, monotone automatically added the key to ssh-agent, making
 entering the passphrase not needed during the push.
 
address@hidden mtn ssh_agent_export @var{filename}
address@hidden address@hidden mtn ssh_agent_export address@hidden
+
 This command will export your private key in a format that ssh-agent
-can read (PKCS8, PEM). You will be asked for your current key's password
-and a new password to encrypt the key with. The key will be printed to
-stdout. Once you have put this key in a file simply add it to ssh-agent
-and you will only have to enter your key password once as ssh-agent
-will cache the key for you.
+can read (PKCS8, PEM), to @var{filename} (defaults to standard
+output). You will be asked for your current key's monotone password
+and a new password to encrypt the key with (the ssh passphrase). The
+key will be printed to stdout. Once you have put this key in a file
+simply add it to ssh-agent and you will only have to enter your key
+password once as ssh-agent will cache the key for you.
 
 @smallexample
 @group
@@ -6778,7 +6784,7 @@ @section Key and Cert
 Monotone would trust a cert on that revision with that value signed by
 those keys.
 
-The specified keys mist exist either in your keystore or in the database.
+The specified keys must exist either in your keystore or in the database.
 
 @end ftable
 
@@ -10244,7 +10250,7 @@ @section Automation
 Keyboard interaction is disabled on the server, just as if
 @option{--non-interactive} would have been specified on server startup.
 Actions which require operations on password-encrypted private keys will
-therefor fail unless a @code{get_passphrase} hook is set up remotely.
+therefor fail unless a @ref{get_passphrase} hook is set up remotely.
 
 @end table
 
@@ -10293,7 +10299,7 @@ @section Automation
 For both, the client and the server, keyboard interaction is disabled,
 just as if @option{--non-interactive} is specified. Actions which require
 operations on password-encrypted private keys will therefor fail unless the
address@hidden hook is set up locally and / or remotely.
address@hidden hook is set up locally and / or remotely.
 
 @end table
 
@@ -10952,7 +10958,7 @@ @section Automation
 
 Keyboard interaction is disabled, just as if @option{--non-interactive} is
 specified. Actions which require operations on password-encrypted private keys
-will therefor fail unless the @code{get_passphrase} hook is set up locally.
+will therefor fail unless the @ref{get_passphrase} hook is set up locally.
 
 @item Multiple streams
 
@@ -11711,7 +11717,7 @@ @subsection User Defaults
 @end group
 @end smallexample
 
address@hidden get_passphrase (@var{key_identity})
address@hidden@item get_passphrase (@var{key_identity})
 
 Returns a string which is the passphrase used to encrypt the private
 half of @var{key_identity} in your key store, using the @sc{TripleDES} symmetric
============================================================
--- Makefile.am	0c1e48ef9dfb72bc9f3ada23437e17c7fca73c18
+++ Makefile.am	442ce438b934c521906098ab2e934027a08b0461
@@ -45,6 +45,7 @@ MOST_SOURCES = 								\
 	botan_pipe_cache.hh						\
 	cache_logger.hh cache_logger.cc					\
 	commands.cc commands.hh $(CMD_SOURCES)				\
+	colorizer.cc colorizer.hh					\
 	diff_output.cc diff_output.hh					\
 	lua_hooks.cc lua_hooks.hh 					\
 	transforms.cc transforms.hh					\
============================================================
--- NEWS	f9ce17392993af31e59748c969baa33ab5296c42
+++ NEWS	d005b48d90eb3b71b743e4696e7625b078660537
@@ -331,6 +331,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.
============================================================
--- diff_output.cc	1e537406208bd9ff6afd2a728389d1c4f34acaf2
+++ diff_output.cc	9aab77314ce27866f7fee966936480d03fa13220
@@ -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::diff_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::diff_delete));
 }
 
 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::diff_separator);
+        ost << color.colorize(encloser, colorizer::diff_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::diff_separator)
+            << color.colorize(encloser, colorizer::diff_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::diff_delete;
+  }
   else if (deletes.empty() && !inserts.empty())
+  {
     prefix = "+";
+    p = colorizer::diff_add;
+  }
   else
+  {
     prefix = "!";
+    p = colorizer::diff_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::diff_comment) << "\n";
       else
-        ost << "# " << filename2 << " is binary\n";
+        ost << color.colorize(string("# ") + filename2 + " is binary",
+                              colorizer::diff_comment) << "\n";
       return;
     }
 
@@ -570,23 +599,23 @@ make_diff(string const & filename1,
     {
       case unified_diff:
       {
-        ost << "--- " << filename1 << '\t'
-            << id1 << '\n';
-        ost << "+++ " << filename2 << '\t'
-            << id2 << '\n';
+        ost << color.colorize(string("--- ") + filename1, colorizer::diff_delete)
+            << '\t' << id1 << '\n';
+        ost << color.colorize(string("+++ ") + filename2, colorizer::diff_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::diff_delete)
+            << '\t' << id1 << '\n';
+        ost << color.colorize(string("--- ") + filename2, colorizer::diff_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;
       }
============================================================
--- diff_output.hh	9125ccd0d0fa725782c9910b5f34e844048d2da8
+++ 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__
 
============================================================
--- monotone.texi	23a45f966060f1b164dd0f7003af4449be8fdb4a
+++ monotone.texi	9174c3285ed2ed4b68615cc1e21a041d9e426fb9
@@ -6122,7 +6122,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 mtn diff [--unified] [--[no-]show-encloser]
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...}
@@ -6164,7 +6164,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
@@ -6186,6 +6186,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,
@@ -6399,7 +6403,7 @@ @section Informative
 files to the current subdirectory of the workspace.
 
 @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
@@ -6470,8 +6474,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.
 
============================================================
--- cmd_diff_log.cc	a3014082674ecb9c3b0617a9603b03452723fec9
+++ cmd_diff_log.cc	9152df5398b88e5d29fc7af0941011c1137e169e
@@ -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);
     }
 
 }
@@ -127,7 +130,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)
 {
   parallel::iter<node_map> i(left_roster.all_nodes(), right_roster.all_nodes());
   while (i.next())
@@ -163,7 +167,7 @@ dump_diffs(lua_hooks & lua,
                         left_id, right_id,
                         left_data, right_data,
                         diff_format, external_diff_args_given, external_diff_args,
-                        encloser, output);
+                        encloser, colorizer, output);
             }
           break;
 
@@ -192,7 +196,7 @@ dump_diffs(lua_hooks & lua,
                         left_id, right_id,
                         left_data, right_data,
                         diff_format, external_diff_args_given, external_diff_args,
-                        encloser, output);
+                        encloser, colorizer, output);
             }
           break;
 
@@ -225,7 +229,7 @@ dump_diffs(lua_hooks & lua,
                         left_id, right_id,
                         left_data, right_data,
                         diff_format, external_diff_args_given, external_diff_args,
-                        encloser, output);
+                        encloser, colorizer, output);
             }
           break;
         }
@@ -390,6 +394,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;
@@ -402,19 +407,23 @@ void dump_header(std::string const & rev
 
   vector<string> lines;
   split_into_lines(summary(), lines);
-  out << "#\n";
+  out << colorizer.colorize("#", colorizer::diff_comment) << "\n";
   if (!summary().empty())
     {
-      out << revs << "#\n";
+      out << colorizer.colorize(revs, colorizer::diff_comment);
+      out << colorizer.colorize("#", colorizer::diff_comment) << "\n";
+
       for (vector<string>::iterator i = lines.begin();
            i != lines.end(); ++i)
-        out << "# " << *i << '\n';
+        out << colorizer.colorize(string("# ") + *i,
+                                  colorizer::diff_comment) << "\n";
     }
   else
     {
-      out << "# " << _("no changes") << '\n';
+      out << colorizer.colorize(string("# ") + _("no changes"),
+                                colorizer::diff_comment) << "\n";
     }
-  out << "#\n";
+  out << colorizer.colorize("#", colorizer::diff_comment) << "\n";
 }
 
 CMD_PRESET_OPTIONS(diff)
@@ -445,9 +454,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);
+
   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,
@@ -455,7 +466,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);
 }
 
 
@@ -484,16 +496,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);
 
   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);
 }
 
 
@@ -551,27 +567,27 @@ void
                        rev_cmp> frontier_t;
 
 void
-log_print_rev (app_state &      app,
-               database &       db,
-               project_t &      project,
-               revision_id      rid,
-               revision_t &     rev,
-               string           date_fmt,
-               node_restriction mask,
-               ostream &        out)
+log_print_rev(app_state & app,
+              database & db,
+              project_t const & project,
+              revision_id const & rid,
+              revision_t const & rev,
+              string const & date_fmt,
+              node_restriction const & mask,
+              colorizer const & color,
+              ostream & out)
 {
-  cert_name const author_name(author_cert_name);
-  cert_name const date_name(date_cert_name);
-  cert_name const branch_name(branch_cert_name);
-  cert_name const tag_name(tag_cert_name);
-  cert_name const changelog_name(changelog_cert_name);
-  cert_name const comment_name(comment_cert_name);
   vector<cert> certs;
   project.get_revision_certs(rid, certs);
 
   if (app.opts.brief)
     {
-      out << rid;
+      cert_name const author_name(author_cert_name);
+      cert_name const date_name(date_cert_name);
+      cert_name const branch_name(branch_cert_name);
+
+      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);
@@ -586,7 +602,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);
@@ -595,7 +611,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;
@@ -627,16 +643,17 @@ 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);
         }
     }
 }
 
 void
-log_common (app_state & app,
-            args_vector args,
-            bool automate,
-            std::ostream & output)
+log_common(app_state & app,
+           args_vector args,
+           bool automate,
+           std::ostream & output)
 {
   database db(app);
   project_t project(db);
@@ -846,8 +863,11 @@ log_common (app_state & app,
 
   set<revision_id> seen;
   revision_t rev;
+
+  colorizer color(app.opts.colorize && !automate);
   // 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;
@@ -943,7 +963,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);
@@ -991,9 +1011,9 @@ 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);
+  log_common(app, args, false, cout);
 }
 
 CMD_AUTOMATE(log, N_("[PATH] ..."),
@@ -1004,7 +1024,7 @@ CMD_AUTOMATE(log, N_("[PATH] ..."),
     options::opts::depth | options::opts::exclude |
     options::opts::no_merges)
 {
-  log_common (app, args, true, output);
+  log_common(app, args, true, output);
 }
 
 // Local Variables:
============================================================
--- cmd_files.cc	7e9ffd4a06daeb0ef7ab7557d3a656c6b99ab2ad
+++ cmd_files.cc	8193666bb289537ceb8ce3fd05d85577dada5fe4
@@ -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));
 }
 
 CMD(annotate, "annotate", "", CMD_REF(informative), N_("PATH"),
============================================================
--- cmd_ws_commit.cc	7b91a53d8eec4e78b062092f85c945bbaaefe23a
+++ cmd_ws_commit.cc	cbcbf79937b6a299324b93357770b225d0e6cde2
@@ -259,7 +259,8 @@ get_log_message_interactively(lua_hooks 
   }
 
   utf8 summary;
-  revision_summary(rev, summary);
+  colorizer color(false);
+  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);
 
   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;
============================================================
--- options_list.hh	1985a3326ea833595edf84b75ae5ab9fde487709
+++ options_list.hh	6e5020c38127f3e043602673b0c8b12a0dccc9e5
@@ -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, )
============================================================
--- asciik.cc	cf946f9a14ad309615704bc960255c50e12b636a
+++ asciik.cc	bdb2253549ec477bf725e9f5ae43c0fa7dff564f
@@ -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), 10);
 
   for (vector<revision_id>::const_iterator rev = sorted.begin();
        rev != sorted.end(); ++rev)
============================================================
--- asciik.hh	592aa966af256f50be9784bfd01c543f54d3447b
+++ 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;
 };
 
============================================================
--- rev_output.cc	a2c70b893b31296917d1a2b974faa1da46c13f1e
+++ rev_output.cc	90f5ca2ff78f91bdf512231482d00a2eee37875b
@@ -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())
@@ -179,7 +186,7 @@ revision_summary(revision_t const & rev,
       // 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)
============================================================
--- rev_output.hh	666dd3ed35e16d8b122b4932c2aad05a21a22e25
+++ 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	
+++ colorizer.cc	c219975b61f0749de94fd6e9a6491022acbde7e3
@@ -0,0 +1,52 @@
+// 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;
+
+colorizer::colorizer(bool enable)
+{
+  if (!have_smart_terminal())
+    enable = false;
+
+  if (enable)
+    {
+      colormap.insert(std::make_pair(normal,         ""));
+      colormap.insert(std::make_pair(reset,          "\033[m"));
+      colormap.insert(std::make_pair(diff_encloser,  "\033[1;34m"));
+      colormap.insert(std::make_pair(diff_add,       "\033[32m"));
+      colormap.insert(std::make_pair(diff_delete,    "\033[31m"));
+      colormap.insert(std::make_pair(diff_change,    "\033[33m"));
+      colormap.insert(std::make_pair(diff_comment,   "\033[36m"));
+      colormap.insert(std::make_pair(diff_separator, "\033[1m"));
+      colormap.insert(std::make_pair(log_revision,   "\033[34m"));
+      colormap.insert(std::make_pair(rev_header,     "\033[1m"));
+    }
+}
+
+string
+colorizer::colorize(string const & in, purpose p) const
+{
+  if (colormap.find(p) == colormap.end())
+    return in;
+  return colormap.find(p)->second + in + colormap.find(reset)->second;
+}
+
+// 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	
+++ colorizer.hh	acac5ffcef7270972ccd94aa0a671ab27c892450
@@ -0,0 +1,47 @@
+// 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 "vocab.hh"
+#include <map>
+
+struct colorizer {
+
+  typedef enum { normal = 0,
+                 reset,
+                 diff_encloser,
+                 diff_add,
+                 diff_delete,
+                 diff_change,
+                 diff_comment,
+                 diff_separator,
+                 log_revision,
+                 rev_header
+                 } purpose;
+
+  colorizer(bool enable);
+
+  std::string
+  colorize(std::string const & in, purpose p = normal) const;
+
+private:
+  std::map<purpose, std::string> colormap;
+};
+
+#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:

reply via email to

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