| 148 |
lars |
1 |
<?php
|
|
|
2 |
|
|
|
3 |
/*
|
|
|
4 |
* This file is part of the Symfony package.
|
|
|
5 |
*
|
|
|
6 |
* (c) Fabien Potencier <fabien@symfony.com>
|
|
|
7 |
*
|
|
|
8 |
* For the full copyright and license information, please view the LICENSE
|
|
|
9 |
* file that was distributed with this source code.
|
|
|
10 |
*/
|
|
|
11 |
|
|
|
12 |
namespace Symfony\Component\Console\Helper;
|
|
|
13 |
|
|
|
14 |
/**
|
|
|
15 |
* Simple output wrapper for "tagged outputs" instead of wordwrap(). This solution is based on a StackOverflow
|
|
|
16 |
* answer: https://stackoverflow.com/a/20434776/1476819 from user557597 (alias SLN).
|
|
|
17 |
*
|
|
|
18 |
* (?:
|
|
|
19 |
* # -- Words/Characters
|
|
|
20 |
* ( # (1 start)
|
|
|
21 |
* (?> # Atomic Group - Match words with valid breaks
|
|
|
22 |
* .{1,16} # 1-N characters
|
|
|
23 |
* # Followed by one of 4 prioritized, non-linebreak whitespace
|
|
|
24 |
* (?: # break types:
|
|
|
25 |
* (?<= [^\S\r\n] ) # 1. - Behind a non-linebreak whitespace
|
|
|
26 |
* [^\S\r\n]? # ( optionally accept an extra non-linebreak whitespace )
|
|
|
27 |
* | (?= \r? \n ) # 2. - Ahead a linebreak
|
|
|
28 |
* | $ # 3. - EOS
|
|
|
29 |
* | [^\S\r\n] # 4. - Accept an extra non-linebreak whitespace
|
|
|
30 |
* )
|
|
|
31 |
* ) # End atomic group
|
|
|
32 |
* |
|
|
|
33 |
* .{1,16} # No valid word breaks, just break on the N'th character
|
|
|
34 |
* ) # (1 end)
|
|
|
35 |
* (?: \r? \n )? # Optional linebreak after Words/Characters
|
|
|
36 |
* |
|
|
|
37 |
* # -- Or, Linebreak
|
|
|
38 |
* (?: \r? \n | $ ) # Stand alone linebreak or at EOS
|
|
|
39 |
* )
|
|
|
40 |
*
|
|
|
41 |
* @author Krisztián Ferenczi <ferenczi.krisztian@gmail.com>
|
|
|
42 |
*
|
|
|
43 |
* @see https://stackoverflow.com/a/20434776/1476819
|
|
|
44 |
*/
|
|
|
45 |
final class OutputWrapper
|
|
|
46 |
{
|
|
|
47 |
private const TAG_OPEN_REGEX_SEGMENT = '[a-z](?:[^\\\\<>]*+ | \\\\.)*';
|
|
|
48 |
private const TAG_CLOSE_REGEX_SEGMENT = '[a-z][^<>]*+';
|
|
|
49 |
private const URL_PATTERN = 'https?://\S+';
|
|
|
50 |
|
|
|
51 |
public function __construct(
|
|
|
52 |
private bool $allowCutUrls = false
|
|
|
53 |
) {
|
|
|
54 |
}
|
|
|
55 |
|
|
|
56 |
public function wrap(string $text, int $width, string $break = "\n"): string
|
|
|
57 |
{
|
|
|
58 |
if (!$width) {
|
|
|
59 |
return $text;
|
|
|
60 |
}
|
|
|
61 |
|
|
|
62 |
$tagPattern = sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT);
|
|
|
63 |
$limitPattern = "{1,$width}";
|
|
|
64 |
$patternBlocks = [$tagPattern];
|
|
|
65 |
if (!$this->allowCutUrls) {
|
|
|
66 |
$patternBlocks[] = self::URL_PATTERN;
|
|
|
67 |
}
|
|
|
68 |
$patternBlocks[] = '.';
|
|
|
69 |
$blocks = implode('|', $patternBlocks);
|
|
|
70 |
$rowPattern = "(?:$blocks)$limitPattern";
|
|
|
71 |
$pattern = sprintf('#(?:((?>(%1$s)((?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|(%1$s))(?:\r?\n)?|(?:\r?\n|$))#imux', $rowPattern);
|
|
|
72 |
$output = rtrim(preg_replace($pattern, '\\1'.$break, $text), $break);
|
|
|
73 |
|
|
|
74 |
return str_replace(' '.$break, $break, $output);
|
|
|
75 |
}
|
|
|
76 |
}
|