diff --git a/README.md b/README.md index b24b4df..d757a59 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ![](https://img.shields.io/badge/dynamic/json?color=brightgreen&label=Latest%20Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Fmmshivesh%2FPython-Nova.novaextension%2Fmaster%2Fextension.json) -Full featured Python Language Server Plugin (implements [PyLS](https://github.com/palantir/python-language-server)) for Nova, supports Jedi Autocomplete, PyFlakes, PyLint, YAPF, Rope, McCabe, PyDoc and CodeStyles. +Full featured Python Language Server plugin (implements [PyLS](https://github.com/python-lsp/python-lsp-server)) for Nova, supports Jedi Autocomplete, PyFlakes, PyLint, YAPF, Rope, McCabe, PyDoc and CodeStyles. Also supports all the Python Language Server plugins → `mypy`, `isort` and `black` @@ -21,10 +21,10 @@ Also supports all the Python Language Server plugins → `mypy`, `isort` and `bl ## Installation -1. Install dependencies using: +1. Install the LSP server and its dependencies using: ```bash -pip3 install 'python-language-server[all]' +pip3 install 'python-lsp-server[all]' ``` 2. Enable required modules from settings. diff --git a/Scripts/main.js b/Scripts/main.js index d32dbdd..7e4b9b3 100644 --- a/Scripts/main.js +++ b/Scripts/main.js @@ -78,11 +78,49 @@ function getPreference(string, def, workspace=false) { } } +// Convenience function to get the 'pyls.executable' preference, or default to an appropriate bin in the user's $PATH. +function getPyLSExecutablePreference() { + return getPreference('pyls.executable', searchUsablePyLSExecutable()) +} + +// Try to find an appropriate bin for the PyLSP server in the user's $PATH. +function searchUsablePyLSExecutable() { + const envPath = nova.environment['PATH'] + if (envPath === undefined) { + return undefined + } + + const possibleBins = ['pylsp', 'pyls'] + const possiblePaths = envPath.split(':') + for (const bin of possibleBins) { + for (const path of possiblePaths) { + const binPath = path + '/' + bin + if (nova.fs.access(binPath, nova.fs.F_OK | nova.fs.X_OK)) { + return binPath + } + } + } + + return undefined +} + +// Return the appropriate settings namespace for the configured Python LSP implementation. +function getSettingsPyLSNamespace() { + if (getPyLSExecutablePreference() === "pyls") { + return "pyls" + } else { + // If the selected binary is not explicitly pyls, default to the fork + // pylsp as it is more up to date and maintained. + return "pylsp" + } +} + // Get and return the preferences dictionary function getSettings() { return { + const pylsNamespace = getSettingsPyLSNamespace() settings: { - "pyls": { + pylsNamespace: { "env": {}, "configurationSources": [ getPreference('pyls.configurationSources') @@ -205,7 +243,7 @@ class PythonLanguageServer { this.addPreferenceObservers(); // First start. showNotification("Starting extension."); - this.start(getPreference('pyls.executable', '/usr/local/bin/pyls')); + this.start(getPyLSExecutablePreference()); } addPreferenceObservers() { @@ -280,9 +318,9 @@ class PythonLanguageServer { showNotification("Stopping extension."); await this.stop(); nova.subscriptions.remove(this.languageClient); - await this.start(getPreference('pyls.executable', '/usr/local/bin/pyls')); + await this.start(getPyLSExecutablePreference()); } else { - await this.start(getPreference('pyls.executable', '/usr/local/bin/pyls')); + await this.start(getPyLSExecutablePreference()); } }, this); }