Skip to content

Commit 485427a

Browse files
authored
Merge pull request #79 from michaelpj/imp/lsp-settings
Rework customization to use lsp-mode's functionality
2 parents 17d7d4c + 63baa1a commit 485427a

File tree

2 files changed

+114
-206
lines changed

2 files changed

+114
-206
lines changed

README.md

Lines changed: 20 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,12 @@ lsp-haskell
44
[![MELPA](https://melpa.org/packages/lsp-haskell-badge.svg)](https://melpa.org/#/lsp-haskell) [![Build Status](https://travis-ci.com/emacs-lsp/lsp-haskell.svg?branch=master)](https://travis-ci.com/emacs-lsp/lsp-haskell)
55

66
An Emacs Lisp library for interacting with
7-
a [haskell-ide-engine](https://github.com/haskell/haskell-ide-engine/)
8-
server using Microsoft's
7+
a Haskell language server such as [`haskell-language-server`](https://github.com/haskell/haskell-langauge-server/)
8+
or [`ghcide`](https://github.com/haskell/ghcide/)
9+
using Microsoft's
910
[Language Server Protocol](https://github.com/Microsoft/language-server-protocol/).
1011

11-
The library is designed to integrate with existing Emacs IDE frameworks
12-
(completion-at-point, xref (beginning with Emacs 25.1), flycheck, haskell-mode, intero, etc).
13-
14-
15-
*This package is still under development, and is not recommended for daily use.*
12+
The library acts as a client for [`lsp-mode`](https://github.com/emacs-lsp/lsp-mode).
1613

1714
## Emacs Configuration
1815

@@ -27,51 +24,27 @@ this repository, or install from MELPA. Add the following to your `.emacs`:
2724

2825
Note: All three packages are also available via MELPA.
2926

30-
It needs the HIE server in your path, so follow the appropriate
27+
It needs the Haskell language server that you plan to use in your path, so follow the appropriate
3128
OSX or Linux section below accordingly.
3229

33-
## Hie Installation (OSX, Linux)
30+
## Language server installation
3431

35-
The following steps are recommended to bootstrap `lsp-haskell` on OSX.
36-
37-
```bash
38-
git clone https://github.com/haskell/haskell-ide-engine
39-
cd haskell-ide-engine
40-
./install.hs hie
41-
```
42-
43-
After this, we need to instruct Emacs to prefer `hie-wrapper` over
44-
`hie` so Hie can infer which version of ghc we need for a particular
45-
project.
46-
47-
```elisp
48-
(setq lsp-haskell-process-path-hie "hie-wrapper")
49-
```
32+
Follow the instructions on the [`haskell-language-server`](https://github.com/haskell/haskell-language-server)
33+
or [`ghcide`](https://github.com/haskell/ghcide/) repositories to install your server of choice.
5034

51-
## Per project configuration
35+
If you have installed a server other than `haskell-language-server`, make sure to
36+
customize the `lsp-haskell-server-path` variable to point to the executable you
37+
have installed (see below).
5238

53-
HIE has some settings that can be changed on the fly. These are
54-
exposed via a set of interactive functions.
39+
## Server configuration
5540

56-
- `lsp-haskell-set-hlint-on` / `lsp-haskell-set-hlint-off` Turn hlint
57-
checks on or off.
58-
- `lsp-haskell-set-max-number-of-problems` Set the maximum number of
59-
diagnostics reported.
60-
- `lsp-haskell-set-liquid-on` / `lsp-haskell-set-liquid-off` Turn
61-
liquid haskell checks on save on or off.
62-
- `lsp-haskell-set-completion-snippets-on` /
63-
`lsp-haskell-set-completion-snippets-off` Whether completion should
64-
return plain text or snippets.
65-
- `lsp-haskell-set-formatter-brittany` /
66-
`lsp-haskell-set-formatter-floskell` /
67-
`lsp-haskell-set-formatter-ormolu` Set code formatter.
41+
`lsp-haskell` exposes a number of configuration options under the `lsp-haskell`
42+
customization group, which should be set like normal customization variables.
43+
Use `M-x customize-group` to get started.
6844

69-
There are also non-interactive versions that do not actually send the
70-
settings to the live server, but are suitable for use in `.dir-locals`
71-
for a specific project.
45+
This includes a few options for for setting the server executable
46+
and arguments, and numerous settings for configuring the server itself (`hlint`,
47+
choice of formatting provider, etc.).
7248

73-
- `lsp-haskell-set-hlint`
74-
- `lsp-haskell-set-max-problems`
75-
- `lsp-haskell-set-liquid`
76-
- `lsp-haskell-set-completion-snippets`
77-
- `lsp-haskell-set-formatter`
49+
Note that server configuration settings will currently [not](https://github.com/emacs-lsp/lsp-mode/issues/1174)
50+
be applied until the server is restarted.

lsp-haskell.el

Lines changed: 94 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -31,38 +31,79 @@
3131
;; ---------------------------------------------------------------------
3232
;; Configuration
3333

34-
;;;###autoload
3534
(defgroup lsp-haskell nil
3635
"Customization group for ‘lsp-haskell’."
3736
:group 'lsp-mode)
3837

39-
;;;###autoload
40-
(defcustom lsp-haskell-process-path-hie
41-
;; "hie"
42-
"hie-wrapper"
43-
"The path for starting the haskell-ide-engine
44-
server. hie-wrapper exists on HIE master from 2018-06-10"
38+
;; ---------------------------------------------------------------------
39+
;; Language server options
40+
41+
;; These are registered with lsp-mode below, which handles preparing them for the server.
42+
;; Originally generated from the vscode extension's package.json using lsp-generate-bindings.
43+
;; Should ideally stay in sync with what's offered in the vscode extension.
44+
45+
(defcustom lsp-haskell-hlint-on
46+
t
47+
"Get suggestions from hlint."
4548
:group 'lsp-haskell
46-
:type '(choice (const "hie-wrapper")
47-
(const "haskell-language-server-wrapper")
48-
(const "ghcide")
49-
string))
50-
51-
;;;###autoload
52-
(defcustom lsp-haskell-process-args-hie
53-
'("-d" "-l" "/tmp/hie.log")
54-
"The arguments for starting the haskell-ide-engine server.
55-
For a debug log, use `-d -l /tmp/hie.log'."
49+
:type 'boolean)
50+
(defcustom lsp-haskell-max-number-of-problems
51+
100
52+
"Controls the maximum number of problems produced by the server."
5653
:group 'lsp-haskell
57-
:type '(repeat (string :tag "Argument")))
54+
:type 'number)
55+
(defcustom
56+
lsp-haskell-diagnostics-on-change
57+
t
58+
"Compute diagnostics continuously as you type. Turn off to only generate diagnostics on file save."
59+
:group 'lsp-haskell
60+
:type 'boolean)
61+
(defcustom lsp-haskell-liquid-on
62+
nil
63+
"Get diagnostics from liquid haskell."
64+
:group 'lsp-haskell
65+
:type 'boolean)
66+
(defcustom lsp-haskell-completion-snippets-on
67+
t
68+
"Show snippets with type information when using code completion."
69+
:group 'lsp-haskell
70+
:type 'boolean)
71+
(defcustom lsp-haskell-format-on-import-on
72+
t
73+
"When adding an import, use the formatter on the result."
74+
:group 'lsp-haskell
75+
:type 'boolean)
76+
(defcustom lsp-haskell-formatting-provider
77+
"ormolu"
78+
"The formatter to use when formatting a document or range."
79+
:group 'lsp-haskell
80+
:type '(choice (const :tag "brittany" "brittany")
81+
(const :tag "floskell" "floskell")
82+
(const :tag "fourmolu" "fourmolu")
83+
(const :tag "ormolu" "ormolu")
84+
(const :tag "stylish-haskell" "stylish-haskell")
85+
(const :tag "none" "none")))
5886

59-
;;;###autoload
60-
(defcustom lsp-haskell-process-wrapper-function
61-
#'identity
62-
"Use this to wrap the haskell-ide-engine process started by lsp-haskell.
87+
;; ---------------------------------------------------------------------
88+
;; Non-language server options
6389

64-
For example, use the following the start the hie process in a nix-shell:
90+
(defcustom lsp-haskell-server-path
91+
"haskell-language-server"
92+
"The language server executable. Can be something on the $PATH (e.g. 'ghcide') or a path to an executable itself."
93+
:group 'lsp-haskell
94+
:type 'string)
95+
96+
(defcustom lsp-haskell-server-args
97+
'("-d" "-l" "/tmp/hls.log")
98+
"The arguments for starting the language server.
99+
For a debug log when using haskell-language-server, use `-d -l /tmp/hls.log'."
100+
:group 'lsp-haskell
101+
:type '(repeat (string :tag "Argument")))
65102

103+
(defcustom lsp-haskell-server-wrapper-function
104+
#'identity
105+
"Use this to wrap the language server process started by lsp-haskell.
106+
For example, use the following the start the process in a nix-shell:
66107
(lambda (argv)
67108
(append
68109
(append (list \"nix-shell\" \"-I\" \".\" \"--command\" )
@@ -76,11 +117,6 @@ For example, use the following the start the hie process in a nix-shell:
76117
(function-item :tag "None" :value identity)
77118
(function :tag "Custom function")))
78119

79-
;; ---------------------------------------------------------------------
80-
;; Internal variables
81-
82-
(defvar lsp-haskell--config-options (make-hash-table))
83-
84120
;; ---------------------------------------------------------------------
85121
;; HaRe functions
86122

@@ -150,6 +186,7 @@ For example, use the following the start the hie process in a nix-shell:
150186
:pos ,(lsp-point-to-position (point))))))
151187

152188
;; ---------------------------------------------------------------------
189+
;; Miscellaneous useful functions
153190

154191
(defun lsp-haskell--session-cabal-dir ()
155192
"Get the session cabal-dir."
@@ -176,144 +213,42 @@ if projectile way fails"
176213
dir))))
177214

178215
;; ---------------------------------------------------------------------
179-
180-
(defun lsp--haskell-hie-command ()
181-
"Comamnd and arguments for launching the inferior hie process.
182-
These are assembled from the customizable variables
183-
`lsp-haskell-process-path-hie' and
184-
`lsp-haskell-process-args-hie'. If the hie executable is
185-
installed via its Makefile, there will be compiler-specific
186-
versions with names like 'hie-8.0.2' or 'hie-8.2.2'."
187-
(append (list lsp-haskell-process-path-hie "--lsp") lsp-haskell-process-args-hie) )
188-
189-
;; ---------------------------------------------------------------------
190-
216+
;; Starting the server and registration with lsp-mode
217+
218+
(defun lsp-haskell--server-command ()
219+
"Command and arguments for launching the inferior language server process.
220+
These are assembled from the customizable variables `lsp-haskell-server-path'
221+
and `lsp-haskell-server-args'."
222+
(append (list lsp-haskell-server-path "--lsp") lsp-haskell-server-args) )
223+
224+
;; Register all the language server settings with lsp-mode.
225+
;; Note that customizing these will currently *not* send the updated configuration to the server,
226+
;; users must manually restart. See https://github.com/emacs-lsp/lsp-mode/issues/1174.
227+
(lsp-register-custom-settings '(
228+
("haskell.formattingProvider" lsp-haskell-formatting-provider)
229+
("haskell.formatOnImportOn" lsp-haskell-format-on-import-on t)
230+
("haskell.completionSnippetsOn" lsp-haskell-completion-snippets-on t)
231+
("haskell.liquidOn" lsp-haskell-liquid-on t)
232+
("haskell.diagnosticsOnChange" lsp-haskell-diagnostics-on-change t)
233+
("haskell.maxNumberOfProblems" lsp-haskell-max-number-of-problems)
234+
("haskell.hlintOn" lsp-haskell-hlint-on t)))
235+
236+
;; Register the client itself
191237
(lsp-register-client
192238
(make-lsp--client
193-
:new-connection (lsp-stdio-connection (lambda () (lsp-haskell--hie-command)))
239+
:new-connection (lsp-stdio-connection (lambda () (lsp-haskell--server-command)))
194240
:major-modes '(haskell-mode)
195-
:server-id 'hie
241+
;; This is arbitrary.
242+
:server-id 'lsp-haskell
243+
;; We need to manually pull out the configuration section and set it. Possibly in
244+
;; the future lsp-mode will asssociate servers with configuration sections more directly.
196245
:initialized-fn (lambda (workspace)
197246
(with-lsp-workspace workspace
198-
(lsp-haskell--set-configuration)))
199-
;; :multi-root t
200-
;; :initialization-options 'lsp-haskell--make-init-options
247+
(lsp--set-configuration (lsp-configuration-section "haskell"))))
248+
;; No need to set :language-id, since there isn't one for Haskell and we
249+
;; don't support multiple languages
201250
))
202251

203-
(defun lsp-haskell--hie-command ()
204-
(funcall lsp-haskell-process-wrapper-function (lsp--haskell-hie-command)))
205-
206-
(cl-defmethod lsp-initialization-options ((_server (eql hie)))
207-
"Initialization options for haskell."
208-
`(:languageServerHaskell ,lsp-haskell--config-options))
209-
210-
;; ---------------------------------------------------------------------
211-
212-
(defun lsp-haskell--set-configuration ()
213-
(lsp--set-configuration `(:languageServerHaskell ,lsp-haskell--config-options)))
214-
215-
(defun lsp-haskell-set-config (name option)
216-
"Set config option NAME to value OPTION in the haskell lsp server."
217-
(puthash name option lsp-haskell--config-options))
218-
219-
;; parseJSON = withObject "Config" $ \v -> do
220-
;; s <- v .: "languageServerHaskell"
221-
;; flip (withObject "Config.settings") s $ \o -> Config
222-
;; <$> o .:? "hlintOn" .!= True
223-
;; <*> o .:? "maxNumberOfProblems" .!= 100
224-
;; <*> o .:? "liquidOn" .!= False
225-
;; <*> o .:? "completionSnippetsOn" .!= True
226-
227-
;; -------------------------------------
228-
229-
(defun lsp-haskell-set-hlint (val)
230-
"Enable(t)/Disable(nil) running hlint."
231-
(lsp-haskell-set-config "hlintOn" val))
232-
233-
(defun lsp-haskell-set-hlint-on ()
234-
"Enable running hlint haskell."
235-
(interactive)
236-
(lsp-haskell-set-hlint t)
237-
(lsp-haskell--set-configuration))
238-
239-
(defun lsp-haskell-set-hlint-off ()
240-
"Disable running hlint."
241-
(interactive)
242-
(lsp-haskell-set-hlint :json-false)
243-
(lsp-haskell--set-configuration))
244-
245-
;; -------------------------------------
246-
247-
(defun lsp-haskell-set-max-problems (val)
248-
"Set maximum number of problems reported to VAL."
249-
(lsp-haskell-set-config "maxNumberOfProblems" val))
250-
251-
(defun lsp-haskell-set-max-number-of-problems (val)
252-
"Set maximum number of problems reported to VAL."
253-
(interactive "nMax number of problems to report: ")
254-
(lsp-haskell-set-max-problems val)
255-
(lsp-haskell--set-configuration))
256-
257-
;; -------------------------------------
258-
259-
(defun lsp-haskell-set-liquid (val)
260-
"Enable(t)/Disable(nil) running liquid haskell on save."
261-
(lsp-haskell-set-config "liquidOn" val))
262-
263-
(defun lsp-haskell-set-liquid-on ()
264-
"Enable running liquid haskell on save."
265-
(interactive)
266-
(lsp-haskell-set-liquid t)
267-
(lsp-haskell--set-configuration))
268-
269-
(defun lsp-haskell-set-liquid-off ()
270-
"Disable running liquid haskell on save."
271-
(interactive)
272-
(lsp-haskell-set-liquid :json-false)
273-
(lsp-haskell--set-configuration))
274-
275-
;; -------------------------------------
276-
277-
(defun lsp-haskell-set-completion-snippets (val)
278-
"Enable(t)/Disable(nil) providing completion snippets."
279-
(lsp-haskell-set-config "completionSnippetsOn" val))
280-
281-
(defun lsp-haskell-set-completion-snippets-on ()
282-
"Enable providing completion snippets."
283-
(interactive)
284-
(lsp-haskell-set-completion-snippets t)
285-
(lsp-haskell--set-configuration))
286-
287-
(defun lsp-haskell-set-completion-snippets-off ()
288-
"Disable providing completion snippets."
289-
(interactive)
290-
(lsp-haskell-set-completion-snippets :json-false)
291-
(lsp-haskell--set-configuration))
292-
293-
;; -------------------------------------
294-
295-
(defun lsp-haskell-set-formatter (val)
296-
"Set code formatter."
297-
(lsp-haskell-set-config "formattingProvider" val))
298-
299-
(defun lsp-haskell-set-formatter-brittany ()
300-
"Use brittany."
301-
(interactive)
302-
(lsp-haskell-set-formatter :brittany)
303-
(lsp-haskell--set-configuration))
304-
305-
(defun lsp-haskell-set-formatter-floskell ()
306-
"Use floskell."
307-
(interactive)
308-
(lsp-haskell-set-formatter :floskell)
309-
(lsp-haskell--set-configuration))
310-
311-
(defun lsp-haskell-set-formatter-ormolu ()
312-
"Use ormolu."
313-
(interactive)
314-
(lsp-haskell-set-formatter :ormolu)
315-
(lsp-haskell--set-configuration))
316-
317252
;; ---------------------------------------------------------------------
318253

319254
(provide 'lsp-haskell)

0 commit comments

Comments
 (0)