Ok, updated patch, now with --diff-args and doc & testsuite fixes. 
This also adds printing a line of "====="'s in between built-in diff
output files, to work around overzealous diff readers that see a line
that starts with '-' and assume that whoever wrote the previous @ must
have made a mistake in the calculation.  I haven't added a specific
regression test for external diff to avoid a dependancy on a diff
program being present, but I guess I can make a "dummy" external diff
hook just to make sure everything's passed through correctly.

    - Vlad
# 
# patch "app_state.cc"
#  from [976ea774c4fd1df5e9d63ee5b19f1a925899c12b]
#    to [8efdcd302100554f04d225c9e5ddfe9ddc1bff3a]
# 
# patch "app_state.hh"
#  from [ad40f04b056e67723f755a752d17e0ab7107dac4]
#    to [15ba734efc432db709cc66ee01c7c104e5554e50]
# 
# patch "commands.cc"
#  from [668364db356c8b18906474160174ee9b30d7d699]
#    to [41f74675806bc533e9ecc46b5dfb5c3ffb09d263]
# 
# patch "constants.cc"
#  from [7d39c51c90d4e9be993c9cef054af6d52cb8abe6]
#    to [899e6fa749d0764a0d480172c97148a8d42f2655]
# 
# patch "database.cc"
#  from [be4bc4ef67ffb1a7fc1c315bddc6de38cefe68e2]
#    to [561c23dcdd77b5888b6d46d58ee63ff1e1112284]
# 
# patch "diff_patch.cc"
#  from [fbef84d6f575c4f14850b8a8e7d78e42021a0e80]
#    to [022e125cb1265ea8d0a484289b952587060053cc]
# 
# patch "diff_patch.hh"
#  from [18be28ae5d744c23da230988bd4a48f6556cb4b4]
#    to [f499e229bf13e49c06c4c9129a1e48b2b1a7ef65]
# 
# patch "lua.cc"
#  from [a8af56ad7fe0d9baa85c265b05dd94877a806c19]
#    to [7f7d2cd8e90e9224d82fc66216093307306fa653]
# 
# patch "lua.hh"
#  from [0c4f6966a60230b591f07d0a0519485bf451a349]
#    to [517f80335c5433b0134e70a53f0d26f9563151dc]
# 
# patch "monotone.cc"
#  from [240b0908b7d873c84df7cd1ca676d44a490b778f]
#    to [46cbc3c75c039ef547e3d566c79fd33a2acdcf52]
# 
# patch "monotone.texi"
#  from [80f97d74395a57fc85b24b54329d0c10f1639c99]
#    to [9e37ce22ceb10715bf1ed4efa1fe44f1b1d02a22]
# 
# patch "options.hh"
#  from [2d21f8009f424d24e5513c3894c0ff321e79feb0]
#    to [814c3c354201a830e7bce20f0a8dc48d79b9cf8c]
# 
# patch "std_hooks.lua"
#  from [072c95bc58425ade43dc08e8361c7aca49275dd4]
#    to [80a530bdeb7e4526a8b97c9f9d6c071a7b1f05e0]
# 
# patch "tests/t_crlf.at"
#  from [ac04c64a00a9691b7599320562dacdb34641779c]
#    to [c77173aa37c0c6a9e628aa5528069ef3afddf6cb]
# 
# patch "tests/t_restrictions.at"
#  from [be72348a94c89d89703de67b40c886edc2bef302]
#    to [84972130299ee9cc3449101f4a4135795cf863f0]
# 
# patch "vocab.hh"
#  from [77bb3d7df9abc7e4e5202cb20b313c925dad2c13]
#    to [d6352245e0e2260db3f53cd0f7731a7bc07fd225]
# 
Index: app_state.cc
===================================================================
--- app_state.cc	976ea774c4fd1df5e9d63ee5b19f1a925899c12b
+++ app_state.cc	8efdcd302100554f04d225c9e5ddfe9ddc1bff3a
@@ -29,17 +29,17 @@ using namespace std;
 
 static string const database_option("database");
 static string const branch_option("branch");
 static string const key_option("key");
 
 app_state::app_state() 
   : branch_name(""), db(""), stdhooks(true), rcfiles(true), diffs(false),
     no_merges(false), set_default(false), verbose(false), search_root("/"),
-    depth(-1), last(-1)
+    depth(-1), last(-1), diff_format(unified_diff)
 {
   db.set_app(this);
 }
 
 app_state::~app_state()
 {
 }
 
@@ -347,16 +347,28 @@ app_state::add_revision(utf8 const & sel
 
 void
 app_state::add_exclude(utf8 const & exclude_pattern)
 {
   exclude_patterns.insert(exclude_pattern);
 }
 
 void
+app_state::set_diff_format(diff_type dtype)
+{
+  diff_format = dtype;
+}
+
+void
+app_state::set_diff_args(utf8 const & args)
+{
+  diff_args = args;
+}
+
+void
 app_state::set_stdhooks(bool b)
 {
   stdhooks = b;
 }
 
 void
 app_state::set_rcfiles(bool b)
 {
Index: app_state.hh
===================================================================
--- app_state.hh	ad40f04b056e67723f755a752d17e0ab7107dac4
+++ app_state.hh	15ba734efc432db709cc66ee01c7c104e5554e50
@@ -45,16 +45,18 @@ public:
   std::set<utf8> exclude_patterns;
   std::vector<utf8> extra_rcfiles;
   path_set restrictions;
   file_path relative_directory;
   bool found_working_copy;
   long depth;
   long last;
   fs::path pidfile;
+  diff_type diff_format;
+  utf8 diff_args;
 
   void allow_working_copy();
   void require_working_copy(std::string const & explanation = "");
   void create_working_copy(std::string const & dir);
 
   file_path prefix(utf8 const & path);
   void app_state::set_restriction(path_set const & valid_paths, 
                              std::vector<utf8> const & paths,
@@ -77,16 +79,18 @@ public:
   void set_message_file(utf8 const & message_file);
   void set_date(utf8 const & date);
   void set_author(utf8 const & author);
   void set_depth(long depth);
   void set_last(long last);
   void set_pidfile(utf8 const & pidfile);
   void add_revision(utf8 const & selector);
   void add_exclude(utf8 const & exclude_pattern);
+  void set_diff_format(diff_type dtype);
+  void set_diff_args(utf8 const & args);
 
   void set_stdhooks(bool b);
   void set_rcfiles(bool b);
   void set_verbose(bool b);
   void add_rcfile(utf8 const & filename);
 
   explicit app_state();
   ~app_state();
Index: commands.cc
===================================================================
--- commands.cc	668364db356c8b18906474160174ee9b30d7d699
+++ commands.cc	41f74675806bc533e9ecc46b5dfb5c3ffb09d263
@@ -2522,16 +2522,60 @@ CMD(commit, "working copy", "[PATH]...",
         certs.insert(make_pair(i->inner().name, vtmp));
       }
     app.lua.hook_note_commit(rid, certs);
   }
 }
 
 ALIAS(ci, commit);
 
+static void
+do_external_diff(change_set::delta_map const & deltas,
+                 app_state & app,
+                 bool new_is_archived)
+{
+  for (change_set::delta_map::const_iterator i = deltas.begin();
+       i != deltas.end(); ++i)
+    {
+      data data_old;
+      data data_new;
+
+      if (!null_id(delta_entry_src(i)))
+        {
+          file_data f_old;
+          app.db.get_file_version(delta_entry_src(i), f_old);
+          data_old = f_old.inner();
+        }
+
+      if (new_is_archived)
+        {
+          file_data f_new;
+          app.db.get_file_version(delta_entry_dst(i), f_new);
+          data_new = f_new.inner();
+        }
+      else
+        {
+          read_localized_data(delta_entry_path(i),
+                              data_new, app.lua);
+        }
+
+      bool is_binary = false;
+      if (guess_binary(data_old()) ||
+          guess_binary(data_new()))
+        is_binary = true;
+
+      app.lua.hook_external_diff(delta_entry_path(i),
+                                 data_old,
+                                 data_new,
+                                 is_binary,
+                                 app.diff_args(),
+                                 delta_entry_src(i).inner()(),
+                                 delta_entry_dst(i).inner()());
+    }
+}
 
 static void 
 dump_diffs(change_set::delta_map const & deltas,
            app_state & app,
            bool new_is_archived,
            diff_type type)
 {
   
@@ -2557,18 +2601,19 @@ dump_diffs(change_set::delta_map const &
           
           if (guess_binary(unpacked()))
             cout << "# " << delta_entry_path(i) << " is binary\n";
           else
             {     
               split_into_lines(unpacked(), lines);
               if (! lines.empty())
                 {
-                  cout << (F("--- %s\n") % delta_entry_path(i))
-                       << (F("+++ %s\n") % delta_entry_path(i))
+                  cout << "===============================================\n";
+                  cout << (F("--- %s\t%s\n") % delta_entry_path(i) % delta_entry_src(i))
+                       << (F("+++ %s\t%s\n") % delta_entry_path(i) % delta_entry_dst(i))
                        << (F("@@ -0,0 +1,%d @@\n") % lines.size());
                   for (vector<string>::const_iterator j = lines.begin();
                        j != lines.end(); ++j)
                     {
                       cout << "+" << *j << endl;
                     }
                 }
             }
@@ -2598,31 +2643,38 @@ dump_diffs(change_set::delta_map const &
               guess_binary(data_old()))
             cout << "# " << delta_entry_path(i) << " is binary\n";
           else
             {
               split_into_lines(data_old(), old_lines);
               split_into_lines(data_new(), new_lines);
               make_diff(delta_entry_path(i)(), 
                         delta_entry_path(i)(), 
+                        delta_entry_src(i),
+                        delta_entry_dst(i),
                         old_lines, new_lines,
                         cout, type);
             }
         }
     }
 }
 
-void do_diff(const string & name, 
-             app_state & app, 
-             vector<utf8> const & args, 
-             diff_type type)
+CMD(diff, "informative", "[PATH]...", 
+    "show current diffs on stdout.\n"
+    "If one revision is given, the diff between the working directory and\n"
+    "that revision is shown.  If two revisions are given, the diff between\n"
+    "them is given.  If no format is specified, unified is used by default.",
+    OPT_BRANCH_NAME % OPT_REVISION % OPT_DEPTH %
+    OPT_UNIFIED_DIFF % OPT_CONTEXT_DIFF % OPT_EXTERNAL_DIFF %
+    OPT_EXTERNAL_DIFF_ARGS)
 {
   revision_set r_old, r_new;
   manifest_map m_new;
   bool new_is_archived;
+  diff_type type = app.diff_format;
 
   change_set composite;
 
   // initialize before transaction so we have a database to work with
 
   if (app.revision_selectors.size() == 0)
     app.require_working_copy();
   else if (app.revision_selectors.size() == 1)
@@ -2721,37 +2773,20 @@ void do_diff(const string & name, 
         cout << "# " << *i << endl;
     }
   else
     {
       cout << F("# no changes") << endl;
     }
   cout << "# " << endl;
 
-  dump_diffs(composite.deltas, app, new_is_archived, type);
-}
-
-CMD(cdiff, "informative", "[PATH]...", 
-    "show current context diffs on stdout.\n"
-    "If one revision is given, the diff between the working directory and\n"
-    "that revision is shown.  If two revisions are given, the diff between\n"
-    "them is given.",
-    OPT_BRANCH_NAME % OPT_REVISION % OPT_DEPTH)
-{
-  do_diff(name, app, args, context_diff);
-}
-
-CMD(diff, "informative", "[PATH]...", 
-    "show current unified diffs on stdout.\n"
-    "If one revision is given, the diff between the working directory and\n"
-    "that revision is shown.  If two revisions are given, the diff between\n"
-    "them is given.",
-    OPT_BRANCH_NAME % OPT_REVISION % OPT_DEPTH)
-{
-  do_diff(name, app, args, unified_diff);
+  if (type == external_diff) {
+    do_external_diff(composite.deltas, app, new_is_archived);
+  } else
+    dump_diffs(composite.deltas, app, new_is_archived, type);
 }
 
 CMD(lca, "debug", "LEFT RIGHT", "print least common ancestor", OPT_NONE)
 {
   if (args.size() != 2)
     throw usage(name);
 
   revision_id anc, left, right;
Index: diff_patch.cc
===================================================================
--- diff_patch.cc	fbef84d6f575c4f14850b8a8e7d78e42021a0e80
+++ diff_patch.cc	022e125cb1265ea8d0a484289b952587060053cc
@@ -1074,16 +1074,18 @@ void cxtdiff_hunk_writer::advance_to(siz
           a_len++;
           b_len++;        
         }
     }
 }
 
 void make_diff(string const & filename1,
                string const & filename2,
+               file_id const & id1,
+               file_id const & id2,
                vector<string> const & lines1,
                vector<string> const & lines2,
                ostream & ost,
                diff_type type)
 {
   vector<long, QA(long)> left_interned;  
   vector<long, QA(long)> right_interned;  
   vector<long, QA(long)> lcs;  
@@ -1105,32 +1107,40 @@ void make_diff(string const & filename1,
                              right_interned.begin(), right_interned.end(),
                              std::min(lines1.size(), lines2.size()),
                              back_inserter(lcs));
 
   switch (type)
     {
       case unified_diff:
       {
-        ost << "--- " << filename1 << endl;
-        ost << "+++ " << filename2 << endl;
+        ost << "===============================================" << endl;
+        ost << "--- " << filename1 << "\t" << id1 << endl;
+        ost << "+++ " << filename2 << "\t" << id2 << endl;
 
         unidiff_hunk_writer hunks(lines1, lines2, 3, ost);
         walk_hunk_consumer(lcs, left_interned, right_interned, hunks);
         break;
       }
       case context_diff:
       {
-        ost << "*** " << filename1 << endl;
-        ost << "--- " << filename2 << endl;
+        ost << "===============================================" << endl;
+        ost << "*** " << filename1 << "\t" << id1 << endl;
+        ost << "--- " << filename2 << "\t" << id2 << endl;
 
         cxtdiff_hunk_writer hunks(lines1, lines2, 3, ost);
         walk_hunk_consumer(lcs, left_interned, right_interned, hunks);
         break;
       }
+      default:
+      {
+        // should never reach this; the external_diff type is not
+        // handled by this function.
+        I(false);
+      }
     }
 }
 
 #ifdef BUILD_UNIT_TESTS
 #include "unit_tests.hh"
 #include "transforms.hh"
 #include <boost/lexical_cast.hpp>
 #include "randomfile.hh"
@@ -1190,34 +1200,39 @@ static void unidiff_append_test()
              + "}\n"
              + "\n"
              + "void say_goodbye()\n"
              + "{\n"
              + "        printf(\"goodbye\\n\");\n"
              + "}\n"
              + "\n");
   
-  string ud(string("--- hello.c\n")
-            + "+++ hello.c\n"
+  string ud(string("===============================================\n")
+            + "--- hello.c\t0123456789abcdef0123456789abcdef01234567\n"
+            + "+++ hello.c\tabcdef0123456789abcdef0123456789abcdef01\n"
             + "@@ -9,3 +9,9 @@\n"
             + " {\n"
             + "         say_hello();\n"
             + " }\n"
             + "+\n"
             + "+void say_goodbye()\n"
             + "+{\n"
             + "+        printf(\"goodbye\\n\");\n"
             + "+}\n"
             + "+\n");
 
   vector<string> src_lines, dst_lines;
   split_into_lines(src, src_lines);
   split_into_lines(dst, dst_lines);
   stringstream sst;
-  make_diff("hello.c", "hello.c", src_lines, dst_lines, sst, unified_diff);
+  make_diff("hello.c", "hello.c",
+            file_id(id("0123456789abcdef0123456789abcdef01234567")),
+            file_id(id("abcdef0123456789abcdef0123456789abcdef01")),
+            src_lines, dst_lines, sst, unified_diff);
+  cout << sst.str() << std::endl;
   BOOST_CHECK(sst.str() == ud);
 }
 
 
 // high tech randomizing test
 
 static void randomizing_merge_test()
 {
Index: diff_patch.hh
===================================================================
--- diff_patch.hh	18be28ae5d744c23da230988bd4a48f6556cb4b4
+++ diff_patch.hh	f499e229bf13e49c06c4c9129a1e48b2b1a7ef65
@@ -14,25 +14,20 @@
 #include <vector>
 #include <iostream>
 
 struct conflict {};
 
 // this file is to contain some stripped down, in-process implementations
 // of GNU-diffutils-like things (diff, diff3, maybe patch..)
 
-
-enum diff_type
-{
-  unified_diff,
-  context_diff
-};
-
 void make_diff(std::string const & filename1,
                std::string const & filename2,
+               file_id const & id1,
+               file_id const & id2,
                std::vector<std::string> const & lines1,
                std::vector<std::string> const & lines2,
                std::ostream & ost,
                diff_type type);
 
 bool merge3(std::vector<std::string> const & ancestor,
             std::vector<std::string> const & left,
             std::vector<std::string> const & right,
Index: lua.cc
===================================================================
--- lua.cc	a8af56ad7fe0d9baa85c265b05dd94877a806c19
+++ lua.cc	7f7d2cd8e90e9224d82fc66216093307306fa653
@@ -1018,16 +1018,50 @@ lua_hooks::hook_resolve_dir_conflict(fil
     .push_str(b())
     .call(3,1)
     .extract_str(tmp)
     .ok();
   res = tmp;
   return ok;  
 }
 
+bool
+lua_hooks::hook_external_diff(file_path const & path,
+                              data const & data_old,
+                              data const & data_new,
+                              bool is_binary,
+                              std::string const & diff_args,
+                              std::string const & oldrev,
+                              std::string const & newrev)
+{
+  Lua ll(st);
+
+  ll
+    .func("external_diff")
+    .push_str(path());
+
+  if (oldrev.length() != 0)
+    ll.push_str(data_old());
+  else
+    ll.push_nil();
+
+  ll.push_str(data_new());
+
+  ll.push_bool(is_binary);
+
+  if (diff_args.length() != 0)
+    ll.push_str(diff_args);
+  else
+    ll.push_nil();
+
+  ll.push_str(oldrev);
+  ll.push_str(newrev);
+
+  return ll.call(7,0).ok();
+}
 
 bool
 lua_hooks::hook_use_inodeprints()
 {
   bool use = false, exec_ok = false;
 
   exec_ok = Lua(st)
     .func("use_inodeprints")
Index: lua.hh
===================================================================
--- lua.hh	0c4f6966a60230b591f07d0a0519485bf451a349
+++ lua.hh	517f80335c5433b0134e70a53f0d26f9563151dc
@@ -90,16 +90,24 @@ public:
                                   file_path const & b,
                                   file_path & res);
 
   bool hook_resolve_dir_conflict(file_path const & anc,
                                  file_path const & a,
                                  file_path const & b,
                                  file_path & res);
 
+  bool hook_external_diff(file_path const & path,
+                          data const & data_old,
+                          data const & data_new,
+                          bool is_binary,
+                          std::string const & diff_args,
+                          std::string const & oldrev,
+                          std::string const & newrev);
+
   // working copy hooks
   bool hook_use_inodeprints();
 
   // attribute hooks
   bool hook_init_attributes(file_path const & filename,
                             std::map<std::string, std::string> & attrs);
   bool hook_apply_attribute(std::string const & attr, 
                             file_path const & filename, 
Index: monotone.cc
===================================================================
--- monotone.cc	240b0908b7d873c84df7cd1ca676d44a490b778f
+++ monotone.cc	46cbc3c75c039ef547e3d566c79fd33a2acdcf52
@@ -54,16 +54,20 @@ struct poptOption coptions[] =
     {"depth", 0, POPT_ARG_LONG, &arglong, OPT_DEPTH, "limit the number of levels of directories to descend", NULL},
     {"last", 0, POPT_ARG_LONG, &arglong, OPT_LAST, "limit the log output to the given number of entries", NULL},
     {"pid-file", 0, POPT_ARG_STRING, &argstr, OPT_PIDFILE, "record process id of server", NULL},
     {"brief", 0, POPT_ARG_NONE, NULL, OPT_BRIEF, "print a brief version of the normal output", NULL},
     {"diffs", 0, POPT_ARG_NONE, NULL, OPT_DIFFS, "print diffs along with logs", NULL},
     {"no-merges", 0, POPT_ARG_NONE, NULL, OPT_NO_MERGES, "skip merges when printing logs", NULL},
     {"set-default", 0, POPT_ARG_NONE, NULL, OPT_SET_DEFAULT, "use the current arguments as the future default", NULL},
     {"exclude", 0, POPT_ARG_STRING, &argstr, OPT_EXCLUDE, "leave out branches matching a pattern", NULL},
+    {"unified", 0, POPT_ARG_NONE, NULL, OPT_UNIFIED_DIFF, "Use unified diff format", NULL},
+    {"context", 0, POPT_ARG_NONE, NULL, OPT_CONTEXT_DIFF, "Use context diff format", NULL},
+    {"external", 0, POPT_ARG_NONE, NULL, OPT_EXTERNAL_DIFF, "Use external diff hook for generating diffs", NULL},
+    {"diff-args", 0, POPT_ARG_STRING, &argstr, OPT_EXTERNAL_DIFF_ARGS, "Argument to pass external diff hook", NULL},
     { NULL, 0, 0, NULL, 0, NULL, NULL }
   };
 
 struct poptOption options[] =
   {
     // Use the coptions table as well.
     { NULL, 0, POPT_ARG_INCLUDE_TABLE, coptions, 0, NULL, NULL },
 
@@ -402,16 +406,32 @@ cpp_main(int argc, char ** argv)
             case OPT_PIDFILE:
               app.set_pidfile(absolutify(tilde_expand(string(argstr))));
               break;
 
             case OPT_ARGFILE:
               my_poptStuffArgFile(ctx(), utf8(string(argstr)));
               break;
 
+            case OPT_UNIFIED_DIFF:
+              app.set_diff_format(unified_diff);
+              break;
+
+            case OPT_CONTEXT_DIFF:
+              app.set_diff_format(context_diff);
+              break;
+
+            case OPT_EXTERNAL_DIFF:
+              app.set_diff_format(external_diff);
+              break;
+              
+            case OPT_EXTERNAL_DIFF_ARGS:
+              app.set_diff_args(utf8(string(argstr)));
+              break;
+
             case OPT_HELP:
             default:
               requested_help = true;
               break;
             }
         }
 
       // verify that there are no errors in the command line
Index: monotone.texi
===================================================================
--- monotone.texi	80f97d74395a57fc85b24b54329d0c10f1639c99
+++ monotone.texi	9e37ce22ceb10715bf1ed4efa1fe44f1b1d02a22
@@ -5830,16 +5830,30 @@ attr_init_functions["manual_merge"] = 
       end 
    end
 @end group
 @end smallexample
 
 The @code{binary_file} function is also defined as a lua hook. See
 @ref{Default hooks}. 
 
[EMAIL PROTECTED] external_diff (@var{file_path}, @var{old_data}, @var{new_data}, @var{is_binary},
+                     @var{diff_args}, @var{old_rev}, @var{new_rev})
+
+Called for each file when @command{diff} is given the
[EMAIL PROTECTED] command.  @var{file_path} is the pathname of the
+file that is being diffed.  @var{old_data} and @var{new_data} are the
+data contents of the old and the new file.  If the data is binary,
[EMAIL PROTECTED] will be true, otherwise false.  @var{old_rev} and
[EMAIL PROTECTED] are the revision IDs of the old and new data.
+
+If an extra arguments are given via @option{--diff-args}, the string
+will be passed in as @var{diff_args}.  Otherwise @var{diff_args} will
+be nil.
+
 @end ftable
 
 @page
 @node   Additional Lua Functions
 @section Additional Lua Functions
 
 This section documents the additional lua functions made available to
 hook writers. 
Index: options.hh
===================================================================
--- options.hh	2d21f8009f424d24e5513c3894c0ff321e79feb0
+++ options.hh	814c3c354201a830e7bce20f0a8dc48d79b9cf8c
@@ -32,8 +32,12 @@
 #define OPT_MSGFILE 23
 #define OPT_BRIEF 24
 #define OPT_DIFFS 25
 #define OPT_NO_MERGES 26
 #define OPT_LAST 27
 #define OPT_VERBOSE 28
 #define OPT_SET_DEFAULT 29
 #define OPT_EXCLUDE 30
+#define OPT_UNIFIED_DIFF 31
+#define OPT_CONTEXT_DIFF 32
+#define OPT_EXTERNAL_DIFF 33
+#define OPT_EXTERNAL_DIFF_ARGS 34
Index: std_hooks.lua
===================================================================
--- std_hooks.lua	072c95bc58425ade43dc08e8361c7aca49275dd4
+++ std_hooks.lua	80a530bdeb7e4526a8b97c9f9d6c071a7b1f05e0
@@ -605,8 +605,19 @@ function expand_date(str)
    end
    
    return nil
 end
 
 function use_inodeprints()
    return false
 end
+
+-- default external diff, works for gnu diff
+function external_diff(file_path, data_old, data_new, is_binary, diff_args, rev_old, rev_new)
+   local old_file = write_to_temporary_file(data_old);
+   local new_file = write_to_temporary_file(data_new);
+
+   execute("diff", "-upNU8", "--label", file_path .. "\told", old_file, "--label", file_path .. "\tnew", new_file);
+
+   os.remove (old_file);
+   os.remove (new_file);
+end
Index: tests/t_crlf.at
===================================================================
--- tests/t_crlf.at	ac04c64a00a9691b7599320562dacdb34641779c
+++ tests/t_crlf.at	c77173aa37c0c6a9e628aa5528069ef3afddf6cb
@@ -7,11 +7,11 @@ AT_CHECK(cp stdout test.crlf)
 AT_CHECK(MONOTONE add test.crlf, [], [ignore], [ignore])
 COMMIT(testbranch)
 
 AT_CHECK(printf "a\r\nb\r\nnew line!\r\nc\r\nd\r\n", [], [stdout])
 AT_CHECK(cp stdout test.crlf)
 
 AT_CHECK(MONOTONE diff, [], [stdout], [ignore])
 LINES=`wc -l <stdout`
-AT_CHECK(test $LINES -eq 13) 
+AT_CHECK(test $LINES -eq 14) 
 
 AT_CLEANUP
Index: tests/t_restrictions.at
===================================================================
--- tests/t_restrictions.at	be72348a94c89d89703de67b40c886edc2bef302
+++ tests/t_restrictions.at	84972130299ee9cc3449101f4a4135795cf863f0
@@ -165,20 +165,20 @@ AT_CHECK(MONOTONE diff, [], [stdout], [i
 AT_CHECK(INCLUDED(X 1 2 3 4), [0], [ignore])
 
 AT_CHECK(MONOTONE diff --depth=0 . , [], [stdout], [ignore])
 AT_CHECK(grep fileAB stdout, [1], [ignore])
 
 AT_CHECK(MONOTONE diff --depth=2 . , [], [stdout], [ignore])
 AT_CHECK(grep fileA stdout, [0], [ignore])
 
-AT_CHECK(MONOTONE cdiff --depth=0 . , [], [stdout], [ignore])
+AT_CHECK(MONOTONE diff --context --depth=0 . , [], [stdout], [ignore])
 AT_CHECK(grep fileAB stdout, [1], [ignore])
 
-AT_CHECK(MONOTONE cdiff --depth=2 . , [], [stdout], [ignore])
+AT_CHECK(MONOTONE diff --context --depth=2 . , [], [stdout], [ignore])
 AT_CHECK(grep fileA stdout, [0], [ignore])
 
 # include both source and target of rename
 
 AT_CHECK(MONOTONE diff work/fileX work/file1, [], [stdout], [ignore])
 AT_CHECK(INCLUDED(X 1), [0], [ignore])
 AT_CHECK(EXCLUDED(2 3 4), [0], [ignore])
 
Index: vocab.hh
===================================================================
--- vocab.hh	77bb3d7df9abc7e4e5202cb20b313c925dad2c13
+++ vocab.hh	d6352245e0e2260db3f53cd0f7731a7bc07fd225
@@ -139,9 +139,18 @@ namespace fs = boost::filesystem;
 
 // kludge: certs are derived types. what else can we do?
 #ifndef __CERT_HH__
 #include "cert.hh"
 extern template class revision<cert>;
 extern template class manifest<cert>;
 #endif
 
+// diff type
+enum diff_type
+{
+  unified_diff,
+  context_diff,
+  external_diff
+};
+
+
 #endif // __VOCAB_HH__
_______________________________________________
Monotone-devel mailing list
Monotone-devel@nongnu.org
http://lists.nongnu.org/mailman/listinfo/monotone-devel

Reply via email to