primo commit
This commit is contained in:
137
libraries/vendor/jfcherng/php-diff/src/Renderer/Text/AbstractText.php
vendored
Normal file
137
libraries/vendor/jfcherng/php-diff/src/Renderer/Text/AbstractText.php
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jfcherng\Diff\Renderer\Text;
|
||||
|
||||
use Jfcherng\Diff\Exception\UnsupportedFunctionException;
|
||||
use Jfcherng\Diff\Renderer\AbstractRenderer;
|
||||
use Jfcherng\Diff\Renderer\RendererConstant;
|
||||
use Jfcherng\Utility\CliColor;
|
||||
|
||||
/**
|
||||
* Base renderer for rendering text-based diffs.
|
||||
*/
|
||||
abstract class AbstractText extends AbstractRenderer
|
||||
{
|
||||
/**
|
||||
* @var bool is this renderer pure text?
|
||||
*/
|
||||
public const IS_TEXT_RENDERER = true;
|
||||
|
||||
/**
|
||||
* @var string the diff output representing there is no EOL at EOF in the GNU diff tool
|
||||
*/
|
||||
public const GNU_OUTPUT_NO_EOL_AT_EOF = '\ No newline at end of file';
|
||||
|
||||
/**
|
||||
* @var bool controls whether cliColoredString() is enabled or not
|
||||
*/
|
||||
protected $isCliColorEnabled = false;
|
||||
|
||||
public function setOptions(array $options): AbstractRenderer
|
||||
{
|
||||
parent::setOptions($options);
|
||||
|
||||
// determine $this->isCliColorEnabled
|
||||
if ($this->options['cliColorization'] === RendererConstant::CLI_COLOR_ENABLE) {
|
||||
$this->isCliColorEnabled = true;
|
||||
} elseif ($this->options['cliColorization'] === RendererConstant::CLI_COLOR_DISABLE) {
|
||||
$this->isCliColorEnabled = false;
|
||||
} else {
|
||||
$this->isCliColorEnabled = \PHP_SAPI === 'cli' && $this->hasColorSupport(\STDOUT);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getResultForIdenticalsDefault(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function renderArrayWorker(array $differArray): string
|
||||
{
|
||||
throw new UnsupportedFunctionException(__METHOD__);
|
||||
|
||||
return ''; // make IDE not complain
|
||||
}
|
||||
|
||||
/**
|
||||
* Colorize the string for CLI output.
|
||||
*
|
||||
* @param string $str the string
|
||||
* @param null|string $symbol the symbol
|
||||
*
|
||||
* @return string the (maybe) colorized string
|
||||
*/
|
||||
protected function cliColoredString(string $str, ?string $symbol): string
|
||||
{
|
||||
static $symbolToStyles = [
|
||||
'@' => ['f_purple', 'bold'], // header
|
||||
'-' => ['f_red', 'bold'], // deleted
|
||||
'+' => ['f_green', 'bold'], // inserted
|
||||
'!' => ['f_yellow', 'bold'], // replaced
|
||||
];
|
||||
|
||||
$styles = $symbolToStyles[$symbol] ?? [];
|
||||
|
||||
if (!$this->isCliColorEnabled || empty($styles)) {
|
||||
return $str;
|
||||
}
|
||||
|
||||
return CliColor::color($str, $styles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the stream supports colorization.
|
||||
*
|
||||
* Colorization is disabled if not supported by the stream:
|
||||
*
|
||||
* This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo
|
||||
* terminals via named pipes, so we can only check the environment.
|
||||
*
|
||||
* Reference: Composer\XdebugHandler\Process::supportsColor
|
||||
* https://github.com/composer/xdebug-handler
|
||||
*
|
||||
* @see https://github.com/symfony/console/blob/647c51ff073300a432a4a504e29323cf0d5e0571/Output/StreamOutput.php#L81-L124
|
||||
*
|
||||
* @param resource $stream
|
||||
*
|
||||
* @return bool true if the stream supports colorization, false otherwise
|
||||
*
|
||||
* @suppress PhanUndeclaredFunction
|
||||
*/
|
||||
protected function hasColorSupport($stream): bool
|
||||
{
|
||||
// Follow https://no-color.org/
|
||||
if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ('Hyper' === getenv('TERM_PROGRAM')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (\DIRECTORY_SEPARATOR === '\\') {
|
||||
return (\function_exists('sapi_windows_vt100_support')
|
||||
&& @sapi_windows_vt100_support($stream))
|
||||
|| false !== getenv('ANSICON')
|
||||
|| 'ON' === getenv('ConEmuANSI')
|
||||
|| 'xterm' === getenv('TERM');
|
||||
}
|
||||
|
||||
if (\function_exists('stream_isatty')) {
|
||||
return @stream_isatty($stream);
|
||||
}
|
||||
|
||||
if (\function_exists('posix_isatty')) {
|
||||
return @posix_isatty($stream);
|
||||
}
|
||||
|
||||
$stat = @fstat($stream);
|
||||
|
||||
// Check if formatted mode is S_IFCHR
|
||||
return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
|
||||
}
|
||||
}
|
||||
160
libraries/vendor/jfcherng/php-diff/src/Renderer/Text/Context.php
vendored
Normal file
160
libraries/vendor/jfcherng/php-diff/src/Renderer/Text/Context.php
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
<?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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
78
libraries/vendor/jfcherng/php-diff/src/Renderer/Text/JsonText.php
vendored
Normal file
78
libraries/vendor/jfcherng/php-diff/src/Renderer/Text/JsonText.php
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jfcherng\Diff\Renderer\Text;
|
||||
|
||||
use Jfcherng\Diff\Differ;
|
||||
use Jfcherng\Diff\SequenceMatcher;
|
||||
|
||||
/**
|
||||
* Plain text Json diff generator.
|
||||
*/
|
||||
final class JsonText extends AbstractText
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public const INFO = [
|
||||
'desc' => 'Text JSON',
|
||||
'type' => 'Text',
|
||||
];
|
||||
|
||||
protected function renderWorker(Differ $differ): string
|
||||
{
|
||||
$ret = [];
|
||||
|
||||
foreach ($differ->getGroupedOpcodes() as $hunk) {
|
||||
$ret[] = $this->renderHunk($differ, $hunk);
|
||||
}
|
||||
|
||||
if ($this->options['outputTagAsString']) {
|
||||
$this->convertTagToString($ret);
|
||||
}
|
||||
|
||||
return json_encode($ret, $this->options['jsonEncodeFlags']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the hunk.
|
||||
*
|
||||
* @param Differ $differ the differ object
|
||||
* @param int[][] $hunk the hunk
|
||||
*/
|
||||
protected function renderHunk(Differ $differ, array $hunk): array
|
||||
{
|
||||
$ret = [];
|
||||
|
||||
foreach ($hunk as [$op, $i1, $i2, $j1, $j2]) {
|
||||
$ret[] = [
|
||||
'tag' => $op,
|
||||
'old' => [
|
||||
'offset' => $i1,
|
||||
'lines' => $differ->getOld($i1, $i2),
|
||||
],
|
||||
'new' => [
|
||||
'offset' => $j1,
|
||||
'lines' => $differ->getNew($j1, $j2),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert tags of changes to their string form for better readability.
|
||||
*
|
||||
* @param array[][] $changes the changes
|
||||
*/
|
||||
protected function convertTagToString(array &$changes): void
|
||||
{
|
||||
foreach ($changes as &$hunks) {
|
||||
foreach ($hunks as &$block) {
|
||||
$block['tag'] = SequenceMatcher::opIntToStr($block['tag']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
144
libraries/vendor/jfcherng/php-diff/src/Renderer/Text/Unified.php
vendored
Normal file
144
libraries/vendor/jfcherng/php-diff/src/Renderer/Text/Unified.php
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jfcherng\Diff\Renderer\Text;
|
||||
|
||||
use Jfcherng\Diff\Differ;
|
||||
use Jfcherng\Diff\SequenceMatcher;
|
||||
|
||||
/**
|
||||
* Unified diff generator.
|
||||
*
|
||||
* @see https://en.wikipedia.org/wiki/Diff#Unified_format
|
||||
*/
|
||||
final class Unified extends AbstractText
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public const INFO = [
|
||||
'desc' => 'Unified',
|
||||
'type' => 'Text',
|
||||
];
|
||||
|
||||
protected function renderWorker(Differ $differ): string
|
||||
{
|
||||
$ret = '';
|
||||
|
||||
foreach ($differ->getGroupedOpcodesGnu() as $hunk) {
|
||||
$ret .= $this->renderHunkHeader($differ, $hunk);
|
||||
$ret .= $this->renderHunkBlocks($differ, $hunk);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the hunk header.
|
||||
*
|
||||
* @param Differ $differ the differ
|
||||
* @param int[][] $hunk the hunk
|
||||
*/
|
||||
protected function renderHunkHeader(Differ $differ, array $hunk): string
|
||||
{
|
||||
$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];
|
||||
|
||||
$oldLinesCount = $i2 - $i1;
|
||||
$newLinesCount = $j2 - $j1;
|
||||
|
||||
return $this->cliColoredString(
|
||||
'@@' .
|
||||
' -' .
|
||||
// the line number in GNU diff is 1-based, so we add 1
|
||||
// a special case is when a hunk has only changed blocks,
|
||||
// i.e., context is set to 0, we do not need the adding
|
||||
($i1 === $i2 ? $i1 : $i1 + 1) .
|
||||
// if the line counts is 1, it can (and mostly) be omitted
|
||||
($oldLinesCount === 1 ? '' : ",{$oldLinesCount}") .
|
||||
' +' .
|
||||
($j1 === $j2 ? $j1 : $j1 + 1) .
|
||||
($newLinesCount === 1 ? '' : ",{$newLinesCount}") .
|
||||
" @@\n",
|
||||
'@', // symbol
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the hunk content.
|
||||
*
|
||||
* @param Differ $differ the differ
|
||||
* @param int[][] $hunk the hunk
|
||||
*/
|
||||
protected function renderHunkBlocks(Differ $differ, array $hunk): string
|
||||
{
|
||||
$ret = '';
|
||||
|
||||
$oldNoEolAtEofIdx = $differ->getOldNoEolAtEofIdx();
|
||||
$newNoEolAtEofIdx = $differ->getNewNoEolAtEofIdx();
|
||||
|
||||
foreach ($hunk as [$op, $i1, $i2, $j1, $j2]) {
|
||||
// note that although we are in a OP_EQ situation,
|
||||
// the old and the new may not be exactly the same
|
||||
// because of ignoreCase, ignoreWhitespace, etc
|
||||
if ($op === SequenceMatcher::OP_EQ) {
|
||||
// we could only pick either the old or the new to show
|
||||
// note that the GNU diff will use the old one because it creates a patch
|
||||
$ret .= $this->renderContext(
|
||||
' ',
|
||||
$differ->getOld($i1, $i2),
|
||||
$i2 === $oldNoEolAtEofIdx,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($op & (SequenceMatcher::OP_REP | SequenceMatcher::OP_DEL)) {
|
||||
$ret .= $this->renderContext(
|
||||
'-',
|
||||
$differ->getOld($i1, $i2),
|
||||
$i2 === $oldNoEolAtEofIdx,
|
||||
);
|
||||
}
|
||||
|
||||
if ($op & (SequenceMatcher::OP_REP | SequenceMatcher::OP_INS)) {
|
||||
$ret .= $this->renderContext(
|
||||
'+',
|
||||
$differ->getNew($j1, $j2),
|
||||
$j2 === $newNoEolAtEofIdx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user