diff --git a/fixtures/format.php b/fixtures/format.php new file mode 100644 index 00000000..b45ebab8 --- /dev/null +++ b/fixtures/format.php @@ -0,0 +1,20 @@ +textDocumentSync = TextDocumentSyncKind::FULL; // Support "Find all symbols" $serverCapabilities->documentSymbolProvider = true; + // Support "Format Code" + $serverCapabilities->documentFormattingProvider = true; return new InitializeResult($serverCapabilities); } diff --git a/src/Server/TextDocument.php b/src/Server/TextDocument.php index f3fd6bb7..23c01c02 100644 --- a/src/Server/TextDocument.php +++ b/src/Server/TextDocument.php @@ -3,6 +3,7 @@ namespace LanguageServer\Server; use PhpParser\{Error, Comment, Node, ParserFactory, NodeTraverser, Lexer}; +use PhpParser\PrettyPrinter\Standard as PrettyPrinter; use PhpParser\NodeVisitor\NameResolver; use LanguageServer\{LanguageClient, ColumnCalculator, SymbolFinder}; use LanguageServer\Protocol\{ @@ -12,7 +13,9 @@ Diagnostic, DiagnosticSeverity, Range, - Position + Position, + FormattingOptions, + TextEdit }; /** @@ -124,4 +127,25 @@ private function updateAst(string $uri, string $content) $this->asts[$uri] = $stmts; } } + + /** + * The document formatting request is sent from the server to the client to format a whole document. + * + * @param TextDocumentIdentifier $textDocument The document to format + * @param FormattingOptions $options The format options + * @return TextEdit[] + */ + public function formatting(TextDocumentIdentifier $textDocument, FormattingOptions $options) + { + $nodes = $this->asts[$textDocument->uri]; + if (empty($nodes)) { + return []; + } + $prettyPrinter = new PrettyPrinter(); + $edit = new TextEdit(); + $edit->range = new Range(new Position(0, 0), new Position(PHP_INT_MAX, PHP_INT_MAX)); + $edit->newText = $prettyPrinter->prettyPrintFile($nodes); + return [$edit]; + } + } diff --git a/tests/LanguageServerTest.php b/tests/LanguageServerTest.php index 4c1ca825..fbba7b54 100644 --- a/tests/LanguageServerTest.php +++ b/tests/LanguageServerTest.php @@ -40,7 +40,7 @@ public function testInitialize() 'workspaceSymbolProvider' => null, 'codeActionProvider' => null, 'codeLensProvider' => null, - 'documentFormattingProvider' => null, + 'documentFormattingProvider' => true, 'documentRangeFormattingProvider' => null, 'documentOnTypeFormattingProvider' => null, 'renameProvider' => null diff --git a/tests/Server/TextDocumentTest.php b/tests/Server/TextDocumentTest.php index 4f795d47..5cbe470a 100644 --- a/tests/Server/TextDocumentTest.php +++ b/tests/Server/TextDocumentTest.php @@ -6,7 +6,7 @@ use PHPUnit\Framework\TestCase; use LanguageServer\Tests\MockProtocolStream; use LanguageServer\{Server, Client, LanguageClient}; -use LanguageServer\Protocol\{TextDocumentItem, TextDocumentIdentifier, SymbolKind, DiagnosticSeverity}; +use LanguageServer\Protocol\{TextDocumentItem, TextDocumentIdentifier, SymbolKind, DiagnosticSeverity, FormattingOptions}; use AdvancedJsonRpc\{Request as RequestBody, Response as ResponseBody}; class TextDocumentTest extends TestCase @@ -197,4 +197,34 @@ public function publishDiagnostics(string $uri, array $diagnostics) ]] ], json_decode(json_encode($args), true)); } + + public function testFormatting() + { + $textDocument = new Server\TextDocument(new LanguageClient(new MockProtocolStream())); + // Trigger parsing of source + $textDocumentItem = new TextDocumentItem(); + $textDocumentItem->uri = 'whatever'; + $textDocumentItem->languageId = 'php'; + $textDocumentItem->version = 1; + $textDocumentItem->text = file_get_contents(__DIR__ . '/../../fixtures/format.php'); + $textDocument->didOpen($textDocumentItem); + + // how code should look after formatting + $expected = file_get_contents(__DIR__ . '/../../fixtures/format_expected.php'); + // Request formatting + $result = $textDocument->formatting(new TextDocumentIdentifier('whatever'), new FormattingOptions()); + $this->assertEquals([0 => [ + 'range' => [ + 'start' => [ + 'line' => 0, + 'character' => 0 + ], + 'end' => [ + 'line' => PHP_INT_MAX, + 'character' => PHP_INT_MAX + ] + ], + 'newText' => $expected + ]], json_decode(json_encode($result), true)); + } }