diff --git a/.php_cs.dist b/.php-cs-fixer.dist.php similarity index 93% rename from .php_cs.dist rename to .php-cs-fixer.dist.php index 47f1c506..aecc1615 100644 --- a/.php_cs.dist +++ b/.php-cs-fixer.dist.php @@ -8,7 +8,7 @@ ]) ; -return PhpCsFixer\Config::create() +return (new PhpCsFixer\Config()) ->setRiskyAllowed(true) ->setRules([ '@PSR2' => true, @@ -22,4 +22,3 @@ ]) ->setFinder($finder) ; - diff --git a/lib/AbstractExtension.php b/lib/AbstractExtension.php new file mode 100644 index 00000000..5c41128c --- /dev/null +++ b/lib/AbstractExtension.php @@ -0,0 +1,14 @@ +get(ClientCapabilities::class); + } +} diff --git a/lib/AbstractHandler.php b/lib/AbstractHandler.php new file mode 100644 index 00000000..c8e52cd1 --- /dev/null +++ b/lib/AbstractHandler.php @@ -0,0 +1,18 @@ +clientCapabilities = $clientCapabilities; + } +} diff --git a/lib/LanguageServerCompletion/Handler/CompletionHandler.php b/lib/LanguageServerCompletion/Handler/CompletionHandler.php index 50778af6..064fb8cf 100644 --- a/lib/LanguageServerCompletion/Handler/CompletionHandler.php +++ b/lib/LanguageServerCompletion/Handler/CompletionHandler.php @@ -6,9 +6,11 @@ use Amp\CancelledException; use Amp\Delayed; use Amp\Promise; +use Phpactor\Extension\AbstractHandler; use Phpactor\Extension\LanguageServerBridge\Converter\PositionConverter; use Phpactor\Extension\LanguageServerCodeTransform\Model\NameImport\NameImporter; use Phpactor\Extension\LanguageServerCodeTransform\Model\NameImport\NameImporterResult; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\CompletionItem; use Phpactor\LanguageServerProtocol\CompletionList; use Phpactor\LanguageServerProtocol\CompletionOptions; @@ -16,7 +18,6 @@ use Phpactor\LanguageServerProtocol\InsertTextFormat; use Phpactor\LanguageServerProtocol\Range; use Phpactor\LanguageServerProtocol\ServerCapabilities; -use Phpactor\LanguageServerProtocol\SignatureHelpOptions; use Phpactor\LanguageServerProtocol\TextDocumentItem; use Phpactor\LanguageServerProtocol\TextEdit; use Phpactor\Completion\Core\Suggestion; @@ -28,7 +29,7 @@ use Phpactor\LanguageServer\Core\Workspace\Workspace; use Phpactor\TextDocument\TextDocumentBuilder; -class CompletionHandler implements Handler, CanRegisterCapabilities +class CompletionHandler extends AbstractHandler implements Handler, CanRegisterCapabilities { /** * @var TypedCompletorRegistry @@ -50,11 +51,6 @@ class CompletionHandler implements Handler, CanRegisterCapabilities */ private $workspace; - /** - * @var bool - */ - private $supportSnippets; - /** * @var NameImporter */ @@ -65,7 +61,7 @@ public function __construct( TypedCompletorRegistry $registry, SuggestionNameFormatter $suggestionNameFormatter, NameImporter $nameImporter, - bool $supportSnippets, + ClientCapabilities $clientCapabilities, bool $provideTextEdit = false ) { $this->registry = $registry; @@ -73,7 +69,7 @@ public function __construct( $this->workspace = $workspace; $this->suggestionNameFormatter = $suggestionNameFormatter; $this->nameImporter = $nameImporter; - $this->supportSnippets = $supportSnippets; + parent::__construct($clientCapabilities); } public function methods(): array @@ -142,8 +138,9 @@ public function completion(CompletionParams $params, CancellationToken $token): public function registerCapabiltiies(ServerCapabilities $capabilities): void { - $capabilities->completionProvider = new CompletionOptions([':', '>', '$']); - $capabilities->signatureHelpProvider = new SignatureHelpOptions(['(', ',']); + $capabilities->completionProvider = (null !== $this->clientCapabilities->textDocument->completion) + ? new CompletionOptions([':', '>', '$']) + : null; } private function determineInsertTextAndFormat( @@ -154,7 +151,7 @@ private function determineInsertTextAndFormat( $insertText = $name; $insertTextFormat = InsertTextFormat::PLAIN_TEXT; - if ($this->supportSnippets) { + if ($this->supportSnippets()) { $insertText = $suggestion->snippet() ?: $name; $insertTextFormat = $suggestion->snippet() ? InsertTextFormat::SNIPPET @@ -170,6 +167,11 @@ private function determineInsertTextAndFormat( return [$insertText, $insertTextFormat]; } + private function supportSnippets(): bool + { + return $this->clientCapabilities->textDocument->completion->completionItem['snippetSupport'] ?? false; + } + private function importClassOrFunctionName( Suggestion $suggestion, CompletionParams $params diff --git a/lib/LanguageServerCompletion/Handler/SignatureHelpHandler.php b/lib/LanguageServerCompletion/Handler/SignatureHelpHandler.php index 7deb47cb..8c85cb0f 100644 --- a/lib/LanguageServerCompletion/Handler/SignatureHelpHandler.php +++ b/lib/LanguageServerCompletion/Handler/SignatureHelpHandler.php @@ -3,7 +3,9 @@ namespace Phpactor\Extension\LanguageServerCompletion\Handler; use Amp\Promise; +use Phpactor\Extension\AbstractHandler; use Phpactor\Extension\LanguageServerBridge\Converter\PositionConverter; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\Position; use Phpactor\LanguageServerProtocol\ServerCapabilities; use Phpactor\LanguageServerProtocol\SignatureHelp; @@ -17,7 +19,7 @@ use Phpactor\LanguageServer\Core\Workspace\Workspace; use Phpactor\TextDocument\TextDocumentBuilder; -class SignatureHelpHandler implements Handler, CanRegisterCapabilities +class SignatureHelpHandler extends AbstractHandler implements Handler, CanRegisterCapabilities { /** * @var Workspace @@ -29,10 +31,11 @@ class SignatureHelpHandler implements Handler, CanRegisterCapabilities */ private $helper; - public function __construct(Workspace $workspace, SignatureHelper $helper) + public function __construct(Workspace $workspace, SignatureHelper $helper, ClientCapabilities $clientCapabilities) { $this->workspace = $workspace; $this->helper = $helper; + parent::__construct($clientCapabilities); } /** @@ -67,8 +70,8 @@ public function signatureHelp( public function registerCapabiltiies(ServerCapabilities $capabilities): void { - $options = new SignatureHelpOptions(); - $options->triggerCharacters = [ '(', ',' ]; - $capabilities->signatureHelpProvider = $options; + $capabilities->signatureHelpProvider = (null !== $this->clientCapabilities->textDocument->signatureHelp) + ? new SignatureHelpOptions(['(', ',']) + : null; } } diff --git a/lib/LanguageServerCompletion/LanguageServerCompletionExtension.php b/lib/LanguageServerCompletion/LanguageServerCompletionExtension.php index 66f1093a..5e2f7183 100644 --- a/lib/LanguageServerCompletion/LanguageServerCompletionExtension.php +++ b/lib/LanguageServerCompletion/LanguageServerCompletionExtension.php @@ -5,16 +5,16 @@ use Phpactor\Container\Container; use Phpactor\Container\ContainerBuilder; use Phpactor\Container\Extension; +use Phpactor\Extension\AbstractExtension; use Phpactor\Extension\Completion\CompletionExtension; use Phpactor\Extension\LanguageServerCodeTransform\Model\NameImport\NameImporter; use Phpactor\Extension\LanguageServerCompletion\Handler\SignatureHelpHandler; use Phpactor\Extension\LanguageServerCompletion\Util\SuggestionNameFormatter; use Phpactor\Extension\LanguageServer\LanguageServerExtension; use Phpactor\Extension\LanguageServerCompletion\Handler\CompletionHandler; -use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\MapResolver\Resolver; -class LanguageServerCompletionExtension implements Extension +class LanguageServerCompletionExtension extends AbstractExtension implements Extension { private const PARAM_TRIM_LEADING_DOLLAR = 'language_server_completion.trim_leading_dollar'; @@ -47,7 +47,7 @@ private function registerHandlers(ContainerBuilder $container): void $container->get(CompletionExtension::SERVICE_REGISTRY), $container->get(SuggestionNameFormatter::class), $container->get(NameImporter::class), - $this->clientCapabilities($container)->textDocument->completion->completionItem['snippetSupport'] ?? false + $this->clientCapabilities($container) ); }, [ LanguageServerExtension::TAG_METHOD_HANDLER => [ 'methods' => [ @@ -62,13 +62,9 @@ private function registerHandlers(ContainerBuilder $container): void $container->register('language_server_completion.handler.signature_help', function (Container $container) { return new SignatureHelpHandler( $container->get(LanguageServerExtension::SERVICE_SESSION_WORKSPACE), - $container->get(CompletionExtension::SERVICE_SIGNATURE_HELPER) + $container->get(CompletionExtension::SERVICE_SIGNATURE_HELPER), + $this->clientCapabilities($container) ); }, [ LanguageServerExtension::TAG_METHOD_HANDLER => [] ]); } - - private function clientCapabilities(Container $container): ClientCapabilities - { - return $container->get(ClientCapabilities::class); - } } diff --git a/lib/LanguageServerHover/Handler/HoverHandler.php b/lib/LanguageServerHover/Handler/HoverHandler.php index a396ac4a..ae00b683 100644 --- a/lib/LanguageServerHover/Handler/HoverHandler.php +++ b/lib/LanguageServerHover/Handler/HoverHandler.php @@ -3,7 +3,9 @@ namespace Phpactor\Extension\LanguageServerHover\Handler; use Amp\Promise; +use Phpactor\Extension\AbstractHandler; use Phpactor\Extension\LanguageServerBridge\Converter\PositionConverter; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\Hover; use Phpactor\LanguageServerProtocol\MarkupContent; use Phpactor\LanguageServerProtocol\Position; @@ -26,7 +28,7 @@ use Phpactor\WorseReflection\Core\Type; use Phpactor\WorseReflection\Reflector; -class HoverHandler implements Handler, CanRegisterCapabilities +class HoverHandler extends AbstractHandler implements Handler, CanRegisterCapabilities { /** * @var Reflector @@ -43,11 +45,16 @@ class HoverHandler implements Handler, CanRegisterCapabilities */ private $workspace; - public function __construct(Workspace $workspace, Reflector $reflector, ObjectRenderer $renderer) - { + public function __construct( + Workspace $workspace, + Reflector $reflector, + ObjectRenderer $renderer, + ClientCapabilities $clientCapabilities + ) { $this->reflector = $reflector; $this->renderer = $renderer; $this->workspace = $workspace; + parent::__construct($clientCapabilities); } public function methods(): array @@ -73,7 +80,7 @@ public function hover( $symbolContext = $offsetReflection->symbolContext(); $info = $this->infoFromReflecionOffset($offsetReflection); $string = new MarkupContent('markdown', $info); - + return new Hover($string, new Range( PositionConverter::byteOffsetToPosition( ByteOffset::fromInt($symbolContext->symbol()->position()->start()), @@ -89,7 +96,7 @@ public function hover( public function registerCapabiltiies(ServerCapabilities $capabilities): void { - $capabilities->hoverProvider = true; + $capabilities->hoverProvider = null !== $this->clientCapabilities->textDocument->hover; } private function infoFromReflecionOffset(ReflectionOffset $offset): string diff --git a/lib/LanguageServerHover/LanguageServerHoverExtension.php b/lib/LanguageServerHover/LanguageServerHoverExtension.php index 62935168..19d0df30 100644 --- a/lib/LanguageServerHover/LanguageServerHoverExtension.php +++ b/lib/LanguageServerHover/LanguageServerHoverExtension.php @@ -5,6 +5,7 @@ use Phpactor\CodeBuilder\Domain\TemplatePathResolver\PhpVersionPathResolver; use Phpactor\Container\Container; use Phpactor\Container\ContainerBuilder; +use Phpactor\Extension\AbstractExtension; use Phpactor\Extension\Logger\LoggingExtension; use Phpactor\Extension\Php\Model\PhpVersionResolver; use Phpactor\Extension\WorseReflection\WorseReflectionExtension; @@ -15,10 +16,10 @@ use Phpactor\Container\Extension; use Phpactor\MapResolver\Resolver; -class LanguageServerHoverExtension implements Extension +class LanguageServerHoverExtension extends AbstractExtension implements Extension { public const PARAM_TEMPLATE_PATHS = 'language_server_hover.template_paths'; - + private const SERVICE_MARKDOWN_RENDERER = 'language_server_completion.object_renderer.markdown'; /** @@ -47,7 +48,8 @@ public function load(ContainerBuilder $container): void return new HoverHandler( $container->get(LanguageServerExtension::SERVICE_SESSION_WORKSPACE), $container->get(WorseReflectionExtension::SERVICE_REFLECTOR), - $container->get(self::SERVICE_MARKDOWN_RENDERER) + $container->get(self::SERVICE_MARKDOWN_RENDERER), + $this->clientCapabilities($container) ); }, [ LanguageServerExtension::TAG_METHOD_HANDLER => []]); @@ -71,7 +73,7 @@ public function load(ContainerBuilder $container): void foreach ($paths as $path) { $builder = $builder->addTemplatePath($path); } - + return $builder->build(); }); } diff --git a/lib/LanguageServerIndexer/Handler/WorkspaceSymbolHandler.php b/lib/LanguageServerIndexer/Handler/WorkspaceSymbolHandler.php index 44260069..1c33e684 100644 --- a/lib/LanguageServerIndexer/Handler/WorkspaceSymbolHandler.php +++ b/lib/LanguageServerIndexer/Handler/WorkspaceSymbolHandler.php @@ -3,23 +3,26 @@ namespace Phpactor\Extension\LanguageServerIndexer\Handler; use Amp\Promise; +use Phpactor\Extension\AbstractHandler; use Phpactor\Extension\LanguageServerIndexer\Model\WorkspaceSymbolProvider; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\ServerCapabilities; use Phpactor\LanguageServerProtocol\SymbolInformation; use Phpactor\LanguageServerProtocol\WorkspaceSymbolParams; use Phpactor\LanguageServer\Core\Handler\CanRegisterCapabilities; use Phpactor\LanguageServer\Core\Handler\Handler; -class WorkspaceSymbolHandler implements Handler, CanRegisterCapabilities +class WorkspaceSymbolHandler extends AbstractHandler implements Handler, CanRegisterCapabilities { /** * @var WorkspaceSymbolProvider */ private $provider; - public function __construct(WorkspaceSymbolProvider $provider) + public function __construct(WorkspaceSymbolProvider $provider, ClientCapabilities $clientCapabilities) { $this->provider = $provider; + parent::__construct($clientCapabilities); } public function methods(): array @@ -42,6 +45,6 @@ public function symbol( public function registerCapabiltiies(ServerCapabilities $capabilities): void { - $capabilities->workspaceSymbolProvider = true; + $capabilities->workspaceSymbolProvider = null !== ($this->clientCapabilities->workspace['symbol'] ?? null); } } diff --git a/lib/LanguageServerIndexer/LanguageServerIndexerExtension.php b/lib/LanguageServerIndexer/LanguageServerIndexerExtension.php index 7304d183..f623923e 100644 --- a/lib/LanguageServerIndexer/LanguageServerIndexerExtension.php +++ b/lib/LanguageServerIndexer/LanguageServerIndexerExtension.php @@ -6,6 +6,7 @@ use Phpactor\Container\Container; use Phpactor\Container\ContainerBuilder; use Phpactor\Container\Extension; +use Phpactor\Extension\AbstractExtension; use Phpactor\Extension\LanguageServerIndexer\Handler\IndexerHandler; use Phpactor\Extension\LanguageServerIndexer\Handler\WorkspaceSymbolHandler; use Phpactor\Extension\LanguageServerIndexer\Listener\ReindexListener; @@ -23,7 +24,7 @@ use Phpactor\TextDocument\TextDocumentLocator; use Psr\EventDispatcher\EventDispatcherInterface; -class LanguageServerIndexerExtension implements Extension +class LanguageServerIndexerExtension extends AbstractExtension implements Extension { public const WORKSPACE_SYMBOL_SEARCH_LIMIT = 'language_server_indexer.workspace_symbol_search_limit'; @@ -40,7 +41,8 @@ public function load(ContainerBuilder $container): void $container->get(SearchClient::class), $container->get(TextDocumentLocator::class), $container->getParameter(self::WORKSPACE_SYMBOL_SEARCH_LIMIT) - ) + ), + $this->clientCapabilities($container) ); }, [ LanguageServerExtension::TAG_METHOD_HANDLER => [] ]); diff --git a/lib/LanguageServerReferenceFinder/Handler/GotoDefinitionHandler.php b/lib/LanguageServerReferenceFinder/Handler/GotoDefinitionHandler.php index 28107629..81495603 100644 --- a/lib/LanguageServerReferenceFinder/Handler/GotoDefinitionHandler.php +++ b/lib/LanguageServerReferenceFinder/Handler/GotoDefinitionHandler.php @@ -3,7 +3,9 @@ namespace Phpactor\Extension\LanguageServerReferenceFinder\Handler; use Amp\Promise; +use Phpactor\Extension\AbstractHandler; use Phpactor\Extension\LanguageServerBridge\Converter\PositionConverter; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\DefinitionParams; use Phpactor\LanguageServerProtocol\ServerCapabilities; use Phpactor\Extension\LanguageServerBridge\Converter\LocationConverter; @@ -14,7 +16,7 @@ use Phpactor\ReferenceFinder\Exception\CouldNotLocateDefinition; use Phpactor\TextDocument\TextDocumentBuilder; -class GotoDefinitionHandler implements Handler, CanRegisterCapabilities +class GotoDefinitionHandler extends AbstractHandler implements Handler, CanRegisterCapabilities { /** * @var DefinitionLocator @@ -31,11 +33,16 @@ class GotoDefinitionHandler implements Handler, CanRegisterCapabilities */ private $locationConverter; - public function __construct(Workspace $workspace, DefinitionLocator $definitionLocator, LocationConverter $locationConverter) - { + public function __construct( + Workspace $workspace, + DefinitionLocator $definitionLocator, + LocationConverter $locationConverter, + ClientCapabilities $clientCapabilities + ) { $this->definitionLocator = $definitionLocator; $this->workspace = $workspace; $this->locationConverter = $locationConverter; + parent::__construct($clientCapabilities); } public function methods(): array @@ -70,6 +77,6 @@ public function definition( public function registerCapabiltiies(ServerCapabilities $capabilities): void { - $capabilities->definitionProvider = true; + $capabilities->definitionProvider = null !== $this->clientCapabilities->textDocument->definition; } } diff --git a/lib/LanguageServerReferenceFinder/Handler/GotoImplementationHandler.php b/lib/LanguageServerReferenceFinder/Handler/GotoImplementationHandler.php index f0fa10b9..40ee8d87 100644 --- a/lib/LanguageServerReferenceFinder/Handler/GotoImplementationHandler.php +++ b/lib/LanguageServerReferenceFinder/Handler/GotoImplementationHandler.php @@ -3,7 +3,9 @@ namespace Phpactor\Extension\LanguageServerReferenceFinder\Handler; use Amp\Promise; +use Phpactor\Extension\AbstractHandler; use Phpactor\Extension\LanguageServerBridge\Converter\PositionConverter; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\ImplementationParams; use Phpactor\LanguageServerProtocol\ServerCapabilities; use Phpactor\Extension\LanguageServerBridge\Converter\LocationConverter; @@ -13,7 +15,7 @@ use Phpactor\ReferenceFinder\ClassImplementationFinder; use Phpactor\TextDocument\TextDocumentBuilder; -class GotoImplementationHandler implements Handler, CanRegisterCapabilities +class GotoImplementationHandler extends AbstractHandler implements Handler, CanRegisterCapabilities { /** * @var Workspace @@ -30,11 +32,16 @@ class GotoImplementationHandler implements Handler, CanRegisterCapabilities */ private $locationConverter; - public function __construct(Workspace $workspace, ClassImplementationFinder $finder, LocationConverter $locationConverter) - { + public function __construct( + Workspace $workspace, + ClassImplementationFinder $finder, + LocationConverter $locationConverter, + ClientCapabilities $clientCapabilities + ) { $this->workspace = $workspace; $this->finder = $finder; $this->locationConverter = $locationConverter; + parent::__construct($clientCapabilities); } /** @@ -68,6 +75,6 @@ public function gotoImplementation(ImplementationParams $params): Promise public function registerCapabiltiies(ServerCapabilities $capabilities): void { - $capabilities->implementationProvider = true; + $capabilities->implementationProvider = null !== $this->clientCapabilities->textDocument->implementation; } } diff --git a/lib/LanguageServerReferenceFinder/Handler/HighlightHandler.php b/lib/LanguageServerReferenceFinder/Handler/HighlightHandler.php index 78a6d2f6..f7d088fe 100644 --- a/lib/LanguageServerReferenceFinder/Handler/HighlightHandler.php +++ b/lib/LanguageServerReferenceFinder/Handler/HighlightHandler.php @@ -4,8 +4,10 @@ use Amp\Promise; use Amp\Success; +use Phpactor\Extension\AbstractHandler; use Phpactor\Extension\LanguageServerBridge\Converter\PositionConverter; use Phpactor\Extension\LanguageServerReferenceFinder\Model\Highlighter; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\DocumentHighlight; use Phpactor\LanguageServerProtocol\DocumentHighlightOptions; use Phpactor\LanguageServerProtocol\DocumentHighlightParams; @@ -15,7 +17,7 @@ use Phpactor\LanguageServer\Core\Handler\Handler; use Phpactor\LanguageServer\Core\Workspace\Workspace; -class HighlightHandler implements Handler, CanRegisterCapabilities +class HighlightHandler extends AbstractHandler implements Handler, CanRegisterCapabilities { /** * @var Workspace @@ -27,10 +29,11 @@ class HighlightHandler implements Handler, CanRegisterCapabilities */ private $highlighter; - public function __construct(Workspace $workspace, Highlighter $highlighter) + public function __construct(Workspace $workspace, Highlighter $highlighter, ClientCapabilities $clientCapabilities) { $this->workspace = $workspace; $this->highlighter = $highlighter; + parent::__construct($clientCapabilities); } /** @@ -56,6 +59,10 @@ public function highlight(DocumentHighlightParams $params): Promise public function registerCapabiltiies(ServerCapabilities $capabilities): void { + if (null === $this->clientCapabilities->textDocument->documentHighlight) { + return; + } + $options = new DocumentHighlightOptions(); $capabilities->documentHighlightProvider = $options; } diff --git a/lib/LanguageServerReferenceFinder/Handler/ReferencesHandler.php b/lib/LanguageServerReferenceFinder/Handler/ReferencesHandler.php index 7b686560..44cf12c2 100644 --- a/lib/LanguageServerReferenceFinder/Handler/ReferencesHandler.php +++ b/lib/LanguageServerReferenceFinder/Handler/ReferencesHandler.php @@ -4,7 +4,9 @@ use Amp\Delayed; use Amp\Promise; +use Phpactor\Extension\AbstractHandler; use Phpactor\Extension\LanguageServerBridge\Converter\PositionConverter; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\Location as LspLocation; use Phpactor\LanguageServerProtocol\Position; use Phpactor\LanguageServerProtocol\ReferenceContext; @@ -23,7 +25,7 @@ use Phpactor\TextDocument\Locations; use Phpactor\TextDocument\TextDocumentBuilder; -class ReferencesHandler implements Handler, CanRegisterCapabilities +class ReferencesHandler extends AbstractHandler implements Handler, CanRegisterCapabilities { /** * @var Workspace @@ -61,7 +63,8 @@ public function __construct( DefinitionLocator $definitionLocator, LocationConverter $locationConverter, ClientApi $clientApi, - float $timeoutSeconds = 5.0 + float $timeoutSeconds = 5.0, + ClientCapabilities $clientCapabilities ) { $this->workspace = $workspace; $this->finder = $finder; @@ -69,6 +72,7 @@ public function __construct( $this->timeoutSeconds = $timeoutSeconds; $this->locationConverter = $locationConverter; $this->clientApi = $clientApi; + parent::__construct($clientCapabilities); } /** @@ -157,7 +161,7 @@ public function references( public function registerCapabiltiies(ServerCapabilities $capabilities): void { - $capabilities->referencesProvider = true; + $capabilities->referencesProvider = null !== $this->clientCapabilities->textDocument->references; } /** diff --git a/lib/LanguageServerReferenceFinder/Handler/TypeDefinitionHandler.php b/lib/LanguageServerReferenceFinder/Handler/TypeDefinitionHandler.php index 6917ef2b..e6e353b5 100644 --- a/lib/LanguageServerReferenceFinder/Handler/TypeDefinitionHandler.php +++ b/lib/LanguageServerReferenceFinder/Handler/TypeDefinitionHandler.php @@ -3,7 +3,9 @@ namespace Phpactor\Extension\LanguageServerReferenceFinder\Handler; use Amp\Promise; +use Phpactor\Extension\AbstractHandler; use Phpactor\Extension\LanguageServerBridge\Converter\PositionConverter; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\Position; use Phpactor\LanguageServerProtocol\ServerCapabilities; use Phpactor\LanguageServerProtocol\TextDocumentIdentifier; @@ -15,7 +17,7 @@ use Phpactor\ReferenceFinder\TypeLocator; use Phpactor\TextDocument\TextDocumentBuilder; -class TypeDefinitionHandler implements Handler, CanRegisterCapabilities +class TypeDefinitionHandler extends AbstractHandler implements Handler, CanRegisterCapabilities { /** * @var TypeLocator @@ -32,11 +34,16 @@ class TypeDefinitionHandler implements Handler, CanRegisterCapabilities */ private $locationConverter; - public function __construct(Workspace $workspace, TypeLocator $typeLocator, LocationConverter $locationConverter) - { + public function __construct( + Workspace $workspace, + TypeLocator $typeLocator, + LocationConverter $locationConverter, + ClientCapabilities $clientCapabilities + ) { $this->typeLocator = $typeLocator; $this->workspace = $workspace; $this->locationConverter = $locationConverter; + parent::__construct($clientCapabilities); } public function methods(): array @@ -70,6 +77,6 @@ public function type( public function registerCapabiltiies(ServerCapabilities $capabilities): void { - $capabilities->typeDefinitionProvider = true; + $capabilities->typeDefinitionProvider = null !== $this->clientCapabilities->textDocument->typeDefinition; } } diff --git a/lib/LanguageServerReferenceFinder/LanguageServerReferenceFinderExtension.php b/lib/LanguageServerReferenceFinder/LanguageServerReferenceFinderExtension.php index ec33b307..a5d447a9 100644 --- a/lib/LanguageServerReferenceFinder/LanguageServerReferenceFinderExtension.php +++ b/lib/LanguageServerReferenceFinder/LanguageServerReferenceFinderExtension.php @@ -6,6 +6,7 @@ use Phpactor\Container\Container; use Phpactor\Container\ContainerBuilder; use Phpactor\Container\Extension; +use Phpactor\Extension\AbstractExtension; use Phpactor\Extension\LanguageServerBridge\Converter\LocationConverter; use Phpactor\Extension\LanguageServerReferenceFinder\Handler\GotoDefinitionHandler; use Phpactor\Extension\LanguageServerReferenceFinder\Handler\GotoImplementationHandler; @@ -21,7 +22,7 @@ use Phpactor\MapResolver\Resolver; use Phpactor\ReferenceFinder\ReferenceFinder; -class LanguageServerReferenceFinderExtension implements Extension +class LanguageServerReferenceFinderExtension extends AbstractExtension implements Extension { const PARAM_REFERENCE_TIMEOUT = 'language_server_reference_reference_finder.reference_timeout'; @@ -34,7 +35,8 @@ public function load(ContainerBuilder $container): void return new GotoDefinitionHandler( $container->get(LanguageServerExtension::SERVICE_SESSION_WORKSPACE), $container->get(ReferenceFinderExtension::SERVICE_DEFINITION_LOCATOR), - $container->get(LocationConverter::class) + $container->get(LocationConverter::class), + $this->clientCapabilities($container) ); }, [ LanguageServerExtension::TAG_METHOD_HANDLER => [] ]); @@ -42,7 +44,8 @@ public function load(ContainerBuilder $container): void return new TypeDefinitionHandler( $container->get(LanguageServerExtension::SERVICE_SESSION_WORKSPACE), $container->get(ReferenceFinderExtension::SERVICE_TYPE_LOCATOR), - $container->get(LocationConverter::class) + $container->get(LocationConverter::class), + $this->clientCapabilities($container) ); }, [ LanguageServerExtension::TAG_METHOD_HANDLER => [] ]); @@ -61,7 +64,8 @@ public function load(ContainerBuilder $container): void $container->get(ReferenceFinderExtension::SERVICE_DEFINITION_LOCATOR), $container->get(LocationConverter::class), $container->get(ClientApi::class), - $container->getParameter(self::PARAM_REFERENCE_TIMEOUT) + $container->getParameter(self::PARAM_REFERENCE_TIMEOUT), + $this->clientCapabilities($container) ); }, [ LanguageServerExtension::TAG_METHOD_HANDLER => [] ]); @@ -69,14 +73,16 @@ public function load(ContainerBuilder $container): void return new GotoImplementationHandler( $container->get(LanguageServerExtension::SERVICE_SESSION_WORKSPACE), $container->get(ReferenceFinderExtension::SERVICE_IMPLEMENTATION_FINDER), - $container->get(LocationConverter::class) + $container->get(LocationConverter::class), + $this->clientCapabilities($container) ); }, [ LanguageServerExtension::TAG_METHOD_HANDLER => [] ]); $container->register(HighlightHandler::class, function (Container $container) { return new HighlightHandler( $container->get(LanguageServerExtension::SERVICE_SESSION_WORKSPACE), - new Highlighter(new Parser()) + new Highlighter(new Parser()), + $this->clientCapabilities($container) ); }, [ LanguageServerExtension::TAG_METHOD_HANDLER => [] ]); } diff --git a/lib/LanguageServerSymbolProvider/Handler/DocumentSymbolProviderHandler.php b/lib/LanguageServerSymbolProvider/Handler/DocumentSymbolProviderHandler.php index e9a8e1aa..9ec156de 100644 --- a/lib/LanguageServerSymbolProvider/Handler/DocumentSymbolProviderHandler.php +++ b/lib/LanguageServerSymbolProvider/Handler/DocumentSymbolProviderHandler.php @@ -4,7 +4,9 @@ use Amp\Promise; use Amp\Success; +use Phpactor\Extension\AbstractHandler; use Phpactor\Extension\LanguageServerSymbolProvider\Model\DocumentSymbolProvider; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\DocumentSymbolOptions; use Phpactor\LanguageServerProtocol\DocumentSymbolParams; use Phpactor\LanguageServerProtocol\DocumentSymbolRequest; @@ -13,7 +15,7 @@ use Phpactor\LanguageServer\Core\Handler\Handler; use Phpactor\LanguageServer\Core\Workspace\Workspace; -class DocumentSymbolProviderHandler implements Handler, CanRegisterCapabilities +class DocumentSymbolProviderHandler extends AbstractHandler implements Handler, CanRegisterCapabilities { /** * @var Workspace @@ -25,10 +27,14 @@ class DocumentSymbolProviderHandler implements Handler, CanRegisterCapabilities */ private $provider; - public function __construct(Workspace $workspace, DocumentSymbolProvider $provider) - { + public function __construct( + Workspace $workspace, + DocumentSymbolProvider $provider, + ClientCapabilities $clientCapabilities + ) { $this->workspace = $workspace; $this->provider = $provider; + parent::__construct($clientCapabilities); } /** @@ -53,6 +59,10 @@ public function documentSymbols(DocumentSymbolParams $params): Promise public function registerCapabiltiies(ServerCapabilities $capabilities): void { + if (null === $this->clientCapabilities->textDocument->documentSymbol) { + return; + } + $capabilities->documentSymbolProvider = new DocumentSymbolOptions(); } } diff --git a/lib/LanguageServerSymbolProvider/LanguageServerSymbolProviderExtension.php b/lib/LanguageServerSymbolProvider/LanguageServerSymbolProviderExtension.php index c293f537..e6d357f8 100644 --- a/lib/LanguageServerSymbolProvider/LanguageServerSymbolProviderExtension.php +++ b/lib/LanguageServerSymbolProvider/LanguageServerSymbolProviderExtension.php @@ -6,13 +6,14 @@ use Phpactor\Container\Container; use Phpactor\Container\ContainerBuilder; use Phpactor\Container\Extension; +use Phpactor\Extension\AbstractExtension; use Phpactor\Extension\LanguageServerSymbolProvider\Adapter\TolerantDocumentSymbolProvider; use Phpactor\Extension\LanguageServerSymbolProvider\Handler\DocumentSymbolProviderHandler; use Phpactor\Extension\LanguageServerSymbolProvider\Model\DocumentSymbolProvider; use Phpactor\Extension\LanguageServer\LanguageServerExtension; use Phpactor\MapResolver\Resolver; -class LanguageServerSymbolProviderExtension implements Extension +class LanguageServerSymbolProviderExtension extends AbstractExtension implements Extension { /** * {@inheritDoc} @@ -22,7 +23,8 @@ public function load(ContainerBuilder $container): void $container->register(DocumentSymbolProviderHandler::class, function (Container $container) { return new DocumentSymbolProviderHandler( $container->get(LanguageServerExtension::SERVICE_SESSION_WORKSPACE), - $container->get(DocumentSymbolProvider::class) + $container->get(DocumentSymbolProvider::class), + $this->clientCapabilities($container) ); }, [ LanguageServerExtension::TAG_METHOD_HANDLER => [], diff --git a/tests/LanguageServerCompletion/Unit/Handler/CompletionHandlerTest.php b/tests/LanguageServerCompletion/Unit/Handler/CompletionHandlerTest.php index 2880503b..82b23954 100644 --- a/tests/LanguageServerCompletion/Unit/Handler/CompletionHandlerTest.php +++ b/tests/LanguageServerCompletion/Unit/Handler/CompletionHandlerTest.php @@ -8,10 +8,15 @@ use Phpactor\CodeTransform\Domain\Refactor\ImportClass\NameImport; use Phpactor\Extension\LanguageServerCodeTransform\Model\NameImport\NameImporter; use Phpactor\Extension\LanguageServerCodeTransform\Model\NameImport\NameImporterResult; +use Phpactor\LanguageServerProtocol\ClientCapabilities; +use Phpactor\LanguageServerProtocol\CompletionClientCapabilities; use Phpactor\LanguageServerProtocol\CompletionItem; use Phpactor\LanguageServerProtocol\CompletionList; +use Phpactor\LanguageServerProtocol\CompletionOptions; use Phpactor\LanguageServerProtocol\Position; use Phpactor\LanguageServerProtocol\Range; +use Phpactor\LanguageServerProtocol\ServerCapabilities; +use Phpactor\LanguageServerProtocol\TextDocumentClientCapabilities; use Phpactor\LanguageServerProtocol\TextEdit; use PHPUnit\Framework\TestCase; use Phpactor\Completion\Core\Completor; @@ -46,6 +51,42 @@ public function testHandleNoSuggestions(): void $this->assertFalse($response->result->isIncomplete); } + public function testDisbledCompletion(): void + { + $handler = $this->createHandler( + LanguageServerTesterBuilder::create(), + [], + false, + false, + [], + [], + false + ); + + $serverCapabilities = new ServerCapabilities(); + $handler->registerCapabiltiies($serverCapabilities); + + $this->assertNull($serverCapabilities->completionProvider); + } + + public function testEnabledCompletion(): void + { + $handler = $this->createHandler( + LanguageServerTesterBuilder::create(), + [], + false, + false, + [], + [], + true + ); + + $serverCapabilities = new ServerCapabilities(); + $handler->registerCapabiltiies($serverCapabilities); + + $this->assertInstanceOf(CompletionOptions::class, $serverCapabilities->completionProvider); + } + public function testHandleACompleteListOfSuggestions(): void { $tester = $this->create([ @@ -377,24 +418,67 @@ private function create( bool $supportSnippets = true, bool $isIncomplete = false, array $importNameTextEdits = [], - array $aliases = [] + array $aliases = [], + bool $supportCompletion = true ): LanguageServerTester { + $builder = LanguageServerTesterBuilder::create(); + $tester = $builder->addHandler($this->createHandler( + $builder, + $suggestions, + $supportSnippets, + $isIncomplete, + $importNameTextEdits, + $aliases, + $supportCompletion + ))->build(); + $tester->textDocument()->open(self::EXAMPLE_URI, self::EXAMPLE_TEXT); + + return $tester; + } + + private function createHandler( + LanguageServerTesterBuilder $builder, + array $suggestions, + bool $supportSnippets = true, + bool $isIncomplete = false, + array $importNameTextEdits = [], + array $aliases = [], + bool $supportCompletion = true + ): CompletionHandler { $completor = $this->createCompletor($suggestions, $isIncomplete); $registry = new TypedCompletorRegistry([ 'php' => $completor, ]); - $builder = LanguageServerTesterBuilder::create(); - $tester = $builder->addHandler(new CompletionHandler( + return new CompletionHandler( $builder->workspace(), $registry, new SuggestionNameFormatter(true), $this->createNameImporter($suggestions, $aliases, $importNameTextEdits), - $supportSnippets, + $this->createClientCapabilities($supportCompletion, $supportSnippets), true - ))->build(); - $tester->textDocument()->open(self::EXAMPLE_URI, self::EXAMPLE_TEXT); + ); + } - return $tester; + private function createClientCapabilities( + bool $completion = true, + bool $supportSnippets = true + ): ClientCapabilities { + $capabilities = new ClientCapabilities(); + $capabilities->textDocument = new TextDocumentClientCapabilities(); + + if (false === $completion) { + return $capabilities; + } + + $completionCapabilities = new CompletionClientCapabilities(); + + if ($supportSnippets) { + $completionCapabilities->completionItem['snippetSupport'] = true; + } + + $capabilities->textDocument->completion = $completionCapabilities; + + return $capabilities; } /** diff --git a/tests/LanguageServerCompletion/Unit/Handler/SignatureHelpHandlerTest.php b/tests/LanguageServerCompletion/Unit/Handler/SignatureHelpHandlerTest.php index c2430223..9edc486d 100644 --- a/tests/LanguageServerCompletion/Unit/Handler/SignatureHelpHandlerTest.php +++ b/tests/LanguageServerCompletion/Unit/Handler/SignatureHelpHandlerTest.php @@ -2,7 +2,10 @@ namespace Phpactor\Extension\LanguageServerCompletion\Tests\Unit\Handler; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\SignatureHelp as LspSignatureHelp; +use Phpactor\LanguageServerProtocol\SignatureHelpClientCapabilities; +use Phpactor\LanguageServerProtocol\TextDocumentClientCapabilities; use Phpactor\LanguageServerProtocol\TextDocumentIdentifier; use PHPUnit\Framework\TestCase; use Phpactor\Completion\Core\SignatureHelp; @@ -38,10 +41,27 @@ private function create(array $suggestions): LanguageServerTester $builder = LanguageServerTesterBuilder::create(); return $builder->addHandler(new SignatureHelpHandler( $builder->workspace(), - $this->createHelper() + $this->createHelper(), + $this->createClientCapabilities(true) ))->build(); } + private function createClientCapabilities( + bool $supportSignatureHelp = true + ): ClientCapabilities { + $capabilities = new ClientCapabilities(); + $capabilities->textDocument = new TextDocumentClientCapabilities(); + + if (false === $supportSignatureHelp) { + return $capabilities; + } + + $signatureHelpCapabilities = new SignatureHelpClientCapabilities(); + $capabilities->textDocument->signatureHelp = $signatureHelpCapabilities; + + return $capabilities; + } + private function createHelper(): SignatureHelper { return new class() implements SignatureHelper { diff --git a/tests/LanguageServerReferenceFinder/Unit/Handler/GotoDefinitionHandlerTest.php b/tests/LanguageServerReferenceFinder/Unit/Handler/GotoDefinitionHandlerTest.php index fd3b7d47..ce2b2942 100644 --- a/tests/LanguageServerReferenceFinder/Unit/Handler/GotoDefinitionHandlerTest.php +++ b/tests/LanguageServerReferenceFinder/Unit/Handler/GotoDefinitionHandlerTest.php @@ -3,6 +3,7 @@ namespace Phpactor\Extension\LanguageServerReferenceFinder\Tests\Unit\Handler; use Phpactor\Extension\LanguageServerBridge\TextDocument\WorkspaceTextDocumentLocator; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\DefinitionRequest; use Phpactor\LanguageServerProtocol\Location; use Phpactor\Extension\LanguageServerBridge\Converter\LocationConverter; @@ -30,7 +31,8 @@ public function testGoesToDefinition(): void TestDefinitionLocator::fromLocation( new DefinitionLocation($document->uri(), ByteOffset::fromInt(2)) ), - new LocationConverter(new WorkspaceTextDocumentLocator($builder->workspace())) + new LocationConverter(new WorkspaceTextDocumentLocator($builder->workspace())), + ClientCapabilities::fromArray(['textDocument' => ['definition' => []]]) ))->build(); $tester->textDocument()->open(self::EXAMPLE_URI, self::EXAMPLE_TEXT); diff --git a/tests/LanguageServerReferenceFinder/Unit/Handler/GotoImplementationHandlerTest.php b/tests/LanguageServerReferenceFinder/Unit/Handler/GotoImplementationHandlerTest.php index 117a7dfd..fea408df 100644 --- a/tests/LanguageServerReferenceFinder/Unit/Handler/GotoImplementationHandlerTest.php +++ b/tests/LanguageServerReferenceFinder/Unit/Handler/GotoImplementationHandlerTest.php @@ -3,6 +3,7 @@ namespace Phpactor\Extension\LanguageServerReferenceFinder\Tests\Unit\Handler; use Phpactor\Extension\LanguageServerBridge\TextDocument\WorkspaceTextDocumentLocator; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\Location as LspLocation; use Phpactor\Extension\LanguageServerBridge\Converter\LocationConverter; use Phpactor\Extension\LanguageServerReferenceFinder\Handler\GotoImplementationHandler; @@ -50,7 +51,8 @@ public function testGoesToImplementation(): void $tester = $builder->addHandler(new GotoImplementationHandler( $builder->workspace(), $this->finder->reveal(), - new LocationConverter(new WorkspaceTextDocumentLocator($builder->workspace())) + new LocationConverter(new WorkspaceTextDocumentLocator($builder->workspace())), + ClientCapabilities::fromArray(['textDocument' => ['implementation' => []]]) ))->build(); $tester->textDocument()->open(self::EXAMPLE_URI, self::EXAMPLE_TEXT); diff --git a/tests/LanguageServerReferenceFinder/Unit/Handler/ReferencesHandlerTest.php b/tests/LanguageServerReferenceFinder/Unit/Handler/ReferencesHandlerTest.php index a02b289c..8fc641bc 100644 --- a/tests/LanguageServerReferenceFinder/Unit/Handler/ReferencesHandlerTest.php +++ b/tests/LanguageServerReferenceFinder/Unit/Handler/ReferencesHandlerTest.php @@ -3,6 +3,7 @@ namespace Phpactor\Extension\LanguageServerReferenceFinder\Tests\Unit\Handler; use Phpactor\Extension\LanguageServerBridge\TextDocument\WorkspaceTextDocumentLocator; +use Phpactor\LanguageServerProtocol\ClientCapabilities; use Phpactor\LanguageServerProtocol\Location as LspLocation; use Phpactor\LanguageServerProtocol\Position; use Phpactor\LanguageServerProtocol\Range; @@ -172,7 +173,9 @@ private function createTester(): LanguageServerTester $this->finder->reveal(), $this->locator->reveal(), new LocationConverter(new WorkspaceTextDocumentLocator($builder->workspace())), - new ClientApi(TestRpcClient::create()) + new ClientApi(TestRpcClient::create()), + 5.0, + ClientCapabilities::fromArray(['textDocument' => ['references' => []]]) ) ); $tester = $builder->build();