diff --git a/README.md b/README.md index c89a784e..4251ad51 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Python language support for [Atom-IDE](https://ide.atom.io/), powered by the [Py ## Requirements -[`ide-python`](https://atom.io/packages/ide-python) requires [Atom `1.21+`](https://atom.io/), [Python language server `0.18+`](https://github.com/palantir/python-language-server) and the [`atom-ide-ui`](https://atom.io/packages/atom-ide-ui) package to expose the functionality within Atom. +[`ide-python`](https://atom.io/packages/ide-python) requires [Atom `1.21+`](https://atom.io/), [Python language server `0.19+`](https://github.com/palantir/python-language-server) and the [`atom-ide-ui`](https://atom.io/packages/atom-ide-ui) package to expose the functionality within Atom. ## Feature Providers @@ -25,15 +25,15 @@ Python language support for [Atom-IDE](https://ide.atom.io/), powered by the [Py ### Language Server -Install the language server with: +Install the language server (0.19.0 or newer) with: ```bash -pip install 'python-language-server[all]' +python -m pip install 'python-language-server[all]' ``` This command will install the language server and all supported feature providers, which can be enabled or disabled in the settings. Checkout the [official installation instructions](https://github.com/palantir/python-language-server#installation) on how to install only the providers you need. -Verify that everything is correctly installed and `pyls` is on your `PATH` by running `pyls --help` from the command line. +You can verify that everything is correctly installed by running `python -m pyls --help` from the command line. It should return ```bash @@ -44,7 +44,7 @@ Python Language Server ... ``` -Depending on your Python setup `pyls` may be installed in a non default folder. In this case either add the directory to your `PATH` or edit the "Python Language Server Path" setting of `ide-python` to point to the `pyls` executable. +If you have installed `pyls` using a non default installation of Python, you can add modify the *Python Executable* config in the `ide-python` settings. ### Atom Package diff --git a/lib/main.js b/lib/main.js index eed494be..b70fd5d4 100644 --- a/lib/main.js +++ b/lib/main.js @@ -24,6 +24,12 @@ class PythonLanguageClient extends AutoLanguageClient { return "ide-python"; } + activate() { + // Remove deprecated option + atom.config.unset("ide-python.pylsPath"); + super.activate(); + } + mapConfigurationObject(configuration) { return { pyls: { @@ -45,27 +51,46 @@ class PythonLanguageClient extends AutoLanguageClient { pylsEnvironment["VIRTUAL_ENV"] = venvPath; } - const childProcess = cp.spawn(atom.config.get("ide-python.pylsPath"), { + const python = atom.config.get("ide-python.python"); + + const childProcess = cp.spawn(python, ["-m", "pyls"], { cwd: projectPath, env: pylsEnvironment }); - childProcess.on("error", err => - atom.notifications.addError("Unable to start the Python language server.", { + + childProcess.on("error", err => { + const description = + err.code == "ENOENT" + ? `No Python interpreter found at \`${python}\`.` + : `Could not spawn the Python interpreter \`${python}\`.`; + atom.notifications.addError("`ide-python` could not launch your Python runtime.", { dismissable: true, - buttons: [ - { - text: "Install Instructions", - onDidClick: () => atom.workspace.open("atom://config/packages/ide-python") - }, - { - text: "Download Python", - onDidClick: () => shell.openExternal("https://www.python.org/downloads/") - } - ], - description: - "This can occur if you do not have Python installed or if it is not in your path.\n\n Make sure to install `pyls` by running:\n```\npip install 'python-language-server[all]'\n```" - }) - ); + description: `${description}
If you have Python installed please set "Python Executable" setting correctly. If you do not please install Python.
` + }); + }); + + childProcess.on("close", (code, signal) => { + if (code !== 0 && signal == null) { + atom.notifications.addError("Unable to start the Python language server.", { + dismissable: true, + buttons: [ + { + text: "Install Instructions", + onDidClick: () => atom.workspace.open("atom://config/packages/ide-python") + }, + { + text: "Download Python", + onDidClick: () => shell.openExternal("https://www.python.org/downloads/") + } + ], + description: + "Make sure to install `pyls` 0.19 or newer by running:\n" + + "```\n" + + `${python} -m pip install 'python-language-server[all]'\n` + + "```" + }); + } + }); return childProcess; } diff --git a/package.json b/package.json index 822e5202..7d690475 100644 --- a/package.json +++ b/package.json @@ -32,12 +32,12 @@ "source.python" ], "configSchema": { - "pylsPath": { - "title": "Python Language Server Path", + "python": { + "title": "Python Executable", "order": 1, "type": "string", - "default": "pyls", - "description": "Absolute path to `pyls` executable." + "default": "python", + "description": "Absolute path of your Python binary. This is used to launch the Python language server. Make sure to install `pyls` for this version of Python. Changes will take effect after a restart of the language server." }, "pylsConfigurationSources": { "order": 2, @@ -46,7 +46,7 @@ "pycodestyle", "flake8" ], - "description": "List of configuration sources to use. Requires `pyls` 0.12.1+", + "description": "List of configuration sources to use.", "items": { "type": "string", "enum": [ @@ -59,7 +59,7 @@ "order": 3, "type": "string", "default": ".ropeproject", - "description": "The name of the folder in which rope stores project configurations and data. Pass `null` for not using such a folder at all. Requires `pyls` 0.17+" + "description": "The name of the folder in which rope stores project configurations and data. Pass `null` for not using such a folder at all." }, "pylsPlugins": { "title": "Python Language Server Plugins", @@ -140,7 +140,7 @@ "title": "All Scopes", "type": "boolean", "default": true, - "description": "If enabled lists the names of all scopes instead of only the module namespace. Requires `pyls` 0.7+" + "description": "If enabled lists the names of all scopes instead of only the module namespace." } } }, @@ -181,7 +181,7 @@ "type": "string" }, "default": [], - "description": "Select errors and warnings. Requires `pyls` 0.14+" + "description": "Select errors and warnings." }, "ignore": { "order": 3, @@ -199,21 +199,21 @@ "items": { "type": "string" }, - "description": "Ignore errors and warnings. Requires `pyls` 0.14+" + "description": "Ignore errors and warnings." }, "hangClosing": { "order": 4, "title": "Hang Closing", "type": "boolean", "default": false, - "description": "Hang closing bracket instead of matching indentation of opening bracket's line. Requires `pyls` 0.12.1+" + "description": "Hang closing bracket instead of matching indentation of opening bracket's line." }, "maxLineLength": { "order": 5, "title": "Max Line Length", "type": "number", "default": 79, - "description": "Set maximum allowed line length. Requires `pyls` 0.12.1+" + "description": "Set maximum allowed line length." } } }, @@ -233,14 +233,14 @@ "title": "Match", "type": "string", "default": "(?!test_).*\\.py", - "description": "Check only files that exactly match the given regular expression; default is to match files that don't start with 'test_' but end with '.py'. Requires `pyls` 0.17+" + "description": "Check only files that exactly match the given regular expression; default is to match files that don't start with 'test_' but end with '.py'." }, "matchDir": { "order": 3, "title": "Match Dir", "type": "string", "default": "[^\\.].*", - "description": "Search only dirs that exactly match the given regular expression; default is to match dirs which do not begin with a dot. Requires `pyls` 0.17+" + "description": "Search only dirs that exactly match the given regular expression; default is to match dirs which do not begin with a dot." }, "select": { "order": 4, @@ -250,7 +250,7 @@ "items": { "type": "string" }, - "description": "Select errors and warnings Requires `pyls` 0.17+" + "description": "Select errors and warnings" }, "ignore": { "order": 5, @@ -260,7 +260,7 @@ "items": { "type": "string" }, - "description": "Ignore errors and warnings Requires `pyls` 0.17+" + "description": "Ignore errors and warnings" }, "convention": { "order": 6, @@ -272,7 +272,7 @@ "" ], "default": "", - "description": "Choose the basic list of checked errors by specifying an existing convention. Requires `pyls` 0.17+" + "description": "Choose the basic list of checked errors by specifying an existing convention." }, "addSelect": { "order": 7, @@ -282,7 +282,7 @@ "items": { "type": "string" }, - "description": "Select errors and warnings in addition to the specified convention. Requires `pyls` 0.17+" + "description": "Select errors and warnings in addition to the specified convention." }, "addIgnore": { "order": 8, @@ -292,7 +292,7 @@ "items": { "type": "string" }, - "description": "Ignore errors and warnings in addition to the specified convention. Requires `pyls` 0.17+" + "description": "Ignore errors and warnings in addition to the specified convention." } } }, @@ -316,7 +316,7 @@ "title": "Enabled", "type": "boolean", "default": false, - "description": "Enable or disable the plugin. Requires `pyls` 0.12.1+" + "description": "Enable or disable the plugin." } } }, @@ -340,7 +340,7 @@ "title": "Enabled", "type": "boolean", "default": true, - "description": "Enable or disable autopep8. Formats code according to PyCodeStyle config. Requires `pyls` 0.17+" + "description": "Enable or disable autopep8. Formats code according to PyCodeStyle config." } } }