feature #29168 [Console] Add hyperlinks support (ostrolucky)
This PR was squashed before being merged into the 4.3-dev branch (closes #29168).
Discussion
----------
[Console] Add hyperlinks support
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #21207
| License | MIT
| Doc PR |
For details about this see https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
Here's one idea/use case which could utilize this feature (not implemented in this PR as it requires more work)
![stack trace with anchors](https://user-images.githubusercontent.com/496233/48305600-00d4c300-e52e-11e8-94e6-33713ff09d50.png)
I checked this in cmd.exe as well and no sideffects there
Commits
-------
db750ed8ae
[Console] Add hyperlinks support
This commit is contained in:
commit
58b29d6a11
@ -1,6 +1,11 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
4.3.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added support for hyperlinks
|
||||||
|
|
||||||
4.2.0
|
4.2.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
|||||||
{
|
{
|
||||||
$offset = 0;
|
$offset = 0;
|
||||||
$output = '';
|
$output = '';
|
||||||
$tagRegex = '[a-z][a-z0-9,_=;-]*+';
|
$tagRegex = '[a-z][^<>]*+';
|
||||||
$currentLineLength = 0;
|
$currentLineLength = 0;
|
||||||
preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, PREG_OFFSET_CAPTURE);
|
preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, PREG_OFFSET_CAPTURE);
|
||||||
foreach ($matches[0] as $i => $match) {
|
foreach ($matches[0] as $i => $match) {
|
||||||
@ -215,6 +215,8 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
|||||||
$style->setForeground($match[1]);
|
$style->setForeground($match[1]);
|
||||||
} elseif ('bg' == $match[0]) {
|
} elseif ('bg' == $match[0]) {
|
||||||
$style->setBackground($match[1]);
|
$style->setBackground($match[1]);
|
||||||
|
} elseif ('href' === $match[0]) {
|
||||||
|
$style->setHref($match[1]);
|
||||||
} elseif ('options' === $match[0]) {
|
} elseif ('options' === $match[0]) {
|
||||||
preg_match_all('([^,;]+)', $match[1], $options);
|
preg_match_all('([^,;]+)', $match[1], $options);
|
||||||
$options = array_shift($options);
|
$options = array_shift($options);
|
||||||
|
@ -52,6 +52,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
|||||||
|
|
||||||
private $foreground;
|
private $foreground;
|
||||||
private $background;
|
private $background;
|
||||||
|
private $href;
|
||||||
private $options = array();
|
private $options = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,6 +119,11 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
|||||||
$this->background = static::$availableBackgroundColors[$color];
|
$this->background = static::$availableBackgroundColors[$color];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setHref(string $url): void
|
||||||
|
{
|
||||||
|
$this->href = $url;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets some specific style option.
|
* Sets some specific style option.
|
||||||
*
|
*
|
||||||
@ -187,11 +193,14 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
|||||||
$setCodes[] = $this->background['set'];
|
$setCodes[] = $this->background['set'];
|
||||||
$unsetCodes[] = $this->background['unset'];
|
$unsetCodes[] = $this->background['unset'];
|
||||||
}
|
}
|
||||||
if (\count($this->options)) {
|
|
||||||
foreach ($this->options as $option) {
|
foreach ($this->options as $option) {
|
||||||
$setCodes[] = $option['set'];
|
$setCodes[] = $option['set'];
|
||||||
$unsetCodes[] = $option['unset'];
|
$unsetCodes[] = $option['unset'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null !== $this->href) {
|
||||||
|
$text = "\033]8;;$this->href\033\\$text\033]8;;\033\\";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 === \count($setCodes)) {
|
if (0 === \count($setCodes)) {
|
||||||
|
@ -228,7 +228,7 @@ class OutputFormatterTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNotDecoratedFormatter()
|
public function testFormatterHasStyles()
|
||||||
{
|
{
|
||||||
$formatter = new OutputFormatter(false);
|
$formatter = new OutputFormatter(false);
|
||||||
|
|
||||||
@ -236,39 +236,26 @@ class OutputFormatterTest extends TestCase
|
|||||||
$this->assertTrue($formatter->hasStyle('info'));
|
$this->assertTrue($formatter->hasStyle('info'));
|
||||||
$this->assertTrue($formatter->hasStyle('comment'));
|
$this->assertTrue($formatter->hasStyle('comment'));
|
||||||
$this->assertTrue($formatter->hasStyle('question'));
|
$this->assertTrue($formatter->hasStyle('question'));
|
||||||
|
}
|
||||||
|
|
||||||
$this->assertEquals(
|
/**
|
||||||
'some error', $formatter->format('<error>some error</error>')
|
* @dataProvider provideDecoratedAndNonDecoratedOutput
|
||||||
);
|
*/
|
||||||
$this->assertEquals(
|
public function testNotDecoratedFormatter(string $input, string $expectedNonDecoratedOutput, string $expectedDecoratedOutput)
|
||||||
'some info', $formatter->format('<info>some info</info>')
|
{
|
||||||
);
|
$this->assertEquals($expectedDecoratedOutput, (new OutputFormatter(true))->format($input));
|
||||||
$this->assertEquals(
|
$this->assertEquals($expectedNonDecoratedOutput, (new OutputFormatter(false))->format($input));
|
||||||
'some comment', $formatter->format('<comment>some comment</comment>')
|
}
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
'some question', $formatter->format('<question>some question</question>')
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
'some text with inline style', $formatter->format('<fg=red>some text with inline style</>')
|
|
||||||
);
|
|
||||||
|
|
||||||
$formatter->setDecorated(true);
|
public function provideDecoratedAndNonDecoratedOutput()
|
||||||
|
{
|
||||||
$this->assertEquals(
|
return array(
|
||||||
"\033[37;41msome error\033[39;49m", $formatter->format('<error>some error</error>')
|
array('<error>some error</error>', 'some error', "\033[37;41msome error\033[39;49m"),
|
||||||
);
|
array('<info>some info</info>', 'some info', "\033[32msome info\033[39m"),
|
||||||
$this->assertEquals(
|
array('<comment>some comment</comment>', 'some comment', "\033[33msome comment\033[39m"),
|
||||||
"\033[32msome info\033[39m", $formatter->format('<info>some info</info>')
|
array('<question>some question</question>', 'some question', "\033[30;46msome question\033[39;49m"),
|
||||||
);
|
array('<fg=red>some text with inline style</>', 'some text with inline style', "\033[31msome text with inline style\033[39m"),
|
||||||
$this->assertEquals(
|
array('<href=idea://open/?file=/path/somefile.php&line=12>some URL</>', 'some URL', "\033]8;;idea://open/?file=/path/somefile.php&line=12\033\\some URL\033]8;;\033\\"),
|
||||||
"\033[33msome comment\033[39m", $formatter->format('<comment>some comment</comment>')
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
"\033[30;46msome question\033[39;49m", $formatter->format('<question>some question</question>')
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
"\033[31msome text with inline style\033[39m", $formatter->format('<fg=red>some text with inline style</>')
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user