File "Context.php"
Full Path: /home/humancap/cl.humancap.com.my/vendor/jfcherng/php-diff/src/Renderer/Text/Context.php
File size: 4.3 KB
MIME-type: text/x-php
Charset: utf-8
<?php
declare(strict_types=1);
namespace Jfcherng\Diff\Renderer\Text;
use Jfcherng\Diff\Differ;
use Jfcherng\Diff\SequenceMatcher;
/**
* Context diff generator.
*
* @see https://en.wikipedia.org/wiki/Diff#Context_format
*/
final class Context extends AbstractText
{
/**
* {@inheritdoc}
*/
public const INFO = [
'desc' => 'Context',
'type' => 'Text',
];
/**
* @var int the union of OPs that indicate there is a change
*/
public const OP_BLOCK_CHANGED =
SequenceMatcher::OP_DEL |
SequenceMatcher::OP_INS |
SequenceMatcher::OP_REP;
/**
* {@inheritdoc}
*/
protected function renderWorker(Differ $differ): string
{
$ret = '';
foreach ($differ->getGroupedOpcodesGnu() as $hunk) {
$lastBlockIdx = \count($hunk) - 1;
// note that these line number variables are 0-based
$i1 = $hunk[0][1];
$i2 = $hunk[$lastBlockIdx][2];
$j1 = $hunk[0][3];
$j2 = $hunk[$lastBlockIdx][4];
$ret .=
$this->cliColoredString("***************\n", '@') .
$this->renderHunkHeader('*', $i1, $i2) .
$this->renderHunkOld($differ, $hunk) .
$this->renderHunkHeader('-', $j1, $j2) .
$this->renderHunkNew($differ, $hunk);
}
return $ret;
}
/**
* Render the hunk header.
*
* @param string $symbol the symbol
* @param int $a1 the begin index
* @param int $a2 the end index
*/
protected function renderHunkHeader(string $symbol, int $a1, int $a2): string
{
$a1x = $a1 + 1; // 1-based begin line number
return $this->cliColoredString(
"{$symbol}{$symbol}{$symbol} " .
($a1x < $a2 ? "{$a1x},{$a2}" : $a2) .
" {$symbol}{$symbol}{$symbol}{$symbol}\n",
'@', // symbol
);
}
/**
* Render the old hunk.
*
* @param Differ $differ the differ object
* @param int[][] $hunk the hunk
*/
protected function renderHunkOld(Differ $differ, array $hunk): string
{
$ret = '';
$hunkOps = 0;
$noEolAtEofIdx = $differ->getOldNoEolAtEofIdx();
foreach ($hunk as [$op, $i1, $i2, $j1, $j2]) {
// OP_INS does not belongs to an old hunk
if ($op === SequenceMatcher::OP_INS) {
continue;
}
$hunkOps |= $op;
$ret .= $this->renderContext(
self::SYMBOL_MAP[$op],
$differ->getOld($i1, $i2),
$i2 === $noEolAtEofIdx,
);
}
// if there is no content changed, the hunk context should be omitted
return $hunkOps & self::OP_BLOCK_CHANGED ? $ret : '';
}
/**
* Render the new hunk.
*
* @param Differ $differ the differ object
* @param int[][] $hunk the hunk
*/
protected function renderHunkNew(Differ $differ, array $hunk): string
{
$ret = '';
$hunkOps = 0;
$noEolAtEofIdx = $differ->getNewNoEolAtEofIdx();
foreach ($hunk as [$op, $i1, $i2, $j1, $j2]) {
// OP_DEL does not belongs to a new hunk
if ($op === SequenceMatcher::OP_DEL) {
continue;
}
$hunkOps |= $op;
$ret .= $this->renderContext(
self::SYMBOL_MAP[$op],
$differ->getNew($j1, $j2),
$j2 === $noEolAtEofIdx,
);
}
// if there is no content changed, the hunk context should be omitted
return $hunkOps & self::OP_BLOCK_CHANGED ? $ret : '';
}
/**
* Render the context array with the symbol.
*
* @param string $symbol the symbol
* @param string[] $context the context
* @param bool $noEolAtEof there is no EOL at EOF in this block
*/
protected function renderContext(string $symbol, array $context, bool $noEolAtEof = false): string
{
if (empty($context)) {
return '';
}
$ret = "{$symbol} " . implode("\n{$symbol} ", $context) . "\n";
$ret = $this->cliColoredString($ret, $symbol);
if ($noEolAtEof) {
$ret .= self::GNU_OUTPUT_NO_EOL_AT_EOF . "\n";
}
return $ret;
}
}