Path.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <?php
  2. /**
  3. * Hoa
  4. *
  5. *
  6. * @license
  7. *
  8. * New BSD License
  9. *
  10. * Copyright © 2007-2017, Hoa community. All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions are met:
  14. * * Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * * Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. * * Neither the name of the Hoa nor the names of its contributors may be
  20. * used to endorse or promote products derived from this software without
  21. * specific prior written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  24. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
  27. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  28. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  29. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  30. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  31. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  32. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33. * POSSIBILITY OF SUCH DAMAGE.
  34. */
  35. namespace Hoa\Console\Readline\Autocompleter;
  36. /**
  37. * Class \Hoa\Console\Readline\Autocompleter\Path.
  38. *
  39. * Path autocompleter.
  40. *
  41. * @copyright Copyright © 2007-2017 Hoa community
  42. * @license New BSD License
  43. */
  44. class Path implements Autocompleter
  45. {
  46. /**
  47. * Root is the current working directory.
  48. *
  49. * @const string
  50. */
  51. const PWD = null;
  52. /**
  53. * Root.
  54. *
  55. * @var string
  56. */
  57. protected $_root = null;
  58. /**
  59. * Iterator factory. Please, see the self::setIteratorFactory method.
  60. *
  61. * @var \Closure
  62. */
  63. protected $_iteratorFactory = null;
  64. /**
  65. * Constructor.
  66. *
  67. * @param string $root Root.
  68. * @param \Closure $iteratorFactory Iterator factory (please, see
  69. * the self::setIteratorFactory
  70. * method).
  71. */
  72. public function __construct(
  73. $root = null,
  74. \Closure $iteratorFactory = null
  75. ) {
  76. if (null === $root) {
  77. $root = static::PWD;
  78. }
  79. $this->setRoot($root);
  80. if (null !== $iteratorFactory) {
  81. $this->setIteratorFactory($iteratorFactory);
  82. }
  83. return;
  84. }
  85. /**
  86. * Complete a word.
  87. * Returns null for no word, a full-word or an array of full-words.
  88. *
  89. * @param string &$prefix Prefix to autocomplete.
  90. * @return mixed
  91. */
  92. public function complete(&$prefix)
  93. {
  94. $root = $this->getRoot();
  95. if (static::PWD === $root) {
  96. $root = getcwd();
  97. }
  98. $path = $root . DS . $prefix;
  99. if (!is_dir($path)) {
  100. $path = dirname($path) . DS;
  101. $prefix = basename($prefix);
  102. } else {
  103. $prefix = null;
  104. }
  105. $iteratorFactory = $this->getIteratorFactory() ?:
  106. static::getDefaultIteratorFactory();
  107. try {
  108. $iterator = $iteratorFactory($path);
  109. $out = [];
  110. $length = mb_strlen($prefix);
  111. foreach ($iterator as $fileinfo) {
  112. $filename = $fileinfo->getFilename();
  113. if (null === $prefix ||
  114. (mb_substr($filename, 0, $length) === $prefix)) {
  115. if ($fileinfo->isDir()) {
  116. $out[] = $filename . '/';
  117. } else {
  118. $out[] = $filename;
  119. }
  120. }
  121. }
  122. } catch (\Exception $e) {
  123. return null;
  124. }
  125. $count = count($out);
  126. if (1 === $count) {
  127. return $out[0];
  128. }
  129. if (0 === $count) {
  130. return null;
  131. }
  132. return $out;
  133. }
  134. /**
  135. * Get definition of a word.
  136. *
  137. * @return string
  138. */
  139. public function getWordDefinition()
  140. {
  141. return '/?[\w\d\\_\-\.]+(/[\w\d\\_\-\.]*)*';
  142. }
  143. /**
  144. * Set root.
  145. *
  146. * @param string $root Root.
  147. * @return string
  148. */
  149. public function setRoot($root)
  150. {
  151. $old = $this->_root;
  152. $this->_root = $root;
  153. return $old;
  154. }
  155. /**
  156. * Get root.
  157. *
  158. * @return string
  159. */
  160. public function getRoot()
  161. {
  162. return $this->_root;
  163. }
  164. /**
  165. * Set iterator factory (a finder).
  166. *
  167. * @param \Closure $iteratorFactory Closore with a single argument:
  168. * $path of the iterator.
  169. * @return string
  170. */
  171. public function setIteratorFactory(\Closure $iteratorFactory)
  172. {
  173. $old = $this->_iteratorFactory;
  174. $this->_iteratorFactory = $iteratorFactory;
  175. return $old;
  176. }
  177. /**
  178. * Get iterator factory.
  179. *
  180. * @return \Closure
  181. */
  182. public function getIteratorFactory()
  183. {
  184. return $this->_iteratorFactory;
  185. }
  186. /**
  187. * Get default iterator factory (based on \DirectoryIterator).
  188. *
  189. * @return \Closure
  190. */
  191. public static function getDefaultIteratorFactory()
  192. {
  193. return function ($path) {
  194. return new \DirectoryIterator($path);
  195. };
  196. }
  197. }