Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ before_script:
script:
- ./vendor/bin/phpunit --coverage-clover ./build/logs/clover.xml
- composer cs
- composer static

after_script:
- bash <(curl -s https://codecov.io/bash)
Expand Down
108 changes: 93 additions & 15 deletions src/MenuStyle.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PhpSchool\CliMenu\Terminal\TerminalFactory;
use PhpSchool\CliMenu\Util\ColourUtil;
use PhpSchool\CliMenu\Util\StringUtil as s;
use PhpSchool\Terminal\Terminal;
use Assert\Assertion;

Expand All @@ -30,14 +31,31 @@ class MenuStyle
protected $bg;

/**
* The width of the menu. Including borders and padding.
* Does not include margin.
*
* May not be the value that was requested in the
* circumstance that the terminal is smaller then the
* requested width.
*
* @var int
*/
protected $width;

/**
* In case the requested width is wider than the terminal
* then we shrink the width to fit the terminal. We keep
* the requested size in case the margins are changed and
* we need to recalculate the width.
*
* @var int
*/
protected $margin;
private $requestedWidth;

/**
* @var int
*/
protected $margin = 0;

/**
* @var int
Expand Down Expand Up @@ -134,6 +152,11 @@ class MenuStyle
*/
private $marginAuto = false;

/**
* @var bool
*/
private $debugMode = false;

/**
* Default Values
*
Expand Down Expand Up @@ -244,8 +267,13 @@ public function hasChangedFromDefaults() : bool
$this->borderColour,
$this->marginAuto,
];

return $currentValues !== array_values(self::$defaultStyleValues);

$defaultStyleValues = self::$defaultStyleValues;
if ($this->width !== $this->requestedWidth) {
$defaultStyleValues['width'] = $this->width;
}

return $currentValues !== array_values($defaultStyleValues);
}

public function getDisabledItemText(string $text) : string
Expand Down Expand Up @@ -312,6 +340,8 @@ public function getColoursResetCode() : string

/**
* Calculate the contents width
*
* The content width is menu width minus borders and padding.
*/
protected function calculateContentWidth() : void
{
Expand Down Expand Up @@ -369,13 +399,12 @@ public function setWidth(int $width) : self
{
Assertion::greaterOrEqualThan($width, 0);

if ($width >= $this->terminal->getWidth()) {
$width = $this->terminal->getWidth();
}
$this->requestedWidth = $width;
$width = $this->maybeShrinkWidth($this->margin, $width);

$this->width = $width;
if ($this->marginAuto) {
$this->setMarginAuto();
$this->calculateMarginAuto($width);
}

$this->calculateContentWidth();
Expand All @@ -385,6 +414,15 @@ public function setWidth(int $width) : self
return $this;
}

private function maybeShrinkWidth(int $margin, int $width) : int
{
if ($width + $margin >= $this->terminal->getWidth()) {
$width = $this->terminal->getWidth() - $margin;
}

return $width;
}

public function getPaddingTopBottom() : int
{
return $this->paddingTopBottom;
Expand All @@ -405,7 +443,7 @@ private function generatePaddingTopBottomRows() : void

$paddingRow = sprintf(
"%s%s%s%s%s%s%s%s%s%s\n",
str_repeat(' ', $this->margin),
$this->debugMode ? $this->getDebugString($this->margin) : str_repeat(' ', $this->margin),
$borderColour,
str_repeat(' ', $this->borderLeftWidth),
$this->getColoursSetCode(),
Expand All @@ -417,6 +455,15 @@ private function generatePaddingTopBottomRows() : void
$this->coloursResetCode
);


if ($this->debugMode && s::length($paddingRow) <= $this->terminal->getWidth()) {
$paddingRow = substr_replace(
$paddingRow,
sprintf("%s\n", $this->getDebugString($this->terminal->getWidth() - (s::length($paddingRow) - 1))),
-1
);
}

$this->paddingTopBottomRows = array_fill(0, $this->paddingTopBottom, $paddingRow);
}

Expand Down Expand Up @@ -469,23 +516,28 @@ public function getMargin() : int
public function setMarginAuto() : self
{
$this->marginAuto = true;
$this->margin = (int) floor(($this->terminal->getWidth() - $this->width) / 2);
$this->margin = 0;

$this->generateBorderRows();
$this->generatePaddingTopBottomRows();
$this->setWidth($this->requestedWidth);

return $this;
}

private function calculateMarginAuto(int $width) : void
{
$this->margin = (int) floor(($this->terminal->getWidth() - ($width)) / 2);
}

public function setMargin(int $margin) : self
{
Assertion::greaterOrEqualThan($margin, 0);

$this->marginAuto = false;
$this->margin = $margin;

$this->generateBorderRows();
$this->generatePaddingTopBottomRows();
//margin + width may now exceed terminal size
//so set width again to trigger width check + maybe resize
$this->setWidth($this->requestedWidth);

return $this;
}
Expand Down Expand Up @@ -549,12 +601,20 @@ private function generateBorderRows() : void
{
$borderRow = sprintf(
"%s%s%s%s\n",
str_repeat(' ', $this->margin),
$this->debugMode ? $this->getDebugString($this->margin) : str_repeat(' ', $this->margin),
$this->getBorderColourCode(),
str_repeat(' ', $this->width),
$this->coloursResetCode
$this->getColoursResetCode()
);

if ($this->debugMode && s::length($borderRow) <= $this->terminal->getWidth()) {
$borderRow = substr_replace(
$borderRow,
sprintf("%s\n", $this->getDebugString($this->terminal->getWidth() - (s::length($borderRow) - 1))),
-1
);
}

$this->borderTopRows = array_fill(0, $this->borderTopWidth, $borderRow);
$this->borderBottomRows = array_fill(0, $this->borderBottomWidth, $borderRow);
}
Expand Down Expand Up @@ -696,4 +756,22 @@ public function getBorderColourCode() : string

return sprintf("\033[%sm", $borderColourCode);
}

/**
* Get a string of given length consisting of 0-9
* eg $length = 15 : 012345678901234
*/
private function getDebugString(int $length) : string
{
$nums = [];
for ($i = 0, $j = 0; $i < $length; $i++, $j++) {
if ($j === 10) {
$j = 0;
}

$nums[] = $j;
}

return implode('', $nums);
}
}
16 changes: 16 additions & 0 deletions src/Util/ArrayUtil.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace PhpSchool\CliMenu\Util;

class ArrayUtil
{
public static function mapWithKeys(array $array, callable $callback) : array
{
return array_combine(
array_keys($array),
array_map($callback, array_keys($array), $array)
);
}
}
5 changes: 5 additions & 0 deletions src/Util/StringUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ public static function stripAnsiEscapeSequence(string $str) : string
{
return (string) preg_replace('/\x1b[^m]*m/', '', $str);
}

public static function length(string $str, bool $ignoreAnsiEscapeSequence = true) : int
{
return mb_strlen($ignoreAnsiEscapeSequence ? self::stripAnsiEscapeSequence($str) : $str);
}
}
26 changes: 18 additions & 8 deletions test/Builder/CliMenuBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,12 @@ public function test256ColoursCodes() : void
{
$terminal = static::createMock(Terminal::class);
$terminal
->expects($this->any())
->method('getWidth')
->willReturn(100);

$terminal
->method('getColourSupport')
->will($this->returnValue(256));
->willReturn(256);

$builder = new CliMenuBuilder($terminal);
$builder->setBackgroundColour(16, 'white');
Expand All @@ -248,9 +251,12 @@ public function test256ColoursCodes() : void

$terminal = static::createMock(Terminal::class);
$terminal
->expects($this->any())
->method('getWidth')
->willReturn(100);

$terminal
->method('getColourSupport')
->will($this->returnValue(8));
->willReturn(8);

$builder = new CliMenuBuilder($terminal);
$builder->setBackgroundColour(16, 'white');
Expand All @@ -269,9 +275,11 @@ public function testSetFgThrowsExceptionWhenColourCodeIsNotInRange() : void

$terminal = static::createMock(Terminal::class);
$terminal
->expects($this->any())
->method('getWidth')
->willReturn(100);
$terminal
->method('getColourSupport')
->will($this->returnValue(256));
->willReturn(256);

$builder = new CliMenuBuilder($terminal);
$builder->setForegroundColour(512, 'white');
Expand All @@ -284,9 +292,11 @@ public function testSetBgThrowsExceptionWhenColourCodeIsNotInRange() : void

$terminal = static::createMock(Terminal::class);
$terminal
->expects($this->any())
->method('getWidth')
->willReturn(100);
$terminal
->method('getColourSupport')
->will($this->returnValue(256));
->willReturn(256);

$builder = new CliMenuBuilder($terminal);
$builder->setBackgroundColour(257, 'white');
Expand Down
10 changes: 6 additions & 4 deletions test/CliMenuTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,7 @@ public function testGetItems() : void
$item2 = new LineBreakItem();


$terminal = $this->createMock(Terminal::class);
$style = $this->getStyle($terminal);
$style = $this->getStyle($terminal = new MockTerminal);

$menu = new CliMenu(
'PHP School FTW',
Expand All @@ -304,8 +303,7 @@ public function testRemoveItem() : void
$item1 = new LineBreakItem();
$item2 = new LineBreakItem();

$terminal = $this->createMock(Terminal::class);
$style = $this->getStyle($terminal);
$style = $this->getStyle($terminal = new MockTerminal);

$menu = new CliMenu(
'PHP School FTW',
Expand Down Expand Up @@ -355,6 +353,10 @@ public function testThrowsExceptionIfTerminalIsNotValidTTY() : void
$this->expectException(\PhpSchool\CliMenu\Exception\InvalidTerminalException::class);

$terminal = $this->createMock(Terminal::class);
$terminal
->method('getWidth')
->willReturn(100);

$terminal->expects($this->once())
->method('isInteractive')
->willReturn(false);
Expand Down
8 changes: 4 additions & 4 deletions test/Input/InputIOTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ class InputIOTest extends TestCase
public function setUp() : void
{
$this->terminal = $this->createMock(Terminal::class);
$this->terminal
->method('getWidth')
->willReturn(100);

$this->output = new BufferedOutput;
$this->menu = $this->createMock(CliMenu::class);
$this->style = new MenuStyle($this->terminal);
Expand All @@ -52,10 +56,6 @@ public function setUp() : void
$this->style->setBg('yellow');
$this->style->setFg('red');

$this->terminal
->method('getWidth')
->willReturn(100);

$parentStyle = new MenuStyle($this->terminal);
$parentStyle->setBg('blue');

Expand Down
Loading