-
Notifications
You must be signed in to change notification settings - Fork 64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add automatic download for haskell-language-server #97
base: master
Are you sure you want to change the base?
Changes from all commits
32adc69
647d7b9
b6fb370
ba8dce7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
;;; lsp-haskell.el --- Haskell support for lsp-mode | ||
;;; lsp-haskell.el --- Haskell support for lsp-mode -*- lexical-binding: t; -*- | ||
|
||
;; Version: 1.0 | ||
;; Package-Requires: ((lsp-mode "3.0") (haskell-mode "1.0")) | ||
;; Package-Requires: ((lsp-mode "7.0") (haskell-mode "1.0")) | ||
;; Keywords: haskell | ||
;; URL: https://github.com/emacs-lsp/lsp-haskell | ||
|
||
|
@@ -74,14 +74,14 @@ | |
:group 'lsp-haskell | ||
:type 'boolean) | ||
(defcustom lsp-haskell-formatting-provider | ||
"ormolu" | ||
"ormolu" | ||
"The formatter to use when formatting a document or range." | ||
:group 'lsp-haskell | ||
:type '(choice (const :tag "brittany" "brittany") | ||
(const :tag "floskell" "floskell") | ||
(const :tag "fourmolu" "fourmolu") | ||
(const :tag "ormolu" "ormolu") | ||
(const :tag "stylish-haskell" "stylish-haskell") | ||
:type '(choice (const :tag "brittany" "brittany") | ||
(const :tag "floskell" "floskell") | ||
(const :tag "fourmolu" "fourmolu") | ||
(const :tag "ormolu" "ormolu") | ||
(const :tag "stylish-haskell" "stylish-haskell") | ||
(const :tag "none" "none"))) | ||
|
||
;; --------------------------------------------------------------------- | ||
|
@@ -229,7 +229,7 @@ and `lsp-haskell-server-args' and `lsp-haskell-server-wrapper-function'." | |
(funcall lsp-haskell-server-wrapper-function (append (list lsp-haskell-server-path "--lsp") lsp-haskell-server-args) )) | ||
|
||
;; Register all the language server settings with lsp-mode. | ||
;; Note that customizing these will currently *not* send the updated configuration to the server, | ||
;; Note that customizing these will currently *not* send the updated configuration to the server, | ||
;; users must manually restart. See https://github.com/emacs-lsp/lsp-mode/issues/1174. | ||
(lsp-register-custom-settings '( | ||
("haskell.formattingProvider" lsp-haskell-formatting-provider) | ||
|
@@ -246,15 +246,58 @@ and `lsp-haskell-server-args' and `lsp-haskell-server-wrapper-function'." | |
;; https://microsoft.github.io/language-server-protocol/specification#textDocumentItem | ||
(add-to-list 'lsp-language-id-configuration '(haskell-literate-mode . "haskell")) | ||
|
||
(defun lsp-haskell--github-system-type-suffix () | ||
(pcase system-type | ||
('gnu/linux "Linux") | ||
('windows-nt "Windows") | ||
('darwin "macOS"))) | ||
|
||
(defcustom lsp-haskell-language-server-github-releases-url | ||
"https://github.com/haskell/haskell-language-server/releases/latest/download/" | ||
"GitHub releases url for haskell-language-server and its binaries. Make sure to include the trailing directory slash." | ||
:type 'string | ||
:group 'lsp-haskell | ||
:package-version '(lsp-haskell . "1.0")) | ||
|
||
(lsp-dependency | ||
'haskell-language-server-wrapper | ||
'(:system "haskell-language-server-wrapper") | ||
`(:download :url ,(concat lsp-haskell-language-server-github-releases-url | ||
(format "haskell-language-server-wrapper-%s.gz" | ||
(lsp-haskell--github-system-type-suffix))) | ||
:store-path ,(f-join lsp-server-install-dir "haskell" "haskell-language-server-wrapper") | ||
:decompress :gzip | ||
:set-executable? t)) | ||
|
||
(defun lsp-haskell--project-ghc-version () | ||
(let ((wrapper-exe (lsp-package-path 'haskell-language-server-wrapper))) | ||
(if wrapper-exe | ||
(s-trim | ||
(shell-command-to-string | ||
(format "%s --project-ghc-version 2>/dev/null" wrapper-exe))) | ||
nil))) | ||
|
||
;; Register the client itself | ||
(lsp-register-client | ||
(make-lsp--client | ||
:new-connection (lsp-stdio-connection (lambda () (lsp-haskell--server-command))) | ||
:new-connection (lsp-stdio-connection | ||
(lambda () | ||
(let* ((proj-ghc-ver (lsp-haskell--project-ghc-version)) | ||
(server-name (format "haskell-language-server-%s" proj-ghc-ver)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should support bare Possibly this is a use for |
||
(path-exe (executable-find server-name)) | ||
(downloaded-exe | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I understand right, this will actually download the server when we try and start it up. That's not ideal, but I can see the problem: we don't know which version of the server to install until this point, and anyway the user might have multiple projects with different GHC versions. I think it would be nicer if the downloading happened only in |
||
(lsp-download-path | ||
:store-path (f-join lsp-server-install-dir "haskell" server-name) | ||
:set-executable? t))) | ||
(lsp--info "Project GHC version is %s" proj-ghc-ver) | ||
(if path-exe | ||
(list path-exe "--lsp") | ||
(list downloaded-exe "--lsp"))))) | ||
|
||
;; Should run under haskell-mode and haskell-literate-mode. We need to list the | ||
;; latter even though it's a derived mode of the former | ||
:major-modes '(haskell-mode haskell-literate-mode) | ||
;; This is arbitrary. | ||
:server-id 'lsp-haskell | ||
:server-id 'haskell-language-server | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this? Does it matter? In particular, I'm pretty sure it doesn't have to match the name used for |
||
;; We need to manually pull out the configuration section and set it. Possibly in | ||
;; the future lsp-mode will asssociate servers with configuration sections more directly. | ||
:initialized-fn (lambda (workspace) | ||
|
@@ -263,6 +306,26 @@ and `lsp-haskell-server-args' and `lsp-haskell-server-wrapper-function'." | |
;; This is somewhat irrelevant, but it is listed in lsp-language-id-configuration, so | ||
;; we should set something consistent here. | ||
:language-id "haskell" | ||
:download-server-fn (lambda (_client callback error-callback _update?) | ||
(lsp-package-ensure | ||
'haskell-language-server-wrapper | ||
(lambda () | ||
(let* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe a named function |
||
((proj-ghc-ver (lsp-haskell--project-ghc-version)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this will only DTRT if it's run from the project directory? I'm not sure what the right behavior for (Again, this would be less of an issue if we just downloaded everything up front) |
||
(binary-store-path | ||
(f-join lsp-server-install-dir "haskell" (format "haskell-language-server-%s" proj-ghc-ver)))) | ||
(lsp-download-install | ||
callback | ||
error-callback | ||
:url (concat | ||
lsp-haskell-language-server-github-releases-url | ||
(format | ||
"haskell-language-server-%s-%s.gz" | ||
(lsp-haskell--github-system-type-suffix) | ||
proj-ghc-ver)) | ||
:store-path binary-store-path | ||
:decompress :gzip))) | ||
error-callback)) | ||
;; This is required for completions to works inside language pragma statements | ||
:completion-in-comments? t | ||
)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For users who've set up the server binary themselves (and maybe set it with
lsp-haskell-server-path
) it would be nice to not force the use and download of the wrapper.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is something that I've yet to figure out, don't take this code as the intended behaviour! I'm wondering how we should decide to do the automatic download: Check for
lsp-haskell-server-path
first and see if it exists?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, something like that makes sense. So
lsp-haskell-server-path
would be how you signal "I know what I'm doing, please just get out of my way and run this binary". And if it's nil, we do the automatic downloading.