From e509aad26313856c2258b1953878c649bf97388b Mon Sep 17 00:00:00 2001 From: Andrew Nagy Date: Fri, 4 Mar 2022 18:04:19 +0000 Subject: [PATCH] ability to debounce onchange events for large projects --- src/Psalm/Internal/Cli/LanguageServer.php | 8 ++++ .../LanguageServer/ClientConfiguration.php | 33 +++++++++++++++++ .../LanguageServer/LanguageServer.php | 37 +++++++++++++++---- 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/src/Psalm/Internal/Cli/LanguageServer.php b/src/Psalm/Internal/Cli/LanguageServer.php index 6cd7b4e33..6887f36e7 100644 --- a/src/Psalm/Internal/Cli/LanguageServer.php +++ b/src/Psalm/Internal/Cli/LanguageServer.php @@ -85,6 +85,7 @@ final class LanguageServer 'enable-provide-signature-help::', 'enable-provide-definition::', 'show-diagnostic-warnings::', + 'on-change-debounce-ms::', 'use-extended-diagnostic-codes', 'verbose' ]; @@ -209,6 +210,9 @@ Options: --use-extended-diagnostic-codes (DEPRECATED) Enables sending help uri links with the code in diagnostic messages. + --on-change-debounce-ms=[INT] + The number of milliseconds to debounce onChange events. + --verbose Will send log messages to the client with information. @@ -308,6 +312,10 @@ HELP; $clientConfiguration->onchangeLineLimit = (int) $options['disable-on-change']; } + if (isset($options['on-change-debounce-ms'])) { + $clientConfiguration->onChangeDebounceMs = (int) $options['on-change-debounce-ms']; + } + $clientConfiguration->provideDefinition = !isset($options['enable-provide-definition']) || !is_string($options['enable-provide-definition']) || strtolower($options['enable-provide-definition']) !== 'false'; diff --git a/src/Psalm/Internal/LanguageServer/ClientConfiguration.php b/src/Psalm/Internal/LanguageServer/ClientConfiguration.php index e6242eb67..c5fd948d1 100644 --- a/src/Psalm/Internal/LanguageServer/ClientConfiguration.php +++ b/src/Psalm/Internal/LanguageServer/ClientConfiguration.php @@ -106,6 +106,29 @@ class ClientConfiguration */ public $onchangeLineLimit; + /** + * Debounce time in milliseconds for onChange events + * + * @var int|null + * + */ + public $onChangeDebounceMs; + + /** + * Undocumented function + * + * @param boolean $hideWarnings + * @param boolean|null $provideCompletion + * @param boolean|null $provideDefinition + * @param boolean|null $provideHover + * @param boolean|null $provideSignatureHelp + * @param boolean|null $provideCodeActions + * @param boolean|null $provideDiagnostics + * @param boolean|null $findUnusedVariables + * @param 'always'|'auto'|null $findUnusedCode + * @param integer|null $logLevel + * @param integer|null $onchangeLineLimit + */ public function __construct( bool $hideWarnings = true, bool $provideCompletion = null, @@ -113,6 +136,11 @@ class ClientConfiguration bool $provideHover = null, bool $provideSignatureHelp = null, bool $provideCodeActions = null, + bool $provideDiagnostics = null, + bool $findUnusedVariables = null, + string $findUnusedCode = null, + int $logLevel = null, + int $onchangeLineLimit = null, ) { $this->hideWarnings = $hideWarnings; $this->provideCompletion = $provideCompletion; @@ -120,5 +148,10 @@ class ClientConfiguration $this->provideHover = $provideHover; $this->provideSignatureHelp = $provideSignatureHelp; $this->provideCodeActions = $provideCodeActions; + $this->provideDiagnostics = $provideDiagnostics; + $this->findUnusedVariables = $findUnusedVariables; + $this->findUnusedCode = $findUnusedCode; + $this->logLevel = $logLevel; + $this->onchangeLineLimit = $onchangeLineLimit; } } diff --git a/src/Psalm/Internal/LanguageServer/LanguageServer.php b/src/Psalm/Internal/LanguageServer/LanguageServer.php index 5878d1f12..272574806 100644 --- a/src/Psalm/Internal/LanguageServer/LanguageServer.php +++ b/src/Psalm/Internal/LanguageServer/LanguageServer.php @@ -141,6 +141,12 @@ class LanguageServer extends Dispatcher */ protected $codebase; + /** + * The AMP Delay token + * @var string + */ + protected $versionedAnalysisDelayToken = ''; + public function __construct( ProtocolReader $reader, ProtocolWriter $writer, @@ -627,7 +633,7 @@ class LanguageServer extends Dispatcher */ public function queueChangeFileAnalysis(string $file_path, string $uri, ?int $version = null): void { - $this->doVersionedAnalysis([$file_path => $uri], $version); + $this->doVersionedAnalysisDebounce([$file_path => $uri], $version); } /** @@ -681,6 +687,25 @@ class LanguageServer extends Dispatcher $this->doVersionedAnalysis($opened); } + /** + * Debounced Queue File Analysis with optional version + * + * @param array $files + * @param int|null $version + */ + public function doVersionedAnalysisDebounce(array $files, ?int $version = null): void + { + Loop::cancel($this->versionedAnalysisDelayToken); + if ($this->client->clientConfiguration->onChangeDebounceMs === null) { + $this->doVersionedAnalysis($files, $version); + } else { + $this->versionedAnalysisDelayToken = Loop::delay( + $this->client->clientConfiguration->onChangeDebounceMs, + fn() => $this->doVersionedAnalysis($files, $version) + ); + } + } + /** * Queue File Analysis with optional version * @@ -689,13 +714,9 @@ class LanguageServer extends Dispatcher */ public function doVersionedAnalysis(array $files, ?int $version = null): void { + Loop::cancel($this->versionedAnalysisDelayToken); try { - if (empty($files)) { - $this->logWarning("No versioned analysis to do."); - return; - } - - $this->logDebug("Reloading Files"); + $this->logDebug("Doing Analysis from version: $version"); $this->codebase->reloadFiles( $this->project_analyzer, array_keys($files) @@ -705,7 +726,7 @@ class LanguageServer extends Dispatcher array_combine(array_keys($files), array_keys($files)) ); - $this->logDebug("Analyze Files"); + $this->logDebug("Reloading Files"); $this->codebase->analyzer->analyzeFiles($this->project_analyzer, 1, false); $this->emitVersionedIssues($files, $version);