branch: elpa/powershell
commit 2cb583c2bc4e68ef1097684a4c7acfa549fd0d41
Merge: 92d4d4f9576 21538cdfb6f
Author: Juergen Hoetzel <[email protected]>
Commit: Juergen Hoetzel <[email protected]>
Merge branch 'squashed_eglot_support'
Closes #41
---
README.md | 11 +++++++++
powershell.el | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 88 insertions(+)
diff --git a/README.md b/README.md
index 3d8c20c9eb6..a7ef4d84684 100644
--- a/README.md
+++ b/README.md
@@ -45,6 +45,17 @@ Download `powershell.el` and place the download directory on
your
(add-to-list 'load-path "~/.emacs.d/path/to/powershell")
```
+eglot & LSP Support
+----------------------
+
+`powershell-mode` has built in support for Language Server Protocol
+(LSP) via `eglot`.
+
+To download the latest language-server and register it with `eglot`,
+simply invoke `M-x powershell-install-langserver`.
+
+Doing this when a version is already installed will overwrite it with
+the latest version available.
History
-------
diff --git a/powershell.el b/powershell.el
index 66d9f2cecfc..697909c624e 100644
--- a/powershell.el
+++ b/powershell.el
@@ -118,6 +118,15 @@ Value is a list of strings, which may be nil."
:type '(repeat (string :tag "Argument"))
:group 'powershell)
+(defcustom powershell-default-langserver-path
+ (expand-file-name ".cache/powershell/" user-emacs-directory)
+ "Default expression used to locate Powershell Languageserver.
+If found, added to eglot. Supports environment-variables and glob-pattterns.
+Changes may require an Emacs-restart to take effect."
+ :type 'string
+ :group 'powershell)
+
+
(defun powershell-continuation-line-p ()
"Return t is the current line is a continuation line.
The current line is a continued line when the previous line ends
@@ -1387,6 +1396,74 @@ This insures we get and display the prompt."
;; (insert " "))
;; success)))
+(defun powershell--fetch-json-array (url)
+ "Fetch JSON from URL, parse as if array."
+ (with-temp-buffer (url-insert-file-contents url)
+ (json-parse-buffer :array-type 'list)))
+
+(defun powershell--unzip-file (zip-file destination)
+ "Unzip ZIP-FILE into DESTINATION directory using the 'unzip' shell command."
+ (unless (file-directory-p destination)
+ (make-directory destination :parents)) ;; Ensure the destination
directory exists
+ (let ((exit-code (call-process "unzip" nil nil nil "-o" zip-file "-d"
destination)))
+ (if (zerop exit-code)
+ (message "Successfully unzipped %s to %s" zip-file destination)
+ (error "Failed to unzip %s (exit code %d)" zip-file exit-code))))
+
+(defun powershell--get-latest-release-version ()
+ (let* ((release-json (powershell--fetch-json-array
"https://api.github.com/repos/PowerShell/PowerShellEditorServices/releases"))
+ (first (car release-json)) ;; assume first = latest
+ (version (gethash "tag_name" first)))
+ version))
+
+(defun powershell--download-langserver ()
+ (let* ((powershell-dir (expand-file-name ".cache/powershell"
user-emacs-directory))
+ (download-dir (expand-file-name "dl" powershell-dir))
+ (download-file (expand-file-name "powershell-langserver.zip"
download-dir)))
+ (make-directory powershell-dir :parents)
+ (make-directory download-dir :parents)
+ (let* ((version (powershell--get-latest-release-version))
+ (url (format
"https://github.com/PowerShell/PowerShellEditorServices/releases/download/%s/PowerShellEditorServices.zip"
version)))
+ (url-copy-file url download-file 't)
+ (powershell--unzip-file download-file powershell-dir)
+ (delete-directory download-dir t)
+ ;; make our function respond with something more interesting than nil :)
+ (message (format "Powershell LangServer version %s downloaded and
unpacked to \'%s\'" version powershell-dir)))))
+
+(defun powershell-install-langserver ()
+ "Downloads the lang-server and unpacks it in the default location."
+ (interactive)
+ (powershell--download-langserver)
+ (powershell--register-langserver))
+
+(defun powershell--register-langserver ()
+ (defvar eglot-server-programs)
+ (let* ((langserver-path (powershell-langserver-file-name))
+ (langserver-exe (expand-file-name
"PowerShellEditorServices/Start-EditorServices.ps1" langserver-path)))
+ (and (file-exists-p langserver-exe)
+ (add-to-list 'eglot-server-programs
+ `(powershell-mode . ("pwsh"
+ "-OutputFormat" "Text"
+ "-File"
+ ,langserver-exe
+ "-Stdio"
+ "-HostVersion" "1.0"
+ "-HostName" "Emacs"
+ "-HostProfileId" "Emacs.Eglot"
+ "-SessionDetailsPath"
+ ,(expand-file-name
"eglot-powershell" temporary-file-directory)
+ "-BundledModulesPath"
+ ,langserver-path))))))
+
+
+(defun powershell-langserver-file-name ()
+ (car (file-expand-wildcards
+ (substitute-in-file-name powershell-default-langserver-path))))
+
+;;;###autoload
+(with-eval-after-load 'eglot
+ (powershell--register-langserver))
+
(provide 'powershell)
;;; powershell.el ends here