1
0
Fork 0

refactor: use composer/xdebug-handler (#616)

pull/599/head^2
Felix Becker 2018-03-08 11:48:56 -08:00 committed by GitHub
parent e10896f905
commit de1af6a165
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 17 deletions

View File

@ -211,6 +211,6 @@ The project parses PHPStorm's PHP stubs to get support for PHP builtins. It re-p
To debug with xDebug ensure that you have this set as an environment variable To debug with xDebug ensure that you have this set as an environment variable
COMPOSER_ALLOW_XDEBUG=1 PHPLS_ALLOW_XDEBUG=1
This tells the Language Server to not restart without XDebug if it detects that XDebug is enabled (XDebug has a high performance impact). This tells the Language Server to not restart without XDebug if it detects that XDebug is enabled (XDebug has a high performance impact).

View File

@ -1,8 +1,8 @@
<?php <?php
use LanguageServer\{LanguageServer, ProtocolStreamReader, ProtocolStreamWriter}; use LanguageServer\{LanguageServer, ProtocolStreamReader, ProtocolStreamWriter, StderrLogger};
use Sabre\Event\Loop; use Sabre\Event\Loop;
use Composer\{Factory, XdebugHandler}; use Composer\XdebugHandler\XdebugHandler;
$options = getopt('', ['tcp::', 'tcp-server::', 'memory-limit::']); $options = getopt('', ['tcp::', 'tcp-server::', 'memory-limit::']);
@ -24,22 +24,27 @@ set_error_handler(function (int $severity, string $message, string $file, int $l
throw new \ErrorException($message, 0, $severity, $file, $line); throw new \ErrorException($message, 0, $severity, $file, $line);
}); });
$logger = new StderrLogger();
// Only write uncaught exceptions to STDERR, not STDOUT // Only write uncaught exceptions to STDERR, not STDOUT
set_exception_handler(function (\Throwable $e) { set_exception_handler(function (\Throwable $e) use ($logger) {
fwrite(STDERR, (string)$e); $logger->critical((string)$e);
}); });
@cli_set_process_title('PHP Language Server'); @cli_set_process_title('PHP Language Server');
// If XDebug is enabled, restart without it // If XDebug is enabled, restart without it
(new XdebugHandler(Factory::createOutput()))->check(); $xdebugHandler = new XdebugHandler('PHPLS');
$xdebugHandler->setLogger($logger);
$xdebugHandler->check();
unset($xdebugHandler);
if (!empty($options['tcp'])) { if (!empty($options['tcp'])) {
// Connect to a TCP server // Connect to a TCP server
$address = $options['tcp']; $address = $options['tcp'];
$socket = stream_socket_client('tcp://' . $address, $errno, $errstr); $socket = stream_socket_client('tcp://' . $address, $errno, $errstr);
if ($socket === false) { if ($socket === false) {
fwrite(STDERR, "Could not connect to language client. Error $errno\n$errstr"); $logger->critical("Could not connect to language client. Error $errno\n$errstr");
exit(1); exit(1);
} }
stream_set_blocking($socket, false); stream_set_blocking($socket, false);
@ -53,29 +58,30 @@ if (!empty($options['tcp'])) {
$address = $options['tcp-server']; $address = $options['tcp-server'];
$tcpServer = stream_socket_server('tcp://' . $address, $errno, $errstr); $tcpServer = stream_socket_server('tcp://' . $address, $errno, $errstr);
if ($tcpServer === false) { if ($tcpServer === false) {
fwrite(STDERR, "Could not listen on $address. Error $errno\n$errstr"); $logger->critical("Could not listen on $address. Error $errno\n$errstr");
exit(1); exit(1);
} }
fwrite(STDOUT, "Server listening on $address\n"); $logger->debug("Server listening on $address");
if (!extension_loaded('pcntl')) { $pcntlAvailable = extension_loaded('pcntl');
fwrite(STDERR, "PCNTL is not available. Only a single connection will be accepted\n"); if (!$pcntlAvailable) {
$logger->notice('PCNTL is not available. Only a single connection will be accepted');
} }
while ($socket = stream_socket_accept($tcpServer, -1)) { while ($socket = stream_socket_accept($tcpServer, -1)) {
fwrite(STDOUT, "Connection accepted\n"); $logger->debug('Connection accepted');
stream_set_blocking($socket, false); stream_set_blocking($socket, false);
if (extension_loaded('pcntl')) { if ($pcntlAvailable) {
// If PCNTL is available, fork a child process for the connection // If PCNTL is available, fork a child process for the connection
// An exit notification will only terminate the child process // An exit notification will only terminate the child process
$pid = pcntl_fork(); $pid = pcntl_fork();
if ($pid === -1) { if ($pid === -1) {
fwrite(STDERR, "Could not fork\n"); $logger->critical('Could not fork');
exit(1); exit(1);
} else if ($pid === 0) { } else if ($pid === 0) {
// Child process // Child process
$reader = new ProtocolStreamReader($socket); $reader = new ProtocolStreamReader($socket);
$writer = new ProtocolStreamWriter($socket); $writer = new ProtocolStreamWriter($socket);
$reader->on('close', function () { $reader->on('close', function () use ($logger) {
fwrite(STDOUT, "Connection closed\n"); $logger->debug('Connection closed');
}); });
$ls = new LanguageServer($reader, $writer); $ls = new LanguageServer($reader, $writer);
Loop\run(); Loop\run();
@ -94,6 +100,7 @@ if (!empty($options['tcp'])) {
} }
} else { } else {
// Use STDIO // Use STDIO
$logger->debug('Listening on STDIN');
stream_set_blocking(STDIN, false); stream_set_blocking(STDIN, false);
$ls = new LanguageServer( $ls = new LanguageServer(
new ProtocolStreamReader(STDIN), new ProtocolStreamReader(STDIN),

View File

@ -22,12 +22,13 @@
], ],
"require": { "require": {
"php": "^7.0", "php": "^7.0",
"composer/composer": "^1.3", "composer/xdebug-handler": "^1.0",
"felixfbecker/advanced-json-rpc": "^3.0.0", "felixfbecker/advanced-json-rpc": "^3.0.0",
"jetbrains/phpstorm-stubs": "dev-master", "jetbrains/phpstorm-stubs": "dev-master",
"microsoft/tolerant-php-parser": "0.0.*", "microsoft/tolerant-php-parser": "0.0.*",
"netresearch/jsonmapper": "^1.0", "netresearch/jsonmapper": "^1.0",
"phpdocumentor/reflection-docblock": "^4.0.0", "phpdocumentor/reflection-docblock": "^4.0.0",
"psr/log": "^1.0",
"sabre/event": "^5.0", "sabre/event": "^5.0",
"sabre/uri": "^2.0", "sabre/uri": "^2.0",
"webmozart/glob": "^4.1", "webmozart/glob": "^4.1",

25
src/StderrLogger.php Normal file
View File

@ -0,0 +1,25 @@
<?php
declare(strict_types = 1);
namespace LanguageServer;
/**
* Simple Logger that logs to STDERR
*/
class StderrLogger extends \Psr\Log\AbstractLogger implements \Psr\Log\LoggerInterface
{
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
*
* @return void
*/
public function log($level, $message, array $context = array())
{
$contextStr = empty($context) ? '' : ' ' . \json_encode($context, \JSON_UNESCAPED_SLASHES);
\fwrite(\STDERR, \str_pad(\strtoupper((string)$level), 10) . $message . $contextStr . \PHP_EOL);
}
}