Proposal: Introduce an `Output` class
Hywan opened this issue · 5 comments
Now
We use echo
to print strings on the output of the current program.
Issue
Sometimes we don't want to echo
but get the output, compute it somewhere with something and delegate the output. For instance, with the Symfony console bridge official contribution, we plug to the Symfony console output object (/cc @jubianchi).
Another issue happens recently with #52. TMUX(1) has some issues with specific control sequences. There is a solution to by-pass TMUX(1) and send control sequences to the upper terminal directly, see #53 for more explanation.
Proposal
We must introduce an output object. How though? This is a coding design discussion.
Output
class and object
I would go for a static Output
class and use it everywhere instead of echo
but this is no easily extensible, nor testable. So we should for an object instead of a class. We do not want to create one instance each time we call the cursor or window API, this would increase memory. Since #51 introduces Console::getStdin
, we can imagine introducing Console::getStdout
and compute an instance of Output
. To be able to extend Hoa\Console
to delegate outputs, we can imagine Console::setStdout(Output $output)
.
What interface Output
implements?
Thus, all echo
s could be replaced by Console::getStdout()->writeAll()
. Why writeAll
? This is the typical naming from Hoa\Stream
interfaces. But I am not likely to implement the Hoa\Stream\IStream\Out
interface right now. Or maybe I would be likely. This is one more dependency and it requires to implement write
, writeLine
etc. It makes a lot of sense!
However, what is the impact of adding a new dependency? Hoa\Stream
is almost always a dependency, except if our program does not need any external resources (like files, sockets & co.), which is very rare. So I would argue that adding this dependency will not hurt anyone.
Conclusion
I would like the opinion of several @hoaproject/hoackers please.
Appendix A
Here is a draft for the Output
object:
use Hoa\Stream;
class Output implements Stream\IStream\Out
{
public function write($string, $length)
{
echo $string;
}
public function writeAll($string)
{
return $this->write($string, strlen($length));
}
…
}
Here is a draft for the new Hoa\Console
methods:
class Console
{
…
protected $_output = null;
public static function setOutput(Output $output)
{
$old = static::$_output;
static::$_output = $output;
return $old;
}
public static function getOutput()
{
if (null === static::$_output) {
static::$_output = new Output();
}
return static::$_output;
}
}
Bonus with outputs and redirection
How to implement redirections (rhetorical question)? Either we add an argument to the Output
class constructor representing a stream or a resource, or because we are using Hoa\Stream\IStream\Out
, we can do this:
use Hoa\Stream;
class Console
{
…
public function setOutput(Stream\IStream\Out $output)
{
…
}
…
}
and then:
Hoa\Console::setOutput(new Hoa\File\Write('/tmp/a'));
to redirect all outputs to the /tmp/a
file!
Tip: Using echo
is strictly equivalent to Hoa\Console::setOutput(new Hoa\File\Write(1));
, which is equivalent to Hoa\Console::setOutput(new Hoa\File\Write('php://fd/1'));
, which is equivalent to Hoa\Console::setOutput(new Hoa\File\Write('php://output'));
.
Next
- We must open an issue to add a new method on
Output
likeenableDemultiplexerByPassing
. This will re-solve #53 more elegantly. - We can imagine introducing an
Input
class? Not sure. Need more grooming.
Hello,
I think it's a really nice idea to add Output
layer here. We can handle more nicely the verbosity or the output destination. Also rely on Stream
add powerful capabilities...
Just one question, I saw that there are echo
calls to move Cursor
, set Window
size... Can it be a problem to redirect the output in a file for that cases ? These cases are more for utils than message...
@shulard The output class will not be responsible to manage the verbosity. We have to check whether Console::isDirect(STDOUT)
returns true to run the cursor API for instance. This is not part of this issue. However, you can open another issue if you want to.
So I would argue that adding this dependency will not hurt anyone.
👍
This seems to be a really nice feature, as @Hywan said, it will solve issues (and simplify code) on the Console contributions:
- https://github.com/hoaproject/Contributions-Symfony-ConsoleBridge/blob/master/Formatter/OutputFormatterStyle.php#L88-L107
- https://github.com/hoaproject/Contributions-Symfony-ConsoleBridge/blob/master/Helper/CursorHelper.php#L128-L137
- https://github.com/hoaproject/Contributions-Symfony-ConsoleBridge/blob/master/Helper/WindowHelper.php#L135-L144
This will also allow us to bridge the new Output
interface to Symfony's output and provide new stuff like piping/redirecting outputs.
-- EDIT --
I forgot to mention this comment: hoaproject/Test#46 (comment) Introducing the Output
class will also let us solve this issue.
@jubianchi Good. So let's go!
Oh, Hoa\Stream
is already a dependency of Hoa\Console
, so it's fine!