-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Php Tooling Extensions Using LSP Framework #14671
Conversation
This PR is Using LSP Framework which are being reviewed in separate PR #14606 . @shubhsnov @swmitra @subhashjha333 please review |
} | ||
|
||
var serverOptions = function (){ | ||
return new Promise(function (resolve, reject) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: The indentation seems off here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentation is correct
var LanguageClient = require(global.LanguageClientInfo.languageClientPath).LanguageClient, | ||
net = require("net"), | ||
cp = require("child_process"), | ||
execa = require("execa"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you introducing a new node_module? (execa)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes execa and semver
confParams["validate_executablePath"] || | ||
(process.platform === 'win32' ? 'php.exe' : 'php'); | ||
|
||
memoryLimit = confParams["memoryLimit"] || 'default'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep the default preferences in Brackets itself, and send from there, instead of using a 'default' string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
}); | ||
// Listen on random port | ||
server.listen(0, '127.0.0.1', function () { | ||
var pathToPHP = __dirname + "/vendor/bin/php-language-server.php"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure this path works for Win and Mac both.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
var clientFilePath = ExtensionUtils.getModulePath(module, "client.js"), | ||
clientName = "PhpClient", | ||
_client = null, | ||
phpConfig = {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comment above. Have defaults set here, which are overridden when the user sets the preferences.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
|
||
PreferencesManager.definePreference("php", "object", { | ||
enablePhpTooling: true, | ||
showDiagnosisOnType: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
showDiagnosisOnType => validateOn{Type, Save} . since we are using validate elsewhere as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
var newPhpConfig = PreferencesManager.get("php"); | ||
|
||
if((newPhpConfig["executablePath"] !== phpConfig["executablePath"]) | ||
|| (newPhpConfig["enablePhpTooling"] !== phpConfig["enablePhpTooling"])) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about validation_executablePath?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed validation_executablePath , as it is not required.
} | ||
|
||
function startPhpServer() { | ||
if(_client && phpConfig["enablePhpTooling"]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two suggestions:
-
Decouple the validation logic from this function. You can do it on App Ready and then prompt the UI on opening a PHP file the first time. Save that to state.
-
I know it seems like a nice optimization to start the server on first open of PHP file, but it doesn't seem like valid enforcement if the extension itself enforces it. Since this is a reference implementation, we'd want to provide the developer with a way where they can defer the activation of the server if they want from the brackets core itself. This is a nice optimization which other LSP extension can leverage as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should always validate Server config before starting.
otherwise if server start fails for any reason (e.g user set wrong executable Path), we wont be able to notify user about failure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's up to you. I find the current way a bit clumsy. Also, I don't think you clearly understood what I meant.
Another thing to note: To test the validation logic against PHP5 and PHP7. Both should give different results, based on syntax. |
@niteskum Please add support for PHP static code hinting as part of this on priority, for completeness. |
@niteskum Some other required features for reference impl: Same for completion resolve. |
@shubhsnov I can see all static code hints and Parameter hints comes from LSP Server except below few variables. are we sure we have to include this in code hints.??, There might be some reason lsp server is not giving these variables as hints. |
if ((newPhpConfig["executablePath"] !== phpConfig["executablePath"]) | ||
|| (newPhpConfig["enablePhpTooling"] !== phpConfig["enablePhpTooling"])) { | ||
phpConfig = newPhpConfig; | ||
startPhpServer(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to differentiate between starting the server and restarting the server. You seem to be just starting the server again and again. I don't see any stop anywhere. Somebody can always change a valid path to another valid path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
var handleProjectOpen = function (event, directory) { | ||
_client.stop() | ||
.done(function () { | ||
setTimeout(function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This timeout is not required. It was for test purpose only,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does not work without timeout function, Can you check from core side.
Better provide a restart function so Extension Developer need not to worry about these things
|
||
PreferencesManager.definePreference("php", "object", { | ||
enablePhpTooling: true, | ||
showDiagnosisOnType: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
Get this resolved. My take is that most of these appear to quite common globals. It would be good to have. |
@shubhsnov Regarding FolderChange Event my understanding is "workspace/didChangeWorkspaceFolders" event is for workspace folder structure change like (folder added or removed from workspace ), not for the workspace project root folder change. correct me if my understanding is wrong. |
Quoting from the actual specification here :
In Brackets we only have one project root, so workspace and project are synonymous. This way we can piggyback on the client capability "workspaceFolders", to change project root. I've done so in the default capabilities. A change in the project root can thus be translated as an addition of a folder and removal of a folder from a workspace which only has one folder. So quoting again:
I believe the reason we have both "rootUri" and "workspaceFolders" in the specification is because of backward compatibility. Earlier the servers didn't support multiple workspace folders, and separate clients had to be created per workspace folder manually in the extension. |
return true; | ||
}; | ||
|
||
CodeHintsProvider.prototype.getHints = function (implicitChar) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need this file. You can create override the getHInts function of the DefaultProvider object since that is the only place is where you need to change anything. See my comments below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see my comment below
}; | ||
|
||
function registerToolingProviders() { | ||
var chProvider = new CodeHintsProvider(_client), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do this instead:
var chProvider = new DefaultProviders.CodeHintsProvider(_client),
chProvider.getHints = yourOwnGetHintsFunction;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see this gives us any benefits, I understand that I have changes only in getHints function but still I have to rewrite all Util functions which are defined in default code Hints provider and I have to access "this" object, If i use "this" variable in normal functions that will look weird. this seems to be an hack code not recommended coding practise.
If you are going to externalise all util functions, then I can reuse your util functions from default provider.
Php server does not support WorkspaceFolders change Notification. so this can not be tested with Php client. so I am not using this in PHP client. we should not ship any feature without having tested. instead I have used servercapabilities.definitionProvider in PHP client this flag is true if Language Server support "go to definition". PHP Server support so i have used this PHP client. |
@niteskum Don't worry, I have added tests for the same already, by creating a sample LSP server, which supports the event. What you need to do here is just check the existence of the server capability |
// There is a bug in Php Language Server, Php Language Server does not provide superGlobals | ||
// Variables as completion. so these variables are being explicity put in response objects | ||
// below code should be removed if php server fix this bug. | ||
for(var key in phpSuperGlobalVariables) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should add the static hints here always, otherwise we'll show hints even when they are not required. It should only come when implicitChar is '$', or otherwise filtered by the current token's prefix in case the token starts with '$'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it will shown only if prefix is '$'. in below code "filterWithQueryAndMatcher" will filter it.
If we are going to use this event , then in initialize function we should also send workspaceFolders which is root_path, this require a change in core side in initialize function. |
For LSP server to work we need PHP 7, with PHP 5 LSP server will not work |
fixed |
"description": "Contains an array of all the arguments passed to the script when running from the command line.", | ||
"type": "array" | ||
}, | ||
"$this": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the "parent" and "self" keyword as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also __destruct.
|
||
function registerToolingProviders() { | ||
var chProvider = new CodeHintsProvider(_client), | ||
phProvider = new DefaultProviders.ParameterHintsProvider(_client), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need servercapabilities in client
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
return matchResults; | ||
} | ||
|
||
CodeHintsProvider.prototype.hasHints = function (editor, implicitChar) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add the ability to add static hints in the Default Provider itself.
|
||
function registerToolingProviders() { | ||
var chProvider = new CodeHintsProvider(_client), | ||
phProvider = new DefaultProviders.ParameterHintsProvider(_client), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@niteskum Please override the hasParameterHints function to handle bug. Use TokenUtils
to check if the previous token is of type "variable", and return true only then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shubhsnov what is the bug?
} | ||
|
||
function restart(project) { | ||
var result = $.Deferred(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try using _client.restart directly.
@niteskum There is a bug with the php server, where it provides the parameter hints just outside the function after the closing parentheses ')'. Can you take a look at this and see if we can do a targeted fix from Brackets side. |
LGTM 👍 💯 |
Please resolve the conflicts @niteskum. |
resolved conflicts in strings.js |
@gavankar I think the Travis CI env configuration should also be updated, for PHP 7 and composer 1.8.4. The CI is failing due to this and will continue to fail otherwise. |
php-Tooling npm package requires felixfbecker/language-server php package, which can only be installed on php7. this should fix the break in brackets travis build
Switch to php7 in travis before dependency installation in travis
Language Server Client Extension using the https://github.com/felixfbecker/php-language-server
Requirements:
Installation:
npm install
Set the following preferences in
to configure the extension: