Merge 11516fb497
into 41e9fb7e8a
commit
feca4c5285
|
@ -27,7 +27,8 @@
|
|||
"nikic/php-parser": "^3.0.0beta1",
|
||||
"phpdocumentor/reflection-docblock": "^3.0",
|
||||
"sabre/event": "^3.0",
|
||||
"felixfbecker/advanced-json-rpc": "^1.2"
|
||||
"felixfbecker/advanced-json-rpc": "^1.2",
|
||||
"friendsofphp/php-cs-fixer" : "^1.12"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
|
|
|
@ -9,7 +9,11 @@ class TestClass
|
|||
{
|
||||
public $testProperty;
|
||||
|
||||
/**
|
||||
* @param $testParameter description
|
||||
*/
|
||||
public function testMethod( $testParameter)
|
||||
|
||||
{
|
||||
$testVariable = 123;
|
||||
|
||||
|
|
|
@ -5,9 +5,14 @@ namespace TestNamespace;
|
|||
class TestClass
|
||||
{
|
||||
public $testProperty;
|
||||
|
||||
/**
|
||||
* @param $testParameter description
|
||||
*/
|
||||
public function testMethod($testParameter)
|
||||
{
|
||||
$testVariable = 123;
|
||||
|
||||
if (empty($testParameter)) {
|
||||
echo 'Empty';
|
||||
}
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
namespace LanguageServer\Server;
|
||||
|
||||
use Symfony\CS\ConfigAwareInterface;
|
||||
use Symfony\CS\ConfigInterface;
|
||||
use Symfony\CS\Fixer;
|
||||
use Symfony\CS\FixerInterface;
|
||||
use Symfony\CS\Tokenizer\Tokens;
|
||||
use Symfony\CS\Utils;
|
||||
|
||||
class CustomCSFixer extends Fixer
|
||||
{
|
||||
/**
|
||||
* @param string $content
|
||||
* @param string $uri
|
||||
* @param ConfigInterface $config
|
||||
*
|
||||
* @return string|null formated source code or null if no change was made
|
||||
*/
|
||||
public function fixContent(string $content, string $uri, ConfigInterface $config)
|
||||
{
|
||||
$fixers = $this->prepareFixers($config);
|
||||
$fixers = $this->sortFixers($fixers);
|
||||
|
||||
return $this->doFixContent($content, $uri, $fixers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $content
|
||||
* @param string $uri
|
||||
* @param array $fixers
|
||||
*
|
||||
* @return string|null formated source code or null if no change was made
|
||||
*/
|
||||
private function doFixContent(string $content, string $uri, array $fixers)
|
||||
{
|
||||
$new = $old = $content;
|
||||
|
||||
if ('' === $old ||
|
||||
// PHP 5.3 has a broken implementation of token_get_all when the file uses __halt_compiler() starting in 5.3.6
|
||||
(PHP_VERSION_ID >= 50306 && PHP_VERSION_ID < 50400 && false !== stripos($old, '__halt_compiler()'))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// we do not need Tokens to still caching previously fixed file - so clear the cache
|
||||
Tokens::clearCache();
|
||||
|
||||
try {
|
||||
$file = new \SplFileInfo($uri);
|
||||
foreach ($fixers as $fixer) {
|
||||
if (!$fixer->supports($file)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newest = $fixer->fix($file, $new);
|
||||
$new = $newest;
|
||||
}
|
||||
} catch (\ParseError $e) {
|
||||
return null;
|
||||
} catch (\Error $e) {
|
||||
return null;
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($new !== $old) {
|
||||
return $new;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FixerInterface[] $fixers
|
||||
*
|
||||
* @return FixerInterface[]
|
||||
*/
|
||||
private function sortFixers(array $fixers)
|
||||
{
|
||||
usort($fixers, function (FixerInterface $a, FixerInterface $b) {
|
||||
return Utils::cmpInt($b->getPriority(), $a->getPriority());
|
||||
});
|
||||
|
||||
return $fixers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ConfigInterface $config
|
||||
*
|
||||
* @return FixerInterface[]
|
||||
*/
|
||||
private function prepareFixers(ConfigInterface $config)
|
||||
{
|
||||
$fixers = $config->getFixers();
|
||||
|
||||
foreach ($fixers as $fixer) {
|
||||
if ($fixer instanceof ConfigAwareInterface) {
|
||||
$fixer->setConfig($config);
|
||||
}
|
||||
}
|
||||
|
||||
return $fixers;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace LanguageServer\Server;
|
||||
|
||||
use Symfony\CS\Config;
|
||||
use Symfony\CS\ConfigurationResolver;
|
||||
use LanguageServer\Protocol\TextEdit;
|
||||
use LanguageServer\Protocol\Range;
|
||||
use LanguageServer\Protocol\Position;
|
||||
|
||||
class Formatter
|
||||
{
|
||||
/**
|
||||
* @var CustomCSFixer
|
||||
*/
|
||||
private $fixer;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->fixer = new CustomCSFixer();
|
||||
$this->fixer->registerBuiltInFixers();
|
||||
$this->fixer->registerBuiltInConfigs();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $content
|
||||
*
|
||||
* @return TextEdit[]
|
||||
*/
|
||||
public function format(string $content, string $uri)
|
||||
{
|
||||
// remove 'file://' prefix
|
||||
$uri = substr($uri, 7);
|
||||
|
||||
$config = new Config();
|
||||
|
||||
// TODO read user configuration from workspace root (.php_cs file)
|
||||
|
||||
// register custom fixers from config
|
||||
$this->fixer->registerCustomFixers($config->getCustomFixers());
|
||||
|
||||
$resolver = new ConfigurationResolver();
|
||||
$resolver->setAllFixers($this->fixer->getFixers())
|
||||
->setConfig($config)
|
||||
//->setOptions(array('level' => 'psr2'))
|
||||
->resolve();
|
||||
|
||||
$config->fixers($resolver->getFixers());
|
||||
$formatted = $this->fixer->fixContent($content, $uri, $config);
|
||||
if ($formatted == null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$edit = new TextEdit();
|
||||
$edit->range = new Range(new Position(0, 0), new Position(PHP_INT_MAX, PHP_INT_MAX));
|
||||
$edit->newText = $formatted;
|
||||
return [$edit];
|
||||
}
|
||||
}
|
|
@ -42,6 +42,13 @@ class TextDocument
|
|||
*/
|
||||
private $client;
|
||||
|
||||
/**
|
||||
* Opened source files content
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $documents = [];
|
||||
|
||||
public function __construct(LanguageClient $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
|
@ -103,6 +110,8 @@ class TextDocument
|
|||
*/
|
||||
private function updateAst(string $uri, string $content)
|
||||
{
|
||||
$this->documents[$uri] = $content;
|
||||
|
||||
$stmts = $this->parser->parse($content);
|
||||
$diagnostics = [];
|
||||
foreach ($this->parser->getErrors() as $error) {
|
||||
|
@ -128,24 +137,34 @@ class TextDocument
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The document close notification is sent from the client to the server when
|
||||
* the document got closed in the client. The document's truth now exists where the document's
|
||||
* uri points to (e.g. if the document's uri is a file uri the truth now exists on disk).
|
||||
*
|
||||
* @param TextDocumentIdentifier $textDocument
|
||||
*/
|
||||
public function didClose(TextDocumentIdentifier $textDocument)
|
||||
{
|
||||
unset($this->documents[$textDocument->uri]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)) {
|
||||
$formatter = new Formatter();
|
||||
$content = $this->documents[$textDocument->uri];
|
||||
if (!$content) {
|
||||
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];
|
||||
}
|
||||
|
||||
return $formatter->format($content, $textDocument->uri);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue