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

Reply via email to