Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 148 | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
/*
4
 * This file is part of Psy Shell.
5
 *
200 lars 6
 * (c) 2012-2023 Justin Hileman
148 lars 7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
namespace Psy\TabCompletion;
13
 
14
use Psy\TabCompletion\Matcher\AbstractMatcher;
15
 
16
/**
17
 * A readline tab completion service.
18
 *
19
 * @author Marc Garcia <markcial@gmail.com>
20
 */
21
class AutoCompleter
22
{
23
    /** @var Matcher\AbstractMatcher[] */
24
    protected $matchers;
25
 
26
    /**
27
     * Register a tab completion Matcher.
28
     *
29
     * @param AbstractMatcher $matcher
30
     */
31
    public function addMatcher(AbstractMatcher $matcher)
32
    {
33
        $this->matchers[] = $matcher;
34
    }
35
 
36
    /**
37
     * Activate readline tab completion.
38
     */
39
    public function activate()
40
    {
41
        \readline_completion_function([&$this, 'callback']);
42
    }
43
 
44
    /**
45
     * Handle readline completion.
46
     *
47
     * @param string $input Readline current word
48
     * @param int    $index Current word index
49
     * @param array  $info  readline_info() data
50
     *
51
     * @return array
52
     */
53
    public function processCallback(string $input, int $index, array $info = []): array
54
    {
55
        // Some (Windows?) systems provide incomplete `readline_info`, so let's
56
        // try to work around it.
57
        $line = $info['line_buffer'];
58
        if (isset($info['end'])) {
59
            $line = \substr($line, 0, $info['end']);
60
        }
61
        if ($line === '' && $input !== '') {
62
            $line = $input;
63
        }
64
 
65
        $tokens = \token_get_all('<?php '.$line);
66
 
67
        // remove whitespaces
68
        $tokens = \array_filter($tokens, function ($token) {
69
            return !AbstractMatcher::tokenIs($token, AbstractMatcher::T_WHITESPACE);
70
        });
71
        // reset index from 0 to remove missing index number
72
        $tokens = \array_values($tokens);
73
 
74
        $matches = [];
75
        foreach ($this->matchers as $matcher) {
76
            if ($matcher->hasMatched($tokens)) {
77
                $matches = \array_merge($matcher->getMatches($tokens), $matches);
78
            }
79
        }
80
 
81
        $matches = \array_unique($matches);
82
 
83
        return !empty($matches) ? $matches : [''];
84
    }
85
 
86
    /**
87
     * The readline_completion_function callback handler.
88
     *
89
     * @see processCallback
90
     *
91
     * @param string $input
92
     * @param int    $index
93
     *
94
     * @return array
95
     */
96
    public function callback(string $input, int $index): array
97
    {
98
        return $this->processCallback($input, $index, \readline_info());
99
    }
100
 
101
    /**
102
     * Remove readline callback handler on destruct.
103
     */
104
    public function __destruct()
105
    {
106
        // PHP didn't implement the whole readline API when they first switched
107
        // to libedit. And they still haven't.
108
        if (\function_exists('readline_callback_handler_remove')) {
109
            \readline_callback_handler_remove();
110
        }
111
    }
112
}