Skip to content
Open
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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ are supported as defined in [ISO/IEC 2022](https://en.wikipedia.org/wiki/ISO/IEC

* PM (Privacy Message)

* SS2 (Single Shift 2)
this means select the following character form the G2 character set
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: from


* SS3 (Single Shift 3)
this means select the following character form the G3 character set
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: from


Each code sequence gets emitted with a dedicated event with its raw byte sequence:

```php
Expand All @@ -90,6 +96,8 @@ $stream->on('osc', function ($sequence) { … });
$stream->on('apc', function ($sequence) { … });
$stream->on('dps', function ($sequence) { … });
$stream->on('pm', function ($sequence) { … });
$stream->on('ss2', function ($sequence) { … });
$stream->on('ss3', function ($sequence) { … });
```

Other lesser known [C1 control codes](https://en.wikipedia.org/wiki/C0_and_C1_control_codes#C1_set)
Expand Down
10 changes: 10 additions & 0 deletions src/ControlCodeParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ class ControlCodeParser extends EventEmitter implements ReadableStreamInterface
* followed by "_" means it's APC (Application Program-Control)
* followed by "P" means it's DPS (Device-Control string)
* followed by "^" means it's PM (Privacy Message)
* followed by "N" means it's SS2 (Single Shift 2)
* followed by "O" means it's SS3 (Single Shift 3)
*
* Each of these will be parsed until the sequence ends and then emitted
* under their respective name.
Expand All @@ -39,6 +41,8 @@ class ControlCodeParser extends EventEmitter implements ReadableStreamInterface
'_' => 'apc',
'P' => 'dps',
'^' => 'pm',
'N' => 'ss2',
'O' => 'ss3',
);

public function __construct(ReadableStreamInterface $input)
Expand Down Expand Up @@ -171,6 +175,12 @@ public function handleData($data)
break;
}
}
} else if ($type === 'ss2' || $type === 'ss3') {
$data = substr($this->buffer, 0, 3);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logic looks about right! 👍 This needs an additional check to ensure that 3 bytes are available in the buffer and set $found accordingly (also needs additional tests).

$this->buffer = (string) substr($this->buffer, 3);

$this->emit($type, array($data));
$found = true;
} else {
// all other types are terminated by ST
// only OSC can also be terminted by BEL (whichever comes first)
Expand Down
32 changes: 32 additions & 0 deletions tests/ControlCodeParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,38 @@ public function testDoesNotEmitDpsIfItDoesNotEndWithSt()
$this->input->emit('data', array("\x1BPasd\x07"));
}

public function testEmitsSs2AndData()
{
$this->parser->on('data', $this->expectCallableOnceWith('hello'));
$this->parser->on('ss2', $this->expectCallableOnceWith("\x1BNE"));

$this->input->emit('data', array("\x1BNEhello"));
}

public function testEmitsDataAndSs2()
{
$this->parser->on('data', $this->expectCallableOnceWith('hello'));
$this->parser->on('ss2', $this->expectCallableOnceWith("\x1BNE"));

$this->input->emit('data', array("hello\x1BNE"));
}

public function testEmitsSs3AndData()
{
$this->parser->on('data', $this->expectCallableOnceWith('hello'));
$this->parser->on('ss3', $this->expectCallableOnceWith("\x1BOP"));

$this->input->emit('data', array("\x1BOPhello"));
}

public function testEmitsDataAndSs3()
{
$this->parser->on('data', $this->expectCallableOnceWith('hello'));
$this->parser->on('ss3', $this->expectCallableOnceWith("\x1BOP"));

$this->input->emit('data', array("hello\x1BOP"));
}

public function testEmitsUnknownC1AsOneChunk()
{
$this->parser->on('data', $this->expectCallableNever());
Expand Down