macroexpansion feature for hover and code action

This commit is contained in:
XeroOl 2025-07-08 20:49:35 -05:00
parent 3855e59cbf
commit e17ecef292
3 changed files with 33 additions and 13 deletions

View File

@ -166,14 +166,20 @@ fntype is one of fn or λ or lambda"
"?")
(view (or definition.binding definition.definition))))
(λ hover-format [server name definition]
(λ hover-format [server name definition ?opts]
"Format code that will appear when the user hovers over a symbol"
{:kind "markdown"
:value (.. (code-block (get-stub server name definition))
(or (-?> (navigate.getmetadata server definition)
(. :fnl/docstring)
(->> (.. "\n---\n")))
""))})
(case (navigate.getmetadata server definition)
{: fnl/docstring}
(.. "\n---\n" fnl/docstring)
_ "")
(case (?. ?opts :macroexpansion)
macroexpansion
(.. "\n---\n"
"Macro expands to:\n"
(code-block macroexpansion))
_ ""))})
;; CompletionItemKind
(local kinds

View File

@ -156,10 +156,16 @@ Every time the client sends a message, it gets handled by a function in the corr
(let [file (files.get-by-uri server uri)
byte (utils.position->byte file.text position server.position-encoding)]
(case-try (analyzer.find-symbol file.ast byte)
symbol (analyzer.search server file symbol {} {: byte})
{:indeterminate nil &as result} {:contents (formatter.hover-format server (tostring symbol) result)
:range (message.ast->range server file
symbol)}
(symbol parents) (analyzer.search server file symbol {} {: byte})
{:indeterminate nil &as result}
(let [opts {:macroexpansion (case-try parents
(where [[(= symbol) &as parent]])
file.macro-calls
{parent expansion}
(fennel.view expansion)
(catch _ nil))}]
{:contents (formatter.hover-format server (tostring symbol) result opts)
:range (message.ast->range server file symbol)})
(catch _ nil))))
(set {:textDocument/completion requests.textDocument/completion
@ -206,8 +212,16 @@ Every time the client sends a message, it gets handled by a function in the corr
(pos<= range-2.start range-1.end)))
(λ requests.textDocument/codeAction [server _send {: range :textDocument {: uri}}]
(let [file (files.get-by-uri server uri)]
(icollect [_ diagnostic (ipairs file.diagnostics)]
(let [file (files.get-by-uri server uri)
byte (utils.position->byte file.text range.start server.position-encoding)
results []]
(case-try (analyzer.find-symbol file.ast byte)
(symbol_ [[symbol_ &as parent]]) file.macro-calls
{parent expansion} (table.insert results
{:title "Expand macro"
:edit {:changes {uri [{:range (message.ast->range server file parent)
:newText (fennel.view expansion)}]}}}))
(icollect [_ diagnostic (ipairs file.diagnostics) &into results]
(if (overlap? diagnostic.range range)
(message.diagnostic->code-action server file diagnostic :quickfix)))))

View File

@ -34,7 +34,7 @@
(fn test-builtins []
(check "(d|o nil)" "```fnl\n(do ...)\n```\n---\nEvaluate multiple forms; return last value.")
(check "(|doto nil (print))" "```fnl\n(doto val ...)\n```\n---\nEvaluate val and splice it into the first argument of subsequent forms.")
(check "(|doto nil (print))" "```fnl\n(doto val ...)\n```\n---\nEvaluate val and splice it into the first argument of subsequent forms.\n---\nMacro expands to:\n```fnl\n(do (print nil) nil)\n```")
(check "(le|t [x 10] 10)" "```fnl\n(let [name1 val1 ... nameN valN] ...)\n```\n---\nIntroduces a new scope in which a given set of local bindings are used.")
nil)
@ -153,7 +153,7 @@ except that it sets a new message handler `msgh`.")
\"docstring!\"
`(,a ,b ,c))
(fo|o print :hello :world)"
"```fnl\n(foo a b c)\n```\n---\ndocstring!")
"```fnl\n(foo a b c)\n```\n---\ndocstring!\n---\nMacro expands to:\n```fnl\n(print \"hello\" \"world\")\n```")
; (check {:main.fnl "(import-macros cool :cool)
; (coo|l.=)"
; :cool.fnl ";; fennel-ls: macro-file