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