Repository navigation
Add a command that removes unused destructured keys - #169
Conversation
59340f0 to
38007a7
Compare
| The whitespace between them and the elements left goes too, but the | ||
| closing bracket never ends up on the line of a comment." | ||
| (let (regions run) | ||
| (dolist (child (append (clojure-ts--value-children coll) (list nil))) |
There was a problem hiding this comment.
Runs are built from the value children only, so a #_ form or a comment between two removed names goes with them. (defn f [{:keys [a #_x c d]}] d) comes out as [{:keys [d]}], and a ;; TODO line between a and c disappears the same way. Ending a run at any comment or dis_expr child would keep them.
| elems))) | ||
| (cond | ||
| ((null unused) (when elems (setq kept t))) | ||
| ((length= unused (length elems)) (setq removed `(,key ,vec ,@removed))) |
There was a problem hiding this comment.
This only counts names, so a :keys vector left with nothing but a #_ form or a comment counts as empty: [{:keys [a #_b]}] becomes [_]. The :or count and the 'empty check for the whole map below have the same problem. The "keeps discarded forms and reader conditionals" spec passes only because the reader conditional is still there.
| (delete-region beg end) | ||
| (insert text)) | ||
| (pcase-dolist (`(,beg . ,end) vecs) | ||
| (indent-region (marker-position beg) (marker-position end)) |
There was a problem hiding this comment.
This starts on the line where the vector opens, which is the let or fn head and wasn't edited. In
(defn f [x]
(foo x)
(let [{:keys [a b]} x] b))the (let line moves from 4 spaces to 2. Reindenting only the lines after that one would leave it alone.
| (interactive) | ||
| (let* ((node (or (clojure-ts--node-at-point t) | ||
| (user-error "No form at point"))) | ||
| (top-level (clojure-ts--top-level-node node)) |
There was a problem hiding this comment.
Top-level metadata sits next to the form in source, not inside it, so with point on the ^ of ^:private (defn f [{:keys [a b]}] b) this gets the meta_lit and reports nothing to remove. Skipping metadata siblings here would fix it.
| (goto-char pos)) | ||
| (user-error "Must be invoked inside a list"))) | ||
|
|
||
| (defun clojure-ts--value-children (node) |
There was a problem hiding this comment.
clojure-ts--unwinding-unsupported-p does this same filter inline, and main now has clojure-ts--counted-child-p for the check.
| children) | ||
| (seq-split children 2)))) | ||
|
|
||
| (defun clojure-ts--core-form-name (node) |
There was a problem hiding this comment.
This is clojure-ts--list-node-sym-text plus the namespace check.
clojure-ts-remove-unused-keys (C-c C-r k) removes what the top-level form at point destructures from maps but never uses: names in :keys, :strs and :syms, :as names and names bound to keys, along with their :or defaults. It covers the arglists of fn, defn, defmethod, letfn and methods, and the bindings of let-like forms. A map with nothing left becomes _. Comments and #_ forms among the names stay, and a map that still has one isn't empty. A name counts as used when any unqualified symbol with that name appears in its scope. That ignores shadowing, so it can only miss a removal. Names starting with _ stay, as do positional args and vector destructuring. A map left with only :as stays a map, as map destructuring turns a seq into a map and the bare name wouldn't. Quoted and syntax-quoted forms are left alone, being data or a macro's template.
38007a7 to
714b21a
Compare
clj-kondo already flags the names a function or let destructures from a map and never uses, and this removes them. It's a structural edit that needs no REPL, so it belongs here rather than in CIDER or clj-refactor. A map left with only
:asstays a map, since the bare name would change what a seq binds, and names starting with_are left alone, as clj-kondo does.clojure-emacs/clojure-mode#708 adds the same command to clojure-mode.