@@ -205,10 +205,18 @@ protected function renderTableBlockReplace(array $block): string
205205
206206 // now $oldLines must has the same line counts with $newlines
207207 for ($ no = 0 ; $ no < $ newLinesCount ; ++$ no ) {
208+ $ mergedLine = $ this ->mergeReplaceLines ($ oldLines [$ no ], $ newLines [$ no ]);
209+
210+ if (!isset ($ mergedLine )) {
211+ $ html .= $ this ->renderTableBlockDelete ($ block ) . $ this ->renderTableBlockInsert ($ block );
212+
213+ continue ;
214+ }
215+
208216 $ html .=
209217 '<tr data-type="!"> ' .
210218 '<td class="rep"> ' .
211- $ this -> mergeReplaceLines ( $ oldLines [ $ no ], $ newLines [ $ no ]) .
219+ $ mergedLine .
212220 '</td> ' .
213221 '</tr> ' ;
214222 }
@@ -225,8 +233,10 @@ protected function renderTableBlockReplace(array $block): string
225233 *
226234 * @param string $oldLine the old line
227235 * @param string $newLine the new line
236+ *
237+ * @return null|string string if merge-able, null otherwise
228238 */
229- protected function mergeReplaceLines (string $ oldLine , string $ newLine ): string
239+ protected function mergeReplaceLines (string $ oldLine , string $ newLine ): ? string
230240 {
231241 $ delParts = $ this ->analyzeClosureParts (
232242 RendererConstant::HTML_CLOSURES_DEL [0 ],
@@ -254,6 +264,11 @@ protected function mergeReplaceLines(string $oldLine, string $newLine): string
254264 );
255265 }
256266
267+ // note that $mergedLine is actually a clean line at this point
268+ if (!$ this ->isLinesMergeable ($ oldLine , $ newLine , $ mergedLine )) {
269+ return null ;
270+ }
271+
257272 // before building the $mergedParts, we do some adjustments
258273 $ this ->revisePartsForBoundaryNewlines ($ delParts , RendererConstant::HTML_CLOSURES_DEL );
259274 $ this ->revisePartsForBoundaryNewlines ($ insParts , RendererConstant::HTML_CLOSURES_INS );
@@ -398,6 +413,26 @@ protected function fixLinesForNoClosure(array &$lines, array $closures): void
398413 }
399414 }
400415
416+ /**
417+ * Determine whether the "replace"-type lines are merge-able or not.
418+ *
419+ * @param string $oldLine the old line
420+ * @param string $newLine the new line
421+ * @param string $cleanLine the clean line
422+ */
423+ protected function isLinesMergeable (string $ oldLine , string $ newLine , string $ cleanLine ): bool
424+ {
425+ $ oldLine = \str_replace (RendererConstant::HTML_CLOSURES_DEL , '' , $ oldLine );
426+ $ newLine = \str_replace (RendererConstant::HTML_CLOSURES_INS , '' , $ newLine );
427+
428+ $ sumLength = \strlen ($ oldLine ) + \strlen ($ newLine );
429+
430+ /** @var float the changed ratio, 0 <= range < 1 */
431+ $ changedRatio = ($ sumLength - (\strlen ($ cleanLine ) << 1 )) / ($ sumLength + 1 );
432+
433+ return $ changedRatio < 0.8 ;
434+ }
435+
401436 /**
402437 * Extract boundary newlines from parts into new parts.
403438 *
0 commit comments