Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | 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
 *
6
 * (c) 2012-2022 Justin Hileman
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\Readline;
13
 
14
/**
15
 * A Readline interface implementation for GNU Readline.
16
 *
17
 * This is by far the coolest way to do it, if you can.
18
 *
19
 * Oh well.
20
 */
21
class GNUReadline implements Readline
22
{
23
    /** @var string|false */
24
    protected $historyFile;
25
    /** @var int */
26
    protected $historySize;
27
    /** @var bool */
28
    protected $eraseDups;
29
 
30
    /**
31
     * GNU Readline is supported iff `readline_list_history` is defined. PHP
32
     * decided it would be awesome to swap out GNU Readline for Libedit, but
33
     * they ended up shipping an incomplete implementation. So we've got this.
34
     *
35
     * NOTE: As of PHP 7.4, PHP sometimes has history support in the Libedit
36
     * wrapper, so that will use the GNUReadline implementation as well!
37
     *
38
     * @return bool
39
     */
40
    public static function isSupported(): bool
41
    {
42
        return \function_exists('readline') && \function_exists('readline_list_history');
43
    }
44
 
45
    /**
46
     * Check whether this readline implementation supports bracketed paste.
47
     *
48
     * Currently, the GNU readline implementation does, but the libedit wrapper does not.
49
     *
50
     * @return bool
51
     */
52
    public static function supportsBracketedPaste(): bool
53
    {
54
        return self::isSupported() && \stripos(\readline_info('library_version') ?: '', 'editline') === false;
55
    }
56
 
57
    public function __construct($historyFile = null, $historySize = 0, $eraseDups = false)
58
    {
59
        $this->historyFile = ($historyFile !== null) ? $historyFile : false;
60
        $this->historySize = $historySize;
61
        $this->eraseDups = $eraseDups;
62
 
63
        \readline_info('readline_name', 'psysh');
64
    }
65
 
66
    /**
67
     * {@inheritdoc}
68
     */
69
    public function addHistory(string $line): bool
70
    {
71
        if ($res = \readline_add_history($line)) {
72
            $this->writeHistory();
73
        }
74
 
75
        return $res;
76
    }
77
 
78
    /**
79
     * {@inheritdoc}
80
     */
81
    public function clearHistory(): bool
82
    {
83
        if ($res = \readline_clear_history()) {
84
            $this->writeHistory();
85
        }
86
 
87
        return $res;
88
    }
89
 
90
    /**
91
     * {@inheritdoc}
92
     */
93
    public function listHistory(): array
94
    {
95
        return \readline_list_history();
96
    }
97
 
98
    /**
99
     * {@inheritdoc}
100
     */
101
    public function readHistory(): bool
102
    {
103
        \readline_read_history();
104
        \readline_clear_history();
105
 
106
        return \readline_read_history($this->historyFile);
107
    }
108
 
109
    /**
110
     * {@inheritdoc}
111
     */
112
    public function readline(string $prompt = null)
113
    {
114
        return \readline($prompt);
115
    }
116
 
117
    /**
118
     * {@inheritdoc}
119
     */
120
    public function redisplay()
121
    {
122
        \readline_redisplay();
123
    }
124
 
125
    /**
126
     * {@inheritdoc}
127
     */
128
    public function writeHistory(): bool
129
    {
130
        // We have to write history first, since it is used
131
        // by Libedit to list history
132
        if ($this->historyFile !== false) {
133
            $res = \readline_write_history($this->historyFile);
134
        } else {
135
            $res = true;
136
        }
137
 
138
        if (!$res || !$this->eraseDups && !$this->historySize > 0) {
139
            return $res;
140
        }
141
 
142
        $hist = $this->listHistory();
143
        if (!$hist) {
144
            return true;
145
        }
146
 
147
        if ($this->eraseDups) {
148
            // flip-flip technique: removes duplicates, latest entries win.
149
            $hist = \array_flip(\array_flip($hist));
150
            // sort on keys to get the order back
151
            \ksort($hist);
152
        }
153
 
154
        if ($this->historySize > 0) {
155
            $histsize = \count($hist);
156
            if ($histsize > $this->historySize) {
157
                $hist = \array_slice($hist, $histsize - $this->historySize);
158
            }
159
        }
160
 
161
        \readline_clear_history();
162
        foreach ($hist as $line) {
163
            \readline_add_history($line);
164
        }
165
 
166
        if ($this->historyFile !== false) {
167
            return \readline_write_history($this->historyFile);
168
        }
169
 
170
        return true;
171
    }
172
}