xref: /OpenGrok/opengrok-web/src/main/webapp/diff.jsp (revision 8628dcedd3ef37bfcd111f86fbea62a0193d0437)
1<%--
2CDDL HEADER START
3
4The contents of this file are subject to the terms of the
5Common Development and Distribution License (the "License").
6You may not use this file except in compliance with the License.
7
8See LICENSE.txt included in this distribution for the specific
9language governing permissions and limitations under the License.
10
11When distributing Covered Code, include this CDDL HEADER in each
12file and include the License file at LICENSE.txt.
13If applicable, add the following below this CDDL HEADER, with the
14fields enclosed by brackets "[]" replaced with your own identifying
15information: Portions Copyright [yyyy] [name of copyright owner]
16
17CDDL HEADER END
18
19Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
20Portions Copyright 2011 Jens Elkner.
21Portions Copyright (c) 2020, Chris Fraire <cfraire@me.com>.
22--%>
23<%@page errorPage="error.jsp" import="
24java.io.ByteArrayInputStream,
25java.io.OutputStream,
26java.io.InputStream,
27java.nio.charset.StandardCharsets,
28
29org.suigeneris.jrcs.diff.delta.Chunk,
30org.suigeneris.jrcs.diff.delta.Delta,
31org.opengrok.indexer.analysis.AbstractAnalyzer,
32org.opengrok.web.DiffData,
33org.opengrok.web.DiffType"
34%>
35<%!
36private String getAnnotateRevision(DiffData data) {
37    if (data.getType() == DiffType.OLD || data.getType() == DiffType.NEW) {
38        String rev = data.getRev(data.getType() == DiffType.NEW ? 1 : 0);
39        return "<script type=\"text/javascript\">/* <![CDATA[ */ "
40            + "document.rev = function() { return " + Util.htmlize(Util.jsStringLiteral(rev))
41            + "; } /* ]]> */</script>";
42    }
43    return "";
44}
45%>
46<%
47{
48    PageConfig cfg = PageConfig.get(request);
49    cfg.addScript("diff");
50    cfg.checkSourceRootExistence();
51    /**
52     * This block must be the first block before any other output in the
53     * response.
54     *
55     * If there is already any output written into the response, and we
56     * use the same response and reset the content and the headers then we have
57     * a collision with the response streams and the "getOutputStream() has
58     * already been called" exception occurs.
59     */
60    DiffData data = cfg.getDiffData();
61    request.setAttribute("diff.jsp-data", data);
62    if (data.getType() == DiffType.TEXT
63            && request.getParameter("action") != null
64            && request.getParameter("action").equals("download")) {
65        try (OutputStream o = response.getOutputStream()) {
66            for (int i = 0; i < data.getRevision().size(); i++) {
67                Delta d = data.getRevision().getDelta(i);
68                try (InputStream in = new ByteArrayInputStream(d.toString().getBytes(StandardCharsets.UTF_8))) {
69                    response.setHeader("content-disposition", "attachment; filename="
70                            + cfg.getResourceFile().getName() + "@" + data.getRev(0)
71                            + "-" + data.getRev(1) + ".diff");
72                    byte[] buffer = new byte[8192];
73                    int nr;
74                    while ((nr = in.read(buffer)) > 0) {
75                        o.write(buffer, 0, nr);
76                    }
77                }
78            }
79            o.flush();
80            o.close();
81            return;
82        }
83    }
84}
85%><%@
86
87include file="mast.jsp"
88
89%><%
90/* ---------------------- diff.jsp start --------------------- */
91{
92    PageConfig cfg = PageConfig.get(request);
93    DiffData data = (DiffData) request.getAttribute("diff.jsp-data");
94
95    // the data is never null as the getDiffData always return valid object
96    if (data.getErrorMsg() != null)  {
97
98%>
99<div class="src">
100    <h3 class="error">Error:</h3>
101    <p><%= data.getErrorMsg() %></p>
102</div><%
103    } else if (data.getGenre() == AbstractAnalyzer.Genre.IMAGE) {
104
105        String link = request.getContextPath() + Prefix.DOWNLOAD_P
106            + Util.htmlize(cfg.getPath());
107%>
108<div id="difftable">
109    <table class="image" aria-label="table with old and new image">
110        <thead>
111        <tr><th><%= data.getFilename() %> (revision <%= data.getRev(0) %>)</th>
112            <th><%= data.getFilename() %> (revision <%= data.getRev(1) %>)</th>
113        </tr>
114        </thead>
115        <tbody>
116        <tr><td><img src="<%= link %>?<%= QueryParameters.REVISION_PARAM_EQ %><%= data.getRev(0) %>" alt="previous image"/>
117            </td>
118            <td><img src="<%= link %>?<%= QueryParameters.REVISION_PARAM_EQ %><%= data.getRev(1) %>" alt="new image"/>
119            </td>
120        </tr>
121        </tbody>
122    </table>
123</div><%
124
125    } else if (data.getGenre() != AbstractAnalyzer.Genre.PLAIN && data.getGenre() != AbstractAnalyzer.Genre.HTML) {
126
127        String link = request.getContextPath() + Prefix.DOWNLOAD_P
128            + Util.htmlize(cfg.getPath());
129%>
130<div id="src">Diffs for binary files cannot be displayed! Files are <a
131    href="<%= link %>?<%= QueryParameters.REVISION_PARAM_EQ %><%= data.getRev(0) %>"><%=
132        data.getFilename() %>(revision <%= data.getRev(0) %>)</a> and <a
133    href="<%= link %>?<%= QueryParameters.REVISION_PARAM_EQ %><%= data.getRev(1) %>"><%=
134        data.getFilename() %>(revision <%= data.getRev(1) %>)</a>.
135</div><%
136
137    } else if (data.getRevision().size() == 0) {
138        %>
139        <%= getAnnotateRevision(data) %>
140        <strong>No differences found!</strong><%
141
142    } else {
143        //-------- Do THE DIFFS ------------
144        int ln1 = 0;
145        int ln2 = 0;
146        String rp1 = data.getParam(0);
147        String rp2 = data.getParam(1);
148        String reqURI = request.getRequestURI();
149        String[] file1 = data.getFile(0);
150        String[] file2 = data.getFile(1);
151
152        DiffType type = data.getType();
153        boolean full = data.isFull();
154%>
155<%= getAnnotateRevision(data) %>
156<div id="diffbar">
157    <div class="legend">
158        <span class="d">Deleted</span>
159        <span class="a">Added</span>
160    </div>
161    <div class="tabs"><%
162        for (DiffType t : DiffType.values()) {
163            if (type == t) {
164        %> <span class="active"><%= t.toString() %><%
165                if (t == DiffType.OLD) {
166            %>  ( <%= data.getRev(0) %> )<%
167                } else if (t == DiffType.NEW) {
168            %>  ( <%= data.getRev(1) %> )<%
169                }
170            %></span><%
171            } else {
172        %> <span><a href="<%= reqURI %>?<%= QueryParameters.REVISION_1_PARAM_EQ %><%= rp1 %>&amp;
173<%= QueryParameters.REVISION_2_PARAM_EQ %><%= rp2 %>&amp;
174<%= QueryParameters.FORMAT_PARAM_EQ %><%= t.getAbbrev() %>&amp;
175<%= QueryParameters.DIFF_LEVEL_PARAM_EQ %><%= full ? '1' : '0'%>"><%= t.toString() %>
176            <%
177                if (t == DiffType.OLD) {
178            %>  ( <%= data.getRev(0) %> )<%
179                } else if (t == DiffType.NEW) {
180            %>  ( <%= data.getRev(1) %> )<%
181                }
182            %></a></span><%
183            }
184        }
185    %></div>
186    <div class="ctype"><%
187        if (!full) {
188        %>
189        <span><a href="<%= reqURI %>?<%= QueryParameters.REVISION_1_PARAM_EQ %><%= rp1 %>&amp;
190<%= QueryParameters.REVISION_2_PARAM_EQ %><%= rp2 %>&amp;
191<%= QueryParameters.FORMAT_PARAM_EQ %><%= type.getAbbrev() %>&amp;
192<%= QueryParameters.DIFF_LEVEL_PARAM_EQ %>1">full</a></span>
193        <span class="active">compact</span><%
194        } else {
195        %>
196        <span class="active">full</span>
197        <span> <a href="<%= reqURI %>?<%= QueryParameters.REVISION_1_PARAM_EQ %><%= rp1 %>&amp;
198<%= QueryParameters.REVISION_2_PARAM_EQ %><%= rp2 %>&amp;
199<%= QueryParameters.FORMAT_PARAM_EQ %><%= type.getAbbrev() %>&amp;
200<%= QueryParameters.DIFF_LEVEL_PARAM_EQ %>0">compact</a></span><%
201        }
202        %><span><a href="#" id="toggle-jumper">jumper</a></span>
203        <span><a href="<%= reqURI %>?<%= QueryParameters.REVISION_1_PARAM_EQ %><%= rp1 %>&amp;
204<%= QueryParameters.REVISION_2_PARAM_EQ %><%= rp2 %>&amp;
205<%= QueryParameters.FORMAT_PARAM_EQ %><%= DiffType.TEXT %>&amp;
206action=download">download diff</a></span><%
207    %></div>
208</div>
209
210<div id="difftable">
211    <div class="pre"><%
212        if (type == DiffType.SIDEBYSIDE || type == DiffType.UNIFIED) {
213        %><table class="plain" aria-label="table with old and new content"><%
214            if (type == DiffType.SIDEBYSIDE) {
215            %>
216            <thead><tr>
217                <th><%= data.getFilename() %> (<%= data.getRev(0) %>)</th>
218                <th><%= data.getFilename() %> (<%= data.getRev(1) %>)</th>
219            </tr></thead><%
220            }
221            %>
222            <tbody><%
223        }
224
225        for (int i=0; i < data.getRevision().size(); i++) {
226            Delta d = data.getRevision().getDelta(i);
227            if (type == DiffType.TEXT) {
228        %><%= Util.htmlize(d.toString()) %><%
229            } else {
230                Chunk c1 = d.getOriginal();
231                Chunk c2 = d.getRevised();
232                int cn1 = c1.first();
233                int cl1 = c1.last();
234                int cn2 = c2.first();
235                int cl2 = c2.last();
236
237                int i1 = cn1, i2 = cn2;
238                StringBuilder bl1 = new StringBuilder(80);
239                StringBuilder bl2 = new StringBuilder(80);
240                for (; i1 <= cl1 && i2 <= cl2; i1++, i2++) {
241                    String[] ss = Util.diffline(
242                            new StringBuilder(file1[i1]),
243                            new StringBuilder(file2[i2]));
244                    file1[i1] = ss[0];
245                    file2[i2] = ss[1];
246                }
247                // deleted
248                for (; i1 <= cl1; i1++) {
249                    bl1.setLength(0);
250                    bl1.append("<span class=\"d\">");
251                    Util.htmlize(file1[i1], bl1);
252                    file1[i1] = bl1.append("</span>").toString();
253                }
254                // added
255                for (; i2 <= cl2; i2++) {
256                    bl2.setLength(0);
257                    bl2.append("<span class=\"a\">");
258                    Util.htmlize(file2[i2], bl2);
259                    file2[i2] = bl2.append("</span>").toString();
260                }
261
262                if (type == DiffType.UNIFIED) {
263// UDIFF
264                    if (cn1 > ln1 || cn2 > ln2) {
265            %>
266            <tr class="k"><td><%
267                        if (full || (cn2 - ln2 < 20)) {
268                            for (int j = ln2; j < cn2; j++) {
269                %><span class="it"><%= ++ln2 %></span><%=
270                    Util.htmlize(file2[j]) %><br/><%
271                            }
272                        } else {
273                            for (int j = ln2; j < ln2 + 8; j++) {
274                %><span class="it"><%= j+1 %></span><%=
275                    Util.htmlize(file2[j]) %><br/><%
276                            }
277                %><br/>--- <strong><%= cn2 - ln2 - 16
278                    %> unchanged lines hidden</strong> (<a href="<%= reqURI
279%>?<%= QueryParameters.REVISION_1_PARAM_EQ %><%= rp1 %>&amp;
280<%= QueryParameters.REVISION_2_PARAM_EQ %><%= rp2 %>&amp;
281<%= QueryParameters.FORMAT_PARAM_EQ %><%= type.getAbbrev() %>&amp;
282<%= QueryParameters.DIFF_LEVEL_PARAM_EQ %>1#<%= ln2 %>">view full</a>)
283                    --- <br/><br/><%
284                            ln2 = cn2 - 8;
285                            for (int j = ln2; j < cn2; j++) {
286                %><span class="it"><%= ++ln2 %></span><%= Util.htmlize(file2[j]) %><br/><%
287                            }
288                        }
289                %></td>
290            </tr><%
291                        ln1 = cn1;
292                    }
293                    if (cn1 <= cl1) {
294            %>
295            <tr class="chunk"><td><%
296                        for (int j = cn1; j  <= cl1 ; j++) {
297                %><del class="d"><%= ++ln1 %></del><%= file1[j]
298                %><br/><%
299                        }
300                %></td>
301            </tr><%
302                    }
303                    if (cn2 <= cl2) {
304            %>
305            <tr class="k<%
306                    if (cn1 > cl1) {
307                        %> chunk<%
308                    }
309                %>"><td><%
310                        for (int j = cn2; j  < cl2; j++) {
311                %><span class="a it"><%= ++ln2 %></span><%= file2[j]
312                %><br/><%
313                        }
314                %><span class="a it"><%= ++ln2 %></span><%= file2[cl2] %><%
315                        if(full) {
316                %><a name="<%= ln2 %>" /><%
317                        }
318                %></td>
319            </tr><%
320                    }
321                } else if (type == DiffType.SIDEBYSIDE) {
322// SDIFF
323                    if (cn1 > ln1 || cn2 > ln2) {
324            %>
325            <tr class="k"><td><%
326                        if (full || cn2 - ln2 < 20) {
327                            for (int j = ln1; j < cn1; j++) {
328                %><span class="it"><%= ++ln1 %></span><%=
329                    Util.htmlize(file1[j]) %><br/><%
330                            }
331                %></td><td><%
332                            for (int j = ln2; j  < cn2 ; j++) {
333                %><span class="it"><%= ++ln2 %></span><%=
334                    Util.htmlize(file2[j]) %><br/><%
335                            }
336                        } else {
337                            for (int j = ln1; j < ln1 + 8; j++) {
338                %><span class="it"><%= j+1 %></span><%=
339                    Util.htmlize(file1[j]) %><br/><%
340                            }
341                %><br/>--- <strong><%= cn1 - ln1 - 16
342                    %> unchanged lines hidden</strong> (<a href="<%= reqURI
343%>?<%= QueryParameters.REVISION_1_PARAM_EQ %><%= rp1 %>&amp;
344<%= QueryParameters.REVISION_2_PARAM_EQ %><%= rp2 %>&amp;
345<%= QueryParameters.FORMAT_PARAM_EQ %><%= type.getAbbrev() %>&amp;
346<%= QueryParameters.DIFF_LEVEL_PARAM_EQ %>1#<%= ln2 %>">view full</a>)
347                    --- <br/><br/><%
348                            ln1 = cn1 - 8;
349                            for (int j = ln1; j < cn1; j++) {
350                %><span class="it"><%= ++ln1 %></span><%=
351                    Util.htmlize(file1[j]) %><br/><%
352                            }
353                %></td><td><%
354                            for (int j = ln2; j < ln2 + 8; j++) {
355                %><span class="it"><%= j+1 %></span><%=
356                    Util.htmlize(file2[j]) %><br/><%
357                            }
358                %><br/>--- <strong><%= cn2 - ln2 - 16
359                    %> unchanged lines hidden</strong> (<a href="<%= reqURI
360%>?<%= QueryParameters.REVISION_1_PARAM_EQ %><%= rp1 %>&amp;
361<%= QueryParameters.REVISION_2_PARAM_EQ %><%= rp2 %>&amp;
362<%= QueryParameters.FORMAT_PARAM_EQ %><%= type.getAbbrev() %>&amp;
363<%= QueryParameters.DIFF_LEVEL_PARAM_EQ %>1#<%= ln2 %>">view full</a>)
364                    --- <br/><br/><%
365                            ln2 = cn2 - 8;
366                            for (int j = ln2; j < cn2; j++) {
367                %><span class="it"><%= ++ln2 %></span><%=
368                    Util.htmlize(file2[j]) %><br/><%
369                            }
370                        }
371                %></td>
372            </tr><%
373                    }
374            %>
375            <tr class="k chunk"><td><%
376                    for (int j = cn1; j  <= cl1; j++) {
377                %><span class="it"><%= ++ln1 %></span><%= file1[j] %><br/><%
378                    }
379                %></td><td><%
380                    for (int j = cn2; j  <= cl2; j++) {
381                %><span class="it"><%= ++ln2 %></span><a name="<%= ln2 %>"></a><%=
382                    file2[j] %><br/><%
383                    }
384                %></td>
385            </tr><%
386// OLD
387                } else if (type == DiffType.OLD) {
388                    // OLD
389                    if (cn1 > ln1) {
390                        if (full || cn1 - ln1 < 20) {
391                            for (int j = ln1; j < cn1; j++) {
392        %><span class="it"><%= ++ln1 %></span><%=
393            Util.htmlize(file1[j]) %><br/><%
394                            }
395                        } else {
396                            for (int j = ln1; j < ln1 + 8; j++) {
397        %><span class="it"><%= j+1 %></span><%=
398            Util.htmlize(file1[j]) %><br/><%
399                            }
400        %><br/>--- <strong><%= cn1 - ln1 - 16
401            %> unchanged lines hidden</strong> (<a href="<%= reqURI
402%>?<%= QueryParameters.REVISION_1_PARAM_EQ %><%= rp1 %>&amp;
403<%= QueryParameters.REVISION_2_PARAM_EQ %><%= rp2 %>&amp;
404<%= QueryParameters.FORMAT_PARAM_EQ %><%= type.getAbbrev() %>&amp;
405<%= QueryParameters.DIFF_LEVEL_PARAM_EQ %>1#<%=ln1%>">view full</a>) --- <br/><br/><%
406                            ln1 = cn1 - 8;
407                            for (int j = ln1; j < cn1; j++) {
408        %><span class="it"><%= ++ln1 %></span><%=
409            Util.htmlize(file1[j]) %><br/><%
410                            }
411                        }
412                    }
413                    for (int j = cn1; j  <= cl1 ; j++) {
414        %><span class="it"><%= ++ln1 %></span><%= file1[j] %><br/><%
415                    }
416                    if (full) {
417        %><a name="<%=ln1%>" ></a><%
418                    }
419// NEW
420                } else if (type == DiffType.NEW) {
421                    if (cn2 > ln2) {
422                        if (full || cn2 - ln2 < 20) {
423                            for (int j = ln2; j  < cn2 ; j++) {
424        %><span class="it"><%= ++ln2 %></span><%=
425            Util.htmlize(file2[j]) %><br/><%
426                            }
427                        } else {
428                            for (int j = ln2; j < ln2 + 8; j++) {
429        %><span class="it"><%= j+1 %></span><%=
430            Util.htmlize(file2[j]) %><br/><%
431                            }
432        %><br/>--- <strong><%= cn2 - ln2 - 16
433            %> unchanged lines hidden</strong> (<a href="<%= reqURI
434%>?<%= QueryParameters.REVISION_1_PARAM_EQ %><%= rp1 %>&amp;
435<%= QueryParameters.REVISION_2_PARAM_EQ %><%= rp2 %>&amp;
436<%= QueryParameters.FORMAT_PARAM_EQ %><%= type.getAbbrev() %>&amp;
437<%= QueryParameters.DIFF_LEVEL_PARAM_EQ %>1#<%= ln2 %>">view full</a>) --- <br/><br/><%
438                            ln2 = cn2 - 8;
439                            for (int j = ln2; j < cn2; j++) {
440            %><span class="it"><%= ++ln2 %></span><%=
441                Util.htmlize(file2[j]) %><br/><%
442                            }
443                        }
444                    }
445                    for (int j = cn2; j  <= cl2 ; j++) {
446        %><span class="it"><%= ++ln2 %></span><%= file2[j] %><br/><%
447                    }
448                    if (full) {
449        %><a name="<%= ln2 %>"></a><%
450                    }
451                }
452            } // else
453        } // for
454// deltas done, dump the remaining
455        if (file1.length >= ln1) {
456            if (type == DiffType.SIDEBYSIDE) {
457                if (full || file1.length - ln1 < 20) {
458            %>
459            <tr><td><%
460                    for (int j = ln1; j < file1.length ; j++) {
461                %><span class="it"><%= j+1 %></span><%= Util.htmlize(file1[j]) %><br/><%
462                    }
463                %></td><td><%
464                    for (int j = ln2; j < file2.length ; j++) {
465                %><span class="it"><%= j+1 %></span><%= Util.htmlize(file2[j]) %><br/><%
466                    }
467                %></td>
468            </tr>
469            </tbody>
470        </table><%
471                } else {
472            %>
473            <tr><td><%
474                    for (int j = ln1; j < ln1 + 8 ; j++) {
475                %><span class="it"><%= j+1 %></span><%= Util.htmlize(file1[j]) %><br/><%
476                    }
477                %><br/> --- <strong><%= file1.length - ln1 - 8
478                %> unchanged lines hidden</strong> --- </td><td><%
479                    for (int j = ln2; j < ln2 + 8 ; j++) {
480                %><span class="it"><%= j+1 %></span><%= Util.htmlize(file2[j]) %><br/><%
481                    }
482                %><br/>--- <strong><%= file1.length - ln1 - 8
483                %> unchanged lines hidden</strong> ---</td>
484            </tr>
485            </tbody>
486        </table><%
487                }
488            } else if (type == DiffType.UNIFIED) {
489                if (full || file2.length - ln2 < 20) {
490            %>
491            <tr><td><%
492                    for (int j = ln2; j < file2.length ; j++) {
493                %><span class="it"><%= j+1 %></span><%= Util.htmlize(file2[j]) %><br/><%
494                    }
495                %></td>
496            </tr>
497            </tbody>
498        </table><%
499                } else {
500            %>
501            <tr><td><%
502                    for (int j = ln2; j < ln2 + 8 ; j++) {
503                %><span class="it"><%= j+1 %></span><%= Util.htmlize(file2[j]) %><br/><%
504                    }
505                %><br/>--- <strong><%= file2.length - ln2 - 8
506                %> unchanged lines hidden</strong> ---</td>
507            </tr>
508            </tbody>
509        </table><%
510                }
511            } else if (type == DiffType.OLD) {
512                if (full || file1.length - ln1 < 20) {
513                    for (int j = ln1; j < file1.length ; j++) {
514        %><span class="it"><%= j+1 %></span><%= Util.htmlize(file1[j]) %><br/><%
515                    }
516                } else {
517                    for (int j = ln1; j < ln1 + 8 ; j++) {
518        %><span class="it"><%= j+1 %></span><%= Util.htmlize(file1[j]) %><br/><%
519                    }
520        %><br/> --- <strong><%= file1.length - ln1 - 8
521        %> unchanged lines hidden</strong> ---<br/><%
522                }
523            } else if (type == DiffType.NEW) {
524                if (full || file2.length - ln2 < 20) {
525                    for (int j = ln2; j < file2.length ; j++) {
526        %><span class="it"><%= j+1 %></span><%=Util.htmlize(file2[j])%><br/><%
527                    }
528                } else {
529                    for (int j = ln2; j < ln2 + 8 ; j++) {
530        %><span class="it"><%= j+1 %></span><%= Util.htmlize(file2[j]) %><br/><%
531                    }
532        %><br/> --- <strong><%= file2.length - ln2 - 8
533        %> unchanged lines hidden</strong> ---<br/><%
534                }
535            }
536        }
537
538//----DIFFS Done--------
539    %></div>
540</div><%
541    }
542}
543/* ---------------------- diff.jsp end --------------------- */
544%><%@
545
546include file="foot.jspf"
547
548%>
549