[JS 工具] 格式化显示 mailman 上的 diff 文本

公司使用 mailman 来显示 patch,mailman 显示的改动只有一堆黑白文字,难以辨认。有时候还把 patch 当成文件再 git add 一遍后再生成一个新的 patch,这时候对于原来 patch 的代码改动来说,整个 patch 都是新增代码,就更加难以看出改动在哪,给 review patch 带来不必要的不便。

 

有天我想可不可以做成跟 github 一样,至少增删有不同的颜色标记出来。但是又接触不到 mailman 的server,不能改动它的代码。

 

受启发于 Chrome 插件的 JS 文件注入启发,做了这样一个标签式的插件。只要把链接拖动到浏览器书签栏上生成标签,点击标签就可以生效。

 

 

 

我觉得这样的方式至少有如下几个优点:

1. 免安装,服务器简单,又不需要修改到原网页代码

2. 脚本无缝迭代版本,如果是不兼容的迭代,大不了重新生成个链接让用户拖动就可以了

3. 是否插入脚本过程可控,对于不需要转化的网页,不加载脚本就是了

 

<a class="bookmark-link" onclick="handleClick(); return false;" href="javascript: void((function() {var element = document.createElement('script');element.charset = 'utf-8',element.setAttribute('src', 'http://127.0.0.1:5120/pretty.js');document.body.appendChild(element);})())"><span>Pretty-Patch</span></a>

标签代码

 

function handleClick() {
        alert("Drag me to the Bookmarks Bar");
        return false;
    }

如果用户点击链接而不是拖动,就提示他/她

 

javascript: void ((function () {
    var element = document.createElement('script');
    element.charset = 'utf-8';
    element.setAttribute('src', 'http://127.0.0.1:5120/pretty.js');
    document.body.appendChild(element); }
)())

拖动链接到浏览器书签栏上形成是书签的链接执行了以上代码。javascript: void() 就是执行一段不需要返回值的表达式,这里是一个自执行的匿名函数。在这个匿名函数里创建了 script 标签,并将 src 属性设置到脚本所在的位置,这样就在当前网页插入了我们的脚本。

 

我在 pretty.js 里放入了 jquery 的代码,还有一个最重要的开源库 “diff2html” 的 js 代码,将它的 css 文件内容复制出来当成字符串存到 prettyStyle 变量。

 

var extralStyle = '.d2h-file-wrapper{margin-top:30px; margin-bottom:30px;} body{margin:30px} .copyright{width:100%; text-align:center; margin-top:10px; font-size:0.9em; color:gray;}'

prettyStyle += extralStyle;

自定义的 css 内容附加到 prettyStyle 变量上

 

接下来所有自己的 js 代码都放到了一个自执行的匿名函数 (function() { ....... })() 防止污染全局变量。虽然也没啥必要,因为这个注入的 js 文件破坏性地更改了页面,但是是一种习惯吧。

 


var diffOption = {inputFormat: 'diff', showFiles: true, matching: 'lines'};
 
if($("#defeng-is-a-nice-person").length !== 0) {
        top.document.location.reload();
        return;
    }

这个 id 是注入的 js 文件设置的,这里判断了是否有这个 id,如果有,说明页面以及被格式化了,那么用户再点击一次标签,就重载页面,让用户看到原始页面

 

var data = $("pre").text();
if(data === undefined)
    return;
data = data.replace(/\r\n/g, "\n").trim();
data = removeFooter(data);

获得 patch 内容

 

if(data.indexOf("\n+diff --git") === -1 && data.indexOf("\n+@@ -") === -1) {
        prettyPatch(data);
    }
    else {
        $("body").empty();
        var splitStr = "\ndiff --git ";
        var filesArr = [];

        var headEnd = data.indexOf(splitStr);
        if(headEnd === -1)
            return;
        data = data.slice(headEnd);

        var each = data.split(splitStr);
        each.shift();
        if(each.length === 0)
            return;
        var len = each.length;
        splitStr = splitStr.slice(1);
        for(var i=0; i<len; i++) {
            each[i] = splitStr + each[i] + "\n";
        }

        prettyPatchPlus(each);
    }

因为有如下好几种情况:

  • patch 是用 diff 生成的
  • patch 是用 git format-patch 生成的
  • patch 被当作文件又被 git add 后生成新 patch,且还包含 diff 的patch 或者 git format-patch 的 patch

对于前两种情况,直接用 prettyPatch 函数生成结果就可以了

对于内容里包含有 patch 的情况,用 "\ndiff --git " 作为分隔符将每个文件分割出来后用 prettyPatchPlus 函数生成结果

 

function removeFooter(str) {
        return str.trim().replace(/.*?--\s*\n\s*\d+(.\d+)+$/, "");
    }

这个函数用来移除最后面的 git 版本号

 

function prettyPatch(str) {
        var diff2htmlUi = new Diff2HtmlUI({diff: str});
        diff2htmlUi.draw('body', diffOption);
    }

只要将 diff 文本直接交给 diff2html 库,就可以生成结果用来替换 body 内容

 

function prettyPatchPlus(each) {
    var len = each.length;
    var found = false;
    for(var i=0; i<len; i++) {
        var oneFile = each[i];
        var lines = oneFile.split("\n");
        var lineLen = lines.length;
        if(oneFile.indexOf("\n++++ ") !== -1) {
            var rmHeader = -1;
            for(var i=0; i<lineLen; i++) {
                var line = lines[i];
                if(line.slice(0, 3) === "+++" && line.slice(-6) === ".patch") {
                    rmHeader = i + 1;
                    continue;
                }
                if(rmHeader === -1) {
                    continue;
                }
                if(line.slice(0, 1) === "+") {
                    lines[i] = line.slice(1);
                }
            }
            oneFile = lines.slice(rmHeader).join("\n");
            oneFile = removeFooter(oneFile);
        }
        var id = "path-plus-list-" + i;
        $("<div id='" + id +"'></div>").appendTo("body");
        var diff2htmlList = new Diff2HtmlUI({diff: oneFile});
        diff2htmlList.draw('#' + id, diffOption);
    }
}

prettyPatchPlus函数通过判断是否有 "\n++++ " 来判断一个文件是 diff 文本还是 patch,如果是 patch,将每一行最前面的 + 号移除。

将生成的结果替换到 body 下的 div 标签

 

$("<style>" + prettyStyle + "</style>").appendTo("head");

附加 diff2html 的 css 样式和自定义样式

 

$("body").attr("id", "defeng-is-a-nice-person");

标记这页面是经过脚本转化的

 

var publish = "2017";
    var current = (new Date()).getFullYear();
    var copyright = "copyright ©2017" + (current == publish? "": "-" + current) + " DNI-XM";
    copyright += "\tdefeng.liu@deltaww.com";
    $("<hr/><div class='copyright'><span>" + copyright + "</span><div>").appendTo("body");

附加 copyright

 

posted @ 2018-01-14 20:58  liqingjht  阅读(769)  评论(0编辑  收藏  举报