- Timestamp:
- 11/30/2017 11:09:33 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/class-wp-text-diff-renderer-table.php
r41162 r42343 21 21 * @since 2.6.0 22 22 */ 23 public $_leading_context_lines = 10000;23 public $_leading_context_lines = 10000; 24 24 25 25 /** … … 67 67 public function __construct( $params = array() ) { 68 68 parent::__construct( $params ); 69 if ( isset( $params[ 'show_split_view' ] ) ) 70 $this->_show_split_view = $params[ 'show_split_view' ]; 69 if ( isset( $params['show_split_view'] ) ) { 70 $this->_show_split_view = $params['show_split_view']; 71 } 71 72 } 72 73 … … 87 88 * @param string $prefix 88 89 */ 89 public function _lines( $lines, $prefix =' ' ) {90 public function _lines( $lines, $prefix = ' ' ) { 90 91 } 91 92 … … 139 140 public function _added( $lines, $encode = true ) { 140 141 $r = ''; 141 foreach ( $lines as $line) {142 foreach ( $lines as $line ) { 142 143 if ( $encode ) { 143 144 $processed_line = htmlspecialchars( $line ); … … 154 155 * @param String $processed_line The processed diffed line. 155 156 * @param String $line The unprocessed diffed line. 156 * @param string null The line context. Values are 'added', 'deleted' or 'unchanged'.157 * @param string null The line context. Values are 'added', 'deleted' or 'unchanged'. 157 158 */ 158 159 $line = apply_filters( 'process_text_diff_html', $processed_line, $line, 'added' ); … … 177 178 public function _deleted( $lines, $encode = true ) { 178 179 $r = ''; 179 foreach ( $lines as $line) {180 foreach ( $lines as $line ) { 180 181 if ( $encode ) { 181 182 $processed_line = htmlspecialchars( $line ); … … 189 190 $r .= '<tr>' . $this->deletedLine( $line ) . "</tr>\n"; 190 191 } 191 192 192 } 193 193 return $r; … … 203 203 public function _context( $lines, $encode = true ) { 204 204 $r = ''; 205 foreach ( $lines as $line) {205 foreach ( $lines as $line ) { 206 206 if ( $encode ) { 207 207 $processed_line = htmlspecialchars( $line ); … … 210 210 $line = apply_filters( 'process_text_diff_html', $processed_line, $line, 'unchanged' ); 211 211 } 212 if ( $this->_show_split_view ) {213 $r .= '<tr>' . $this->contextLine( $line ) . $this->emptyLine() . $this->contextLine( $line ) . "</tr>\n";212 if ( $this->_show_split_view ) { 213 $r .= '<tr>' . $this->contextLine( $line ) . $this->emptyLine() . $this->contextLine( $line ) . "</tr>\n"; 214 214 } else { 215 215 $r .= '<tr>' . $this->contextLine( $line ) . "</tr>\n"; … … 249 249 // Compute word diffs for each matched pair using the inline diff 250 250 foreach ( $orig_matches as $o => $f ) { 251 if ( is_numeric( $o) && is_numeric($f) ) {252 $text_diff = new Text_Diff( 'auto', array( array( $orig[$o]), array($final[$f]) ) );253 $renderer = new $this->inline_diff_renderer;254 $diff = $renderer->render( $text_diff );251 if ( is_numeric( $o ) && is_numeric( $f ) ) { 252 $text_diff = new Text_Diff( 'auto', array( array( $orig[ $o ] ), array( $final[ $f ] ) ) ); 253 $renderer = new $this->inline_diff_renderer; 254 $diff = $renderer->render( $text_diff ); 255 255 256 256 // If they're too different, don't include any <ins> or <dels> 257 257 if ( preg_match_all( '!(<ins>.*?</ins>|<del>.*?</del>)!', $diff, $diff_matches ) ) { 258 258 // length of all text between <ins> or <del> 259 $stripped_matches = strlen( strip_tags( join(' ', $diff_matches[0]) ));259 $stripped_matches = strlen( strip_tags( join( ' ', $diff_matches[0] ) ) ); 260 260 // since we count lengith of text between <ins> or <del> (instead of picking just one), 261 261 // we double the length of chars not in those tags. 262 $stripped_diff = strlen( strip_tags( $diff )) * 2 - $stripped_matches;263 $diff_ratio = $stripped_matches / $stripped_diff;264 if ( $diff_ratio > $this->_diff_threshold ) 262 $stripped_diff = strlen( strip_tags( $diff ) ) * 2 - $stripped_matches; 263 $diff_ratio = $stripped_matches / $stripped_diff; 264 if ( $diff_ratio > $this->_diff_threshold ) { 265 265 continue; // Too different. Don't save diffs. 266 } 266 267 } 267 268 268 269 // Un-inline the diffs by removing del or ins 269 $orig_diffs[ $o] = preg_replace( '|<ins>.*?</ins>|', '', $diff );270 $final_diffs[ $f] = preg_replace( '|<del>.*?</del>|', '', $diff );271 } 272 } 273 274 foreach ( array_keys( $orig_rows) as $row ) {270 $orig_diffs[ $o ] = preg_replace( '|<ins>.*?</ins>|', '', $diff ); 271 $final_diffs[ $f ] = preg_replace( '|<del>.*?</del>|', '', $diff ); 272 } 273 } 274 275 foreach ( array_keys( $orig_rows ) as $row ) { 275 276 // Both columns have blanks. Ignore them. 276 if ( $orig_rows[ $row] < 0 && $final_rows[$row] < 0 )277 if ( $orig_rows[ $row ] < 0 && $final_rows[ $row ] < 0 ) { 277 278 continue; 279 } 278 280 279 281 // If we have a word based diff, use it. Otherwise, use the normal line. 280 if ( isset( $orig_diffs[ $orig_rows[$row]] ) )281 $orig_line = $orig_diffs[ $orig_rows[$row]];282 elseif ( isset( $orig[$orig_rows[$row]] ) )283 $orig_line = htmlspecialchars( $orig[$orig_rows[$row]]);284 else282 if ( isset( $orig_diffs[ $orig_rows[ $row ] ] ) ) { 283 $orig_line = $orig_diffs[ $orig_rows[ $row ] ]; 284 } elseif ( isset( $orig[ $orig_rows[ $row ] ] ) ) { 285 $orig_line = htmlspecialchars( $orig[ $orig_rows[ $row ] ] ); 286 } else { 285 287 $orig_line = ''; 286 287 if ( isset( $final_diffs[$final_rows[$row]] ) ) 288 $final_line = $final_diffs[$final_rows[$row]]; 289 elseif ( isset( $final[$final_rows[$row]] ) ) 290 $final_line = htmlspecialchars($final[$final_rows[$row]]); 291 else 288 } 289 290 if ( isset( $final_diffs[ $final_rows[ $row ] ] ) ) { 291 $final_line = $final_diffs[ $final_rows[ $row ] ]; 292 } elseif ( isset( $final[ $final_rows[ $row ] ] ) ) { 293 $final_line = htmlspecialchars( $final[ $final_rows[ $row ] ] ); 294 } else { 292 295 $final_line = ''; 293 294 if ( $orig_rows[$row] < 0 ) { // Orig is blank. This is really an added row. 295 $r .= $this->_added( array($final_line), false ); 296 } elseif ( $final_rows[$row] < 0 ) { // Final is blank. This is really a deleted row. 297 $r .= $this->_deleted( array($orig_line), false ); 296 } 297 298 if ( $orig_rows[ $row ] < 0 ) { // Orig is blank. This is really an added row. 299 $r .= $this->_added( array( $final_line ), false ); 300 } elseif ( $final_rows[ $row ] < 0 ) { // Final is blank. This is really a deleted row. 301 $r .= $this->_deleted( array( $orig_line ), false ); 298 302 } else { // A true changed row. 299 303 if ( $this->_show_split_view ) { 300 304 $r .= '<tr>' . $this->deletedLine( $orig_line ) . $this->emptyLine() . $this->addedLine( $final_line ) . "</tr>\n"; 301 305 } else { 302 $r .= '<tr>' . $this->deletedLine( $orig_line ) . "</tr><tr>". $this->addedLine( $final_line ) . "</tr>\n";306 $r .= '<tr>' . $this->deletedLine( $orig_line ) . '</tr><tr>' . $this->addedLine( $final_line ) . "</tr>\n"; 303 307 } 304 308 } … … 340 344 // Contains all pairwise string comparisons. Keys are such that this need only be a one dimensional array. 341 345 $matches = array(); 342 foreach ( array_keys( $orig) as $o ) {343 foreach ( array_keys( $final) as $f ) {344 $matches[ "$o,$f"] = $this->compute_string_distance( $orig[$o], $final[$f] );345 } 346 } 347 asort( $matches); // Order by string distance.346 foreach ( array_keys( $orig ) as $o ) { 347 foreach ( array_keys( $final ) as $f ) { 348 $matches[ "$o,$f" ] = $this->compute_string_distance( $orig[ $o ], $final[ $f ] ); 349 } 350 } 351 asort( $matches ); // Order by string distance. 348 352 349 353 $orig_matches = array(); … … 351 355 352 356 foreach ( $matches as $keys => $difference ) { 353 list($o, $f) = explode( ',', $keys);354 $o = (int) $o;355 $f = (int) $f;357 list($o, $f) = explode( ',', $keys ); 358 $o = (int) $o; 359 $f = (int) $f; 356 360 357 361 // Already have better matches for these guys 358 if ( isset( $orig_matches[$o]) && isset($final_matches[$f]) )362 if ( isset( $orig_matches[ $o ] ) && isset( $final_matches[ $f ] ) ) { 359 363 continue; 364 } 360 365 361 366 // First match for these guys. Must be best match 362 if ( ! isset($orig_matches[$o]) && !isset($final_matches[$f]) ) {363 $orig_matches[ $o]= $f;364 $final_matches[ $f] = $o;367 if ( ! isset( $orig_matches[ $o ] ) && ! isset( $final_matches[ $f ] ) ) { 368 $orig_matches[ $o ] = $f; 369 $final_matches[ $f ] = $o; 365 370 continue; 366 371 } 367 372 368 373 // Best match of this final is already taken? Must mean this final is a new row. 369 if ( isset( $orig_matches[$o]) )370 $final_matches[ $f] = 'x';371 372 // Best match of this orig is already taken? Must mean this orig is a deleted row.373 elseif ( isset($final_matches[$f]) )374 $orig_matches[$o] = 'x';374 if ( isset( $orig_matches[ $o ] ) ) { 375 $final_matches[ $f ] = 'x'; 376 } // Best match of this orig is already taken? Must mean this orig is a deleted row. 377 elseif ( isset( $final_matches[ $f ] ) ) { 378 $orig_matches[ $o ] = 'x'; 379 } 375 380 } 376 381 377 382 // We read the text in this order 378 ksort( $orig_matches);379 ksort( $final_matches);383 ksort( $orig_matches ); 384 ksort( $final_matches ); 380 385 381 386 // Stores rows and blanks for each column. 382 $orig_rows = $orig_rows_copy = array_keys($orig_matches);383 $final_rows = array_keys( $final_matches);387 $orig_rows = $orig_rows_copy = array_keys( $orig_matches ); 388 $final_rows = array_keys( $final_matches ); 384 389 385 390 // Interleaves rows with blanks to keep matches aligned. 386 391 // We may end up with some extraneous blank rows, but we'll just ignore them later. 387 392 foreach ( $orig_rows_copy as $orig_row ) { 388 $final_pos = array_search( $orig_matches[$orig_row], $final_rows, true);389 $orig_pos = (int) array_search($orig_row, $orig_rows, true);393 $final_pos = array_search( $orig_matches[ $orig_row ], $final_rows, true ); 394 $orig_pos = (int) array_search( $orig_row, $orig_rows, true ); 390 395 391 396 if ( false === $final_pos ) { // This orig is paired with a blank final. … … 393 398 } elseif ( $final_pos < $orig_pos ) { // This orig's match is up a ways. Pad final with blank rows. 394 399 $diff_pos = $final_pos - $orig_pos; 395 while ( $diff_pos < 0 ) 400 while ( $diff_pos < 0 ) { 396 401 array_splice( $final_rows, $orig_pos, 0, $diff_pos++ ); 402 } 397 403 } elseif ( $final_pos > $orig_pos ) { // This orig's match is down a ways. Pad orig with blank rows. 398 404 $diff_pos = $orig_pos - $final_pos; 399 while ( $diff_pos < 0 ) 405 while ( $diff_pos < 0 ) { 400 406 array_splice( $orig_rows, $orig_pos, 0, $diff_pos++ ); 407 } 401 408 } 402 409 } 403 410 404 411 // Pad the ends with blank rows if the columns aren't the same length 405 $diff_count = count( $orig_rows) - count($final_rows);412 $diff_count = count( $orig_rows ) - count( $final_rows ); 406 413 if ( $diff_count < 0 ) { 407 while ( $diff_count < 0 ) 408 array_push($orig_rows, $diff_count++); 414 while ( $diff_count < 0 ) { 415 array_push( $orig_rows, $diff_count++ ); 416 } 409 417 } elseif ( $diff_count > 0 ) { 410 418 $diff_count = -1 * $diff_count; 411 while ( $diff_count < 0 ) 412 array_push($final_rows, $diff_count++); 413 } 414 415 return array($orig_matches, $final_matches, $orig_rows, $final_rows); 419 while ( $diff_count < 0 ) { 420 array_push( $final_rows, $diff_count++ ); 421 } 422 } 423 424 return array( $orig_matches, $final_matches, $orig_rows, $final_rows ); 416 425 } 417 426 … … 427 436 public function compute_string_distance( $string1, $string2 ) { 428 437 // Vectors containing character frequency for all chars in each string 429 $chars1 = count_chars( $string1);430 $chars2 = count_chars( $string2);438 $chars1 = count_chars( $string1 ); 439 $chars2 = count_chars( $string2 ); 431 440 432 441 // L1-norm of difference vector. 433 $difference = array_sum( array_map( array( $this, 'difference'), $chars1, $chars2 ) );442 $difference = array_sum( array_map( array( $this, 'difference' ), $chars1, $chars2 ) ); 434 443 435 444 // $string1 has zero length? Odd. Give huge penalty by not dividing. 436 if ( ! $string1 )445 if ( ! $string1 ) { 437 446 return $difference; 447 } 438 448 439 449 // Return distance per character (of string1). 440 return $difference / strlen( $string1);450 return $difference / strlen( $string1 ); 441 451 } 442 452
Note: See TracChangeset
for help on using the changeset viewer.