annotate vendor/psy/psysh/src/Readline/GNUReadline.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@13 1 <?php
Chris@13 2
Chris@13 3 /*
Chris@13 4 * This file is part of Psy Shell.
Chris@13 5 *
Chris@13 6 * (c) 2012-2018 Justin Hileman
Chris@13 7 *
Chris@13 8 * For the full copyright and license information, please view the LICENSE
Chris@13 9 * file that was distributed with this source code.
Chris@13 10 */
Chris@13 11
Chris@13 12 namespace Psy\Readline;
Chris@13 13
Chris@13 14 /**
Chris@13 15 * A Readline interface implementation for GNU Readline.
Chris@13 16 *
Chris@13 17 * This is by far the coolest way to do it, but it doesn't work with new PHP.
Chris@13 18 *
Chris@13 19 * Oh well.
Chris@13 20 */
Chris@13 21 class GNUReadline implements Readline
Chris@13 22 {
Chris@13 23 /** @var string|false */
Chris@13 24 protected $historyFile;
Chris@13 25 /** @var int */
Chris@13 26 protected $historySize;
Chris@13 27 /** @var bool */
Chris@13 28 protected $eraseDups;
Chris@13 29
Chris@13 30 /**
Chris@13 31 * GNU Readline is supported iff `readline_list_history` is defined. PHP
Chris@13 32 * decided it would be awesome to swap out GNU Readline for Libedit, but
Chris@13 33 * they ended up shipping an incomplete implementation. So we've got this.
Chris@13 34 *
Chris@13 35 * @return bool
Chris@13 36 */
Chris@13 37 public static function isSupported()
Chris@13 38 {
Chris@17 39 return \function_exists('readline_list_history');
Chris@13 40 }
Chris@13 41
Chris@13 42 /**
Chris@13 43 * GNU Readline constructor.
Chris@13 44 *
Chris@13 45 * @param string|false $historyFile
Chris@13 46 * @param int $historySize
Chris@13 47 * @param bool $eraseDups
Chris@13 48 */
Chris@13 49 public function __construct($historyFile = null, $historySize = 0, $eraseDups = false)
Chris@13 50 {
Chris@13 51 $this->historyFile = ($historyFile !== null) ? $historyFile : false;
Chris@13 52 $this->historySize = $historySize;
Chris@13 53 $this->eraseDups = $eraseDups;
Chris@13 54 }
Chris@13 55
Chris@13 56 /**
Chris@13 57 * {@inheritdoc}
Chris@13 58 */
Chris@13 59 public function addHistory($line)
Chris@13 60 {
Chris@17 61 if ($res = \readline_add_history($line)) {
Chris@13 62 $this->writeHistory();
Chris@13 63 }
Chris@13 64
Chris@13 65 return $res;
Chris@13 66 }
Chris@13 67
Chris@13 68 /**
Chris@13 69 * {@inheritdoc}
Chris@13 70 */
Chris@13 71 public function clearHistory()
Chris@13 72 {
Chris@17 73 if ($res = \readline_clear_history()) {
Chris@13 74 $this->writeHistory();
Chris@13 75 }
Chris@13 76
Chris@13 77 return $res;
Chris@13 78 }
Chris@13 79
Chris@13 80 /**
Chris@13 81 * {@inheritdoc}
Chris@13 82 */
Chris@13 83 public function listHistory()
Chris@13 84 {
Chris@13 85 return readline_list_history();
Chris@13 86 }
Chris@13 87
Chris@13 88 /**
Chris@13 89 * {@inheritdoc}
Chris@13 90 */
Chris@13 91 public function readHistory()
Chris@13 92 {
Chris@13 93 // Workaround PHP bug #69054
Chris@13 94 //
Chris@13 95 // If open_basedir is set, readline_read_history() segfaults. This was fixed in 5.6.7:
Chris@13 96 //
Chris@13 97 // https://github.com/php/php-src/blob/423a057023ef3c00d2ffc16a6b43ba01d0f71796/NEWS#L19-L21
Chris@13 98 //
Chris@17 99 if (\version_compare(PHP_VERSION, '5.6.7', '>=') || !\ini_get('open_basedir')) {
Chris@17 100 \readline_read_history();
Chris@13 101 }
Chris@17 102 \readline_clear_history();
Chris@13 103
Chris@17 104 return \readline_read_history($this->historyFile);
Chris@13 105 }
Chris@13 106
Chris@13 107 /**
Chris@13 108 * {@inheritdoc}
Chris@13 109 */
Chris@13 110 public function readline($prompt = null)
Chris@13 111 {
Chris@17 112 return \readline($prompt);
Chris@13 113 }
Chris@13 114
Chris@13 115 /**
Chris@13 116 * {@inheritdoc}
Chris@13 117 */
Chris@13 118 public function redisplay()
Chris@13 119 {
Chris@17 120 \readline_redisplay();
Chris@13 121 }
Chris@13 122
Chris@13 123 /**
Chris@13 124 * {@inheritdoc}
Chris@13 125 */
Chris@13 126 public function writeHistory()
Chris@13 127 {
Chris@13 128 // We have to write history first, since it is used
Chris@13 129 // by Libedit to list history
Chris@13 130 if ($this->historyFile !== false) {
Chris@17 131 $res = \readline_write_history($this->historyFile);
Chris@13 132 } else {
Chris@13 133 $res = true;
Chris@13 134 }
Chris@13 135
Chris@13 136 if (!$res || !$this->eraseDups && !$this->historySize > 0) {
Chris@13 137 return $res;
Chris@13 138 }
Chris@13 139
Chris@13 140 $hist = $this->listHistory();
Chris@13 141 if (!$hist) {
Chris@13 142 return true;
Chris@13 143 }
Chris@13 144
Chris@13 145 if ($this->eraseDups) {
Chris@13 146 // flip-flip technique: removes duplicates, latest entries win.
Chris@17 147 $hist = \array_flip(\array_flip($hist));
Chris@13 148 // sort on keys to get the order back
Chris@17 149 \ksort($hist);
Chris@13 150 }
Chris@13 151
Chris@13 152 if ($this->historySize > 0) {
Chris@17 153 $histsize = \count($hist);
Chris@13 154 if ($histsize > $this->historySize) {
Chris@17 155 $hist = \array_slice($hist, $histsize - $this->historySize);
Chris@13 156 }
Chris@13 157 }
Chris@13 158
Chris@17 159 \readline_clear_history();
Chris@13 160 foreach ($hist as $line) {
Chris@17 161 \readline_add_history($line);
Chris@13 162 }
Chris@13 163
Chris@13 164 if ($this->historyFile !== false) {
Chris@17 165 return \readline_write_history($this->historyFile);
Chris@13 166 }
Chris@13 167
Chris@13 168 return true;
Chris@13 169 }
Chris@13 170 }