![JAR search and dependency download from the Maven repository](/logo.png)
net.sf.yal10n.diff.UnifiedDiff Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of yal10n-maven-plugin Show documentation
Show all versions of yal10n-maven-plugin Show documentation
Yet Another L10N Maven Plugin
The newest version!
package net.sf.yal10n.diff;
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.tools.generic.EscapeTool;
/**
* This class represents a diff produced by subversion.
* It can convert the diff into a side-by-side comparison html format.
*/
public class UnifiedDiff
{
private static final Pattern HUNK_START_PATTERN = Pattern.compile( "^@@ \\-(\\d+),(\\d+) \\+(\\d+),(\\d+) @@" );
private String originalName;
private String newName;
private List hunks = new ArrayList();
/**
* Create a new {@link UnifiedDiff} with the given diff.
* @param diffString the diff data
*/
public UnifiedDiff( String diffString )
{
this( diffString, false, null );
}
/**
* Creates a new {@link UnifiedDiff} with the given diff.
* If the flag newFile
is true, then not a diff is assumed,
* simply the content of the new file is expected.
* @param diffString the diff data or file content
* @param newFile if false
, a real diff is expected.
* @param filename the file name. Only needed if not a real diff is provided.
*/
public UnifiedDiff( String diffString, boolean newFile, String filename )
{
if ( !newFile )
{
parse( diffString );
}
else
{
parseNewFile( diffString, filename );
}
}
private void parseNewFile( String content, String filename )
{
String[] lines = content.split( "\n" );
int lineNumber = 1;
Hunk hunk = new Hunk();
hunk.firstLineNumber = lineNumber;
for ( String line : lines )
{
hunk.newLines.put( lineNumber, line );
hunk.indicators.put( lineNumber, '+' );
lineNumber++;
}
hunk.lastLineNumber = lineNumber;
hunks.add( hunk );
originalName = "--";
newName = String.valueOf( filename );
}
private void parse( String diff )
{
String[] lines = diff.split( "\n" );
if ( lines.length < 5 )
{
throw new IllegalArgumentException( "The given diff is too short. " );
}
originalName = lines[2].substring( 4 );
newName = lines[3].substring( 4 );
int origLineNumber = 0;
int newLineNumber = 0;
Hunk currentHunk = null;
for ( int i = 4; i < lines.length; i++ )
{
String line = lines[i];
String nextLine = "\\\\";
if ( i + 1 < lines.length )
{
nextLine = lines[i + 1];
}
if ( StringUtils.isEmpty( nextLine ) )
{
nextLine = "\\\\";
}
Matcher m = HUNK_START_PATTERN.matcher( line );
boolean newHunkStarted = m.find();
if ( newHunkStarted || StringUtils.isEmpty( line ) )
{
if ( currentHunk != null )
{
currentHunk.lastLineNumber = newLineNumber;
calculateChangedLines( currentHunk );
hunks.add( currentHunk );
currentHunk = null;
}
if ( newHunkStarted )
{
currentHunk = new Hunk();
origLineNumber = Integer.parseInt( m.group( 1 ) );
newLineNumber = origLineNumber;
currentHunk.firstLineNumber = origLineNumber;
}
}
else
{
if ( currentHunk == null )
{
// ignore this line outside of a hunk
continue;
}
char indicator = line.charAt( 0 );
String diffLine = line.substring( 1 );
switch ( indicator )
{
case ' ':
if ( origLineNumber < newLineNumber )
{
origLineNumber = newLineNumber;
}
else
{
newLineNumber = origLineNumber;
}
currentHunk.commonLines.put( origLineNumber, diffLine );
currentHunk.indicators.put( origLineNumber, ' ' );
origLineNumber++;
newLineNumber++;
break;
case '-':
currentHunk.origLines.put( origLineNumber, diffLine );
currentHunk.indicators.put( origLineNumber, '-' );
origLineNumber++;
break;
case '+':
currentHunk.newLines.put( newLineNumber, diffLine );
currentHunk.indicators.put( newLineNumber, '+' );
newLineNumber++;
break;
default:
// ignore
}
}
}
if ( currentHunk != null )
{
currentHunk.lastLineNumber = newLineNumber;
calculateChangedLines( currentHunk );
hunks.add( currentHunk );
}
}
private void calculateChangedLines( Hunk currentHunk )
{
for ( Integer line : currentHunk.origLines.keySet() )
{
if ( currentHunk.newLines.containsKey( line ) )
{
currentHunk.indicators.put( line, 'C' );
}
}
}
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
StringBuilder out = new StringBuilder();
out.append( "orig: " ).append( originalName ).append( "\n" );
out.append( " new: " ).append( newName ).append( "\n" );
out.append( "found " + hunks.size() + " hunks\n" );
for ( Hunk hunk : hunks )
{
for ( int i = hunk.firstLineNumber; i < hunk.lastLineNumber; i++ )
{
Character indicator = hunk.indicators.get( i );
out.append( indicator ).append( i ).append( " " );
switch ( indicator )
{
case '-':
out.append( hunk.origLines.get( i ) );
break;
case ' ':
out.append( hunk.commonLines.get( i ) );
break;
case '+':
out.append( hunk.newLines.get( i ) );
break;
case 'C':
default:
out.append( hunk.origLines.get( i ) ).append( " || " ).append( hunk.newLines.get( i ) );
break;
}
out.append( "\n" );
}
}
return out.toString();
}
/**
* Converts this diff into a side-by-side html format.
* @return the html code
*/
public String asHtmlSnippet()
{
EscapeTool escapeTool = new EscapeTool();
final String lightYellow = "#ffff80";
final String lightRed = "#f08080";
final String lightGreen = "#90ee90";
final String lightGrey = "#d3d3d3";
final String darkCyan = "#008b8b";
final String firstColumnStyle = " style=\"padding: 0 0.5em 0 0.5em; text-align: right;\"";
StringBuilder out = new StringBuilder();
out.append( "\n" );
out.append( "\n" );
out.append( " " );
out.append( "" ).append( escapeTool.html( originalName ) ).append( " " );
out.append( "" ).append( escapeTool.html( newName ) ).append( " " );
out.append( " \n" );
for ( Hunk hunk : hunks )
{
out.append( "" );
out.append( "# " );
out.append( "Line " ).append( hunk.firstLineNumber ).append( " " );
out.append( "Line " ).append( hunk.firstLineNumber ).append( " " );
out.append( " " );
for ( int i = hunk.firstLineNumber; i < hunk.lastLineNumber; i++ )
{
Character indicator = hunk.indicators.get( i );
String currentLine = escapeTool.html( hunk.commonLines.get( i ) );
String originalLine = escapeTool.html( hunk.origLines.get( i ) );
String newLine = escapeTool.html( hunk.newLines.get( i ) );
if ( originalLine == null || originalLine.isEmpty() )
{
originalLine = " ";
}
if ( currentLine == null || currentLine.isEmpty() )
{
currentLine = " ";
}
if ( newLine == null || newLine.isEmpty() )
{
newLine = " ";
}
out.append( "" );
out.append( "" ).append( i ).append( " " );
switch ( indicator )
{
case '-':
out.append( "" )
.append( originalLine ).append( " " );
out.append( " " );
break;
case ' ':
out.append( "" ).append( currentLine ).append( " " );
out.append( "" ).append( currentLine ).append( " " );
break;
case '+':
out.append( " " );
out.append( "" )
.append( newLine ).append( " " );
break;
case 'C':
default:
out.append( "" )
.append( originalLine ).append( " " );
out.append( "" )
.append( newLine ).append( " " );
break;
}
out.append( " \n" );
}
}
out.append( "
\n" );
out.append( "
\n" );
out.append( "\n" );
out.append( "\n" );
out.append( " \n" );
out.append( " \n" );
out.append( " \n" );
out.append( "Legend: \n" );
out.append( "removed " )
.append( " \n" );
out.append( "changed lines \n" );
out.append( " " )
.append( "added \n" );
out.append( "
\n" );
out.append( "\n" );
return out.toString();
}
/**
* Gets the original name.
*
* @return the original name
*/
public String getOriginalName()
{
return originalName;
}
/**
* Gets the new name.
*
* @return the new name
*/
public String getNewName()
{
return newName;
}
/**
* Gets the hunks.
*
* @return the hunks
*/
public List getHunks()
{
return hunks;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy