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\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
    public static function isSupported(): bool
39
    {
40
        return \function_exists('readline') && \function_exists('readline_list_history');
41
    }
42
 
43
    /**
44
     * Check whether this readline implementation supports bracketed paste.
45
     *
46
     * Currently, the GNU readline implementation does, but the libedit wrapper does not.
47
     */
48
    public static function supportsBracketedPaste(): bool
49
    {
50
        return self::isSupported() && \stripos(\readline_info('library_version') ?: '', 'editline') === false;
51
    }
52
 
53
    public function __construct($historyFile = null, $historySize = 0, $eraseDups = false)
54
    {
55
        $this->historyFile = ($historyFile !== null) ? $historyFile : false;
56
        $this->historySize = $historySize;
57
        $this->eraseDups = $eraseDups;
58
 
59
        \readline_info('readline_name', 'psysh');
60
    }
61
 
62
    /**
63
     * {@inheritdoc}
64
     */
65
    public function addHistory(string $line): bool
66
    {
67
        if ($res = \readline_add_history($line)) {
68
            $this->writeHistory();
69
        }
70
 
71
        return $res;
72
    }
73
 
74
    /**
75
     * {@inheritdoc}
76
     */
77
    public function clearHistory(): bool
78
    {
79
        if ($res = \readline_clear_history()) {
80
            $this->writeHistory();
81
        }
82
 
83
        return $res;
84
    }
85
 
86
    /**
87
     * {@inheritdoc}
88
     */
89
    public function listHistory(): array
90
    {
91
        return \readline_list_history();
92
    }
93
 
94
    /**
95
     * {@inheritdoc}
96
     */
97
    public function readHistory(): bool
98
    {
99
        \readline_read_history();
100
        \readline_clear_history();
101
 
102
        return \readline_read_history($this->historyFile);
103
    }
104
 
105
    /**
106
     * {@inheritdoc}
107
     */
108
    public function readline(string $prompt = null)
109
    {
110
        return \readline($prompt);
111
    }
112
 
113
    /**
114
     * {@inheritdoc}
115
     */
116
    public function redisplay()
117
    {
118
        \readline_redisplay();
119
    }
120
 
121
    /**
122
     * {@inheritdoc}
123
     */
124
    public function writeHistory(): bool
125
    {
126
        // We have to write history first, since it is used
127
        // by Libedit to list history
128
        if ($this->historyFile !== false) {
129
            $res = \readline_write_history($this->historyFile);
130
        } else {
131
            $res = true;
132
        }
133
 
134
        if (!$res || !$this->eraseDups && !$this->historySize > 0) {
135
            return $res;
136
        }
137
 
138
        $hist = $this->listHistory();
139
        if (!$hist) {
140
            return true;
141
        }
142
 
143
        if ($this->eraseDups) {
144
            // flip-flip technique: removes duplicates, latest entries win.
145
            $hist = \array_flip(\array_flip($hist));
146
            // sort on keys to get the order back
147
            \ksort($hist);
148
        }
149
 
150
        if ($this->historySize > 0) {
151
            $histsize = \count($hist);
152
            if ($histsize > $this->historySize) {
153
                $hist = \array_slice($hist, $histsize - $this->historySize);
154
            }
155
        }
156
 
157
        \readline_clear_history();
158
        foreach ($hist as $line) {
159
            \readline_add_history($line);
160
        }
161
 
162
        if ($this->historyFile !== false) {
163
            return \readline_write_history($this->historyFile);
164
        }
165
 
166
        return true;
167
    }
168
}