From bfb87d1a9288becb9ff6c5f2c9112611a066534f Mon Sep 17 00:00:00 2001 From: Shubham Yadav Date: Wed, 24 Apr 2019 09:41:25 +0530 Subject: [PATCH 1/6] Fix for node process failing --- src/extensions/default/PhpTooling/main.js | 86 ++++++++++++------- src/languageTools/ClientLoader.js | 51 ++++++++--- .../node/RegisterLanguageClientInfo.js | 12 +++ 3 files changed, 105 insertions(+), 44 deletions(-) diff --git a/src/extensions/default/PhpTooling/main.js b/src/extensions/default/PhpTooling/main.js index 017b7cb0232..0f45c127684 100755 --- a/src/extensions/default/PhpTooling/main.js +++ b/src/extensions/default/PhpTooling/main.js @@ -24,11 +24,12 @@ define(function (require, exports, module) { "use strict"; var LanguageTools = brackets.getModule("languageTools/LanguageTools"), + ClientLoader = brackets.getModule("languageTools/ClientLoader"), AppInit = brackets.getModule("utils/AppInit"), ExtensionUtils = brackets.getModule("utils/ExtensionUtils"), ProjectManager = brackets.getModule("project/ProjectManager"), - EditorManager = brackets.getModule("editor/EditorManager"), - LanguageManager = brackets.getModule("language/LanguageManager"), + EditorManager = brackets.getModule("editor/EditorManager"), + LanguageManager = brackets.getModule("language/LanguageManager"), CodeHintManager = brackets.getModule("editor/CodeHintManager"), QuickOpen = brackets.getModule("search/QuickOpen"), ParameterHintManager = brackets.getModule("features/ParameterHintsManager"), @@ -39,13 +40,13 @@ define(function (require, exports, module) { CodeHintsProvider = require("CodeHintsProvider").CodeHintsProvider, SymbolProviders = require("PHPSymbolProviders").SymbolProviders, DefaultEventHandlers = brackets.getModule("languageTools/DefaultEventHandlers"), - PreferencesManager = brackets.getModule("preferences/PreferencesManager"), - Strings = brackets.getModule("strings"), - Dialogs = brackets.getModule("widgets/Dialogs"), - DefaultDialogs = brackets.getModule("widgets/DefaultDialogs"), - Commands = brackets.getModule("command/Commands"), - CommandManager = brackets.getModule("command/CommandManager"), - StringUtils = brackets.getModule("utils/StringUtils"); + PreferencesManager = brackets.getModule("preferences/PreferencesManager"), + Strings = brackets.getModule("strings"), + Dialogs = brackets.getModule("widgets/Dialogs"), + DefaultDialogs = brackets.getModule("widgets/DefaultDialogs"), + Commands = brackets.getModule("command/Commands"), + CommandManager = brackets.getModule("command/CommandManager"), + StringUtils = brackets.getModule("utils/StringUtils"); var clientFilePath = ExtensionUtils.getModulePath(module, "client.js"), clientName = "PhpClient", @@ -57,7 +58,7 @@ define(function (require, exports, module) { memoryLimit: "4095M", validateOnType: "false" }, - DEBUG_OPEN_PREFERENCES_IN_SPLIT_VIEW = "debug.openPrefsInSplitView", + DEBUG_OPEN_PREFERENCES_IN_SPLIT_VIEW = "debug.openPrefsInSplitView", phpServerRunning = false, serverCapabilities, currentRootPath, @@ -79,8 +80,8 @@ define(function (require, exports, module) { if (lProvider && newPhpConfig["validateOnType"] !== phpConfig["validateOnType"]) { lProvider._validateOnType = !(newPhpConfig["validateOnType"] === "false"); } - if ((newPhpConfig["executablePath"] !== phpConfig["executablePath"]) - || (newPhpConfig["enablePhpTooling"] !== phpConfig["enablePhpTooling"])) { + if ((newPhpConfig["executablePath"] !== phpConfig["executablePath"]) || + (newPhpConfig["enablePhpTooling"] !== phpConfig["enablePhpTooling"])) { phpConfig = newPhpConfig; runPhpServer(); return; @@ -90,7 +91,7 @@ define(function (require, exports, module) { var handleProjectOpen = function (event, directory) { lProvider.clearExistingResults(); - if(serverCapabilities["workspace"] && serverCapabilities["workspace"]["workspaceFolders"]) { + if (serverCapabilities["workspace"] && serverCapabilities["workspace"]["workspaceFolders"]) { _client.notifyProjectRootsChanged({ foldersAdded: [directory.fullPath], foldersRemoved: [currentRootPath] @@ -105,9 +106,9 @@ define(function (require, exports, module) { function registerToolingProviders() { chProvider = new CodeHintsProvider(_client), - phProvider = new DefaultProviders.ParameterHintsProvider(_client), - lProvider = new DefaultProviders.LintingProvider(_client), - jdProvider = new DefaultProviders.JumpToDefProvider(_client); + phProvider = new DefaultProviders.ParameterHintsProvider(_client), + lProvider = new DefaultProviders.LintingProvider(_client), + jdProvider = new DefaultProviders.JumpToDefProvider(_client); dSymProvider = new SymbolProviders.DocumentSymbolsProvider(_client); pSymProvider = new SymbolProviders.ProjectSymbolsProvider(_client); refProvider = new DefaultProviders.ReferencesProvider(_client); @@ -176,7 +177,7 @@ define(function (require, exports, module) { } function showErrorPopUp(err) { - if(!err) { + if (!err) { return; } var localizedErrStr = ""; @@ -185,15 +186,21 @@ define(function (require, exports, module) { } else { localizedErrStr = StringUtils.format(Strings[err[0]], err[1]); } - if(!localizedErrStr) { + if (!localizedErrStr) { console.error("Php Tooling Error: " + err); return; } var Buttons = [ - { className: Dialogs.DIALOG_BTN_CLASS_NORMAL, id: Dialogs.DIALOG_BTN_CANCEL, - text: Strings.CANCEL }, - { className: Dialogs.DIALOG_BTN_CLASS_PRIMARY, id: Dialogs.DIALOG_BTN_DOWNLOAD, - text: Strings.OPEN_PREFERENNCES} + { + className: Dialogs.DIALOG_BTN_CLASS_NORMAL, + id: Dialogs.DIALOG_BTN_CANCEL, + text: Strings.CANCEL + }, + { + className: Dialogs.DIALOG_BTN_CLASS_PRIMARY, + id: Dialogs.DIALOG_BTN_DOWNLOAD, + text: Strings.OPEN_PREFERENNCES + } ]; Dialogs.showModalDialog( DefaultDialogs.DIALOG_ID_ERROR, @@ -239,7 +246,13 @@ define(function (require, exports, module) { serverCapabilities = result.capabilities; handlePostPhpServerStart(); }); - }).fail(showErrorPopUp); + }).fail(function (err) { + showErrorPopUp(err); + //Retry on next active editor change + EditorManager.on("activeEditorChange.php", activeEditorChangeHandler); + LanguageManager.on("languageModified.php", languageModifiedHandler); + activeEditorChangeHandler(null, EditorManager.getActiveEditor()); + }); } } @@ -262,15 +275,28 @@ define(function (require, exports, module) { } } + function initiateService() { + if (!phpServerRunning) { + LanguageTools.initiateToolingService(clientName, clientFilePath, ['php']).done(function (client) { + _client = client; + //Attach only once + EditorManager.off("activeEditorChange.php"); + EditorManager.on("activeEditorChange.php", activeEditorChangeHandler); + //Attach only once + LanguageManager.off("languageModified.php"); + LanguageManager.on("languageModified.php", languageModifiedHandler); + activeEditorChangeHandler(null, EditorManager.getActiveEditor()); + }); + } + } + AppInit.appReady(function () { - LanguageTools.initiateToolingService(clientName, clientFilePath, ['php']).done(function (client) { - _client = client; - EditorManager.on("activeEditorChange.php", activeEditorChangeHandler); - LanguageManager.on("languageModified.php", languageModifiedHandler); - activeEditorChangeHandler(null, EditorManager.getActiveEditor()); - }); + initiateService(); + ClientLoader.on("clientsReloaded", initiateService); }); //Only for Unit testing - exports.getClient = function() { return _client; }; + exports.getClient = function () { + return _client; + }; }); diff --git a/src/languageTools/ClientLoader.js b/src/languageTools/ClientLoader.js index c2fa615da6b..c41be020ca1 100644 --- a/src/languageTools/ClientLoader.js +++ b/src/languageTools/ClientLoader.js @@ -29,8 +29,10 @@ define(function (require, exports, module) { var ToolingInfo = JSON.parse(require("text!languageTools/ToolingInfo.json")), NodeDomain = require("utils/NodeDomain"), FileUtils = require("file/FileUtils"), + EventDispatcher = require("utils/EventDispatcher"), BracketsToNodeInterface = require("languageTools/BracketsToNodeInterface").BracketsToNodeInterface; + EventDispatcher.makeEventDispatcher(exports); //Register paths required for Language Client and also register default brackets capabilities. var _bracketsPath = FileUtils.getNativeBracketsDirectoryPath(); // The native directory path ends with either "test" or "src". @@ -39,21 +41,13 @@ define(function (require, exports, module) { var _modulePath = FileUtils.getNativeModuleDirectoryPath(module), _nodePath = "node/RegisterLanguageClientInfo", _domainPath = [_bracketsPath, _modulePath, _nodePath].join("/"), - clientInfoDomain = new NodeDomain("LanguageClientInfo", _domainPath), - //Init node with Information required by Language Client - clientInfoLoadedPromise = clientInfoDomain.exec("initialize", _bracketsPath, ToolingInfo), + clientInfoDomain = null, + clientInfoLoadedPromise = null, //Clients that have to be loaded once the LanguageClient info is successfully loaded on the //node side. - pendingClientsToBeLoaded = []; - - //Attach success and failure function for the clientInfoLoadedPromise - clientInfoLoadedPromise.then(function () { - pendingClientsToBeLoaded.forEach(function (pendingClient) { - pendingClient.load(); - }); - }, function () { - console.log("Failed to Initialize LanguageClient Module Information."); - }); + pendingClientsToBeLoaded = [], + //list of the client which have to be loaded + clientMap = {}; function syncPrefsWithDomain(languageToolsPrefs) { if (clientInfoDomain) { @@ -110,8 +104,9 @@ define(function (require, exports, module) { function initiateLanguageClient(clientName, clientFilePath) { var result = $.Deferred(); + clientMap[clientName] = clientFilePath; //Only load clients after the LanguageClient Info has been initialized - if (clientInfoLoadedPromise.state() === "pending") { + if (!clientInfoLoadedPromise || clientInfoLoadedPromise.state() === "pending") { var pendingClient = { load: _clientLoader.bind(null, clientName, clientFilePath, result) }; @@ -123,6 +118,34 @@ define(function (require, exports, module) { return result; } + function sendLanguageClientInfo() { + //Init node with Information required by Language Client + clientInfoLoadedPromise = clientInfoDomain.exec("initialize", _bracketsPath, ToolingInfo); + + //Attach success and failure function for the clientInfoLoadedPromise + clientInfoLoadedPromise.then(function () { + if (Array.isArray(pendingClientsToBeLoaded)) { + pendingClientsToBeLoaded.forEach(function (pendingClient) { + pendingClient.load(); + }); + } else { + //the node process might have restarted, so try loading all the clients again +// console.log("Reloading clients due to Node process crash..."); +// var clients = Object.keys(clientMap); +// clients.forEach(function (client) { +// var clientPromise = $.Deferred(); +// _clientLoader(client, clientMap[client], clientPromise); +// }); + exports.trigger("clientsReloaded"); + } + pendingClientsToBeLoaded = null; + }, function () { + console.error("Failed to Initialize LanguageClient Module Information."); + }); + } + clientInfoDomain = new NodeDomain("LanguageClientInfo", _domainPath); + clientInfoDomain.on("requestLanguageClientInfo", sendLanguageClientInfo); + exports.initiateLanguageClient = initiateLanguageClient; exports.syncPrefsWithDomain = syncPrefsWithDomain; }); diff --git a/src/languageTools/node/RegisterLanguageClientInfo.js b/src/languageTools/node/RegisterLanguageClientInfo.js index 614be647561..2ab728053a5 100644 --- a/src/languageTools/node/RegisterLanguageClientInfo.js +++ b/src/languageTools/node/RegisterLanguageClientInfo.js @@ -285,6 +285,18 @@ function init(domainManager) { ], [] ); + + domainManager.registerEvent( + domainName, + "requestLanguageClientInfo", + [] + ); + + function requestInfo() { + domainManager.emitEvent(domainName, "requestLanguageClientInfo", []); + } + //Allow the handler enough time to get registered on Brackets side. + setTimeout(requestInfo, 500); } exports.init = init; From 7867779bbd21401021fb9e5e3b18c85db106e50b Mon Sep 17 00:00:00 2001 From: Shubham Yadav Date: Wed, 24 Apr 2019 11:16:25 +0530 Subject: [PATCH 2/6] Modification #1 --- src/extensions/default/PhpTooling/main.js | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/extensions/default/PhpTooling/main.js b/src/extensions/default/PhpTooling/main.js index 0f45c127684..6f6f36cc71c 100755 --- a/src/extensions/default/PhpTooling/main.js +++ b/src/extensions/default/PhpTooling/main.js @@ -276,18 +276,18 @@ define(function (require, exports, module) { } function initiateService() { - if (!phpServerRunning) { - LanguageTools.initiateToolingService(clientName, clientFilePath, ['php']).done(function (client) { - _client = client; - //Attach only once - EditorManager.off("activeEditorChange.php"); - EditorManager.on("activeEditorChange.php", activeEditorChangeHandler); - //Attach only once - LanguageManager.off("languageModified.php"); - LanguageManager.on("languageModified.php", languageModifiedHandler); - activeEditorChangeHandler(null, EditorManager.getActiveEditor()); - }); - } + console.log("Php tooling: Starting the service"); + phpServerRunning = false; + LanguageTools.initiateToolingService(clientName, clientFilePath, ['php']).done(function (client) { + _client = client; + //Attach only once + EditorManager.off("activeEditorChange.php"); + EditorManager.on("activeEditorChange.php", activeEditorChangeHandler); + //Attach only once + LanguageManager.off("languageModified.php"); + LanguageManager.on("languageModified.php", languageModifiedHandler); + activeEditorChangeHandler(null, EditorManager.getActiveEditor()); + }); } AppInit.appReady(function () { From 0194e1e1ae026166fef8b4021701e1810040adc0 Mon Sep 17 00:00:00 2001 From: Shubham Yadav Date: Wed, 24 Apr 2019 14:55:46 +0530 Subject: [PATCH 3/6] Code cleanup --- .../default/PhpTooling/PHPSymbolProviders.js | 12 +++- src/extensions/default/PhpTooling/main.js | 55 ++++++++++++++----- src/languageTools/ClientLoader.js | 14 +---- src/languageTools/DefaultProviders.js | 18 +++++- .../node/RegisterLanguageClientInfo.js | 8 +-- 5 files changed, 74 insertions(+), 33 deletions(-) diff --git a/src/extensions/default/PhpTooling/PHPSymbolProviders.js b/src/extensions/default/PhpTooling/PHPSymbolProviders.js index 8517e1db574..9265bd16dda 100644 --- a/src/extensions/default/PhpTooling/PHPSymbolProviders.js +++ b/src/extensions/default/PhpTooling/PHPSymbolProviders.js @@ -22,7 +22,7 @@ */ /*jslint regexp: true */ - +/*eslint no-invalid-this: 0, max-len: 0*/ define(function (require, exports, module) { "use strict"; @@ -34,6 +34,12 @@ define(function (require, exports, module) { var SymbolKind = QuickOpen.SymbolKind; + function setClient(client) { + if (client) { + this.client = client; + } + } + function convertRangePosToEditorPos(rangePos) { return { line: rangePos.line, @@ -112,6 +118,8 @@ define(function (require, exports, module) { this.client = client; } + DocumentSymbolsProvider.prototype.setClient = setClient; + DocumentSymbolsProvider.prototype.match = function (query) { return query.startsWith("@"); }; @@ -171,6 +179,8 @@ define(function (require, exports, module) { this.client = client; } + ProjectSymbolsProvider.prototype.setClient = setClient; + ProjectSymbolsProvider.prototype.match = function (query) { return query.startsWith("#"); }; diff --git a/src/extensions/default/PhpTooling/main.js b/src/extensions/default/PhpTooling/main.js index 6f6f36cc71c..07db6ae9ec8 100755 --- a/src/extensions/default/PhpTooling/main.js +++ b/src/extensions/default/PhpTooling/main.js @@ -62,13 +62,14 @@ define(function (require, exports, module) { phpServerRunning = false, serverCapabilities, currentRootPath, - chProvider, - phProvider, - lProvider, - jdProvider, - dSymProvider, - pSymProvider, - refProvider; + chProvider = null, + phProvider = null, + lProvider = null, + jdProvider = null, + dSymProvider = null, + pSymProvider = null, + refProvider = null, + providersRegistered = false; PreferencesManager.definePreference("php", "object", phpConfig, { description: Strings.DESCRIPTION_PHP_TOOLING_CONFIGURATION @@ -104,11 +105,22 @@ define(function (require, exports, module) { } }; + function resetClientInProviders() { + var logErr = "PhpTooling: Can't reset client for : "; + chProvider ? chProvider.setClient(_client) : console.log(logErr, "CodeHintsProvider"); + phProvider ? phProvider.setClient(_client) : console.log(logErr, "ParameterHintsProvider"); + lProvider ? lProvider.setClient(_client) : console.log(logErr, "LintingProvider"); + jdProvider ? jdProvider.setClient(_client) : console.log(logErr, "JumpToDefProvider"); + dSymProvider ? dSymProvider.setClient(_client) : console.log(logErr, "DocumentSymbolsProvider"); + pSymProvider ? pSymProvider.setClient(_client) : console.log(logErr, "ProjectSymbolsProvider"); + refProvider ? refProvider.setClient(_client) : console.log(logErr, "FindReferencesProvider"); + } + function registerToolingProviders() { chProvider = new CodeHintsProvider(_client), - phProvider = new DefaultProviders.ParameterHintsProvider(_client), - lProvider = new DefaultProviders.LintingProvider(_client), - jdProvider = new DefaultProviders.JumpToDefProvider(_client); + phProvider = new DefaultProviders.ParameterHintsProvider(_client), + lProvider = new DefaultProviders.LintingProvider(_client), + jdProvider = new DefaultProviders.JumpToDefProvider(_client); dSymProvider = new SymbolProviders.DocumentSymbolsProvider(_client); pSymProvider = new SymbolProviders.ProjectSymbolsProvider(_client); refProvider = new DefaultProviders.ReferencesProvider(_client); @@ -148,6 +160,8 @@ define(function (require, exports, module) { CommandManager.get(Commands.NAVIGATE_GOTO_DEFINITION_PROJECT).setEnabled(true); _client.addOnCodeInspection(lProvider.setInspectionResults.bind(lProvider)); + + providersRegistered = true; } function addEventHandlers() { @@ -221,7 +235,13 @@ define(function (require, exports, module) { function handlePostPhpServerStart() { if (!phpServerRunning) { phpServerRunning = true; - registerToolingProviders(); + + if (providersRegistered) { + resetClientInProviders(); + } else { + registerToolingProviders(); + } + addEventHandlers(); EditorManager.off("activeEditorChange.php"); LanguageManager.off("languageModified.php"); @@ -275,8 +295,13 @@ define(function (require, exports, module) { } } - function initiateService() { - console.log("Php tooling: Starting the service"); + function initiateService(onAppReady) { + if (onAppReady) { + console.log("Php tooling: Starting the service"); + } else { + console.log("Php tooling: Something went wrong. Restarting the service"); + } + phpServerRunning = false; LanguageTools.initiateToolingService(clientName, clientFilePath, ['php']).done(function (client) { _client = client; @@ -291,8 +316,8 @@ define(function (require, exports, module) { } AppInit.appReady(function () { - initiateService(); - ClientLoader.on("clientsReloaded", initiateService); + initiateService(true); + ClientLoader.on("languageClientModuleInitialized", initiateService); }); //Only for Unit testing diff --git a/src/languageTools/ClientLoader.js b/src/languageTools/ClientLoader.js index c41be020ca1..ca40370eb83 100644 --- a/src/languageTools/ClientLoader.js +++ b/src/languageTools/ClientLoader.js @@ -45,9 +45,7 @@ define(function (require, exports, module) { clientInfoLoadedPromise = null, //Clients that have to be loaded once the LanguageClient info is successfully loaded on the //node side. - pendingClientsToBeLoaded = [], - //list of the client which have to be loaded - clientMap = {}; + pendingClientsToBeLoaded = []; function syncPrefsWithDomain(languageToolsPrefs) { if (clientInfoDomain) { @@ -104,7 +102,6 @@ define(function (require, exports, module) { function initiateLanguageClient(clientName, clientFilePath) { var result = $.Deferred(); - clientMap[clientName] = clientFilePath; //Only load clients after the LanguageClient Info has been initialized if (!clientInfoLoadedPromise || clientInfoLoadedPromise.state() === "pending") { var pendingClient = { @@ -129,14 +126,7 @@ define(function (require, exports, module) { pendingClient.load(); }); } else { - //the node process might have restarted, so try loading all the clients again -// console.log("Reloading clients due to Node process crash..."); -// var clients = Object.keys(clientMap); -// clients.forEach(function (client) { -// var clientPromise = $.Deferred(); -// _clientLoader(client, clientMap[client], clientPromise); -// }); - exports.trigger("clientsReloaded"); + exports.trigger("languageClientModuleInitialized"); } pendingClientsToBeLoaded = null; }, function () { diff --git a/src/languageTools/DefaultProviders.js b/src/languageTools/DefaultProviders.js index 47761ac0aa9..a75ea695de7 100644 --- a/src/languageTools/DefaultProviders.js +++ b/src/languageTools/DefaultProviders.js @@ -23,7 +23,7 @@ /*global Map*/ /* eslint-disable indent */ -/* eslint max-len: ["error", { "code": 200 }]*/ +/* eslint max-len: ["error", { "code": 200 }], no-invalid-this: 0*/ define(function (require, exports, module) { "use strict"; @@ -44,12 +44,20 @@ define(function (require, exports, module) { ExtensionUtils.loadStyleSheet(module, "styles/default_provider_style.css"); + function setClient(client) { + if (client) { + this.client = client; + } + } + function CodeHintsProvider(client) { this.client = client; this.query = ""; this.ignoreQuery = ["-", "->", ">", ":", "::", "(", "()", ")", "[", "[]", "]", "{", "{}", "}"]; } + CodeHintsProvider.prototype.setClient = setClient; + function formatTypeDataForToken($hintObj, token) { $hintObj.addClass('brackets-hints-with-type-details'); if (token.detail) { @@ -197,6 +205,8 @@ define(function (require, exports, module) { this.client = client; } + ParameterHintsProvider.prototype.setClient = setClient; + ParameterHintsProvider.prototype.hasParameterHints = function (editor, implicitChar) { if (!this.client) { return false; @@ -273,6 +283,8 @@ define(function (require, exports, module) { this.client = client; } + JumpToDefProvider.prototype.setClient = setClient; + JumpToDefProvider.prototype.canJumpToDef = function (editor, implicitChar) { if (!this.client) { return false; @@ -342,6 +354,8 @@ define(function (require, exports, module) { this._validateOnType = false; } + LintingProvider.prototype.setClient = setClient; + LintingProvider.prototype.clearExistingResults = function (filePath) { var filePathProvided = !!filePath; @@ -451,6 +465,8 @@ define(function (require, exports, module) { this.client = client; } + ReferencesProvider.prototype.setClient = setClient; + ReferencesProvider.prototype.hasReferences = function() { if (!this.client) { return false; diff --git a/src/languageTools/node/RegisterLanguageClientInfo.js b/src/languageTools/node/RegisterLanguageClientInfo.js index 2ab728053a5..befbf232a50 100644 --- a/src/languageTools/node/RegisterLanguageClientInfo.js +++ b/src/languageTools/node/RegisterLanguageClientInfo.js @@ -285,18 +285,18 @@ function init(domainManager) { ], [] ); - + domainManager.registerEvent( domainName, "requestLanguageClientInfo", - [] + [] //no parameters ); - + function requestInfo() { domainManager.emitEvent(domainName, "requestLanguageClientInfo", []); } //Allow the handler enough time to get registered on Brackets side. - setTimeout(requestInfo, 500); + setTimeout(requestInfo, 250); } exports.init = init; From 96145293a54e27bf2646923b6ff970c72e01838e Mon Sep 17 00:00:00 2001 From: Shubham Yadav Date: Wed, 24 Apr 2019 15:17:49 +0530 Subject: [PATCH 4/6] Code cleanup #1 --- .../default/PhpTooling/CodeHintsProvider.js | 4 ++++ src/extensions/default/PhpTooling/main.js | 11 +++-------- src/languageTools/node/RegisterLanguageClientInfo.js | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/extensions/default/PhpTooling/CodeHintsProvider.js b/src/extensions/default/PhpTooling/CodeHintsProvider.js index 3f54d82f2e1..958dcd33238 100644 --- a/src/extensions/default/PhpTooling/CodeHintsProvider.js +++ b/src/extensions/default/PhpTooling/CodeHintsProvider.js @@ -54,6 +54,10 @@ define(function (require, exports, module) { this.defaultCodeHintProviders = new DefaultProviders.CodeHintsProvider(client); } + CodeHintsProvider.prototype.setClient = function (client) { + this.defaultCodeHintProviders.setClient(client); + }; + function setStyleAndCacheToken($hintObj, token) { $hintObj.addClass('brackets-hints-with-type-details'); $hintObj.data('completionItem', token); diff --git a/src/extensions/default/PhpTooling/main.js b/src/extensions/default/PhpTooling/main.js index 07db6ae9ec8..aceef3b1780 100755 --- a/src/extensions/default/PhpTooling/main.js +++ b/src/extensions/default/PhpTooling/main.js @@ -109,11 +109,12 @@ define(function (require, exports, module) { var logErr = "PhpTooling: Can't reset client for : "; chProvider ? chProvider.setClient(_client) : console.log(logErr, "CodeHintsProvider"); phProvider ? phProvider.setClient(_client) : console.log(logErr, "ParameterHintsProvider"); - lProvider ? lProvider.setClient(_client) : console.log(logErr, "LintingProvider"); jdProvider ? jdProvider.setClient(_client) : console.log(logErr, "JumpToDefProvider"); dSymProvider ? dSymProvider.setClient(_client) : console.log(logErr, "DocumentSymbolsProvider"); pSymProvider ? pSymProvider.setClient(_client) : console.log(logErr, "ProjectSymbolsProvider"); refProvider ? refProvider.setClient(_client) : console.log(logErr, "FindReferencesProvider"); + lProvider ? lProvider.setClient(_client) : console.log(logErr, "LintingProvider"); + _client.addOnCodeInspection(lProvider.setInspectionResults.bind(lProvider)); } function registerToolingProviders() { @@ -266,13 +267,7 @@ define(function (require, exports, module) { serverCapabilities = result.capabilities; handlePostPhpServerStart(); }); - }).fail(function (err) { - showErrorPopUp(err); - //Retry on next active editor change - EditorManager.on("activeEditorChange.php", activeEditorChangeHandler); - LanguageManager.on("languageModified.php", languageModifiedHandler); - activeEditorChangeHandler(null, EditorManager.getActiveEditor()); - }); + }).fail(showErrorPopUp); } } diff --git a/src/languageTools/node/RegisterLanguageClientInfo.js b/src/languageTools/node/RegisterLanguageClientInfo.js index befbf232a50..27cc95e4673 100644 --- a/src/languageTools/node/RegisterLanguageClientInfo.js +++ b/src/languageTools/node/RegisterLanguageClientInfo.js @@ -296,7 +296,7 @@ function init(domainManager) { domainManager.emitEvent(domainName, "requestLanguageClientInfo", []); } //Allow the handler enough time to get registered on Brackets side. - setTimeout(requestInfo, 250); + setTimeout(requestInfo, 500); } exports.init = init; From b28aff02d0b0bbb5f850276dd39fbf255bdaee61 Mon Sep 17 00:00:00 2001 From: Shubham Yadav Date: Wed, 24 Apr 2019 23:46:37 +0530 Subject: [PATCH 5/6] Code cleanup #2: Removing timeout and adding comments --- src/languageTools/ClientLoader.js | 46 +++++++++++++++++-- .../node/RegisterLanguageClientInfo.js | 22 ++++----- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/languageTools/ClientLoader.js b/src/languageTools/ClientLoader.js index ca40370eb83..63d5c28784a 100644 --- a/src/languageTools/ClientLoader.js +++ b/src/languageTools/ClientLoader.js @@ -115,12 +115,27 @@ define(function (require, exports, module) { return result; } + /** + * This function passes Brackets's native directory path as well as the tooling commands + * required by the LanguageClient node module. This information is then maintained in memory + * in the node process server for succesfully loading and functioning of all language clients + * since it is a direct dependency. + */ function sendLanguageClientInfo() { //Init node with Information required by Language Client clientInfoLoadedPromise = clientInfoDomain.exec("initialize", _bracketsPath, ToolingInfo); + function logInitializationError() { + console.error("Failed to Initialize LanguageClient Module Information."); + } + //Attach success and failure function for the clientInfoLoadedPromise - clientInfoLoadedPromise.then(function () { + clientInfoLoadedPromise.then(function (success) { + if (!success) { + logInitializationError(); + return; + } + if (Array.isArray(pendingClientsToBeLoaded)) { pendingClientsToBeLoaded.forEach(function (pendingClient) { pendingClient.load(); @@ -130,11 +145,34 @@ define(function (require, exports, module) { } pendingClientsToBeLoaded = null; }, function () { - console.error("Failed to Initialize LanguageClient Module Information."); + logInitializationError(); }); } - clientInfoDomain = new NodeDomain("LanguageClientInfo", _domainPath); - clientInfoDomain.on("requestLanguageClientInfo", sendLanguageClientInfo); + + /** + * This function starts a domain which initializes the LanguageClient node module + * required by the Language Server Protocol framework in Brackets. All the LSP clients + * can only be successfully initiated once this domain has been successfully loaded and + * the LanguageClient info initialized. Refer to sendLanguageClientInfo for more. + */ + function initDomainAndHandleNodeCrash() { + clientInfoDomain = new NodeDomain("LanguageClientInfo", _domainPath); + //Initialize LanguageClientInfo once the domain has successfully loaded. + clientInfoDomain.promise().done(function () { + sendLanguageClientInfo(); + //This is to handle the node failure. If the node process dies, we get an on close + //event on the websocket connection object. Brackets then spawns another process and + //restablishes the connection. Once the connection is restablished we send reinitialize + //the LanguageClient info. + clientInfoDomain.connection.on("close", function (event, reconnectedPromise) { + reconnectedPromise.done(sendLanguageClientInfo); + }); + }).fail(function (err) { + console.error("ClientInfo domain could not be loaded: ", err); + }); + } + initDomainAndHandleNodeCrash(); + exports.initiateLanguageClient = initiateLanguageClient; exports.syncPrefsWithDomain = syncPrefsWithDomain; diff --git a/src/languageTools/node/RegisterLanguageClientInfo.js b/src/languageTools/node/RegisterLanguageClientInfo.js index 27cc95e4673..01b65fb7f1b 100644 --- a/src/languageTools/node/RegisterLanguageClientInfo.js +++ b/src/languageTools/node/RegisterLanguageClientInfo.js @@ -229,7 +229,11 @@ function syncPreferences(prefs) { global.LanguageClientInfo.preferences = prefs || global.LanguageClientInfo.preferences || {}; } -function initialize(bracketsSourcePath, toolingInfo) { +function initialize(bracketsSourcePath, toolingInfo, resolve) { + if (!bracketsSourcePath || !toolingInfo) { + resolve(true, null); //resolve with err param + } + var normalizedBracketsSourcePath = bracketsSourcePath.split(BACKWARD_SLASH).join(FORWARD_SLASH), bracketsSourcePathArray = normalizedBracketsSourcePath.split(FORWARD_SLASH), languageClientAbsolutePath = bracketsSourcePathArray.concat(LANGUAGE_CLIENT_RELATIVE_PATH_ARRAY).join(FORWARD_SLASH); @@ -239,6 +243,8 @@ function initialize(bracketsSourcePath, toolingInfo) { global.LanguageClientInfo.defaultBracketsCapabilities = defaultBracketsCapabilities; global.LanguageClientInfo.toolingInfo = toolingInfo; global.LanguageClientInfo.preferences = {}; + + resolve(null, true); //resolve with boolean denoting success } function init(domainManager) { @@ -253,7 +259,7 @@ function init(domainManager) { domainName, "initialize", initialize, - false, + true, "Initialize node environment for Language Client Module", [ { @@ -285,18 +291,6 @@ function init(domainManager) { ], [] ); - - domainManager.registerEvent( - domainName, - "requestLanguageClientInfo", - [] //no parameters - ); - - function requestInfo() { - domainManager.emitEvent(domainName, "requestLanguageClientInfo", []); - } - //Allow the handler enough time to get registered on Brackets side. - setTimeout(requestInfo, 500); } exports.init = init; From 161ebcf2bf6a804b59a486b6b9c87d43ed332baa Mon Sep 17 00:00:00 2001 From: Shubham Yadav Date: Wed, 24 Apr 2019 23:55:46 +0530 Subject: [PATCH 6/6] Fixing Logging issue --- src/extensions/default/PhpTooling/main.js | 52 ++++++++++------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/src/extensions/default/PhpTooling/main.js b/src/extensions/default/PhpTooling/main.js index aceef3b1780..fad20cd2429 100755 --- a/src/extensions/default/PhpTooling/main.js +++ b/src/extensions/default/PhpTooling/main.js @@ -28,8 +28,8 @@ define(function (require, exports, module) { AppInit = brackets.getModule("utils/AppInit"), ExtensionUtils = brackets.getModule("utils/ExtensionUtils"), ProjectManager = brackets.getModule("project/ProjectManager"), - EditorManager = brackets.getModule("editor/EditorManager"), - LanguageManager = brackets.getModule("language/LanguageManager"), + EditorManager = brackets.getModule("editor/EditorManager"), + LanguageManager = brackets.getModule("language/LanguageManager"), CodeHintManager = brackets.getModule("editor/CodeHintManager"), QuickOpen = brackets.getModule("search/QuickOpen"), ParameterHintManager = brackets.getModule("features/ParameterHintsManager"), @@ -40,13 +40,13 @@ define(function (require, exports, module) { CodeHintsProvider = require("CodeHintsProvider").CodeHintsProvider, SymbolProviders = require("PHPSymbolProviders").SymbolProviders, DefaultEventHandlers = brackets.getModule("languageTools/DefaultEventHandlers"), - PreferencesManager = brackets.getModule("preferences/PreferencesManager"), - Strings = brackets.getModule("strings"), - Dialogs = brackets.getModule("widgets/Dialogs"), - DefaultDialogs = brackets.getModule("widgets/DefaultDialogs"), - Commands = brackets.getModule("command/Commands"), - CommandManager = brackets.getModule("command/CommandManager"), - StringUtils = brackets.getModule("utils/StringUtils"); + PreferencesManager = brackets.getModule("preferences/PreferencesManager"), + Strings = brackets.getModule("strings"), + Dialogs = brackets.getModule("widgets/Dialogs"), + DefaultDialogs = brackets.getModule("widgets/DefaultDialogs"), + Commands = brackets.getModule("command/Commands"), + CommandManager = brackets.getModule("command/CommandManager"), + StringUtils = brackets.getModule("utils/StringUtils"); var clientFilePath = ExtensionUtils.getModulePath(module, "client.js"), clientName = "PhpClient", @@ -58,7 +58,7 @@ define(function (require, exports, module) { memoryLimit: "4095M", validateOnType: "false" }, - DEBUG_OPEN_PREFERENCES_IN_SPLIT_VIEW = "debug.openPrefsInSplitView", + DEBUG_OPEN_PREFERENCES_IN_SPLIT_VIEW = "debug.openPrefsInSplitView", phpServerRunning = false, serverCapabilities, currentRootPath, @@ -81,8 +81,8 @@ define(function (require, exports, module) { if (lProvider && newPhpConfig["validateOnType"] !== phpConfig["validateOnType"]) { lProvider._validateOnType = !(newPhpConfig["validateOnType"] === "false"); } - if ((newPhpConfig["executablePath"] !== phpConfig["executablePath"]) || - (newPhpConfig["enablePhpTooling"] !== phpConfig["enablePhpTooling"])) { + if ((newPhpConfig["executablePath"] !== phpConfig["executablePath"]) + || (newPhpConfig["enablePhpTooling"] !== phpConfig["enablePhpTooling"])) { phpConfig = newPhpConfig; runPhpServer(); return; @@ -92,7 +92,7 @@ define(function (require, exports, module) { var handleProjectOpen = function (event, directory) { lProvider.clearExistingResults(); - if (serverCapabilities["workspace"] && serverCapabilities["workspace"]["workspaceFolders"]) { + if(serverCapabilities["workspace"] && serverCapabilities["workspace"]["workspaceFolders"]) { _client.notifyProjectRootsChanged({ foldersAdded: [directory.fullPath], foldersRemoved: [currentRootPath] @@ -192,7 +192,7 @@ define(function (require, exports, module) { } function showErrorPopUp(err) { - if (!err) { + if(!err) { return; } var localizedErrStr = ""; @@ -201,21 +201,15 @@ define(function (require, exports, module) { } else { localizedErrStr = StringUtils.format(Strings[err[0]], err[1]); } - if (!localizedErrStr) { + if(!localizedErrStr) { console.error("Php Tooling Error: " + err); return; } var Buttons = [ - { - className: Dialogs.DIALOG_BTN_CLASS_NORMAL, - id: Dialogs.DIALOG_BTN_CANCEL, - text: Strings.CANCEL - }, - { - className: Dialogs.DIALOG_BTN_CLASS_PRIMARY, - id: Dialogs.DIALOG_BTN_DOWNLOAD, - text: Strings.OPEN_PREFERENNCES - } + { className: Dialogs.DIALOG_BTN_CLASS_NORMAL, id: Dialogs.DIALOG_BTN_CANCEL, + text: Strings.CANCEL }, + { className: Dialogs.DIALOG_BTN_CLASS_PRIMARY, id: Dialogs.DIALOG_BTN_DOWNLOAD, + text: Strings.OPEN_PREFERENNCES} ]; Dialogs.showModalDialog( DefaultDialogs.DIALOG_ID_ERROR, @@ -290,7 +284,7 @@ define(function (require, exports, module) { } } - function initiateService(onAppReady) { + function initiateService(evt, onAppReady) { if (onAppReady) { console.log("Php tooling: Starting the service"); } else { @@ -311,12 +305,10 @@ define(function (require, exports, module) { } AppInit.appReady(function () { - initiateService(true); + initiateService(null, true); ClientLoader.on("languageClientModuleInitialized", initiateService); }); //Only for Unit testing - exports.getClient = function () { - return _client; - }; + exports.getClient = function() { return _client; }; });