-
Notifications
You must be signed in to change notification settings - Fork 106
Refactor IO #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor IO #80
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
namespace PhpSchool\CliMenu\IO; | ||
|
||
/** | ||
* @author Aydin Hassan <[email protected]> | ||
*/ | ||
class BufferedOutput implements OutputStream | ||
{ | ||
private $buffer = ''; | ||
|
||
public function write(string $buffer): void | ||
{ | ||
$this->buffer .= $buffer; | ||
} | ||
|
||
public function fetch(bool $clean = true) : string | ||
{ | ||
$buffer = $this->buffer; | ||
|
||
if ($clean) { | ||
$this->buffer = ''; | ||
} | ||
|
||
return $buffer; | ||
} | ||
|
||
public function __toString() : string | ||
{ | ||
return $this->fetch(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?php | ||
|
||
namespace PhpSchool\CliMenu\IO; | ||
|
||
/** | ||
* @author Aydin Hassan <[email protected]> | ||
*/ | ||
interface InputStream | ||
{ | ||
/** | ||
* Callback should be called with the number of bytes requested | ||
* when ready. | ||
*/ | ||
public function read(int $numBytes, callable $callback) : void; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
namespace PhpSchool\CliMenu\IO; | ||
|
||
/** | ||
* @author Aydin Hassan <[email protected]> | ||
*/ | ||
interface OutputStream | ||
{ | ||
public function write(string $buffer) : void; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?php | ||
|
||
namespace PhpSchool\CliMenu\IO; | ||
|
||
use function is_resource; | ||
use function get_resource_type; | ||
use function stream_get_meta_data; | ||
use function strpos; | ||
|
||
/** | ||
* @author Aydin Hassan <[email protected]> | ||
*/ | ||
class ResourceInputStream implements InputStream | ||
{ | ||
/** | ||
* @var resource | ||
*/ | ||
private $stream; | ||
|
||
public function __construct($stream = null) | ||
{ | ||
if ($stream === null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe I'm being silly, can't you have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's give it a whirl There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed we can! |
||
$stream = STDIN; | ||
} | ||
|
||
if (!is_resource($stream) || get_resource_type($stream) !== 'stream') { | ||
throw new \InvalidArgumentException('Expected a valid stream'); | ||
} | ||
|
||
$meta = stream_get_meta_data($stream); | ||
if (strpos($meta['mode'], 'r') === false && strpos($meta['mode'], '+') === false) { | ||
throw new \InvalidArgumentException('Expected a readable stream'); | ||
} | ||
|
||
$this->stream = $stream; | ||
} | ||
|
||
public function read(int $numBytes, callable $callback) : void | ||
{ | ||
$buffer = fread($this->stream, $numBytes); | ||
$callback($buffer); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?php | ||
|
||
namespace PhpSchool\CliMenu\IO; | ||
|
||
use function is_resource; | ||
use function get_resource_type; | ||
use function stream_get_meta_data; | ||
use function strpos; | ||
|
||
/** | ||
* @author Aydin Hassan <[email protected]> | ||
*/ | ||
class ResourceOutputStream implements OutputStream | ||
{ | ||
/** | ||
* @var resource | ||
*/ | ||
private $stream; | ||
|
||
public function __construct($stream = null) | ||
{ | ||
if ($stream === null) { | ||
$stream = STDOUT; | ||
} | ||
|
||
if (!is_resource($stream) || get_resource_type($stream) !== 'stream') { | ||
throw new \InvalidArgumentException('Expected a valid stream'); | ||
} | ||
|
||
$meta = stream_get_meta_data($stream); | ||
if (strpos($meta['mode'], 'r') !== false && strpos($meta['mode'], '+') === false) { | ||
throw new \InvalidArgumentException('Expected a writable stream'); | ||
} | ||
|
||
$this->stream = $stream; | ||
} | ||
|
||
public function write(string $buffer): void | ||
{ | ||
fwrite($this->stream, $buffer); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,13 +2,16 @@ | |
|
||
namespace PhpSchool\CliMenu\Terminal; | ||
|
||
use PhpSchool\CliMenu\IO\ResourceInputStream; | ||
use PhpSchool\CliMenu\IO\ResourceOutputStream; | ||
|
||
/** | ||
* @author Michael Woodward <[email protected]> | ||
*/ | ||
class TerminalFactory | ||
{ | ||
public static function fromSystem() : TerminalInterface | ||
{ | ||
return new UnixTerminal(); | ||
return new UnixTerminal(new ResourceInputStream, new ResourceOutputStream); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,8 @@ | |
|
||
namespace PhpSchool\CliMenu\Terminal; | ||
|
||
use PhpSchool\CliMenu\IO\OutputStream; | ||
|
||
/** | ||
* @author Michael Woodward <[email protected]> | ||
*/ | ||
|
@@ -85,5 +87,10 @@ public function disableCursor() : void; | |
/** | ||
* @return string | ||
*/ | ||
public function getKeyedInput() : string; | ||
public function getKeyedInput(array $map = []) : ?string; | ||
|
||
/** | ||
* Get the output stream | ||
*/ | ||
public function getOutput() : OutputStream; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,9 @@ | |
|
||
namespace PhpSchool\CliMenu\Terminal; | ||
|
||
use PhpSchool\CliMenu\IO\InputStream; | ||
use PhpSchool\CliMenu\IO\OutputStream; | ||
|
||
/** | ||
* @author Michael Woodward <[email protected]> | ||
*/ | ||
|
@@ -37,13 +40,25 @@ class UnixTerminal implements TerminalInterface | |
*/ | ||
private $originalConfiguration; | ||
|
||
/** | ||
* @var InputStream | ||
*/ | ||
private $input; | ||
|
||
/** | ||
* @var OutputStream | ||
*/ | ||
private $output; | ||
|
||
/** | ||
* Initialise the terminal from resource | ||
* | ||
*/ | ||
public function __construct() | ||
public function __construct(InputStream $input, OutputStream $output) | ||
{ | ||
$this->getOriginalConfiguration(); | ||
$this->input = $input; | ||
$this->output = $output; | ||
} | ||
|
||
/** | ||
|
@@ -129,7 +144,7 @@ public function supportsColour() : bool | |
return $this->isTTY(); | ||
} | ||
|
||
public function getKeyedInput() : string | ||
public function getKeyedInput(array $map = []) : ?string | ||
{ | ||
// TODO: Move to class var? | ||
// TODO: up, down, enter etc in Abstract CONSTs | ||
|
@@ -145,7 +160,11 @@ public function getKeyedInput() : string | |
" " => 'enter', | ||
]; | ||
|
||
$input = fread(STDIN, 4); | ||
$input = ''; | ||
$this->input->read(4, function ($buffer) use (&$input) { | ||
$input .= $buffer; | ||
}); | ||
|
||
$this->clearLine(); | ||
|
||
return array_key_exists($input, $map) | ||
|
@@ -158,23 +177,23 @@ public function getKeyedInput() : string | |
*/ | ||
public function clear() : void | ||
{ | ||
echo "\033[2J"; | ||
$this->output->write("\033[2J"); | ||
} | ||
|
||
/** | ||
* Enable cursor | ||
*/ | ||
public function enableCursor() : void | ||
{ | ||
echo "\033[?25h"; | ||
$this->output->write("\033[?25h"); | ||
} | ||
|
||
/** | ||
* Disable cursor | ||
*/ | ||
public function disableCursor() : void | ||
{ | ||
echo "\033[?25l"; | ||
$this->output->write("\033[?25l"); | ||
} | ||
|
||
/** | ||
|
@@ -184,31 +203,31 @@ public function disableCursor() : void | |
*/ | ||
public function moveCursorToTop() : void | ||
{ | ||
echo "\033[H"; | ||
$this->output->write("\033[H"); | ||
} | ||
|
||
/** | ||
* Move the cursor to the start of a specific row | ||
*/ | ||
public function moveCursorToRow(int $rowNumber) : void | ||
{ | ||
echo sprintf("\033[%d;0H", $rowNumber); | ||
$this->output->write(sprintf("\033[%d;0H", $rowNumber)); | ||
} | ||
|
||
/** | ||
* Move the cursor to the start of a specific column | ||
*/ | ||
public function moveCursorToColumn(int $column) : void | ||
{ | ||
echo sprintf("\033[%dC", $column); | ||
$this->output->write(sprintf("\033[%dC", $column)); | ||
} | ||
|
||
/** | ||
* Clear the current cursors line | ||
*/ | ||
public function clearLine() : void | ||
{ | ||
echo sprintf("\033[%dD\033[K", $this->getWidth()); | ||
$this->output->write(sprintf("\033[%dD\033[K", $this->getWidth())); | ||
} | ||
|
||
/** | ||
|
@@ -221,4 +240,9 @@ public function clean() : void | |
$this->clearLine(); | ||
} | ||
} | ||
|
||
public function getOutput() : OutputStream | ||
{ | ||
return $this->output; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like this would always return an empty string ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope - it will return whatever has been written so far and clean the buffer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh my dayz... obvs .. I must have been tired not to see that 😂