Page MenuHomePhabricator

Pipe output to a pager
Closed, ResolvedPublic

Description

It would be great if we could have arc help pipe its output through a pager (less or more). This provides much more readable help documentation. One possible solution is demonstrated below, although a more elegant solution could likely be constructed using PhutilExecPassthru and TempFile.

<?php

$pipes = array();

$proc = @proc_open(
  'less',
  array(
    0 => array('pipe', 'r'),
    1 => STDOUT,
    2 => STDERR,
  ),
  $pipes);

fwrite($pipes[0], 'foobar');
fclose($pipes[0]);

// It is important that you close any pipes before calling
// proc_close in order to avoid a deadlock
$err = proc_close($proc);

Event Timeline

joshuaspence raised the priority of this task from to Wishlist.
joshuaspence updated the task description. (Show Details)
joshuaspence added a project: libphutil.
joshuaspence added a subscriber: joshuaspence.

@epriestley, do you know if this is possible? I was thinking that something like this might work (pseudo-code):

<?php

$pager = new PhutilExecPassthru('less');
$stdin = $pager->getStdin();

$console = PhutilConsole::getConsole();
$console->setStdout($stdin);

$pager->execute();

I'm actually not sure how to do this offhand, beyond making arc help really run arc help --no-pager | $PAGER.

Abusing PhutilInteractiveEditor seems to work actually:

<?php

ob_start();
echo("Hello there!");
$text = ob_get_contents();
ob_end_clean();

$pager = id(new PhutilInteractiveEditor($text))
  ->setPreferredEditor('less')
  ->editInteractively();

Oh, interesting. I guess that's just less <filename>, which seems like a reasonable option that all pagers should probably support. PhutilExecPassthru + TempFile should be able to do that less hackily, probably.

Its probably still possible to do this "properly", but using TempFile provides a nice fallback. I guess we would need to create a file descriptor and pass it to PhutilExecPassthru to be used instead of STDIN.

Ultimately I sorted of hoped that this could be added as a method on PhutilConsole, such as $console->setPager('less').

This is a better example:

<?php

$pipes = array();

$proc = @proc_open(
  'less',
  array(
    0 => array('pipe', 'r'),
    1 => STDOUT,
    2 => STDERR,
  ),
  $pipes);

fwrite($pipes[0], 'foobar');
fclose($pipes[0]);

// It is important that you close any pipes before calling
// proc_close in order to avoid a deadlock
$err = proc_close($proc);