
| Current Path : /var/www/html/c12park/vendor/psy/psysh/src/Completion/Source/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : /var/www/html/c12park/vendor/psy/psysh/src/Completion/Source/MatcherAdapterSource.php |
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2026 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Completion\Source;
use Psy\Completion\AnalysisResult;
use Psy\Completion\CompletionKind;
use Psy\TabCompletion\Matcher\AbstractMatcher;
use Psy\TabCompletion\Matcher\ClassAttributesMatcher;
use Psy\TabCompletion\Matcher\ClassMethodsMatcher;
use Psy\TabCompletion\Matcher\ClassNamesMatcher;
use Psy\TabCompletion\Matcher\CommandsMatcher;
use Psy\TabCompletion\Matcher\ConstantsMatcher;
use Psy\TabCompletion\Matcher\FunctionsMatcher;
use Psy\TabCompletion\Matcher\KeywordsMatcher;
use Psy\TabCompletion\Matcher\MagicMethodsMatcher;
use Psy\TabCompletion\Matcher\MagicPropertiesMatcher;
use Psy\TabCompletion\Matcher\ObjectAttributesMatcher;
use Psy\TabCompletion\Matcher\ObjectMethodsMatcher;
use Psy\TabCompletion\Matcher\VariablesMatcher;
/**
* Compatibility adapter for legacy TabCompletion matchers.
*
* Wraps one or more legacy AbstractMatcher instances and adapts them to work
* with the CompletionEngine system, so users with custom matchers can continue
* using them alongside the new AST-based completion sources.
*
* Default matchers that have been superseded by new-style completion sources
* are automatically filtered out to avoid duplicate results.
*/
class MatcherAdapterSource implements SourceInterface
{
/**
* Matchers superseded by new-style completion sources.
*
* @var string[]
*/
private const SUPERSEDED_MATCHERS = [
ClassAttributesMatcher::class,
ClassMethodsMatcher::class,
ClassNamesMatcher::class,
CommandsMatcher::class,
ConstantsMatcher::class,
FunctionsMatcher::class,
KeywordsMatcher::class,
MagicMethodsMatcher::class,
MagicPropertiesMatcher::class,
ObjectAttributesMatcher::class,
ObjectMethodsMatcher::class,
VariablesMatcher::class,
];
/** @var AbstractMatcher[] */
private array $matchers;
/**
* @param AbstractMatcher[] $matchers Legacy matchers to wrap
*/
public function __construct(array $matchers)
{
$this->matchers = \array_filter(
$matchers,
fn ($matcher) => !\in_array(\get_class($matcher), self::SUPERSEDED_MATCHERS, true)
);
}
/**
* {@inheritdoc}
*/
public function appliesToKind(int $kinds): bool
{
// Legacy matchers don't understand command argument contexts.
return ($kinds & ~CompletionKind::COMMAND_ARGUMENT) !== 0;
}
/**
* {@inheritdoc}
*/
public function getCompletions(AnalysisResult $analysis): array
{
$tokens = $this->convertToTokens($analysis);
$info = $this->buildReadlineInfo($analysis);
$matches = [];
foreach ($this->matchers as $matcher) {
if ($matcher->hasMatched($tokens)) {
$matches = \array_merge($matches, $matcher->getMatches($tokens, $info));
}
}
return $matches;
}
/**
* Convert AnalysisResult to token array for legacy matchers.
*
* Legacy matchers expect tokens from token_get_all(). We reconstruct
* a reasonable approximation from the analysis result.
*
* @return array Token array compatible with legacy matchers
*/
private function convertToTokens(AnalysisResult $analysis): array
{
if (!empty($analysis->tokens)) {
return $this->filterTokens($analysis->tokens);
}
// Reconstruct a token array from the analysis result
$tokens = [];
if ($analysis->leftSide !== null) {
$leftTokens = \token_get_all('<?php '.$analysis->leftSide);
$tokens = \array_merge($tokens, \array_slice($leftTokens, 1));
}
if (($analysis->kinds & CompletionKind::OBJECT_MEMBER) !== 0) {
$tokens[] = [\T_OBJECT_OPERATOR, '->', 0];
} elseif (($analysis->kinds & CompletionKind::STATIC_MEMBER) !== 0) {
$tokens[] = [\T_DOUBLE_COLON, '::', 0];
}
if ($analysis->prefix !== '') {
$tokens[] = [\T_STRING, $analysis->prefix, 0];
}
return $this->filterTokens($tokens);
}
/**
* Filter tokens to remove whitespace (legacy matcher expectation).
*
* @return array Filtered token array
*/
private function filterTokens(array $tokens): array
{
$filtered = \array_filter($tokens, fn ($token) => !AbstractMatcher::tokenIs($token, AbstractMatcher::T_WHITESPACE));
return \array_values($filtered);
}
/**
* Build readline_info array for legacy matchers.
*
* @return array readline_info-like array
*/
private function buildReadlineInfo(AnalysisResult $analysis): array
{
if ($analysis->readlineInfo !== []) {
return $analysis->readlineInfo;
}
$lineBuffer = '';
if ($analysis->leftSide !== null) {
$lineBuffer .= $analysis->leftSide;
if (($analysis->kinds & CompletionKind::OBJECT_MEMBER) !== 0) {
$lineBuffer .= '->';
} elseif (($analysis->kinds & CompletionKind::STATIC_MEMBER) !== 0) {
$lineBuffer .= '::';
}
}
$lineBuffer .= $analysis->prefix;
return [
'line_buffer' => $lineBuffer,
'point' => \strlen($lineBuffer),
'end' => \strlen($lineBuffer),
];
}
}