better completions in destructure bindings

This commit is contained in:
XeroOl 2025-07-08 21:59:53 -05:00
parent b7e497228f
commit 28e20f74cb
4 changed files with 87 additions and 51 deletions

View File

@ -293,7 +293,16 @@ identifiers are declared / referenced in which places."
(let [old (tostring ?ast)]
(tset ?ast 1 "!!invalid-multi-symbol!!")
(table.insert defer #(tset ?ast 1 old))
true))))
true))
(when (and (= 1 (msg:find "expected name and value"))
(list? ?ast))
(when (= 1 (length ?ast))
(table.insert ?ast (sym "_"))
(table.insert defer #(table.remove ?ast)))
(when (= 2 (length ?ast))
(table.insert ?ast nil*)
(table.insert defer #(table.remove ?ast)))
(= 3 (length ?ast)))))
(λ on-compile-error [_ msg ast call-me-to-reset-the-compiler]
(let [range (or (message.ast->range server file ast)

View File

@ -40,7 +40,7 @@
"add the completion. also recursively adds the fields' completions"
(when (not (. seen definition))
(set (. seen definition) true)
(add-completion! name definition)
(add-completion! name definition "Value")
(each [field def ?string-method (navigate.iter-fields server definition)]
(if (or (= :self (tostring (?. def :metadata :fnl/arglist 1)))
?string-method
@ -56,62 +56,77 @@
(add-completion-recursively! (.. name "." field) def)))
(set (. seen definition) false)))
(each [name documentation (pairs hardcoded-completions)]
(add-completion! name documentation))
(fn expression-completions []
(each [name documentation (pairs hardcoded-completions)]
(add-completion! name documentation))
(local seen-manglings {})
(local seen-manglings {})
(each [_ global* (ipairs file.allowed-globals)]
(when (not (. seen-manglings global*))
(set (. seen-manglings global*) true)
(case (analyzer.search-name-and-scope server file global* scope)
def (if (and (= :_G (tostring global*))
(not (: (tostring ?symbol) :match "_G[:.]")))
(add-completion! global* def)
(add-completion-recursively! global* def))
_ (do
(io.stderr:write "BAD!!!! undocumented global: " (tostring global*) "\n")
(add-completion! global* {})))))
(each [_ global* (ipairs file.allowed-globals)]
(when (not (. seen-manglings global*))
(set (. seen-manglings global*) true)
(case (analyzer.search-name-and-scope server file global* scope)
def (if (and (= :_G (tostring global*))
(not (: (tostring ?symbol) :match "_G[:.]")))
(add-completion! global* def)
(add-completion-recursively! global* def))
_ (do
(io.stderr:write "BAD!!!! undocumented global: " (tostring global*) "\n")
(add-completion! global* {})))))
(var scope scope)
(while scope
(each [mangling (pairs scope.manglings)]
(when (not (. seen-manglings mangling))
(set (. seen-manglings mangling) true)
(case (analyzer.search-name-and-scope server file mangling scope)
def (add-completion-recursively! mangling def)
_ (add-completion-recursively! mangling {}))))
(when in-call-position?
(each [macro* macro-value (pairs scope.macros)]
(add-completion! macro*
{:binding macro*
:metadata (. METADATA macro-value)}
:Keyword))
(each [special (pairs scope.specials)]
(case (analyzer.search-name-and-scope server file special scope)
def (add-completion! special def :Operator)
_ (do
(io.stderr:write "BAD!!!! undocumented special: " (tostring special) "\n")
{:label special}))))
(set scope scope.parent)))
(fn binding-completions []
"completions when you're writing a destructure pattern. We suggest identifiers which are unknown"
(each [_ {: message} (ipairs file.diagnostics)]
(case (message:match "unknown identifier: ([a-zA-Z0-9_-]+)")
identifier (add-completion! identifier {} :Variable))))
(if (. file.definitions ?symbol)
(binding-completions)
(expression-completions))
(var scope scope)
(while scope
(each [mangling (pairs scope.manglings)]
(when (not (. seen-manglings mangling))
(set (. seen-manglings mangling) true)
(case (analyzer.search-name-and-scope server file mangling scope)
def (add-completion-recursively! mangling def)
_ (add-completion-recursively! mangling {}))))
(when in-call-position?
(each [macro* macro-value (pairs scope.macros)]
(add-completion! macro*
{:binding macro*
:metadata (. METADATA macro-value)}
:Keyword))
(each [special (pairs scope.specials)]
(case (analyzer.search-name-and-scope server file special scope)
def (add-completion! special def :Operator)
_ (do
(io.stderr:write "BAD!!!! undocumented special: " (tostring special) "\n")
{:label special}))))
(set scope scope.parent))
(if server.can-do-good-completions?
{:itemDefaults {:editRange range :data {: uri : byte}}
:items results}
results)))
(fn completionItem/resolve [server _send completion-item]
(or (. hardcoded-completions completion-item.label)
(let [{: uri : byte} completion-item.data
file (files.get-by-uri server uri)
(_symbol parents) (analyzer.find-symbol file.ast byte)
scope (or (accumulate [?find nil _ parent (ipairs parents) &until ?find]
(. file.scopes parent))
file.scope)]
(case (analyzer.search-name-and-scope server file completion-item.label scope)
result (doto completion-item (tset :documentation (format.hover-format server completion-item.label result)))))))
(let [result
(or (. hardcoded-completions completion-item.name)
(let [{: uri : byte} completion-item.data
file (files.get-by-uri server uri)
(_symbol parents) (analyzer.find-symbol file.ast byte)
scope (or (accumulate [?find nil _ parent (ipairs parents) &until ?find]
(. file.scopes parent))
file.scope)]
(analyzer.search-name-and-scope server file completion-item.label scope)))]
(when result
(set completion-item.documentation (format.hover-format server completion-item.label result)))
completion-item))
{: textDocument/completion
: completionItem/resolve}

View File

@ -193,12 +193,13 @@ fntype is one of fn or λ or lambda"
{:label name
:documentation (when (not server.can-do-good-completions?) (hover-format server name definition))
:textEdit (when (not server.can-do-good-completions?) {:newText name : range})
:kind (or (?. kinds ?kind)
:kind (or (if (not= ?kind :Value) (?. kinds ?kind))
(case (navigate.getmetadata server definition)
metadata
(or (?. kinds metadata.fls/itemKind)
(when metadata.fnl/arglist
(if (name:find ":") kinds.Method kinds.Function))))
(?. kinds ?kind)
kinds.Text)})
{: signature-help-format

View File

@ -164,7 +164,8 @@
(check "(local x {:field (fn [self])})\n(x::f" [] [])
(check
"(let [my-table {:foo 10 :bar 20}]\n my-table.|)))"
[:my-table.foo :my-table.bar]
[{:label :my-table.foo :kind kinds.Value}
{:label :my-table.bar :kind kinds.Value}]
[])
(check
{:main.fnl "(let [foo (require :fooo)]
@ -256,6 +257,15 @@
[])
nil)
(fn test-destructure []
;; this is a binding variable, we don't want all the normal completions
(check "(local f|)\n(print foo)"
[:foo]
[:setmetatable :_G])
(check "(let [f|]\n(print foo)"
[:foo]
[:setmetatable :_G])
nil)
;; ;; Future tests / features
;; ;; Scope Ordering Rules
@ -283,4 +293,5 @@
: test-fn-arg
: test-field
: test-docs
: test-module}
: test-module
: test-destructure}