From 00b2db982da3c2cb8695679493eff2475a16fe23 Mon Sep 17 00:00:00 2001 From: cormacc Date: Mon, 28 Jan 2019 10:47:03 +0000 Subject: [PATCH] Added support for Microsoft Python Language Server <<26/04/2019>> Incorporated feedback from robbyoconnor and yyoncho. Rebased. <<08/04/2019>> Rebased on develop tip <<17/04/2019>> Rebased <<02/06/2019>> Rebased. Incorporated feedback from duianto. --- CHANGELOG.develop | 6 +++- layers/+lang/python/README.org | 56 ++++++++++++++++++++++++++++++++- layers/+lang/python/config.el | 7 +++++ layers/+lang/python/funcs.el | 21 ++++++------- layers/+lang/python/packages.el | 17 ++++++++++ 5 files changed, 94 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.develop b/CHANGELOG.develop index 5d3050d89..fba0aa3a0 100644 --- a/CHANGELOG.develop +++ b/CHANGELOG.develop @@ -2045,7 +2045,11 @@ Other: - Use =python-mode= for SCons script files (thanks to shanemikel) - Added LSP support, which can be used by enabling the =lsp= layer and setting the =python= layer's =python-backend= variable to =lsp= - (thanks to Yuan Fu and Sylvain Benner) + (thanks to Yuan Fu and Sylvain Benner). +- The LSP backend can use either the =pyls= (default) server or the =mspyls= + (Microsoft) implementation, which may be selected by setting the + =python-lsp-server= layer variable to =mspyls= + (thanks to Cormac Cannon). - Added ~SPC m t l~ key binding to re-run the last test command (thanks to Benoit Coste). - Added support for breakpoints for the =trepan3k= python debugger diff --git a/layers/+lang/python/README.org b/layers/+lang/python/README.org index 39d623643..6aecc1dff 100644 --- a/layers/+lang/python/README.org +++ b/layers/+lang/python/README.org @@ -13,6 +13,8 @@ - [[#backends][Backends]] - [[#anaconda][Anaconda]] - [[#language-server-protocol][Language Server Protocol]] + - [[#python-language-server][python-language-server]] + - [[#microsoft-python-language-server][Microsoft python language server]] - [[#additional-tools][Additional tools]] - [[#syntax-checking][Syntax checking]] - [[#test-runner][Test runner]] @@ -46,7 +48,9 @@ This layer adds support for the Python language. ** Features: - Support for the following backends: - [[https://github.com/proofit404/anaconda-mode][anaconda]] (default), - - [[https://github.com/emacs-lsp/lsp-python][Language Server Protocol]] (experimental), + - [[https://github.com/emacs-lsp/lsp-python][Language Server Protocol]] (experimental - 2 implementations), + - python-language-server + - Microsoft python language server - Auto-completion - Code Navigation - Documentation Lookup using [[https://github.com/proofit404/anaconda-mode][anaconda-mode]] and [[https://github.com/tsgates/pylookup][pylookup]] @@ -87,6 +91,14 @@ Backend can be chosen on a per project basis using directory local variables *Note:* you can easily add a directory local variable with ~SPC f v d~. +The available options are: + +| symbol | description | +|-----------+----------------------------------| +| 'anaconda | Default | +| 'lsp | python-language-server package | +| 'lsp-ms | Microsoft python language server | + * Backends ** Anaconda =anaconda-mode= tries to install the dependencies itself but sometimes @@ -113,6 +125,22 @@ setting your =PYTHONPATH= as explained at [[https://github.com/proofit404/anaconda-mode#pythonpath]] ** Language Server Protocol + +The =lsp= backend can use either of the following language server implementations: + +| symbol | description | +|---------+------------------------------------------| +| 'pyls | python-language-server package (default) | +| 'mspyls | Microsoft python language server | + +=pyls= is used by default - to use the Microsoft server, set the =python-lsp-server= +layer variable as follows: + +#+BEGIN_SRC elisp + (python :variables python-backend 'lsp python-lsp-server 'mspyls) +#+END_SRC + +*** python-language-server You just have to install python language server package: #+BEGIN_SRC sh @@ -133,6 +161,32 @@ dependencies in a pipenv environment, you'll want to set the ~python-pipenv-acti config variable to ~t~. This activates your pipenv before enabling the lsp backend. +*** Microsoft python language server +Paraphrasing the instructions provided by the author of the =lsp-python-ms= package: + +#+BEGIN_SRC sh + git clone https://github.com/Microsoft/python-language-server.git + cd python-language-server/src/LanguageServer/Impl + dotnet build -c Release + dotnet publish -c Release -r +#+END_SRC + +where ~~ is one of the [[https://docs.microsoft.com/en-us/dotnet/core/rid-catalog][runtime IDs supported by dotnet core]]. One of ~linux-x64~, ~osx-x64~, ~win10-x64~ should +cover most use cases. + +The default package configuration assumes the executable is located in a folder included in your system path. +To use the latest built version in a cloned git repo, use the ~python-lsp-git-root~ config variable, e.g.: + +#+BEGIN_SRC elisp + (setq-default dotspacemacs-configuration-layers + '((python :variables + python-backend 'lsp-ms + python-lsp-git-root "~/dev/python/python-language-server"))) +#+END_SRC + +N.B. If you're using Arch linux or a derivative distribution, you can install the =microsoft-python-language-server= +package from the AUR. + * Additional tools ** Syntax checking Syntax checking uses =flake8= package: diff --git a/layers/+lang/python/config.el b/layers/+lang/python/config.el index 667d307c4..8437d7b35 100644 --- a/layers/+lang/python/config.el +++ b/layers/+lang/python/config.el @@ -18,6 +18,13 @@ "The backend to use for IDE features. Possible values are `anaconda' and `lsp'.") +(defvar python-lsp-server 'pyls + "Language server to use for lsp backend. Possible values are `pyls' +and `mspyls'") + +(defvar python-lsp-git-root nil + "If non-nil, use a development version of the language server in this folder") + (defvar python-pipenv-activate nil "If non-nil, activate pipenv before enabling backend") diff --git a/layers/+lang/python/funcs.el b/layers/+lang/python/funcs.el index 17c997f1f..7ff4936e0 100644 --- a/layers/+lang/python/funcs.el +++ b/layers/+lang/python/funcs.el @@ -18,16 +18,15 @@ (defun spacemacs//python-setup-company () "Conditionally setup company based on backend." - (pcase python-backend - (`anaconda (spacemacs//python-setup-anaconda-company)) - (`lsp (spacemacs//python-setup-lsp-company)))) + (if (eq python-backend `anaconda) + (spacemacs//python-setup-anaconda-company) + (spacemacs//python-setup-lsp-company))) (defun spacemacs//python-setup-eldoc () "Conditionally setup eldoc based on backend." (pcase python-backend ;; lsp setup eldoc on its own - (`anaconda (spacemacs//python-setup-anaconda-eldoc)))) - + (spacemacs//python-setup-anaconda-eldoc))) ;; anaconda @@ -89,8 +88,8 @@ (defun spacemacs//python-default () "Defaut settings for python buffers" (setq mode-name "Python" - tab-width python-tab-width - fill-column python-fill-column) + tab-width python-tab-width + fill-column python-fill-column) ;; since we changed the tab-width we need to manually call python-indent-guess-indent-offset here (when python-spacemacs-indent-guess @@ -187,10 +186,10 @@ as the pyenv version then also return nil. This works around https://github.com/ "autoflake --remove-all-unused-imports -i unused_imports.py" (interactive) (if (executable-find "autoflake") - (progn - (shell-command (format "autoflake --remove-all-unused-imports -i %s" - (shell-quote-argument (buffer-file-name)))) - (revert-buffer t t t)) + (progn + (shell-command (format "autoflake --remove-all-unused-imports -i %s" + (shell-quote-argument (buffer-file-name)))) + (revert-buffer t t t)) (message "Error: Cannot find autoflake executable."))) (defun spacemacs//pyenv-mode-set-local-version () diff --git a/layers/+lang/python/packages.el b/layers/+lang/python/packages.el index 74a0cdd1d..9ba29a4dc 100644 --- a/layers/+lang/python/packages.el +++ b/layers/+lang/python/packages.el @@ -43,6 +43,8 @@ ;; packages for anaconda backend anaconda-mode (company-anaconda :requires company) + ;; packages for Microsoft LSP backend + (lsp-python-ms :requires lsp-mode) )) (defun python/init-anaconda-mode () @@ -420,3 +422,18 @@ fix this issue." (eq 'yapf python-formatter)) (add-hook 'python-mode-hook 'yapf-mode))) :config (spacemacs|hide-lighter yapf-mode))) + +(defun python/init-lsp-python-ms () + (use-package lsp-python-ms + :if (eq python-lsp-server 'mspyls) + :ensure nil + :config + + (if python-lsp-git-root + ;; Use dev version of language server checked out from github + (progn + (setq lsp-python-ms-dir + (expand-file-name (concat python-lsp-git-root "/output/bin/Release/"))) + (message "lsp-python-ms: Using version at `%s'" lsp-python-ms-dir)) + ;; Use a precompiled exe + (setq lsp-python-ms-executable "Microsoft.Python.LanguageServer"))))