Hi Benjamin!
On Fr, 08 Jun 2012, Benjamin Fritz wrote:
> I've been working on a plugin to provide a manual diff alignment feature,
> similar to KDiff3 or BeyondCompare. The idea is that a human can sometimes
> figure out which lines should be shown side-by-side in a diff than a
> computer can, so we should let them.
>
> :help diff-diffexpr simply says:
>
> > The output of "diff" must be a normal "ed" style diff. Do NOT use a context
> > diff. This example explains the format that Vim expects: >
> >
> > 1a2
> > > bbb
> > 4d4
> > < 111
> > 7c7
> > < GGG
> > ---
> > > ggg
> >
> > The "1a2" item appends the line "bbb".
> > The "4d4" item deletes the line "111".
> > The '7c7" item replaces the line "GGG" with "ggg".
>
> I took this to mean that any valid ed-style diff can be generated by the
> diffexpr and used by Vim. I assumed that Vim would basically use the hunks
> in the diff to place filler lines and align the text for each buffer. with
> this assumption, my design for the manual alignment was to break each file
> into chunks, write the chunks with writefile(), diff the chunks, and
> combine the output of those diffs into one big diff for diffexpr to
> finally return to Vim (correcting line numbers based on the starting line
> number of the current chunk). For simple diffs, this seems to work fine.
> See the attached diff2_with_alignment.png.
>
> But, a slightly more complicated example is shown in
> diff_without_alignment.png. This is the view before using the plugin to
> align things; the ed-style diff is attached as orig.patch.
>
> Using my plugin, the diffexpr can generate the aligned.patch output. I can
> use GNU patch and this patch to transform either file into the other
> without errors. However, Vim displays the diff as shown in
> diff_with_alignment.png. Note that there is no diff filler whatsoever, and
> the highlighting is wrong! This also happens in gvim -N -u NONE -i NONE,
> after sourcing my plugin and running a diff.
>
> I think I've accidentally uncovered a bug in Vim; or at least, an
> undocumented dependency on a specific diff *algorithm*, not just any old
> ed-style diff format. I spent a few minutes looking at the code in diff.c,
> but it looks like I'll need to spend a couple hours at least just to
> figure out what's going on in there. Any help? Am I doing something wrong?
>
> Current version of the plugin is attached if you want to play with it and
> generate the diffs yourself, otherwise see the attached diffs and
> screenshots.
>
How did you generate the aligned.patch file? No matter what I do, for me
the plugin always generates:
2,7c2,4
< a
< b
< cb
< db
< eb
< f
---
> cc
> dd
> ee
But perhaps, I'm using your plugin wrongly, e.g. how many alignemnt
points do I have to set and where? But even after I manually copied the
aligned.patch file over the resulting file, Vim still gets the alignment
wrong.
BTW: attached is a patch, that prevents the use of using diffexpr for
checking if diff really works (using the "line1" vs. "line2" check):
regards,
Christian
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
diff --git a/src/diff.c b/src/diff.c
--- a/src/diff.c
+++ b/src/diff.c
@@ -42,7 +42,7 @@
static int diff_check_sanity __ARGS((tabpage_T *tp, diff_T *dp));
static void diff_redraw __ARGS((int dofold));
static int diff_write __ARGS((buf_T *buf, char_u *fname));
-static void diff_file __ARGS((char_u *tmp_orig, char_u *tmp_new, char_u *tmp_diff));
+static void diff_file __ARGS((char_u *tmp_orig, char_u *tmp_new, char_u *tmp_diff, int doit));
static int diff_equal_entry __ARGS((diff_T *dp, int idx1, int idx2));
static int diff_cmp __ARGS((char_u *s1, char_u *s2));
#ifdef FEAT_FOLDING
@@ -716,7 +716,7 @@
if (fwrite("line2\n", (size_t)6, (size_t)1, fd) != 1)
io_error = TRUE;
fclose(fd);
- diff_file(tmp_orig, tmp_new, tmp_diff);
+ diff_file(tmp_orig, tmp_new, tmp_diff, FALSE);
fd = mch_fopen((char *)tmp_diff, "r");
if (fd == NULL)
io_error = TRUE;
@@ -805,7 +805,7 @@
continue;
if (diff_write(buf, tmp_new) == FAIL)
continue;
- diff_file(tmp_orig, tmp_new, tmp_diff);
+ diff_file(tmp_orig, tmp_new, tmp_diff, TRUE);
/* Read the diff output and add each entry to the diff list. */
diff_read(idx_orig, idx_new, tmp_diff);
@@ -829,16 +829,17 @@
* Make a diff between files "tmp_orig" and "tmp_new", results in "tmp_diff".
*/
static void
-diff_file(tmp_orig, tmp_new, tmp_diff)
+diff_file(tmp_orig, tmp_new, tmp_diff, doit)
char_u *tmp_orig;
char_u *tmp_new;
char_u *tmp_diff;
+ int doit; /* FALSE, when checking diff works, TRUE when really using a diff */
{
char_u *cmd;
size_t len;
#ifdef FEAT_EVAL
- if (*p_dex != NUL)
+ if (*p_dex != NUL && doit)
/* Use 'diffexpr' to generate the diff file. */
eval_diff(tmp_orig, tmp_new, tmp_diff);
else