Skip to content

Commit da1d994

Browse files
committed
Introduce support for incrementally updating text documents
- Bump protocol package - Add incrementally updated event - Allow the handler to be configured with the sync kind
1 parent 41295a9 commit da1d994

File tree

5 files changed

+138
-9
lines changed

5 files changed

+138
-9
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"amphp/socket": "^1.1",
1414
"dantleech/argument-resolver": "^1.1",
1515
"dantleech/invoke": "^2.0",
16-
"phpactor/language-server-protocol": "^3.17",
16+
"phpactor/language-server-protocol": "^3.17.5",
1717
"psr/event-dispatcher": "^1.0",
1818
"psr/log": "^1.0",
1919
"ramsey/uuid": "^4.0"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace Phpactor\LanguageServer\Event;
4+
5+
use Phpactor\LanguageServerProtocol\TextDocumentContentChangeIncrementalEvent;
6+
use Phpactor\LanguageServerProtocol\VersionedTextDocumentIdentifier;
7+
8+
class TextDocumentIncrementallyUpdated
9+
{
10+
/**
11+
* @param TextDocumentContentChangeIncrementalEvent[] $events
12+
*/
13+
public function __construct(private VersionedTextDocumentIdentifier $identifier, private array $events)
14+
{
15+
}
16+
17+
public function identifier(): VersionedTextDocumentIdentifier
18+
{
19+
return $this->identifier;
20+
}
21+
22+
/**
23+
* @return TextDocumentContentChangeIncrementalEvent[]
24+
*/
25+
public function events(): array
26+
{
27+
return $this->events;
28+
}
29+
}

lib/Handler/TextDocument/TextDocumentHandler.php

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,28 @@
77
use Phpactor\LanguageServerProtocol\DidOpenTextDocumentParams;
88
use Phpactor\LanguageServerProtocol\DidSaveTextDocumentParams;
99
use Phpactor\LanguageServerProtocol\ServerCapabilities;
10+
use Phpactor\LanguageServerProtocol\TextDocumentContentChangeFullEvent;
11+
use Phpactor\LanguageServerProtocol\TextDocumentContentChangeIncrementalEvent;
1012
use Phpactor\LanguageServerProtocol\TextDocumentSyncKind;
1113
use Phpactor\LanguageServerProtocol\WillSaveTextDocumentParams;
1214
use Phpactor\LanguageServer\Core\Handler\CanRegisterCapabilities;
1315
use Phpactor\LanguageServer\Core\Handler\Handler;
1416
use Phpactor\LanguageServer\Event\TextDocumentClosed;
1517
use Phpactor\LanguageServer\Event\TextDocumentOpened;
18+
use Phpactor\LanguageServer\Event\TextDocumentIncrementallyUpdated;
1619
use Phpactor\LanguageServer\Event\TextDocumentSaved;
1720
use Phpactor\LanguageServer\Event\TextDocumentUpdated;
1821
use Psr\EventDispatcher\EventDispatcherInterface;
1922

2023
final class TextDocumentHandler implements Handler, CanRegisterCapabilities
2124
{
22-
public function __construct(private EventDispatcherInterface $dispatcher)
23-
{
25+
/**
26+
* @param TextDocumentSyncKind::* $syncKind
27+
*/
28+
public function __construct(
29+
private EventDispatcherInterface $dispatcher,
30+
private int $syncKind = TextDocumentSyncKind::FULL,
31+
) {
2432
}
2533

2634
public function methods(): array
@@ -42,9 +50,27 @@ public function didOpen(DidOpenTextDocumentParams $params): void
4250

4351
public function didChange(DidChangeTextDocumentParams $params): void
4452
{
53+
$increments = [];
4554
foreach ($params->contentChanges as $contentChange) {
46-
$this->dispatcher->dispatch(new TextDocumentUpdated($params->textDocument, $contentChange['text']));
55+
if ($contentChange instanceof TextDocumentContentChangeIncrementalEvent) {
56+
$increments[] = $contentChange;
57+
continue;
58+
59+
}
60+
if ($contentChange instanceof TextDocumentContentChangeFullEvent) {
61+
$this->dispatcher->dispatch(new TextDocumentUpdated($params->textDocument, $contentChange->text));
62+
continue;
63+
}
4764
}
65+
66+
if ($increments === []) {
67+
return;
68+
}
69+
70+
$this->dispatcher->dispatch(new TextDocumentIncrementallyUpdated(
71+
$params->textDocument,
72+
$increments,
73+
));
4874
}
4975

5076
public function didClose(DidCloseTextDocumentParams $params): void
@@ -67,6 +93,6 @@ public function willSaveWaitUntil(WillSaveTextDocumentParams $params): void
6793

6894
public function registerCapabiltiies(ServerCapabilities $capabilities): void
6995
{
70-
$capabilities->textDocumentSync = TextDocumentSyncKind::FULL;
96+
$capabilities->textDocumentSync = $this->syncKind;
7197
}
7298
}

lib/Test/LanguageServerTester/TextDocumentTester.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Phpactor\LanguageServerProtocol\DidChangeTextDocumentParams;
77
use Phpactor\LanguageServerProtocol\DidSaveTextDocumentNotification;
88
use Phpactor\LanguageServerProtocol\DidSaveTextDocumentParams;
9+
use Phpactor\LanguageServerProtocol\TextDocumentContentChangeFullEvent;
910
use Phpactor\LanguageServer\Test\ProtocolFactory;
1011
use Phpactor\LanguageServerProtocol\DidOpenTextDocumentParams;
1112
use Phpactor\LanguageServerProtocol\DidOpenTextDocumentNotification;
@@ -43,9 +44,7 @@ public function update(string $uri, string $newText): void
4344
$this->tester->notifyAndWait(DidChangeTextDocumentNotification::METHOD, new DidChangeTextDocumentParams(
4445
ProtocolFactory::versionedTextDocumentIdentifier($uri, self::$versions[$uri]),
4546
[
46-
[
47-
'text' => $newText
48-
]
47+
new TextDocumentContentChangeFullEvent($newText),
4948
]
5049
));
5150
}

tests/Unit/Handler/TextDocument/TextDocumentHandlerTest.php

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,18 @@
22

33
namespace Phpactor\LanguageServer\Tests\Unit\Handler\TextDocument;
44

5+
use Phpactor\LanguageServerProtocol\Position;
6+
use Phpactor\LanguageServerProtocol\Range;
7+
use Phpactor\LanguageServerProtocol\ServerCapabilities;
8+
use Phpactor\LanguageServerProtocol\TextDocumentContentChangeIncrementalEvent;
59
use Phpactor\LanguageServerProtocol\TextDocumentIdentifier;
610
use Phpactor\LanguageServerProtocol\TextDocumentItem;
11+
use Phpactor\LanguageServerProtocol\TextDocumentSyncKind;
12+
use Phpactor\LanguageServer\Core\Handler\CanRegisterCapabilities;
713
use Phpactor\LanguageServer\Core\Handler\Handler;
814
use Phpactor\LanguageServer\Core\Rpc\ResponseMessage;
915
use Phpactor\LanguageServer\Event\TextDocumentClosed;
16+
use Phpactor\LanguageServer\Event\TextDocumentIncrementallyUpdated;
1017
use Phpactor\LanguageServer\Event\TextDocumentOpened;
1118
use Phpactor\LanguageServer\Event\TextDocumentSaved;
1219
use Phpactor\LanguageServer\Event\TextDocumentUpdated;
@@ -26,6 +33,11 @@ class TextDocumentHandlerTest extends HandlerTestCase
2633
*/
2734
private ObjectProphecy $dispatcher;
2835

36+
/**
37+
* @var TextDocumentSyncKind::*
38+
*/
39+
private int $syncKind = TextDocumentSyncKind::FULL;
40+
2941
protected function setUp(): void
3042
{
3143
$this->dispatcher = $this->prophesize(EventDispatcherInterface::class);
@@ -34,10 +46,31 @@ protected function setUp(): void
3446
public function handler(): Handler
3547
{
3648
return new TextDocumentHandler(
37-
$this->dispatcher->reveal()
49+
$this->dispatcher->reveal(),
50+
$this->syncKind,
3851
);
3952
}
4053

54+
public function testSyncKindFull(): void
55+
{
56+
$handler = $this->handler();
57+
self::assertInstanceOf(CanRegisterCapabilities::class, $handler);
58+
$capabiltiies = new ServerCapabilities();
59+
$handler->registerCapabiltiies($capabiltiies);
60+
self::assertEquals(TextDocumentSyncKind::FULL, $capabiltiies->textDocumentSync);
61+
}
62+
63+
public function testSyncKindIncremental(): void
64+
{
65+
$this->syncKind = TextDocumentSyncKind::INCREMENTAL;
66+
$handler = $this->handler();
67+
self::assertInstanceOf(CanRegisterCapabilities::class, $handler);
68+
$capabiltiies = new ServerCapabilities();
69+
$handler->registerCapabiltiies($capabiltiies);
70+
self::assertEquals(TextDocumentSyncKind::INCREMENTAL, $capabiltiies->textDocumentSync);
71+
72+
}
73+
4174
public function testOpensDocument(): void
4275
{
4376
$textDocument = ProtocolFactory::textDocumentItem('foobar', 'foo');
@@ -65,6 +98,48 @@ public function testUpdatesDocument(): void
6598
$this->dispatcher->dispatch(new TextDocumentUpdated($identifier, 'asd'))->shouldHaveBeenCalled();
6699
}
67100

101+
public function testUpdatesDocumentIncrementally(): void
102+
{
103+
$textDocument = ProtocolFactory::textDocumentItem('foobar', 'foo');
104+
$identifier = ProtocolFactory::versionedTextDocumentIdentifier('foobar', 1);
105+
106+
$this->dispatch('textDocument/didChange', [
107+
'textDocument' => $identifier,
108+
'contentChanges' => [
109+
[
110+
'range' => [
111+
'start' => [
112+
'character' => 0,
113+
'line' => 75,
114+
],
115+
'end' => [
116+
'character' => 0,
117+
'line' => 75,
118+
],
119+
],
120+
'rangeLength' => 1,
121+
'text' => 'hello',
122+
],
123+
],
124+
]);
125+
126+
$this->dispatcher->dispatch(
127+
new TextDocumentIncrementallyUpdated(
128+
$identifier,
129+
[
130+
new TextDocumentContentChangeIncrementalEvent(
131+
new Range(
132+
new Position(75, 0),
133+
new Position(75, 0),
134+
),
135+
rangeLength: 1,
136+
text: 'hello',
137+
),
138+
],
139+
)
140+
)->shouldHaveBeenCalled();
141+
}
142+
68143
public function testWillSave(): void
69144
{
70145
$response = $this->dispatch('textDocument/willSave', [

0 commit comments

Comments
 (0)