Hi there! Considering the following use case:
(defn get-data [{:keys [data]}]
data)
(defmacro $ [op arg1 & args]
`(~op ~arg1))
($ get-data {:| })
; cursor ^
Is there a way to write a clj-kondo hook which would keep autocompletion for the args (keys) working? (Same as with a direct call to get-data).
I haven't found a solution yet. I'm using Calva in VSCode, not sure whether that matters.
Thanks! (Originally posted in #clj-kondo)If your custom hook expand to something that defines those keywords it may work, the problem is get a working hook for this
clojure-lsp just suggests keywords that are available in analysis, so if your hook expands to a:
(do
:data
...rest-of-the-hook...)
it will be availableIt's not just to make it available, but to be the same as a direct call to the function with a closed list of keywords. Currently there is autocompletion but with all known keywords.
yeah that specifically would be quite hard to support, right now clojure-lsp scans for destructuring args in the function being called, but with a macro/hook I can't see how we would make that work
With clj-kondo, rewriting macros in hooks for linting works well, there might be a way to use that too in place of scanning args, for unknown macros.
Real use case is for libraries like uix for component props or dom properties (writing html-like trees).
maybe we could have some kinda of meta that you could append to the keyword so clojure-lsp could work on that, but I think I need more detailed cases, especially a hook
For the original easy case, the hook could be something like that:
(defn $ [{:keys [node]}]
{:node (with-meta
(api/list-node (rest (:children node)))
(meta node))})
Analyzing the list-node as a function call might just work (as I expected at the beginning).
It won't handle the case where the first argument is a keyword representing a HTML element, unless we create fake functions for those. Specifying a list of keywords for a map-node can do the job:
(defn $ [{:keys [node]}]
(let [[element props-map & _children] (rest (:children node))]
{:node (with-meta
(api/list-node
[(api/token-node 'identity)
(with-meta
props-map ; assume it is already a map-node
(merge (meta props-map)
{:clj-kondo/allowed-keys (get-html-attrs-for-element element)}))])
(meta node))}))
We could use this API for the first case too.
Alternatively we could call a api/reg-map-keys! or similar.