1
0
Fork 0
pull/32/merge
Michal Niewrzal 2016-09-23 16:56:45 +00:00 committed by GitHub
commit feca4c5285
6 changed files with 209 additions and 16 deletions

View File

@ -27,7 +27,8 @@
"nikic/php-parser": "^3.0.0beta1", "nikic/php-parser": "^3.0.0beta1",
"phpdocumentor/reflection-docblock": "^3.0", "phpdocumentor/reflection-docblock": "^3.0",
"sabre/event": "^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", "minimum-stability": "dev",
"prefer-stable": true, "prefer-stable": true,

View File

@ -9,7 +9,11 @@ class TestClass
{ {
public $testProperty; public $testProperty;
/**
* @param $testParameter description
*/
public function testMethod( $testParameter) public function testMethod( $testParameter)
{ {
$testVariable = 123; $testVariable = 123;

View File

@ -5,9 +5,14 @@ namespace TestNamespace;
class TestClass class TestClass
{ {
public $testProperty; public $testProperty;
/**
* @param $testParameter description
*/
public function testMethod($testParameter) public function testMethod($testParameter)
{ {
$testVariable = 123; $testVariable = 123;
if (empty($testParameter)) { if (empty($testParameter)) {
echo 'Empty'; echo 'Empty';
} }

View File

@ -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;
}
}

59
src/Server/Formatter.php Normal file
View File

@ -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];
}
}

View File

@ -42,6 +42,13 @@ class TextDocument
*/ */
private $client; private $client;
/**
* Opened source files content
*
* @var string[]
*/
private $documents = [];
public function __construct(LanguageClient $client) public function __construct(LanguageClient $client)
{ {
$this->client = $client; $this->client = $client;
@ -103,6 +110,8 @@ class TextDocument
*/ */
private function updateAst(string $uri, string $content) private function updateAst(string $uri, string $content)
{ {
$this->documents[$uri] = $content;
$stmts = $this->parser->parse($content); $stmts = $this->parser->parse($content);
$diagnostics = []; $diagnostics = [];
foreach ($this->parser->getErrors() as $error) { 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. * 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 TextDocumentIdentifier $textDocument The document to format
* @param FormattingOptions $options The format options * @param FormattingOptions $options The format options
*
* @return TextEdit[] * @return TextEdit[]
*/ */
public function formatting(TextDocumentIdentifier $textDocument, FormattingOptions $options) public function formatting(TextDocumentIdentifier $textDocument, FormattingOptions $options)
{ {
$nodes = $this->asts[$textDocument->uri]; $formatter = new Formatter();
if (empty($nodes)) { $content = $this->documents[$textDocument->uri];
if (!$content) {
return []; 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);
}
} }