Cursor.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Console;
  11. use Symfony\Component\Console\Output\OutputInterface;
  12. /**
  13. * @author Pierre du Plessis <pdples@gmail.com>
  14. */
  15. final class Cursor
  16. {
  17. private $output;
  18. private $input;
  19. /**
  20. * @param resource|null $input
  21. */
  22. public function __construct(OutputInterface $output, $input = null)
  23. {
  24. $this->output = $output;
  25. $this->input = $input ?? (\defined('STDIN') ? \STDIN : fopen('php://input', 'r+'));
  26. }
  27. /**
  28. * @return $this
  29. */
  30. public function moveUp(int $lines = 1): self
  31. {
  32. $this->output->write(sprintf("\x1b[%dA", $lines));
  33. return $this;
  34. }
  35. /**
  36. * @return $this
  37. */
  38. public function moveDown(int $lines = 1): self
  39. {
  40. $this->output->write(sprintf("\x1b[%dB", $lines));
  41. return $this;
  42. }
  43. /**
  44. * @return $this
  45. */
  46. public function moveRight(int $columns = 1): self
  47. {
  48. $this->output->write(sprintf("\x1b[%dC", $columns));
  49. return $this;
  50. }
  51. /**
  52. * @return $this
  53. */
  54. public function moveLeft(int $columns = 1): self
  55. {
  56. $this->output->write(sprintf("\x1b[%dD", $columns));
  57. return $this;
  58. }
  59. /**
  60. * @return $this
  61. */
  62. public function moveToColumn(int $column): self
  63. {
  64. $this->output->write(sprintf("\x1b[%dG", $column));
  65. return $this;
  66. }
  67. /**
  68. * @return $this
  69. */
  70. public function moveToPosition(int $column, int $row): self
  71. {
  72. $this->output->write(sprintf("\x1b[%d;%dH", $row + 1, $column));
  73. return $this;
  74. }
  75. /**
  76. * @return $this
  77. */
  78. public function savePosition(): self
  79. {
  80. $this->output->write("\x1b7");
  81. return $this;
  82. }
  83. /**
  84. * @return $this
  85. */
  86. public function restorePosition(): self
  87. {
  88. $this->output->write("\x1b8");
  89. return $this;
  90. }
  91. /**
  92. * @return $this
  93. */
  94. public function hide(): self
  95. {
  96. $this->output->write("\x1b[?25l");
  97. return $this;
  98. }
  99. /**
  100. * @return $this
  101. */
  102. public function show(): self
  103. {
  104. $this->output->write("\x1b[?25h\x1b[?0c");
  105. return $this;
  106. }
  107. /**
  108. * Clears all the output from the current line.
  109. *
  110. * @return $this
  111. */
  112. public function clearLine(): self
  113. {
  114. $this->output->write("\x1b[2K");
  115. return $this;
  116. }
  117. /**
  118. * Clears all the output from the current line after the current position.
  119. */
  120. public function clearLineAfter(): self
  121. {
  122. $this->output->write("\x1b[K");
  123. return $this;
  124. }
  125. /**
  126. * Clears all the output from the cursors' current position to the end of the screen.
  127. *
  128. * @return $this
  129. */
  130. public function clearOutput(): self
  131. {
  132. $this->output->write("\x1b[0J");
  133. return $this;
  134. }
  135. /**
  136. * Clears the entire screen.
  137. *
  138. * @return $this
  139. */
  140. public function clearScreen(): self
  141. {
  142. $this->output->write("\x1b[2J");
  143. return $this;
  144. }
  145. /**
  146. * Returns the current cursor position as x,y coordinates.
  147. */
  148. public function getCurrentPosition(): array
  149. {
  150. static $isTtySupported;
  151. if (null === $isTtySupported && \function_exists('proc_open')) {
  152. $isTtySupported = (bool) @proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes);
  153. }
  154. if (!$isTtySupported) {
  155. return [1, 1];
  156. }
  157. $sttyMode = shell_exec('stty -g');
  158. shell_exec('stty -icanon -echo');
  159. @fwrite($this->input, "\033[6n");
  160. $code = trim(fread($this->input, 1024));
  161. shell_exec(sprintf('stty %s', $sttyMode));
  162. sscanf($code, "\033[%d;%dR", $row, $col);
  163. return [$col, $row];
  164. }
  165. }