branch: externals/bicep-ts-mode
commit 5a1029df3ea66633d2dc1dca3087792fcde8b3b4
Author: Jostein Kjønigsen <jost...@kjonigsen.net>
Commit: Jostein Kjønigsen <jost...@kjonigsen.net>
Don't depend on VSCode to install language-server.
We can install it ourselves :)
---
README.md | 9 ++++++---
bicep-ts-mode.el | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 61 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index 7ea95eb7c4..57d1aa5cbf 100644
--- a/README.md
+++ b/README.md
@@ -11,9 +11,9 @@ Emacs](https://www.gnu.org/software/emacs/), powered by the
- Syntax highlighting
- Indentation
- Imenu-support, when LSP not configured
-- Automatic eglot-configuration, if Bicep Langserver found with
- configurable default search-location (by default it looks for
- location installed by VSCode Bicep-extension)
+- Automatic LSP langserver installation and eglot-configuration (`M-x
+ bicep-install-langserver`) with configurable search-location when
+ not using default install.
## Prerequisites
@@ -45,6 +45,9 @@ package-manager, so you will have to install both manually.
:rev :newest))
```
+4. Use `M-x bicep-install-langserver` to install or update to latest
+ langserver version.
+
If you have any issues or corrections, feel free to provide a PR to
help others :)
diff --git a/bicep-ts-mode.el b/bicep-ts-mode.el
index 906a9b336f..f5b8beadb1 100644
--- a/bicep-ts-mode.el
+++ b/bicep-ts-mode.el
@@ -30,6 +30,8 @@
;;; Code:
(require 'treesit)
+(require 'json)
+(require 'url)
(declare-function treesit-parser-create "treesit.c")
(declare-function treesit-induce-sparse-tree "treesit.c")
@@ -47,7 +49,8 @@
:type 'natnum
:safe #'natnump)
-(defcustom bicep-ts-mode-default-langserver-path
"$HOME/.vscode/extensions/ms-azuretools.vscode-bicep-*/bicepLanguageServer/Bicep.LangServer.dll"
+(defcustom bicep-ts-mode-default-langserver-path
+ (expand-file-name ".cache/bicep/Bicep.LangServer.dll" user-emacs-directory)
;; FIXME: Document the ability to use $ENV vars and glob patterns?
"Default expression used to locate Bicep Languageserver.
If found, added to eglot."
@@ -177,6 +180,56 @@ If found, added to eglot."
'((ERROR) @font-lock-warning-face))
"Font-lock settings for BICEP.")
+(defun bicep--fetch-json-array (url)
+ "Fetch JSON from URL, extract first array element, and return PROPERTY."
+ (with-current-buffer (url-retrieve-synchronously url t)
+ (goto-char (point-min))
+ (re-search-forward "\n\n") ;; Skip headers
+ (let* ((json-array (json-parse-buffer :array-type 'list)))
+ json-array)))
+
+(defun bicep--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 bicep--get-latest-release-version ()
+ (let* ((release-json (bicep--fetch-json-array
"https://api.github.com/repos/Azure/bicep/releases"))
+ (first (car release-json)) ;; assume first = latest
+ (version (gethash "tag_name" first)))
+ version))
+
+(defun bicep--download-langserver ()
+ (let* ((bicep-dir (expand-file-name ".cache/bicep" user-emacs-directory))
+ (download-dir (expand-file-name "dl" bicep-dir))
+ (download-file (expand-file-name "bicep-langserver.zip"
download-dir)))
+ (make-directory bicep-dir :parents)
+ (make-directory download-dir :parents)
+ (let* ((version (bicep--get-latest-release-version))
+ (url (format
"https://github.com/Azure/bicep/releases/download/%s/bicep-langserver.zip"
version)))
+ (url-copy-file url download-file 't)
+ (bicep--unzip-file download-file bicep-dir)
+ (delete-directory download-dir t)
+ ;; make our function respond with something more interesting than nil :)
+ (message (format "Bicep LangServer version %s downloaded and unpacked to
\'%s\'" version bicep-dir)))))
+
+(defun bicep-install-langserver ()
+ "Downloads the lang-server and unpacks it in the default location."
+ (interactive)
+ (bicep--download-langserver)
+ (bicep--register-langserver))
+
+(defun bicep--register-langserver ()
+ (defvar eglot-server-programs)
+ (and (file-exists-p (bicep-langserver-path))
+ (add-to-list 'eglot-server-programs
+ `(bicep-ts-mode . ("dotnet" ,(bicep-langserver-path))))))
+
+
(defun bicep-langserver-path ()
;; Note: In GNU land, we call this a file name, not a path.
(car (file-expand-wildcards
@@ -262,10 +315,7 @@ Return the first matching node, or nil if none is found."
;;;###autoload
(with-eval-after-load 'eglot
- (defvar eglot-server-programs)
- (and (file-exists-p (bicep-langserver-path))
- (add-to-list 'eglot-server-programs
- `(bicep-ts-mode . ("dotnet" ,(bicep-langserver-path))))))
+ (bicep--register-langserver))
(provide 'bicep-ts-mode)