Skip to content

Commit

Permalink
Support output formatter wordwraping.
Browse files Browse the repository at this point in the history
  • Loading branch information
greg-1-anderson committed Nov 18, 2016
1 parent 0bcb15e commit ef87a2d
Show file tree
Hide file tree
Showing 9 changed files with 234 additions and 27 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ It is also possible to add InputInterface or OutputInterface parameters to any a

## API Usage

If you would like to use Annotated Commands to build a commandline tool, it is recommended that you use [Robo as a framework](http://robo.li/framework.md), as it will set up all of the various command classes for you. If you would like to integrate Annotated Commands into some other framework, see the sections below.

### Set up Command Factory and Instantiate Commands

To use annotated commands in an application, pass an instance of your command class in to AnnotatedCommandFactory::createCommandsFromClass(). The result will be a list of Commands that may be added to your application.
```php
$myCommandClassInstance = new MyCommandClass();
Expand All @@ -182,6 +186,8 @@ Note that the `setFormatterManager()` operation is optional; omit this if not us

A CommandInfoAltererInterface can be added via AnnotatedCommandFactory::addCommandInfoAlterer(); it will be given the opportunity to adjust every CommandInfo object parsed from a command file prior to the creation of commands.

### Command File Discovery

A discovery class, CommandFileDiscovery, is also provided to help find command files on the filesystem. Usage is as follows:
```php
$discovery = new CommandFileDiscovery();
Expand All @@ -199,6 +205,20 @@ $myCommandFiles = $discovery->discover(['\Ns1' => $path1, '\Ns2' => $path2]);
```
As a shortcut for the above, the method `discoverNamespaced()` will take the last directory name of each path, and append it to the base namespace provided. This matches the conventions used by Drupal modules, for example.

### Configuring Output Formatts (e.g. to enable wordwrap)

The Output Formatters project supports automatic formatting of tabular output. In order for wordwrapping to work correctly, the terminal width must be passed in to the Output Formatters handlers via `FormatterOptions::setWidth()`.

In the Annotated Commands project, this is done via dependency injection. If a `PrepareFormatter` object is passed to `CommandProcessor::addPrepareFormatter()`, then it will be given an opportunity to set properties on the `FormatterOptions` when it is created.

A `PrepareTerminalWidthOption` class is provided to use the Symfony Application class to fetch the terminal width, and provide it to the FormatterOptions. It is injected as follows:
```php
$terminalWidthOption = new PrepareTerminalWidthOption();
$terminalWidthOption->setApplication($application);
$commandFactory->commandProcessor()->addPrepareFormatter($terminalWidthOption);
```
To provide greater control over the width used, create your own `PrepareTerminalWidthOption` subclass, and adjust the width as needed.

## Other Callbacks

In addition to the hooks provided by the hook manager, there are additional callbacks available to alter the way the annotated command library operates.
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
},
"require": {
"php": ">=5.4.0",
"consolidation/output-formatters": "~2|~3",
"consolidation/output-formatters": "^3.1",
"psr/log": "~1",
"symfony/console": "^2.8|~3",
"symfony/event-dispatcher": "^2.5|~3",
Expand Down
44 changes: 22 additions & 22 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 25 additions & 3 deletions src/CommandProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Consolidation\OutputFormatters\FormatterManager;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\AnnotatedCommand\Hooks\HookManager;
use Consolidation\AnnotatedCommand\Options\PrepareFormatter;

/**
* Process a command, including hooks and other callbacks.
Expand All @@ -24,6 +25,8 @@ class CommandProcessor
protected $formatterManager;
/** var callable */
protected $displayErrorFunction;
/** var PrepareFormatterOptions[] */
protected $prepareOptionsList = [];

public function __construct(HookManager $hookManager)
{
Expand All @@ -39,6 +42,11 @@ public function hookManager()
return $this->hookManager;
}

public function addPrepareFormatter(PrepareFormatter $preparer)
{
$this->prepareOptionsList[] = $preparer;
}

public function setFormatterManager(FormatterManager $formatterManager)
{
$this->formatterManager = $formatterManager;
Expand Down Expand Up @@ -236,9 +244,8 @@ protected function chooseOutputStream(OutputInterface $output, $status)
*/
protected function writeUsingFormatter(OutputInterface $output, $structuredOutput, CommandData $commandData)
{
$options = $commandData->input()->getOptions();
$format = $this->getFormat($options);
$formatterOptions = new FormatterOptions($commandData->annotationData()->getArrayCopy(), $options);
$format = $this->getFormat($commandData->input()->getOptions());
$formatterOptions = $this->createFormatterOptions($commandData);
$this->formatterManager->write(
$output,
$format,
Expand All @@ -248,6 +255,21 @@ protected function writeUsingFormatter(OutputInterface $output, $structuredOutpu
return 0;
}

/**
* Create a FormatterOptions object for use in writing the formatted output.
* @param CommandData $commandData
* @return FormatterOptions
*/
protected function createFormatterOptions($commandData)
{
$options = $commandData->input()->getOptions();
$formatterOptions = new FormatterOptions($commandData->annotationData()->getArrayCopy(), $options);
foreach ($this->prepareOptionsList as $preparer) {
$preparer->prepare($commandData, $formatterOptions);
}
return $formatterOptions;
}

/**
* Description
* @param OutputInterface $output
Expand Down
10 changes: 10 additions & 0 deletions src/Options/PrepareFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
namespace Consolidation\AnnotatedCommand\Options;

use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\OutputFormatters\Options\FormatterOptions;

interface PrepareFormatter
{
public function prepare(CommandData $commandData, FormatterOptions $options);
}
69 changes: 69 additions & 0 deletions src/Options/PrepareTerminalWidthOption.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
namespace Consolidation\AnnotatedCommand\Options;

use Symfony\Component\Console\Application;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\OutputFormatters\Options\FormatterOptions;

class PrepareTerminalWidthOption implements PrepareFormatter
{
/** var Application */
protected $application;

/** var int */
protected $defaultWidth;

/** var int */
protected $maxWidth = PHP_INT_MAX;

/** var int */
protected $minWidth = 0;

public function __construct($defaultWidth = 0)
{
$this->defaultWidth = $defaultWidth;
}

public function setApplication(Application $application)
{
$this->application = $application;
}

public function prepare(CommandData $commandData, FormatterOptions $options)
{
$width = $this->getTerminalWidth();
if (!$width) {
$width = $this->defaultWidth;
}

// Enforce minimum and maximum widths
$width = min($width, $this->getMaxWidth($commandData));
$width = max($width, $this->getMinWidth($commandData));

$options->setWidth($width);
}

protected function getTerminalWidth()
{
if (!$this->application) {
return 0;
}

$dimensions = $this->application->getTerminalDimensions();
if ($dimensions[0] == null) {
return 0;
}

return $dimensions[0];
}

protected function getMaxWidth(CommandData $commandData)
{
return $this->maxWidth;
}

protected function getMinWidth(CommandData $commandData)
{
return $this->minWidth;
}
}
26 changes: 26 additions & 0 deletions tests/src/ApplicationWithTerminalWidth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php
namespace Consolidation\TestUtils;

use Symfony\Component\Console\Application;

class ApplicationWithTerminalWidth extends Application
{
protected $width = 0;
protected $height = 0;

public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
{
parent::__construct($name, $version);
}

public function setWidthAndHeight($width, $height)
{
$this->width = $width;
$this->height = $height;
}

public function getTerminalDimensions()
{
return [ $this->width, $this->height ];
}
}
21 changes: 21 additions & 0 deletions tests/src/alpha/AlphaCommandFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,27 @@ public function exampleTable($options = ['format' => 'table', 'fields' => ''])
return new RowsOfFields($outputData);
}

/**
* Test word wrapping
*
* @command example:wrap
* @field-labels
* first: First
* second: Second
*
* @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
*/
public function exampleWrap()
{
$data = [
[
'first' => 'This is a really long cell that contains a lot of data. When it is rendered, it should be wrapped across multiple lines.',
'second' => 'This is the second column of the same table. It is also very long, and should be wrapped across multiple lines, just like the first column.',
]
];
return new RowsOfFields($data);
}

/**
* @hook option example:table
*/
Expand Down
Loading

0 comments on commit ef87a2d

Please sign in to comment.