python实现web svn diff

最近想做一个在线codereivew的功能,需要在web页面上分两栏(side-by-side)展示新老代码的差异(diff)。

在github参考了一些项目,例如:coderev、cdiff;经过一定的尝试,最终选择了使用Python来实现这个功能,因为python内置的difflib标准库里有一个计算diff的函数是专门用来生成两栏(side-by-side)视图用的,而这个算法是挺复杂的,网上并没有资料讲解,所以拿来即用吧。

项目地址:https://github.com/owenliang/side-by-side-diff

项目效果:https://owenliang.github.io/side-by-side-diff/sample/side-by-side-view.html

思路

生成patch

首先,需要生成diff内容,也就是patch。这种patch文件的格式如下:

一般我们通过svn diff或者git diff就可以生成,或者通过diff -u filename1 filename2也可以生成。

解析patch

我们需要解析patch文件,这个过程并不复杂。

类似于这种段落,表示是某个文件发生了变更:

类似于这种段落,表示文件内的某一段发生了变化:

可见,上述段落删掉了一行,又增加了一行,相当于替换了原先的行。

而没有-号与+号的行,称为上下文(context)行,表示新老文件都拥有且没有变化过的行。

还原老与新段落

对于上述每个段落,我们需要还原出老文件和新文件。

context和-的行是老文件拥有的,而context和+的行是新文件拥有的,通过这样划分就可以得到每个差异段落的老内容和新内容。

调用python重算diff

现在可以将每个段落的老内容和新内容,作为一个pair传递给python的difflib._mdiff函数,这个函数会计算返回一个数组,每一个元素代表了双栏(side-by-side)视图中的一行。

我们需要根据_mdiff的返回值,对新老的行号进行重新标记。

在我的diff.py程序中,最终输出的结果在这里查看:https://raw.githubusercontent.com/owenliang/side-by-side-diff/master/sample/diff.json

可以观察到,最外层数组是若干的index,即发生变化的文件。

而index.segments里的每一个元素则是一个发生差异的段落。

段落内的rows记录了差异的行,我们只需要顺序的展示为两栏即可;左侧是老文件的行内容,右侧是新文件的行内容,红色标识变化前的行,绿色标识变化后的行。

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~