<?php declare(strict_types=1); namespace Jfcherng\Diff\Renderer\Html\LineRenderer; use Jfcherng\Diff\Renderer\RendererConstant; use Jfcherng\Utility\MbString; final class Line extends AbstractLineRenderer { /** * {@inheritdoc} * * @return static */ public function render(MbString $mbOld, MbString $mbNew): LineRendererInterface { [$start, $end] = $this->getChangedExtentRegion($mbOld, $mbNew); // two strings are the same if ($end === 0) { return $this; } // two strings are different, we do rendering $mbOld->str_enclose_i( RendererConstant::HTML_CLOSURES, $start, $end + $mbOld->strlen() - $start + 1 ); $mbNew->str_enclose_i( RendererConstant::HTML_CLOSURES, $start, $end + $mbNew->strlen() - $start + 1 ); return $this; } /** * Given two strings, determine where the changes in the two strings begin, * and where the changes in the two strings end. * * @param MbString $mbOld the old megabytes line * @param MbString $mbNew the new megabytes line * * @return int[] Array containing the starting position (non-negative) and the ending position (negative) * [0, 0] if two strings are the same */ protected function getChangedExtentRegion(MbString $mbOld, MbString $mbNew): array { // two strings are the same // most lines should be this cases, an early return could save many function calls if ($mbOld->getRaw() === $mbNew->getRaw()) { return [0, 0]; } // calculate $start $start = 0; $startMax = \min($mbOld->strlen(), $mbNew->strlen()); while ( $start < $startMax // index out of range && $mbOld->getAtRaw($start) === $mbNew->getAtRaw($start) ) { ++$start; } // calculate $end $end = -1; // trick $endMin = $startMax - $start; while ( -$end <= $endMin // index out of range && $mbOld->getAtRaw($end) === $mbNew->getAtRaw($end) ) { --$end; } return [$start, $end]; } }