-
-
Notifications
You must be signed in to change notification settings - Fork 149
/
signature_help.clj
91 lines (84 loc) · 4.09 KB
/
signature_help.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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
(ns clojure-lsp.feature.signature-help
(:require
[clojure-lsp.feature.file-management :as f.file-management]
[clojure-lsp.parser :as parser]
[clojure-lsp.queries :as q]
[clojure-lsp.refactor.edit :as edit]
[clojure-lsp.shared :as shared :refer [assoc-some]]
[edamame.core :as edamame]
[rewrite-clj.node :as n]
[rewrite-clj.zip :as z])
(:import
[clojure.lang PersistentVector]))
(set! *warn-on-reflection* true)
(defn ^:private function-loc->arglist-nodes [zloc]
(->> zloc
z/up
z/node
n/children
(remove n/whitespace-or-comment?)
(drop 1)))
(defn ^:private get-active-parameter-index
[signatures active-signature arglist-nodes cursor-row cursor-col]
(let [params-count (-> (nth signatures active-signature)
:parameters
count)
selected-arg (->> arglist-nodes
reverse
(filter (fn [node]
(let [{:keys [row col]} (meta node)]
(or (< row cursor-row)
(and (= row cursor-row)
(<= col cursor-col))))))
first)]
(if selected-arg
(let [index (.indexOf ^PersistentVector (vec arglist-nodes) selected-arg)]
(if (> index (dec params-count))
(dec params-count)
index))
0)))
(defn ^:private get-active-signature-index [{:keys [fixed-arities arglist-strs]} arglist-nodes]
(let [arities (vec (sort-by max (if fixed-arities
(if (= (count fixed-arities) (count arglist-strs))
fixed-arities
(conj fixed-arities (inc (apply max fixed-arities))))
#{(count arglist-strs)})))
args-count (count arglist-nodes)
current-arity (first (filter #(= % args-count) arities))]
(if current-arity
(.indexOf ^PersistentVector arities current-arity)
(if (>= args-count (count arities))
(.indexOf ^PersistentVector arities (apply max arities))
(.indexOf ^PersistentVector arities (apply min arities))))))
(defn ^:private arglist-str->parameters [arglist-str]
(let [parameters (edamame/parse-string arglist-str {:auto-resolve #(symbol (str ":" %))})
rest-args? (some #(= '& %) parameters)
available-params (filter (complement #(= '& %)) parameters)
params-count (dec (count available-params))]
(->> available-params
(map-indexed (fn [index arg]
(let [last-arg? (= index params-count)]
(if (and rest-args? last-arg?)
{:label (format "& %s" arg)}
{:label (str arg)})))))))
(defn ^:private definition->signature-informations [{:keys [arglist-strs] :as definition}]
(map (fn [arglist-str]
(-> {:label (format "(%s %s)" (-> definition :name str) arglist-str)
:parameters (arglist-str->parameters arglist-str)}
(assoc-some :documentation (:doc definition))))
arglist-strs))
(defn signature-help [uri row col {:keys [db*] :as components}]
(when-let [function-loc (some-> (f.file-management/force-get-document-text uri components)
parser/safe-zloc-of-string
(parser/to-pos row col)
edit/find-function-usage-name-loc)]
(let [db @db*
arglist-nodes (function-loc->arglist-nodes function-loc)
function-meta (meta (z/node function-loc))
definition (q/find-definition-from-cursor db uri (:row function-meta) (:col function-meta))
signatures (definition->signature-informations definition)
active-signature (get-active-signature-index definition arglist-nodes)]
(when (seq signatures)
{:signatures signatures
:active-parameter (get-active-parameter-index signatures active-signature arglist-nodes row col)
:active-signature active-signature}))))