-
-
Notifications
You must be signed in to change notification settings - Fork 97
/
completion.clj
69 lines (60 loc) · 3.22 KB
/
completion.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
(ns nrepl.middleware.completion
"Code completion middleware.
The middleware is a simple wrapper around the
functionality in `nrepl.completion`. Its
API is inspired by cider-nrepl's \"complete\" middleware.
The middleware can be configured to use a different completion
function via a dynamic variable or a request parameter.
NOTE: The functionality here is experimental and
the API is subject to changes."
{:author "Bozhidar Batsov"
:added "0.8"}
(:require
[clojure.walk :as walk]
[nrepl.util.completion :as complete]
[nrepl.middleware :as middleware :refer [set-descriptor!]]
[nrepl.misc :refer [response-for] :as misc]
[nrepl.transport :as t])
(:import nrepl.transport.Transport))
(def ^:dynamic *complete-fn*
"Function to use for completion. Takes three arguments: `prefix`, the completion prefix,
`ns`, the namespace in which to look for completions, and `options`, a map of additional
options for the completion function."
complete/completions)
(def ^:private parse-options
(memoize
(fn [options]
(update (walk/keywordize-keys options) :extra-metadata (comp set (partial map keyword))))))
(defn completion-reply
[{:keys [session prefix ns complete-fn options] :as msg}]
(let [ns (if ns (symbol ns) (symbol (str (@session #'*ns*))))
completion-fn (or (and complete-fn (misc/requiring-resolve (symbol complete-fn))) *complete-fn*)]
(try
(response-for msg {:status :done :completions (completion-fn prefix ns (parse-options options))})
(catch Exception _e
(if (nil? ns)
(response-for msg {:status #{:done :completion-error}})
(response-for msg {:status #{:done :completion-error :namespace-not-found}}))))))
(defn wrap-completion
"Middleware that provides code completion.
It understands the following params:
* `prefix` - the prefix which to complete.
* `ns`- the namespace in which to do completion. Defaults to `*ns*`.
* `complete-fn` – a fully-qualified symbol naming a var whose function to use for
completion. Must point to a function with signature [prefix ns options].
* `options` – a map of options to pass to the completion function."
[h]
(fn [{:keys [op ^Transport transport] :as msg}]
(if (= op "completions")
(t/send transport (completion-reply msg))
(h msg))))
(set-descriptor! #'wrap-completion
{:requires #{"clone"}
:expects #{}
:handles {"completions"
{:doc "Provides a list of completion candidates."
:requires {"prefix" "The prefix to complete."}
:optional {"ns" "The namespace in which we want to obtain completion candidates. Defaults to `*ns*`."
"complete-fn" "The fully qualified name of a completion function to use instead of the default one (e.g. `my.ns/completion`)."
"options" "A map of options supported by the completion function. Supported keys: `extra-metadata` (possible values: `:arglists`, `:docs`)."}
:returns {"completions" "A list of completion candidates. Each candidate is a map with `:candidate` and `:type` keys. Vars also have a `:ns` key."}}}})