diff --git a/src/config/arc/ArcanistArcConfigurationEngineExtension.php b/src/config/arc/ArcanistArcConfigurationEngineExtension.php --- a/src/config/arc/ArcanistArcConfigurationEngineExtension.php +++ b/src/config/arc/ArcanistArcConfigurationEngineExtension.php @@ -125,6 +125,18 @@ array( '["master"]', )), + id(new ArcanistStringListConfigOption()) + ->setKey('pager') + ->setDefaultValue(array()) + ->setSummary(pht('Default pager command.')) + ->setHelp( + pht( + 'Specify the pager command to use when displaying '. + 'documentation.')) + ->setExamples( + array( + '["less", "-R", "--"]', + )), id(new ArcanistStringConfigOption()) ->setKey('arc.land.onto-remote') ->setSummary(pht('Default list of "onto" remote for "arc land".')) diff --git a/src/future/exec/PhutilExecPassthru.php b/src/future/exec/PhutilExecPassthru.php --- a/src/future/exec/PhutilExecPassthru.php +++ b/src/future/exec/PhutilExecPassthru.php @@ -20,6 +20,12 @@ */ final class PhutilExecPassthru extends PhutilExecutableFuture { + private $stdinData; + + public function write($data) { + $this->stdinData = $data; + return $this; + } /* -( Executing Passthru Commands )---------------------------------------- */ @@ -34,7 +40,15 @@ public function execute() { $command = $this->getCommand(); - $spec = array(STDIN, STDOUT, STDERR); + $is_write = ($this->stdinData !== null); + + if ($is_write) { + $stdin_spec = array('pipe', 'r'); + } else { + $stdin_spec = STDIN; + } + + $spec = array($stdin_spec, STDOUT, STDERR); $pipes = array(); $unmasked_command = $command->getUnmaskedString(); @@ -81,6 +95,11 @@ $errors)); } } else { + if ($is_write) { + fwrite($pipes[0], $this->stdinData); + fclose($pipes[0]); + } + $err = proc_close($proc); } diff --git a/src/parser/argument/workflow/PhutilHelpArgumentWorkflow.php b/src/parser/argument/workflow/PhutilHelpArgumentWorkflow.php --- a/src/parser/argument/workflow/PhutilHelpArgumentWorkflow.php +++ b/src/parser/argument/workflow/PhutilHelpArgumentWorkflow.php @@ -2,6 +2,17 @@ final class PhutilHelpArgumentWorkflow extends PhutilArgumentWorkflow { + private $workflow; + + public function setWorkflow($workflow) { + $this->workflow = $workflow; + return $this; + } + + public function getWorkflow() { + return $this->workflow; + } + protected function didConstruct() { $this->setName('help'); $this->setExamples(<<getArg('help-with-what'); if (!$with) { + // TODO: Update this to use a pager, too. + $args->printHelpAndExit(); } else { + $out = array(); foreach ($with as $thing) { - echo phutil_console_format( + $out[] = phutil_console_format( "**%s**\n\n", pht('%s WORKFLOW', strtoupper($thing))); - echo $args->renderWorkflowHelp($thing, $show_flags = true); - echo "\n"; + $out[] = $args->renderWorkflowHelp($thing, $show_flags = true); + $out[] = "\n"; + } + $out = implode('', $out); + + $workflow = $this->getWorkflow(); + if ($workflow) { + $workflow->writeToPager($out); + } else { + echo $out; } - exit(PhutilArgumentParser::PARSE_ERROR_CODE); } } diff --git a/src/toolset/workflow/ArcanistHelpWorkflow.php b/src/toolset/workflow/ArcanistHelpWorkflow.php --- a/src/toolset/workflow/ArcanistHelpWorkflow.php +++ b/src/toolset/workflow/ArcanistHelpWorkflow.php @@ -8,7 +8,8 @@ } public function newPhutilWorkflow() { - return new PhutilHelpArgumentWorkflow(); + return id(new PhutilHelpArgumentWorkflow()) + ->setWorkflow($this); } public function supportsToolset(ArcanistToolset $toolset) { diff --git a/src/workflow/ArcanistLandWorkflow.php b/src/workflow/ArcanistLandWorkflow.php --- a/src/workflow/ArcanistLandWorkflow.php +++ b/src/workflow/ArcanistLandWorkflow.php @@ -122,7 +122,7 @@ return $this->newWorkflowInformation() ->setSynopsis(pht('Publish reviewed changes.')) - ->addExample(pht('**land** [__options__] [__ref__ ...]')) + ->addExample(pht('**land** [__options__] -- [__ref__ ...]')) ->setHelp($help); } diff --git a/src/workflow/ArcanistWorkflow.php b/src/workflow/ArcanistWorkflow.php --- a/src/workflow/ArcanistWorkflow.php +++ b/src/workflow/ArcanistWorkflow.php @@ -2451,4 +2451,30 @@ return $raw_uri; } + final public function writeToPager($corpus) { + $is_tty = (function_exists('posix_isatty') && posix_isatty(STDOUT)); + + if (!$is_tty) { + echo $corpus; + } else { + $pager = $this->getConfig('pager'); + + if (!$pager) { + $pager = array('less', '-R', '--'); + } + + // Try to show the content through a pager. + $err = id(new PhutilExecPassthru('%Ls', $pager)) + ->write($corpus) + ->resolve(); + + // If the pager exits with an error, print the content normally. + if ($err) { + echo $corpus; + } + } + + return $this; + } + }