Skip to content
This repository was archived by the owner on Jul 31, 2023. It is now read-only.

Commit e987d3d

Browse files
seagle0128yyoncho
authored andcommitted
Setup MS PYLS automatically. (#37)
* Setup MS PYLS automatically. Close #33. Get the lastest version of MS PYLS from the Microsoft website, and download to the specified path, then setup to lsp automatically. Additional setup is not necessary. It's out of box. * Add an option for nupkg channel. * Update docstring of lsp-python-ms-update-server for Windows.
1 parent 006bfc7 commit e987d3d

File tree

2 files changed

+114
-82
lines changed

2 files changed

+114
-82
lines changed

README.org

+16-45
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,21 @@
1-
lsp-mode client leveraging microsoft's [[https://github.com/Microsoft/python-language-server][python-language-server]]
1+
=lsp-mode= client leveraging microsoft's [[https://github.com/Microsoft/python-language-server][python-language-server]]
22

33
* Installation
4-
5-
1. Install [[https://www.microsoft.com/net/download][dotnet-sdk]]
6-
2. Clone and install [[https://github.com/Microsoft/python-language-server][python-language-server]]:
7-
#+BEGIN_SRC bash
8-
git clone https://github.com/Microsoft/python-language-server.git
9-
cd python-language-server/src/LanguageServer/Impl
10-
dotnet build -c Release
11-
#+END_SRC
12-
13-
If you choose, compile the language server to a single executable
14-
with:
15-
#+BEGIN_SRC bash
16-
dotnet publish -c Release -r osx-x64 # mac
17-
#+END_SRC
18-
19-
change the value of the ~-r~ flag depending on your architecture and
20-
operating system. See Microsoft's [[https://docs.microsoft.com/en-us/dotnet/core/rid-catalog][Runtime ID Catalog]] for the right
21-
value for your system.
22-
23-
Then, link the executable to somewhere on your path, e.g.
24-
#+BEGIN_SRC bash
25-
ln -sf $(git rev-parse --show-toplevel)/output/bin/Release/osx-x64/publish/Microsoft.Python.LanguageServer ~/.local/bin/
26-
#+END_SRC
27-
note that, on some systems (for example, Fedora), the executable comes out as
28-
~Microsoft.Python.LanguageServer.LanguageServer~.
29-
30-
3. Include ~lsp-python-ms~ in your config in your preferred manner. A
31-
minimal ~use-package~ initialization might be:
32-
33-
#+BEGIN_SRC elisp
34-
(use-package lsp-python-ms
35-
:ensure nil
36-
:hook (python-mode . lsp)
37-
:config
38-
39-
;; for dev build of language server
40-
(setq lsp-python-ms-dir
41-
(expand-file-name "~/python-language-server/output/bin/Release/"))
42-
;; for executable of language server, if it's not symlinked on your PATH
43-
(setq lsp-python-ms-executable
44-
"~/python-language-server/output/bin/Release/osx-x64/publish/Microsoft.Python.LanguageServer"))
45-
#+END_SRC
46-
47-
For developement, you might find it useful to run =cask install=.
4+
Include ~lsp-python-ms~ in the configuration file:
5+
#+BEGIN_SRC emacs-lisp
6+
(require lsp-python-ms)
7+
(add-hook 'python-mode #'lsp) ; or lsp-deferred
8+
#+END_SRC
9+
10+
A minimal ~use-package~ initialization might be:
11+
#+BEGIN_SRC elisp
12+
(use-package lsp-python-ms
13+
:ensure t
14+
:demand
15+
:hook (python-mode . lsp)) ; or lsp-deferred
16+
#+END_SRC
17+
18+
For development, you might find it useful to run =cask install=.
4819
* Credit
4920

5021
All credit to [[https://cpbotha.net][cpbotha]] on [[https://vxlabs.com/2018/11/19/configuring-emacs-lsp-mode-and-microsofts-visual-studio-code-python-language-server/][vxlabs]]! This just tidies and packages his

lsp-python-ms.el

+98-37
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
;; Author: Charl Botha
44
;; Maintainer: Andrew Christianson
5-
;; Version: 0.1.0
5+
;; Version: 0.2.0
66
;; Package-Requires: ((cl-lib "0.6.1") (lsp-mode "6.0") (python "0.26.1") (json "1.4") (emacs "24.4"))
77
;; Homepage: https://github.com/andrew-christianson/lsp-python-ms
88
;; Keywords: languages tools
@@ -39,7 +39,7 @@
3939
;; forward declare variable
4040
(defvar lsp-render-markdown-markup-content)
4141

42-
(defvar lsp-python-ms-dir nil
42+
(defvar lsp-python-ms-dir (expand-file-name "mspyls/" user-emacs-directory)
4343
"Path to language server directory.
4444
4545
This is the directory containing Microsoft.Python.LanguageServer.dll.")
@@ -53,20 +53,6 @@ This is the directory containing Microsoft.Python.LanguageServer.dll.")
5353
;; If this is nil, the language server will write cache files in a directory
5454
;; sibling to the root of every project you visit")
5555

56-
(defun lsp-python-ms--find-dotnet ()
57-
"Get the path to dotnet, or return `lsp-python-ms-dotnet'."
58-
(cond
59-
((boundp 'lsp-python-ms-dotnet) lsp-python-ms-dotnet)
60-
((executable-find "dotnet"))
61-
((eq system-type 'windows-nt) "dotnet")
62-
(t nil)))
63-
64-
(defvar lsp-python-ms-dotnet
65-
(lsp-python-ms--find-dotnet)
66-
"Full path to dotnet executable.
67-
68-
You only need to set this if dotnet is not on your path.")
69-
7056
(defvar lsp-python-ms-extra-paths '()
7157
"A list of additional paths to search for python packages.
7258
@@ -85,19 +71,86 @@ e.g, there are `python2' and `python3', both in system PATH,
8571
and the default `python' links to python2,
8672
set as `python3' to let ms-pyls use python 3 environments.")
8773

88-
(defun lsp-python-ms--find-server-executable ()
89-
"Get path to the python language server executable."
90-
(cond
91-
((boundp 'lsp-python-ms-executable) lsp-python-ms-executable)
92-
((executable-find "Microsoft.Python.LanguageServer"))
93-
((executable-find "Microsoft.Python.LanguageServer.LanguageServer"))
94-
((executable-find "Microsoft.Python.LanguageServer.exe"))
95-
(t nil)))
96-
97-
(defvar lsp-python-ms-executable
98-
(lsp-python-ms--find-server-executable)
74+
(defvar lsp-python-ms-executable (concat lsp-python-ms-dir
75+
"Microsoft.Python.LanguageServer"
76+
(and (eq system-type 'windows-nt) ".exe"))
9977
"Path to Microsoft.Python.LanguageServer.exe.")
10078

79+
(defvar lsp-python-ms-nupkg-channel "stable"
80+
"The channel of nupkg for Microsoft Python Language Server:
81+
stable, beta or daily.")
82+
83+
(defun lsp-python-ms-latest-nupkg-url (&optional channel)
84+
"Get the nupkg url of the latest Microsoft Python Language Server."
85+
(let ((channel (or channel "stable")))
86+
(unless (member channel '("stable" "beta" "daily"))
87+
(error (format "Unknown channel: %s" channel)))
88+
(with-current-buffer
89+
(url-retrieve-synchronously
90+
(format "https://pvsc.blob.core.windows.net/python-language-server-%s\
91+
?restype=container&comp=list&prefix=Python-Language-Server-%s-x64"
92+
channel
93+
(cond ((eq system-type 'darwin) "osx")
94+
((eq system-type 'gnu/linux) "linux")
95+
((eq system-type 'windows-nt) "win")
96+
(t (error (format "Unsupported system: %s" system-type))))))
97+
(goto-char (point-min))
98+
(re-search-forward "\n\n")
99+
(pcase (xml-parse-region (point) (point-max))
100+
(`((EnumerationResults
101+
((ContainerName . ,_))
102+
(Prefix nil ,_)
103+
(Blobs nil . ,blobs)
104+
(NextMarker nil)))
105+
(cdar
106+
(sort
107+
(mapcar (lambda (blob)
108+
(pcase blob
109+
(`(Blob
110+
nil
111+
(Name nil ,_)
112+
(Url nil ,url)
113+
(Properties nil (Last-Modified nil ,last-modified) . ,_))
114+
(cons (encode-time (parse-time-string last-modified)) url))))
115+
blobs)
116+
(lambda (t1 t2)
117+
(time-less-p (car t2) (car t1))))))))))
118+
119+
(defun lsp-python-ms-setup (&optional forced)
120+
"Downloading Microsoft Python Language Server to path specified.
121+
With prefix, FORCED to redownload the server."
122+
(interactive "P")
123+
(unless (and (not forced)
124+
(file-exists-p lsp-python-ms-executable))
125+
(let ((temp-file (make-temp-file "mspyls" nil ".zip"))
126+
(unzip-script (cond ((executable-find "unzip")
127+
"bash -c 'mkdir -p %2$s && unzip -qq %1$s -d %2$s'")
128+
((executable-find "powershell")
129+
"powershell -noprofile -noninteractive \
130+
-nologo -ex bypass Expand-Archive -path '%s' -dest '%s'")
131+
(t nil))))
132+
(message "Downloading Microsoft Python Language Server...")
133+
134+
(url-copy-file (lsp-python-ms-latest-nupkg-url lsp-python-ms-nupkg-channel)
135+
temp-file 'overwrite)
136+
(when (file-exists-p lsp-python-ms-dir)
137+
(delete-directory lsp-python-ms-dir 'recursive))
138+
(shell-command (format unzip-script temp-file lsp-python-ms-dir))
139+
(when (file-exists-p lsp-python-ms-executable)
140+
(chmod lsp-python-ms-executable #o755))
141+
142+
(message "Downloaded Microsoft Python Language Server!"))))
143+
144+
(defun lsp-python-ms-update-server ()
145+
"Update Microsoft Python Language Server.
146+
147+
On Windows, if the server is running, the updating will fail.
148+
After stopping or killing the process, retry to update."
149+
(interactive)
150+
(message "Server update started...")
151+
(lsp-python-ms-setup t)
152+
(message "Server update finished..."))
153+
101154
;; it's crucial that we send the correct Python version to MS PYLS,
102155
;; else it returns no docs in many cases furthermore, we send the
103156
;; current Python's (can be virtualenv) sys.path as searchPaths
@@ -137,7 +190,7 @@ lsp-workspace-root function that finds the current buffer's
137190
workspace root. If nothing works, default to the current file's
138191
directory"
139192
(let ((workspace-root (if workspace (lsp--workspace-root workspace) (lsp-python-ms--workspace-root))))
140-
(cl-destructuring-bind (pyver pysyspath)
193+
(cl-destructuring-bind (pyver _pysyspath)
141194
(lsp-python-ms--get-python-ver-and-syspath workspace-root)
142195
`(:interpreter
143196
(:properties (:InterpreterPath
@@ -160,7 +213,6 @@ directory"
160213
:asyncStartup t
161214
:typeStubSearchPaths ,(vector (concat lsp-python-ms-dir "Typeshed"))))))
162215

163-
164216
(defun lsp-python-ms--filter-nbsp (str)
165217
"Filter nbsp entities from STR."
166218
(let ((rx " "))
@@ -201,26 +253,35 @@ other handlers. "
201253

202254
(defun lsp-python-ms--command-string ()
203255
"Return the command to start the server."
204-
(cond
205-
((lsp-python-ms--find-server-executable))
206-
((and (lsp-python-ms--find-dotnet) lsp-python-ms-dir)
207-
(list (lsp-python-ms--find-dotnet)
208-
(concat lsp-python-ms-dir "Microsoft.Python.LanguageServer.dll")))
209-
(t (error "Could find Microsoft python language server"))))
256+
;; Try to download server if it doesn't exists
257+
(unless (file-exists-p lsp-python-ms-executable)
258+
(lsp-python-ms-setup))
259+
260+
(if (file-exists-p lsp-python-ms-executable)
261+
lsp-python-ms-executable
262+
(error "Could find Microsoft python language server")))
210263

264+
(defgroup lsp-mspyls nil
265+
"LSP support for Python, using Microsoft Python Language Server."
266+
:group 'lsp-mode
267+
:link '(url-link "https://github.com/emacs-lsp/lsp-python-ms"))
211268

212269
;; See https://github.com/microsoft/python-language-server for more diagnostics
213270
(defcustom lsp-mspyls-errors ["unknown-parameter-name"
214271
"undefined-variable"
215272
"parameter-missing"
216273
"positional-argument-after-keyword"
217274
"too-many-function-arguments"]
218-
"Microsoft Python LSP Error types.")
275+
"Microsoft Python LSP Error types."
276+
:group 'lsp-mspyls
277+
:type 'vector)
219278

220279
(defcustom lsp-mspyls-warnings ["unresolved-import"
221280
"parameter-already-specified"
222281
"too-many-positional-arguments-before-star"]
223-
"Microsoft Python LSP Warning types.")
282+
"Microsoft Python LSP Warning types."
283+
:group 'lsp-mspyls
284+
:type 'vector)
224285

225286
(lsp-register-custom-settings '(("python.analysis.errors" lsp-mspyls-errors)))
226287
(lsp-register-custom-settings '(("python.analysis.warnings" lsp-mspyls-warnings)))

0 commit comments

Comments
 (0)