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