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
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"phpactor/amp-fswatch": "^0.3.0",
"amphp/process": "^1.1.5",
"phpactor/phly-event-dispatcher": "^2.2.0",
"phpactor/language-server": "^7.0.1",
"phpactor/language-server-protocol": "^3.17.4",
"phpactor/language-server": "dev-master",
"phpactor/language-server-protocol": "^3.17.5",
"dantleech/object-renderer": "^0.1.1",
"monolog/monolog": "^1.23",
"sebastian/diff": "^5.0",
Expand Down
276 changes: 138 additions & 138 deletions composer.lock

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions doc/reference/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,19 @@ Additive stubs files relative to the project root. These stubs augment existing
**Default**: ``[]``


.. _param_worse_reflection.ast_provider_service:


``worse_reflection.ast_provider_service``
"""""""""""""""""""""""""""""""""""""""""


(internal) service used to provide the AST


**Default**: ``"Phpactor\\WorseReflection\\Bridge\\TolerantParser\\AstProvider\\TolerantAstProvider"``


.. _param_worse_reflection.diagnostics.undefined_variable.suggestion_levenshtein_disatance:


Expand Down Expand Up @@ -1211,6 +1224,19 @@ LanguageServerExtension
**Default**: ``true``


.. _param_language_server.text_sync_incremental:


``language_server.text_sync_incremental``
"""""""""""""""""""""""""""""""""""""""""


Sync text documents incrementally (experimental)


**Default**: ``false``


.. _param_language_server.enable_workspace:


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public function getListenersForEvent(object $event): iterable
{
if (null === $this->aggregateProvider) {
$this->aggregateProvider = new ListenerProviderAggregate();

foreach ($this->serviceIds as $serviceId) {
/** @var object|null $listenerProvider */
$listenerProvider = $this->container->get($serviceId);
Expand Down
28 changes: 23 additions & 5 deletions lib/Extension/LanguageServer/LanguageServerExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use Phpactor\Extension\LanguageServer\Command\StartCommand;
use Phpactor\FilePathResolver\PathResolver;
use Phpactor\LanguageServerProtocol\ClientCapabilities;
use Phpactor\LanguageServerProtocol\TextDocumentSyncKind;
use Phpactor\LanguageServer\Core\CodeAction\AggregateCodeActionProvider;
use Phpactor\LanguageServer\Core\CodeAction\CodeActionProvider;
use Phpactor\LanguageServer\Core\Command\CommandDispatcher;
Expand All @@ -50,6 +51,7 @@
use Phpactor\LanguageServer\Core\Dispatcher\ArgumentResolver;
use Phpactor\LanguageServer\Handler\Workspace\DidChangeWatchedFilesHandler;
use Phpactor\LanguageServer\Listener\DidChangeWatchedFilesListener;
use Phpactor\LanguageServer\Listener\WorkspaceListener;
use Phpactor\LanguageServer\Middleware\HandlerMiddleware;
use Phpactor\LanguageServer\Core\Server\ResponseWatcher;
use Phpactor\LanguageServer\Middleware\ResponseHandlingMiddleware;
Expand All @@ -67,7 +69,6 @@
use Phpactor\LanguageServer\Core\Service\ServiceManager;
use Phpactor\LanguageServer\Handler\System\ServiceHandler;
use Phpactor\LanguageServer\Core\Server\ClientApi;
use Phpactor\LanguageServer\Listener\WorkspaceListener;
use Phpactor\LanguageServer\Core\Workspace\Workspace;
use Phpactor\LanguageServer\LanguageServerBuilder;
use Phpactor\LanguageServer\Core\Server\ServerStats;
Expand Down Expand Up @@ -129,11 +130,13 @@ class LanguageServerExtension implements Extension
public const PARAM_DIAGNOSTIC_EXCLUDE_PATHS = 'language_server.diagnostic_exclude_paths';
public const PARAM_DIAGNOSTIC_IGNORE_CODES = 'language_server.diagnostic_ignore_codes';
public const PARAM_ENABLE_TRUST_CHECK = 'language_server.enable_trust_check';
public const PARAM_INCREMENTAL = 'language_server.text_sync_incremental';

public function configure(Resolver $schema): void
{
$schema->setDefaults([
self::PARAM_CATCH_ERRORS => true,
self::PARAM_INCREMENTAL => false,
self::PARAM_ENABLE_WORKPACE => true,
self::PARAM_SESSION_PARAMETERS => [],
self::PARAM_METHOD_ALIAS_MAP => [],
Expand All @@ -158,6 +161,7 @@ public function configure(Resolver $schema): void
$schema->setDescriptions([
self::PARAM_ENABLE_TRUST_CHECK => 'Check to see if project path is trusted before loading configurations from it',
self::PARAM_TRACE => 'Log incoming and outgoing messages (needs log formatter to be set to ``json``)',
self::PARAM_INCREMENTAL => 'Sync text documents incrementally (experimental)',
self::PARAM_PROFILE => 'Logs timing information for incoming LSP requests',
self::PARAM_METHOD_ALIAS_MAP => 'Allow method names to be re-mapped. Useful for maintaining backwards compatibility',
self::PARAM_SESSION_PARAMETERS => 'Phpactor parameters (config) that apply only to the language server session',
Expand Down Expand Up @@ -251,6 +255,10 @@ private function registerSession(ContainerBuilder $container): void
return null;
}

if ($container->parameter(self::PARAM_INCREMENTAL)->bool() === true) {
return null;
}

return new WorkspaceListener($this->workspace($container));
}, [
self::TAG_LISTENER_PROVIDER => [],
Expand Down Expand Up @@ -336,6 +344,7 @@ private function registerEventDispatcher(ContainerBuilder $container): void
);

return new EventDispatcher($aggregate);

});
}

Expand Down Expand Up @@ -470,7 +479,10 @@ private function registerHandlers(ContainerBuilder $container): void
});

$container->register(TextDocumentHandler::class, function (Container $container) {
return new TextDocumentHandler($container->get(EventDispatcherInterface::class));
return new TextDocumentHandler(
$container->get(EventDispatcherInterface::class),
$container->parameter(self::PARAM_INCREMENTAL)->bool() ? TextDocumentSyncKind::INCREMENTAL : TextDocumentSyncKind::FULL,
);
}, [ self::TAG_METHOD_HANDLER => []]);

$container->register(StatsHandler::class, function (Container $container) {
Expand Down Expand Up @@ -541,7 +553,9 @@ private function registerServices(ContainerBuilder $container): void
);
}, [
self::TAG_SERVICE_PROVIDER => [],
self::TAG_LISTENER_PROVIDER => [],
self::TAG_LISTENER_PROVIDER => [
'priority' => 100,
],
]);
}

Expand Down Expand Up @@ -655,7 +669,11 @@ private function taggedServices(Container $container, string $tag, ?string $fqn
*/
private function resolveListeners(Container $container): array
{
return array_filter(array_keys($container->getServiceIdsForTag(self::TAG_LISTENER_PROVIDER)), function (string $service) use ($container) {
$serviceIds = $container->getServiceIdsForTag(self::TAG_LISTENER_PROVIDER);
uasort($serviceIds, function (array $a, array $b) {
return ($a['priority'] ?? 0) <=> ($b['priority'] ?? 0);
});
return array_filter(array_keys($serviceIds), function (string $service) use ($container) {
if (false === $container->parameter(self::PARAM_FILE_EVENTS)->bool() && $service === DidChangeWatchedFilesListener::class) {
return false;
}
Expand Down Expand Up @@ -707,7 +725,7 @@ private function collectDiagnosticProviders(Container $container, ?bool $outsour
$providers[$attrs[DiagnosticProviderTag::NAME] ?? $serviceId] = $provider;
}

$enabled = $container->getParameter(self::PARAM_DIAGNOSTIC_PROVIDERS);
$enabled = $container->parameter(self::PARAM_DIAGNOSTIC_PROVIDERS)->value();

if (null !== $enabled) {
Assert::isArray($enabled);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Phpactor\Extension\LanguageServerBridge\Converter\PositionConverter;
use Phpactor\Extension\LanguageServerBridge\Converter\RangeConverter;
use Phpactor\LanguageServerProtocol\Range;
use Phpactor\LanguageServer\Test\ProtocolFactory;
use Phpactor\TextDocument\ByteOffset;
use Phpactor\TextDocument\ByteOffsetRange;

Expand All @@ -27,4 +28,20 @@ public function testConvertsRanges(): void
)
);
}

public function testPositionToByteOffsetOutOfRange(): void
{
self::assertEquals(
ByteOffsetRange::fromInts(25, 27),
RangeConverter::toPhpactorRange(
ProtocolFactory::range(1, 19, 1, 21),
<<<'EOT'
<?php
$this->update

EOT
)
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public function testPositionToByteOffset(): void
)
);
}

public function testWhenOutOfBoundsAssumeEndOfDocument(): void
{
self::assertEquals(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Phpactor\Extension\LanguageServerWorseReflection\Handler\InlayHintHandler;
use Phpactor\Extension\LanguageServerWorseReflection\InlayHint\InlayHintOptions;
use Phpactor\Extension\LanguageServerWorseReflection\InlayHint\InlayHintProvider;
use Phpactor\Extension\LanguageServerWorseReflection\Listener\IncrementalAstListener;
use Phpactor\Extension\LanguageServerWorseReflection\Listener\InvalidateDocumentCacheListener;
use Phpactor\Extension\LanguageServerWorseReflection\Listener\StubValidationListener;
use Phpactor\Extension\LanguageServerWorseReflection\SourceLocator\WorkspaceSourceLocator;
Expand All @@ -20,6 +21,7 @@
use Phpactor\LanguageServer\Core\Server\ClientApi;
use Phpactor\LanguageServer\Core\Workspace\Workspace;
use Phpactor\MapResolver\Resolver;
use Phpactor\WorseReflection\Bridge\TolerantParser\AstProvider\IncrementalAstProvider;
use Phpactor\WorseReflection\Core\CacheForDocument;
use Phpactor\WorseReflection\Core\Reflector\SourceCodeReflector;
use Phpactor\WorseReflection\Reflector;
Expand All @@ -43,6 +45,19 @@ public function load(ContainerBuilder $container): void
$container->parameter(WorseReflectionExtension::PARAM_ADDITIVE_STUBS)->listOfString(),
);
}, [ LanguageServerExtension::TAG_LISTENER_PROVIDER => [] ]);

$container->register(IncrementalAstListener::class, function (Container $container) {
if ($container->parameter(LanguageServerExtension::PARAM_INCREMENTAL)->bool() === false) {
return null;
}

return new IncrementalAstListener(
$container->get(IncrementalAstProvider::class),
$container->expect(LanguageServerExtension::SERVICE_SESSION_WORKSPACE, Workspace::class),
);
}, [
LanguageServerExtension::TAG_LISTENER_PROVIDER => [],
]);
}

public function configure(Resolver $schema): void
Expand Down Expand Up @@ -81,7 +96,18 @@ private function registerSourceLocator(ContainerBuilder $container): void

$container->register(InvalidateDocumentCacheListener::class, function (Container $container) {
return new InvalidateDocumentCacheListener($container->get(CacheForDocument::class));
}, [ LanguageServerExtension::TAG_LISTENER_PROVIDER => [] ]);
}, [ LanguageServerExtension::TAG_LISTENER_PROVIDER => [
'priority' => -100,
] ]);

$container->register(IncrementalAstListener::class, function (Container $container) {
return new IncrementalAstListener(
$container->get(IncrementalAstProvider::class),
$container->expect(LanguageServerExtension::SERVICE_SESSION_WORKSPACE, Workspace::class)
);
}, [ LanguageServerExtension::TAG_LISTENER_PROVIDER => [
'priority' => -100,
] ]);

$container->register(WorkspaceIndex::class, function (Container $container) {
return new WorkspaceIndex(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

namespace Phpactor\Extension\LanguageServerWorseReflection\Listener;

use Phpactor\Extension\LanguageServerBridge\Converter\RangeConverter;
use Phpactor\Extension\LanguageServerBridge\Converter\TextDocumentConverter;
use Phpactor\LanguageServer\Core\Workspace\Workspace;
use Phpactor\LanguageServer\Event\TextDocumentClosed;
use Phpactor\LanguageServer\Event\TextDocumentIncrementallyUpdated;
use Phpactor\LanguageServer\Event\TextDocumentOpened;
use Phpactor\LanguageServer\Event\TextDocumentUpdated;
use Phpactor\LanguageServerProtocol\TextDocumentContentChangeIncrementalEvent;
use Phpactor\TextDocument\TextDocumentBuilder;
use Phpactor\WorseReflection\Bridge\TolerantParser\AstProvider\IncrementalAstProvider;
use Psr\EventDispatcher\ListenerProviderInterface;
use Phpactor\TextDocument\TextDocumentUri;
use Phpactor\TextDocument\TextEdit;
use Phpactor\TextDocument\TextEdits;

final class IncrementalAstListener implements ListenerProviderInterface
{
public function __construct(
private IncrementalAstProvider $provider,
private Workspace $workspace,
) {
}

/**
* @return iterable<mixed>
*/
public function getListenersForEvent(object $event): iterable
{
if ($event instanceof TextDocumentIncrementallyUpdated) {
yield $this->update(...);
return;
}

if ($event instanceof TextDocumentClosed) {
yield function (TextDocumentClosed $closed): void {
$this->workspace->remove($closed->identifier());
$this->provider->close(TextDocumentUri::fromString($closed->identifier()->uri));
};
return;
}

if ($event instanceof TextDocumentOpened) {
yield function (TextDocumentOpened $opened): void {
$this->workspace->open($opened->textDocument());
$this->provider->open(TextDocumentConverter::fromLspTextItem($opened->textDocument()));
};
return;
}

if ($event instanceof TextDocumentUpdated) {
yield function (TextDocumentUpdated $updated): void {
$this->workspace->update($updated->identifier(), $updated->updatedText());
$this->provider->open(TextDocumentBuilder::create($updated->updatedText())->uri($updated->identifier()->uri)->build());
};
return;
}
}

private function update(TextDocumentIncrementallyUpdated $event): void
{
$uri = TextDocumentUri::fromString($event->identifier()->uri);
$document = $this->workspace->get($event->identifier()->uri);

// convert the text edits
$content = $document->text;
$edits = array_map(function (TextDocumentContentChangeIncrementalEvent $event) use (&$content) {
$range = RangeConverter::toPhpactorRange($event->range, $content);
$edit = TextEdit::create(
$range->start(),
$range->length(),
$event->text
);
$content = TextEdits::one($edit)->apply($content);
return $edit;
}, $event->events());

$uri = TextDocumentUri::fromString($uri);

$ast = $this->provider->update($uri, $edits);

$this->workspace->update(
$event->identifier(),
$ast->fileContents
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
namespace Phpactor\Extension\LanguageServerWorseReflection\Listener;

use Phpactor\LanguageServer\Event\TextDocumentClosed;
use Phpactor\LanguageServer\Event\TextDocumentIncrementallyUpdated;
use Phpactor\LanguageServer\Event\TextDocumentSaved;
use Phpactor\LanguageServer\Event\TextDocumentUpdated;
use Phpactor\TextDocument\TextDocumentUri;
use Phpactor\WorseReflection\Bridge\TolerantParser\Reflector\TolerantSourceCodeReflector;
use Phpactor\WorseReflection\Core\CacheForDocument;
use Psr\EventDispatcher\ListenerProviderInterface;

Expand All @@ -20,6 +22,13 @@ public function __construct(private CacheForDocument $cache)
*/
public function getListenersForEvent($event): iterable
{
if ($event instanceof TextDocumentIncrementallyUpdated) {
yield function () use ($event): void {
$this->cache->cacheForDocument(
TextDocumentUri::fromString($event->identifier()->uri),
)->remove(TolerantSourceCodeReflector::CACHE_KEY_DIAGNOSTICS);
};
}
if ($event instanceof TextDocumentUpdated) {
yield function () use ($event): void {
$this->cache->purge(TextDocumentUri::fromString($event->identifier()->uri));
Expand Down
Loading