001/* 002 * Copyright 2025 The Apache Software Foundation. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.apache.wiki.diff; 017 018import com.github.difflib.DiffUtils; 019import com.github.difflib.patch.AbstractDelta; 020import com.github.difflib.patch.Patch; 021import java.io.IOException; 022import java.util.List; 023import java.util.Properties; 024import org.apache.wiki.api.core.Context; 025import org.apache.wiki.api.core.Engine; 026import org.apache.wiki.api.exceptions.NoRequiredPropertyException; 027 028/** 029 * SVN/Git style diff provider. Uses the DiffLib, ASF 2.0 licensed. 030 * 031 * @since 3.0.0 032 */ 033public class SvnStyleDiffProvider implements DiffProvider { 034 035 public static final String CSS_DIFF_ADDED = "<tr class=\"diffadd\"><td>"; 036 public static final String CSS_DIFF_REMOVED = "<tr class=\"diffrem\"><td>"; 037 public static final String CSS_DIFF_UNCHANGED = "<tr class=\"diff\"><td>"; 038 public static final String CSS_DIFF_CLOSE = "</td></tr>\n"; 039 public static final String CELL_CHANGE = "</td><td>"; 040 041 @Override 042 public String makeDiffHtml(Context context, String originalText, String modifiedText) { 043 044 List<String> original = originalText.lines().toList(); 045 List<String> modified = modifiedText.lines().toList(); 046 StringBuilder ret = new StringBuilder(); 047 ret.append("<table class=\"diff\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"); 048 049 Patch<String> patch = DiffUtils.diff(original, modified); 050 int lineNumber = 1; 051 int currentOriginalLine = 0; 052 int currentModifiedLine = 0; 053 054 for (AbstractDelta<String> delta : patch.getDeltas()) { 055 int originalPosition = delta.getSource().getPosition(); 056 int modifiedPosition = delta.getTarget().getPosition(); 057 058 // Output unchanged lines before the delta 059 while (currentOriginalLine < originalPosition && currentModifiedLine < modifiedPosition) { 060 ret.append(CSS_DIFF_UNCHANGED); 061 ret.append(lineNumber).append(CELL_CHANGE); 062 ret.append(original.get(currentOriginalLine)); 063 ret.append(CSS_DIFF_CLOSE); 064 //System.out.println(" " + lineNumber + " " + original.get(currentOriginalLine)); 065 lineNumber++; 066 currentOriginalLine++; 067 currentModifiedLine++; 068 } 069 070 List<String> originalLines = delta.getSource().getLines(); 071 List<String> revisedLines = delta.getTarget().getLines(); 072 073 for (String line : originalLines) { 074 ret.append(CSS_DIFF_REMOVED); 075 ret.append(lineNumber).append(CELL_CHANGE); 076 ret.append(line); 077 ret.append(CSS_DIFF_CLOSE); 078 //System.out.println("- " + lineNumber + " " + line); 079 lineNumber++; 080 currentOriginalLine++; 081 } 082 083 for (String line : revisedLines) { 084 ret.append(CSS_DIFF_ADDED); 085 ret.append(lineNumber).append(CELL_CHANGE); 086 ret.append(line); 087 ret.append(CSS_DIFF_CLOSE); 088 //System.out.println("+ " + lineNumber + " " + line); 089 lineNumber++; 090 currentModifiedLine++; 091 } 092 } 093 094 // Output any remaining unchanged lines at the end 095 while (currentOriginalLine < original.size() && currentModifiedLine < modified.size()) { 096 ret.append(CSS_DIFF_UNCHANGED); 097 ret.append(lineNumber).append(CELL_CHANGE); 098 ret.append(original.get(currentOriginalLine)); 099 ret.append(CSS_DIFF_CLOSE); 100 101 //System.out.println(" " + lineNumber + " " + original.get(currentOriginalLine)); 102 lineNumber++; 103 currentOriginalLine++; 104 currentModifiedLine++; 105 } 106 ret.append("</table>\n"); 107 return ret.toString(); 108 } 109 110 @Override 111 public void initialize(Engine engine, Properties properties) throws NoRequiredPropertyException, IOException { 112 } 113 114 @Override 115 public String getProviderInfo() { 116 return "SvnStyleDiffProvider"; 117 } 118 119}