Process changed lines to do word-by-word diffs for extra highlighting.
Description
(TRAC style) sometimes these lines can actually be deleted or added rows.
We do additional processing to figure that out
Parameters
$orig
arrayrequired$final
arrayrequired
Source
public function _changed( $orig, $final ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.finalFound
$r = '';
/*
* Does the aforementioned additional processing:
* *_matches tell what rows are "the same" in orig and final. Those pairs will be diffed to get word changes.
* - match is numeric: an index in other column.
* - match is 'X': no match. It is a new row.
* *_rows are column vectors for the orig column and the final column.
* - row >= 0: an index of the $orig or $final array.
* - row < 0: a blank row for that column.
*/
list($orig_matches, $final_matches, $orig_rows, $final_rows) = $this->interleave_changed_lines( $orig, $final );
// These will hold the word changes as determined by an inline diff.
$orig_diffs = array();
$final_diffs = array();
// Compute word diffs for each matched pair using the inline diff.
foreach ( $orig_matches as $o => $f ) {
if ( is_numeric( $o ) && is_numeric( $f ) ) {
$text_diff = new Text_Diff( 'auto', array( array( $orig[ $o ] ), array( $final[ $f ] ) ) );
$renderer = new $this->inline_diff_renderer();
$diff = $renderer->render( $text_diff );
// If they're too different, don't include any <ins> or <del>'s.
if ( preg_match_all( '!(<ins>.*?</ins>|<del>.*?</del>)!', $diff, $diff_matches ) ) {
// Length of all text between <ins> or <del>.
$stripped_matches = strlen( strip_tags( implode( ' ', $diff_matches[0] ) ) );
/*
* Since we count length of text between <ins> or <del> (instead of picking just one),
* we double the length of chars not in those tags.
*/
$stripped_diff = strlen( strip_tags( $diff ) ) * 2 - $stripped_matches;
$diff_ratio = $stripped_matches / $stripped_diff;
if ( $diff_ratio > $this->_diff_threshold ) {
continue; // Too different. Don't save diffs.
}
}
// Un-inline the diffs by removing <del> or <ins>.
$orig_diffs[ $o ] = preg_replace( '|<ins>.*?</ins>|', '', $diff );
$final_diffs[ $f ] = preg_replace( '|<del>.*?</del>|', '', $diff );
}
}
foreach ( array_keys( $orig_rows ) as $row ) {
// Both columns have blanks. Ignore them.
if ( $orig_rows[ $row ] < 0 && $final_rows[ $row ] < 0 ) {
continue;
}
// If we have a word based diff, use it. Otherwise, use the normal line.
if ( isset( $orig_diffs[ $orig_rows[ $row ] ] ) ) {
$orig_line = $orig_diffs[ $orig_rows[ $row ] ];
} elseif ( isset( $orig[ $orig_rows[ $row ] ] ) ) {
$orig_line = htmlspecialchars( $orig[ $orig_rows[ $row ] ] );
} else {
$orig_line = '';
}
if ( isset( $final_diffs[ $final_rows[ $row ] ] ) ) {
$final_line = $final_diffs[ $final_rows[ $row ] ];
} elseif ( isset( $final[ $final_rows[ $row ] ] ) ) {
$final_line = htmlspecialchars( $final[ $final_rows[ $row ] ] );
} else {
$final_line = '';
}
if ( $orig_rows[ $row ] < 0 ) { // Orig is blank. This is really an added row.
$r .= $this->_added( array( $final_line ), false );
} elseif ( $final_rows[ $row ] < 0 ) { // Final is blank. This is really a deleted row.
$r .= $this->_deleted( array( $orig_line ), false );
} else { // A true changed row.
if ( $this->_show_split_view ) {
$r .= '<tr>' . $this->deletedLine( $orig_line ) . $this->addedLine( $final_line ) . "</tr>\n";
} else {
$r .= '<tr>' . $this->deletedLine( $orig_line ) . '</tr><tr>' . $this->addedLine( $final_line ) . "</tr>\n";
}
}
}
return $r;
}
Changelog
Version | Description |
---|---|
2.6.0 | Introduced. |
User Contributed Notes
You must log in before being able to contribute a note or feedback.