Skip to content

Commit bcfe134

Browse files
committed
Merge pull request #1172 from geraldus/g/non-interactive-completions
Support simple completions in non-interactive context. Support keyword completions
2 parents 2193190 + c990a4f commit bcfe134

File tree

4 files changed

+134
-33
lines changed

4 files changed

+134
-33
lines changed

haskell-completions.el

Lines changed: 125 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
;;; haskell-completions.el --- Haskell Completion package -*- lexical-binding: t -*-
22

3-
;; Copyright © 2015 Athur Fayzrakhmanov. All rights reserved.
3+
;; Copyright © 2015-2016 Athur Fayzrakhmanov. All rights reserved.
44

55
;; This file is part of haskell-mode package.
66
;; You can contact with authors using GitHub issue tracker:
@@ -40,7 +40,7 @@
4040
(require 'haskell-process)
4141
(require 'haskell-interactive-mode)
4242

43-
(defvar haskell-completions-pragma-names
43+
(defvar haskell-completions--pragma-names
4444
(list "DEPRECATED"
4545
"INCLUDE"
4646
"INCOHERENT"
@@ -63,8 +63,51 @@
6363
"WARNING")
6464
"A list of supported pragmas.
6565
This list comes from GHC documentation (URL
66-
`https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/pragmas.html'.
67-
")
66+
`https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/pragmas.html'.")
67+
68+
(defvar haskell-completions--keywords
69+
(list
70+
"as"
71+
"case"
72+
"class"
73+
"data family"
74+
"data instance"
75+
"data"
76+
"default"
77+
"deriving instance"
78+
"deriving"
79+
"do"
80+
"else"
81+
"family"
82+
"forall"
83+
"foreign import"
84+
"foreign"
85+
"hiding"
86+
"if"
87+
"import qualified"
88+
"import"
89+
"in"
90+
"infix"
91+
"infixl"
92+
"infixr"
93+
"instance"
94+
"let"
95+
"mdo"
96+
"module"
97+
"newtype"
98+
"of"
99+
"proc"
100+
"qualified"
101+
"rec"
102+
"then"
103+
"type family"
104+
"type instance"
105+
"type"
106+
"where")
107+
"A list of Haskell's keywords (URL `https://wiki.haskell.org/Keywords').
108+
Single char keywords and operator like keywords are not included
109+
in this list.")
110+
68111

69112
(defun haskell-completions-can-grab-prefix ()
70113
"Check if the case is appropriate for grabbing completion prefix.
@@ -206,9 +249,20 @@ identifier at point depending on result of function
206249
Returns a list of form '(prefix-start-position
207250
prefix-end-position prefix-value prefix-type) depending on
208251
situation, e.g. is it needed to complete pragma, module name,
209-
arbitrary identifier, etc. Returns nil in case it is
252+
arbitrary identifier, etc. Returns nil in case it is
210253
impossible to grab prefix.
211254
255+
Possible prefix types are:
256+
257+
* haskell-completions-pragma-name-prefix
258+
* haskell-completions-ghc-option-prefix
259+
* haskell-completions-language-extension-prefix
260+
* haskell-completions-module-name-prefix
261+
* haskell-completions-identifier-prefix
262+
* haskell-completions-general-prefix
263+
264+
the last type is used in cases when completing things inside comments.
265+
212266
If provided optional MINLEN parameter this function will return
213267
result only if prefix length is not less than MINLEN."
214268
(when (haskell-completions-can-grab-prefix)
@@ -220,36 +274,77 @@ result only if prefix length is not less than MINLEN."
220274
prefix))
221275
(prefix prefix)))))
222276

277+
(defun haskell-completions--simple-completions (prefix)
278+
"Provide a list of completion candidates for given PREFIX.
279+
This function is used internally in
280+
`haskell-completions-completion-at-point' and
281+
`haskell-completions-sync-repl-completion-at-point'.
282+
283+
It provides completions for haskell keywords, language pragmas,
284+
GHC's options, and language extensions.
285+
286+
PREFIX should be a list such one returned by
287+
`haskell-completions-grab-identifier-prefix'."
288+
(cl-destructuring-bind (beg end _pfx typ) prefix
289+
(let ((candidates
290+
(cl-case typ
291+
('haskell-completions-pragma-name-prefix
292+
haskell-completions--pragma-names)
293+
('haskell-completions-ghc-option-prefix
294+
haskell-ghc-supported-options)
295+
('haskell-completions-language-extension-prefix
296+
haskell-ghc-supported-extensions)
297+
(otherwise
298+
haskell-completions--keywords))))
299+
(list beg end candidates))))
300+
301+
302+
(defun haskell-completions-completion-at-point ()
303+
"Provide completion list for thing at point.
304+
This function is used in non-interactive `haskell-mode'. It
305+
provides completions for haskell keywords, language pragmas,
306+
GHC's options, and language extensions, but not identifiers."
307+
(let ((prefix (haskell-completions-grab-prefix)))
308+
(haskell-completions--simple-completions prefix)))
309+
310+
(defun haskell-completions-sync-repl-completion-at-point ()
311+
"A completion function used in `interactive-haskell-mode'.
312+
Completion candidates are provided quering current haskell
313+
process, that is sending `:complete repl' command.
314+
315+
Completes all possible things: everything that can be completed
316+
with non-interactive function
317+
`haskell-completions-completion-at-point' plus identifier
318+
completions.
223319
224-
(defun haskell-completions-sync-completions-at-point ()
225-
"A `completion-at-point' function using the current haskell process.
226320
Returns nil if no completions available."
227321
(let ((prefix-data (haskell-completions-grab-prefix)))
228322
(when prefix-data
229323
(cl-destructuring-bind (beg end pfx typ) prefix-data
230-
(let ((imp (eql typ 'haskell-completions-module-name-prefix))
231-
lst)
232-
(setq lst
233-
(cl-case typ
234-
;; non-interactive completions first
235-
('haskell-completions-pragma-name-prefix
236-
haskell-completions-pragma-names)
237-
('haskell-completions-ghc-option-prefix
238-
haskell-ghc-supported-options)
239-
('haskell-completions-language-extension-prefix
240-
haskell-ghc-supported-extensions)
241-
(otherwise
242-
(when (and
243-
(not (eql typ 'haskell-completions-general-prefix))
244-
(haskell-session-maybe)
245-
(not
246-
(haskell-process-cmd (haskell-interactive-process))))
247-
;; if REPL is available and not busy try to query it
248-
;; for completions list in case of module name or
249-
;; identifier prefixes
250-
(haskell-completions-sync-complete-repl pfx imp)))))
251-
(when lst
252-
(list beg end lst)))))))
324+
(when (not (eql typ 'haskell-completions-general-prefix))
325+
;; do not complete things in comments
326+
(if (cl-member
327+
typ
328+
'(haskell-completions-pragma-name-prefix
329+
haskell-completions-ghc-option-prefix
330+
haskell-completions-language-extension-prefix))
331+
;; provide simple completions
332+
(haskell-completions--simple-completions prefix-data)
333+
;; only two cases left: haskell-completions-module-name-prefix
334+
;; and haskell-completions-identifier-prefix
335+
(let* ((is-import (eql typ 'haskell-completions-module-name-prefix))
336+
(candidates
337+
(when (and (haskell-session-maybe)
338+
(not (haskell-process-cmd
339+
(haskell-interactive-process))))
340+
;; if REPL is available and not busy try to query it for
341+
;; completions list in case of module name or identifier
342+
;; prefixes
343+
(haskell-completions-sync-complete-repl pfx is-import))))
344+
;; append candidates with keywords
345+
(list beg end (append
346+
candidates
347+
haskell-completions--keywords)))))))))
253348

254349
(defun haskell-completions-sync-complete-repl (prefix &optional import)
255350
"Return completion list for given PREFIX querying REPL synchronously.

haskell-interactive-mode.el

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1016,7 +1016,8 @@ don't care when the thing completes as long as it's soonish."
10161016
(remove-overlays))))
10171017

10181018
(defun haskell-interactive-mode-completion-at-point-function ()
1019-
"Offer completions for partial expression between prompt and point"
1019+
"Offer completions for partial expression between prompt and point.
1020+
This completion function is used in interactive REPL buffer itself."
10201021
(when (haskell-interactive-at-prompt)
10211022
(let* ((process (haskell-interactive-process))
10221023
(inp (haskell-interactive-mode-input-partial))

haskell-mode.el

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,11 @@ Minor modes that work well with `haskell-mode':
783783
(setq haskell-literate nil)
784784
(add-hook 'before-save-hook 'haskell-mode-before-save-handler nil t)
785785
(add-hook 'after-save-hook 'haskell-mode-after-save-handler nil t)
786+
;; provide non-interactive completion function
787+
(add-hook 'completion-at-point-functions
788+
#'haskell-completions-completion-at-point
789+
nil
790+
t)
786791
(haskell-indentation-mode))
787792

788793
(defun haskell-fill-paragraph (justify)

haskell.el

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@
6767
:lighter " Interactive"
6868
:keymap interactive-haskell-mode-map
6969
(add-hook 'completion-at-point-functions
70-
#'haskell-completions-sync-completions-at-point
70+
#'haskell-completions-sync-repl-completion-at-point
7171
nil
7272
t))
7373

7474
(make-obsolete 'haskell-process-completions-at-point
75-
'haskell-completions-sync-completions-at-point
75+
'haskell-completions-sync-repl-completion-at-point
7676
"June 19, 2015")
7777
(defun haskell-process-completions-at-point ()
7878
"A completion-at-point function using the current haskell process."

0 commit comments

Comments
 (0)