diff --git a/.idea/blade.xml b/.idea/blade.xml
index 93870c7..fca757d 100644
--- a/.idea/blade.xml
+++ b/.idea/blade.xml
@@ -86,6 +86,7 @@
+
@@ -99,7 +100,7 @@
-
+
diff --git a/src/AnsiChar.php b/src/AnsiChar.php
index 6a02b5b..0a22c7c 100644
--- a/src/AnsiChar.php
+++ b/src/AnsiChar.php
@@ -2,12 +2,14 @@
namespace Glhd\AnsiPants;
-class AnsiChar
+use Stringable;
+
+class AnsiChar implements Stringable
{
public function __construct(
public string $value,
/** @var \Glhd\AnsiPants\Flag[] */
- public array $flags,
+ public array $flags = [],
) {
}
@@ -20,4 +22,9 @@ public function hasFlag(Flag $flag): bool
{
return in_array($flag, $this->flags, true);
}
+
+ public function __toString(): string
+ {
+ return $this->value;
+ }
}
diff --git a/src/AnsiString.php b/src/AnsiString.php
index 76ccea8..b6bb1a5 100644
--- a/src/AnsiString.php
+++ b/src/AnsiString.php
@@ -2,6 +2,7 @@
namespace Glhd\AnsiPants;
+use Generator;
use Glhd\AnsiPants\Support\Parsing\EscapeSequence;
use Glhd\AnsiPants\Support\Parsing\Text;
use Glhd\AnsiPants\Support\Parsing\Tokenizer;
@@ -18,8 +19,12 @@ public static function make(AnsiString|Collection|string $input): static
return new static($input);
}
- public function __construct(AnsiString|Collection|string $input)
+ public function __construct(AnsiString|AnsiChar|Collection|string $input)
{
+ if ($input instanceof AnsiChar) {
+ $input = new Collection([$input]);
+ }
+
if ($input instanceof Collection) {
$input->ensure(AnsiChar::class);
$this->chars = clone $input;
@@ -35,18 +40,14 @@ public function withFlags(Flag ...$flags): static
return new static($this->chars->map(fn(AnsiChar $char) => $char->withFlags(...$flags)));
}
- public function prepend(AnsiString|string $string): static
+ public function prepend(AnsiString|AnsiChar|string $string): static
{
- $string = new AnsiString($string);
-
- return new AnsiString($string->chars->merge($this->chars));
+ return new AnsiString(AnsiString::make($string)->chars->merge($this->chars));
}
- public function append(AnsiString|string $string): static
+ public function append(AnsiString|AnsiChar|string $string): static
{
- $string = new AnsiString($string);
-
- return new AnsiString($this->chars->merge($string->chars));
+ return new AnsiString($this->chars->merge(AnsiString::make($string)->chars));
}
public function padLeft(int $length, AnsiString|string $pad = ' '): static
@@ -83,6 +84,34 @@ public function padBoth(int $length, AnsiString|string $pad = ' '): static
->append($right_padding);
}
+ public function wordwrap(int $width = 75, AnsiString|string $break = "\e[0m\n", bool $cut_long_words = false): static
+ {
+ $break = new AnsiString($break);
+ $buffer = new AnsiString('');
+ $wrapped = new AnsiString('');
+
+ foreach ($this->words() as $word) {
+ [$sep, $word] = $word;
+
+ if (($buffer->length() + $sep->length() + $word->length()) > $width) {
+ if ($wrapped->length()) {
+ $wrapped = $wrapped->append($break);
+ }
+
+ $wrapped = $wrapped->append($buffer);
+ $buffer = new AnsiString($word);
+ } else {
+ $buffer = $buffer->append($sep)->append($word);
+ }
+ }
+
+ if ($buffer->length() > 0) {
+ $wrapped = $wrapped->append($break)->append($buffer);
+ }
+
+ return $wrapped;
+ }
+
public function length(): int
{
return count($this->chars);
@@ -125,6 +154,28 @@ public function __toString(): string
return $result;
}
+ /** @return Generator */
+ protected function words(): Generator
+ {
+ $sep = new static('');
+ $word = new static('');
+
+ foreach ($this->chars as $char) {
+ if ($word->length() > 0 && in_array($char->value, [' ', "\n"])) {
+ yield [$sep, $word];
+ $word = new static('');
+ $sep = new static($char);
+ continue;
+ }
+
+ $word->chars->push($char);
+ }
+
+ if ($word->length() > 0 || $sep->length() > 0) {
+ yield [$sep, $word];
+ }
+ }
+
/** @return \Glhd\AnsiPants\Flag[][] */
protected function diffFlags($a, $b): array
{
diff --git a/tests/Unit/AnsiStringTest.php b/tests/Unit/AnsiStringTest.php
index 41772f8..ef25754 100644
--- a/tests/Unit/AnsiStringTest.php
+++ b/tests/Unit/AnsiStringTest.php
@@ -38,4 +38,21 @@ public function test_pad_both(): void
$this->assertEquals($expected, (string) $parsed->padBoth(15));
}
+
+ public function test_word_wrap(): void
+ {
+ $input = "The \e[1mquick\e[0m \e[33mbrown fox \e[3mjumps\e[0m over the lazy dog";
+
+ $expected = <<assertEquals($expected, (string) $parsed->wordwrap(10));
+ }
}