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)] (let [old (tostring ?ast)]
(tset ?ast 1 "!!invalid-multi-symbol!!") (tset ?ast 1 "!!invalid-multi-symbol!!")
(table.insert defer #(tset ?ast 1 old)) (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] (λ on-compile-error [_ msg ast call-me-to-reset-the-compiler]
(let [range (or (message.ast->range server file ast) (let [range (or (message.ast->range server file ast)

View File

@ -40,7 +40,7 @@
"add the completion. also recursively adds the fields' completions" "add the completion. also recursively adds the fields' completions"
(when (not (. seen definition)) (when (not (. seen definition))
(set (. seen definition) true) (set (. seen definition) true)
(add-completion! name definition) (add-completion! name definition "Value")
(each [field def ?string-method (navigate.iter-fields server definition)] (each [field def ?string-method (navigate.iter-fields server definition)]
(if (or (= :self (tostring (?. def :metadata :fnl/arglist 1))) (if (or (= :self (tostring (?. def :metadata :fnl/arglist 1)))
?string-method ?string-method
@ -56,6 +56,7 @@
(add-completion-recursively! (.. name "." field) def))) (add-completion-recursively! (.. name "." field) def)))
(set (. seen definition) false))) (set (. seen definition) false)))
(fn expression-completions []
(each [name documentation (pairs hardcoded-completions)] (each [name documentation (pairs hardcoded-completions)]
(add-completion! name documentation)) (add-completion! name documentation))
@ -73,7 +74,6 @@
(io.stderr:write "BAD!!!! undocumented global: " (tostring global*) "\n") (io.stderr:write "BAD!!!! undocumented global: " (tostring global*) "\n")
(add-completion! global* {}))))) (add-completion! global* {})))))
(var scope scope) (var scope scope)
(while scope (while scope
(each [mangling (pairs scope.manglings)] (each [mangling (pairs scope.manglings)]
@ -96,22 +96,37 @@
_ (do _ (do
(io.stderr:write "BAD!!!! undocumented special: " (tostring special) "\n") (io.stderr:write "BAD!!!! undocumented special: " (tostring special) "\n")
{:label special})))) {:label special}))))
(set scope scope.parent)) (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))
(if server.can-do-good-completions? (if server.can-do-good-completions?
{:itemDefaults {:editRange range :data {: uri : byte}} {:itemDefaults {:editRange range :data {: uri : byte}}
:items results} :items results}
results))) results)))
(fn completionItem/resolve [server _send completion-item] (fn completionItem/resolve [server _send completion-item]
(or (. hardcoded-completions completion-item.label) (let [result
(or (. hardcoded-completions completion-item.name)
(let [{: uri : byte} completion-item.data (let [{: uri : byte} completion-item.data
file (files.get-by-uri server uri) file (files.get-by-uri server uri)
(_symbol parents) (analyzer.find-symbol file.ast byte) (_symbol parents) (analyzer.find-symbol file.ast byte)
scope (or (accumulate [?find nil _ parent (ipairs parents) &until ?find] scope (or (accumulate [?find nil _ parent (ipairs parents) &until ?find]
(. file.scopes parent)) (. file.scopes parent))
file.scope)] file.scope)]
(case (analyzer.search-name-and-scope server file completion-item.label scope) (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))))))) (when result
(set completion-item.documentation (format.hover-format server completion-item.label result)))
completion-item))
{: textDocument/completion {: textDocument/completion
: completionItem/resolve} : completionItem/resolve}

View File

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

View File

@ -164,7 +164,8 @@
(check "(local x {:field (fn [self])})\n(x::f" [] []) (check "(local x {:field (fn [self])})\n(x::f" [] [])
(check (check
"(let [my-table {:foo 10 :bar 20}]\n my-table.|)))" "(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 (check
{:main.fnl "(let [foo (require :fooo)] {:main.fnl "(let [foo (require :fooo)]
@ -256,6 +257,15 @@
[]) [])
nil) 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 ;; ;; Future tests / features
;; ;; Scope Ordering Rules ;; ;; Scope Ordering Rules
@ -283,4 +293,5 @@
: test-fn-arg : test-fn-arg
: test-field : test-field
: test-docs : test-docs
: test-module} : test-module
: test-destructure}