refactor: use composer/xdebug-handler (#616)
parent
e10896f905
commit
de1af6a165
|
@ -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
|
||||
|
||||
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).
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
use LanguageServer\{LanguageServer, ProtocolStreamReader, ProtocolStreamWriter};
|
||||
use LanguageServer\{LanguageServer, ProtocolStreamReader, ProtocolStreamWriter, StderrLogger};
|
||||
use Sabre\Event\Loop;
|
||||
use Composer\{Factory, XdebugHandler};
|
||||
use Composer\XdebugHandler\XdebugHandler;
|
||||
|
||||
$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);
|
||||
});
|
||||
|
||||
$logger = new StderrLogger();
|
||||
|
||||
// Only write uncaught exceptions to STDERR, not STDOUT
|
||||
set_exception_handler(function (\Throwable $e) {
|
||||
fwrite(STDERR, (string)$e);
|
||||
set_exception_handler(function (\Throwable $e) use ($logger) {
|
||||
$logger->critical((string)$e);
|
||||
});
|
||||
|
||||
@cli_set_process_title('PHP Language Server');
|
||||
|
||||
// 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'])) {
|
||||
// Connect to a TCP server
|
||||
$address = $options['tcp'];
|
||||
$socket = stream_socket_client('tcp://' . $address, $errno, $errstr);
|
||||
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);
|
||||
}
|
||||
stream_set_blocking($socket, false);
|
||||
|
@ -53,29 +58,30 @@ if (!empty($options['tcp'])) {
|
|||
$address = $options['tcp-server'];
|
||||
$tcpServer = stream_socket_server('tcp://' . $address, $errno, $errstr);
|
||||
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);
|
||||
}
|
||||
fwrite(STDOUT, "Server listening on $address\n");
|
||||
if (!extension_loaded('pcntl')) {
|
||||
fwrite(STDERR, "PCNTL is not available. Only a single connection will be accepted\n");
|
||||
$logger->debug("Server listening on $address");
|
||||
$pcntlAvailable = extension_loaded('pcntl');
|
||||
if (!$pcntlAvailable) {
|
||||
$logger->notice('PCNTL is not available. Only a single connection will be accepted');
|
||||
}
|
||||
while ($socket = stream_socket_accept($tcpServer, -1)) {
|
||||
fwrite(STDOUT, "Connection accepted\n");
|
||||
$logger->debug('Connection accepted');
|
||||
stream_set_blocking($socket, false);
|
||||
if (extension_loaded('pcntl')) {
|
||||
if ($pcntlAvailable) {
|
||||
// If PCNTL is available, fork a child process for the connection
|
||||
// An exit notification will only terminate the child process
|
||||
$pid = pcntl_fork();
|
||||
if ($pid === -1) {
|
||||
fwrite(STDERR, "Could not fork\n");
|
||||
$logger->critical('Could not fork');
|
||||
exit(1);
|
||||
} else if ($pid === 0) {
|
||||
// Child process
|
||||
$reader = new ProtocolStreamReader($socket);
|
||||
$writer = new ProtocolStreamWriter($socket);
|
||||
$reader->on('close', function () {
|
||||
fwrite(STDOUT, "Connection closed\n");
|
||||
$reader->on('close', function () use ($logger) {
|
||||
$logger->debug('Connection closed');
|
||||
});
|
||||
$ls = new LanguageServer($reader, $writer);
|
||||
Loop\run();
|
||||
|
@ -94,6 +100,7 @@ if (!empty($options['tcp'])) {
|
|||
}
|
||||
} else {
|
||||
// Use STDIO
|
||||
$logger->debug('Listening on STDIN');
|
||||
stream_set_blocking(STDIN, false);
|
||||
$ls = new LanguageServer(
|
||||
new ProtocolStreamReader(STDIN),
|
||||
|
|
|
@ -22,12 +22,13 @@
|
|||
],
|
||||
"require": {
|
||||
"php": "^7.0",
|
||||
"composer/composer": "^1.3",
|
||||
"composer/xdebug-handler": "^1.0",
|
||||
"felixfbecker/advanced-json-rpc": "^3.0.0",
|
||||
"jetbrains/phpstorm-stubs": "dev-master",
|
||||
"microsoft/tolerant-php-parser": "0.0.*",
|
||||
"netresearch/jsonmapper": "^1.0",
|
||||
"phpdocumentor/reflection-docblock": "^4.0.0",
|
||||
"psr/log": "^1.0",
|
||||
"sabre/event": "^5.0",
|
||||
"sabre/uri": "^2.0",
|
||||
"webmozart/glob": "^4.1",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue