Added hover and completion for specials
next on the todo list is macros and globals, and then I want to be able to choose extra globals to add in.
This commit is contained in:
parent
957def8e42
commit
20b9094592
@ -20,6 +20,14 @@ user code."
|
||||
" ...)"))
|
||||
(if docstring (.. "\n" docstring) "")))
|
||||
|
||||
(fn metadata-format [{: binding : metadata}]
|
||||
"formats a special using its builtin metadata magic"
|
||||
(..
|
||||
(code-block
|
||||
(.. "(" (tostring binding) " " (table.concat metadata.fnl/arglist " ") ")"))
|
||||
"\n"
|
||||
metadata.fnl/docstring))
|
||||
|
||||
(λ fn? [symbol]
|
||||
(if (sym? symbol)
|
||||
(let [name (tostring symbol)]
|
||||
@ -27,14 +35,14 @@ user code."
|
||||
(= name "λ")
|
||||
(= name "lambda")))))
|
||||
|
||||
(λ analyze-fn [ast]
|
||||
(λ analyze-fn [?ast]
|
||||
"if ast is a function definition, try to fill out as much of this as possible:
|
||||
{: name
|
||||
: arglist
|
||||
: docstring
|
||||
: fntype}
|
||||
fntype is one of fn or λ or lambda"
|
||||
(case ast
|
||||
(case ?ast
|
||||
;; name + docstring
|
||||
(where [fntype name arglist docstring _body]
|
||||
(fn? fntype)
|
||||
@ -66,13 +74,16 @@ fntype is one of fn or λ or lambda"
|
||||
:value
|
||||
(case (analyze-fn result.definition)
|
||||
{:fntype ?fntype :name ?name :arglist ?arglist :docstring ?docstring} (fn-format ?fntype ?name ?arglist ?docstring)
|
||||
_ (code-block
|
||||
(if (-?>> result.keys length (< 0))
|
||||
_ (if (-?>> result.keys length (< 0))
|
||||
(code-block
|
||||
(.. "ERROR, I don't know how to show this "
|
||||
"(. "
|
||||
(view result.definition {:prefer-colon? true}) " "
|
||||
(view result.keys {:prefer-colon? true}) ")")
|
||||
(view result.definition {:prefer-colon? true}))))})
|
||||
(view result.keys {:prefer-colon? true}) ")"))
|
||||
result.metadata
|
||||
(metadata-format result)
|
||||
(code-block
|
||||
(view result.definition {:prefer-colon? true}))))})
|
||||
|
||||
;; CompletionItemKind
|
||||
(local kinds
|
||||
|
||||
@ -140,7 +140,7 @@ Every time the client sends a message, it gets handled by a function in the corr
|
||||
|
||||
(λ scope-completion [self file byte ?symbol parents]
|
||||
(let [scope (or (accumulate [result nil
|
||||
i parent (ipairs parents)
|
||||
_ parent (ipairs parents)
|
||||
&until result]
|
||||
(. file.scopes parent))
|
||||
file.scope)
|
||||
@ -150,7 +150,7 @@ Every time the client sends a message, it gets handled by a function in the corr
|
||||
(collect-scope scope :manglings #(make-completion-item self file $ scope) result)
|
||||
(when in-call-position?
|
||||
(collect-scope scope :macros #{:label $ :kind kinds.Keyword} result)
|
||||
(collect-scope scope :specials #{:label $ :kind kinds.Keyword} result))
|
||||
(collect-scope scope :specials #(make-completion-item self file $ scope) result))
|
||||
(icollect [_ k (ipairs file.allowed-globals) &into result]
|
||||
{:label k :kind kinds.Variable})))
|
||||
|
||||
@ -162,9 +162,9 @@ Every time the client sends a message, it gets handled by a function in the corr
|
||||
(case (language.search-assignment self file ref stack {})
|
||||
{: definition}
|
||||
(case (values definition (type definition))
|
||||
(_str :string) (icollect [k v (pairs string)]
|
||||
(_str :string) (icollect [k _ (pairs string)]
|
||||
{:label k :kind kinds.Field})
|
||||
(tbl :table) (icollect [k v (pairs tbl)]
|
||||
(tbl :table) (icollect [k _ (pairs tbl)]
|
||||
(if (= (type k) :string)
|
||||
{:label k :kind kinds.Field})))
|
||||
_ nil))))
|
||||
|
||||
@ -90,6 +90,10 @@ the data provided by compiler.fnl."
|
||||
(= 0 (length stack)) {:definition item} ;; BASE CASE !!
|
||||
(error (.. "I don't know what to do with " (view item))))))
|
||||
|
||||
(local {:metadata METADATA
|
||||
:scopes {:global {:specials SPECIALS}}}
|
||||
(require :fennel.compiler))
|
||||
|
||||
(λ search-main [self file symbol opts ?byte]
|
||||
"Find the definition of a symbol
|
||||
|
||||
@ -125,11 +129,8 @@ Returns:
|
||||
(if (sym? symbol)
|
||||
(let [split (utils.multi-sym-split symbol (if ?byte (+ 1 (- ?byte symbol.bytestart))))
|
||||
stack (stack-add-split! [] split)]
|
||||
(local {:metadata METADATA
|
||||
:scopes {:global {:specials SPECIALS}}}
|
||||
(require :fennel.compiler))
|
||||
(case (. METADATA (. SPECIALS (tostring symbol)))
|
||||
metadata {: metadata}
|
||||
metadata {:binding symbol : metadata}
|
||||
_ (case (. file.references symbol)
|
||||
ref (search-assignment self file ref stack opts)
|
||||
_ (case (. file.definitions symbol)
|
||||
@ -141,9 +142,13 @@ Returns:
|
||||
(find-local-definition file name ?scope.parent))))
|
||||
|
||||
(λ search-name-and-scope [self file name scope ?opts]
|
||||
"find a definition just from the name of the item, and the scope it is in"
|
||||
(assert (= (type name) :string))
|
||||
(let [stack (stack-add-multisym! [] name)]
|
||||
(case (find-local-definition file name scope)
|
||||
def (search self file def.definition (stack-add-keys! stack def.keys) (or ?opts {})))))
|
||||
(case (. METADATA (. SPECIALS name))
|
||||
metadata {:binding (sym name) : metadata}
|
||||
_ (case (find-local-definition file name scope)
|
||||
def (search self file def.definition (stack-add-keys! stack def.keys) (or ?opts {}))))))
|
||||
|
||||
(λ past? [?ast byte]
|
||||
;; check if a byte is past an ast object
|
||||
|
||||
@ -119,6 +119,25 @@
|
||||
(assert completion.kind "completion kind should be present")
|
||||
(assert completion.documentation "completion documentation should be present")))))
|
||||
|
||||
; (it "offers rich information about global completions"
|
||||
; (let [client (doto (create-client)
|
||||
; (: :open-file! filename "("))
|
||||
; [{:result completions}] (client:completion filename 0 1)
|
||||
; _ (table.sort completions #(< $1.label $2.label))
|
||||
; count (accumulate [sum 0 _ completion (ipairs completions)]
|
||||
; (if (and (= (type completion.label) :string)
|
||||
; (= (type completion.kind) :number)
|
||||
; (= (type completion.documentation) :table))
|
||||
; (+ sum 1)
|
||||
; sum))]
|
||||
; (if (< count (length completions))
|
||||
; (print "!!!" (- (length completions) count) "items are missing a label or kind or doc"))
|
||||
; (each [_ completion (ipairs completions)]
|
||||
; (is.same (type completion.label) :string "unlabeled completion")
|
||||
; (is.same (type completion.kind) :number (.. completion.label " needs a kind"))
|
||||
; (is.same (type completion.documentation) :table (.. completion.label " needs documentation")))))))
|
||||
|
||||
|
||||
;; (it "offers rich information about macro completions")
|
||||
;; (it "offers rich information about variable completions")
|
||||
;; (it "offers rich information about field completions")
|
||||
|
||||
@ -49,4 +49,7 @@
|
||||
(is-matching message [{:jsonrpc "2.0" :id 2}] "")))
|
||||
|
||||
(it "can go backward through (case)"
|
||||
(check "hover.fnl" 22 22 "```fnl\n{:AB :CD}\n```")))
|
||||
(check "hover.fnl" 22 22 "```fnl\n{:AB :CD}\n```"))
|
||||
|
||||
(it "hovers over a special"
|
||||
(check "hover.fnl" 5 2 "```fnl\n(let [name1 val1 ... nameN valN] ...)\n```\nIntroduces a new scope in which a given set of local bindings are used.")))
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
(local {: view} (require :fennel))
|
||||
(local {: expect} (require :test.lust))
|
||||
;; lust uses weird terminology, but equal is by __eq, same is by recursively having the same contents
|
||||
(setmetatable {:equal #(do ((. (expect $1) :to :be) $2) true)
|
||||
:same #(do ((. (expect $1) :to :equal) $2) true)
|
||||
(setmetatable {:equal #(do ((. (expect $1) :to :be) $2) true)
|
||||
:same #(do ((. (expect $1) :to :equal) $2 $3) true)
|
||||
:nil #(do ((. (expect $1) :to_not :exist)) true)
|
||||
:not {:nil #(do ((. (expect $1) :to :exist)) true)}
|
||||
:truthy #(do ((. (expect $1) :to :be :truthy)) true)}
|
||||
|
||||
@ -147,10 +147,10 @@ local paths = {
|
||||
end
|
||||
},
|
||||
equal = {
|
||||
test = function(v, x)
|
||||
test = function(v, x, message)
|
||||
return strict_eq(v, x),
|
||||
'expected ' .. tostring(v) .. ' and ' .. tostring(x) .. ' to be exactly equal',
|
||||
'expected ' .. tostring(v) .. ' and ' .. tostring(x) .. ' to not be exactly equal'
|
||||
message or 'expected ' .. tostring(v) .. ' and ' .. tostring(x) .. ' to be exactly equal',
|
||||
message or 'expected ' .. tostring(v) .. ' and ' .. tostring(x) .. ' to not be exactly equal'
|
||||
end
|
||||
},
|
||||
have = {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user