Skip to content

Commit 4f52f2c

Browse files
author
Bruce Hauman
committed
Add partial formatting support to sexp-edit-pipeline
Thread reindent-fn through find-and-edit-multi-sexp so each match site gets the replacement form re-indented to its column. In :partial mode, new-form is formatted once at col 1, then adjusted per match position. Adds comprehensive test suite mirroring the edit-form-pipeline partial tests: replace, insert-before, insert-after, replace-all, nested sexps, multi-form replacements, and deeply nested replacements.
1 parent 9521fbd commit 4f52f2c

3 files changed

Lines changed: 498 additions & 46 deletions

File tree

src/clojure_mcp/tools/form_edit/core.clj

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -580,36 +580,48 @@
580580
(filter #(match-multi-sexp match-sexprs %))
581581
first))
582582

583-
(defn find-and-edit-one-multi-sexp [zloc operation match-form new-form]
584-
{:pre [(#{:insert-before :insert-after :replace} operation) zloc (string? match-form) (string? new-form)]}
585-
;; no-op
586-
(when-not (and (str/blank? new-form) (#{:insert-before :insert-after} operation))
587-
(let [new-node (when-not (str/blank? new-form) (p/parse-string-all new-form))
588-
match-sexprs (str-forms->sexps match-form)]
589-
(when-let [found-loc (find-multi-sexp zloc match-sexprs)]
590-
(condp = operation
591-
:insert-before (insert-before-multi found-loc match-sexprs new-node)
592-
:insert-after (insert-after-multi found-loc match-sexprs new-node)
593-
(replace-multi found-loc match-sexprs new-form))))))
594-
595-
(defn find-and-edit-all-multi-sexp [zloc operation match-form new-form]
596-
{:pre [(#{:insert-before :insert-after :replace} operation) zloc (string? match-form) (string? new-form)]}
597-
(when-not (and (str/blank? new-form) (#{:insert-before :insert-after} operation))
598-
(loop [loc zloc
599-
locations []]
600-
(if-let [{:keys [after-loc edit-span-loc]}
601-
(find-and-edit-one-multi-sexp loc operation match-form new-form)]
602-
(recur after-loc (conj locations edit-span-loc))
603-
(when-not (empty? locations)
604-
;; this is a location after the last match
605-
;; z/root-string on this will produce the final edited form
606-
{:zloc loc
607-
:locations locations})))))
608-
609-
(defn find-and-edit-multi-sexp* [zloc match-form new-form {:keys [operation all?]}]
583+
(defn find-and-edit-one-multi-sexp
584+
([zloc operation match-form new-form]
585+
(find-and-edit-one-multi-sexp zloc operation match-form new-form nil))
586+
([zloc operation match-form new-form reindent-fn]
587+
{:pre [(#{:insert-before :insert-after :replace} operation) zloc (string? match-form) (string? new-form)]}
588+
;; no-op
589+
(when-not (and (str/blank? new-form) (#{:insert-before :insert-after} operation))
590+
(let [match-sexprs (str-forms->sexps match-form)]
591+
(when-let [found-loc (find-multi-sexp zloc match-sexprs)]
592+
(let [adjusted-form (if reindent-fn
593+
(if-let [col (some-> (z/position found-loc) second)]
594+
(reindent-fn new-form col)
595+
new-form)
596+
new-form)
597+
new-node (when-not (str/blank? adjusted-form)
598+
(p/parse-string-all adjusted-form))]
599+
(condp = operation
600+
:insert-before (insert-before-multi found-loc match-sexprs new-node)
601+
:insert-after (insert-after-multi found-loc match-sexprs new-node)
602+
(replace-multi found-loc match-sexprs adjusted-form))))))))
603+
604+
(defn find-and-edit-all-multi-sexp
605+
([zloc operation match-form new-form]
606+
(find-and-edit-all-multi-sexp zloc operation match-form new-form nil))
607+
([zloc operation match-form new-form reindent-fn]
608+
{:pre [(#{:insert-before :insert-after :replace} operation) zloc (string? match-form) (string? new-form)]}
609+
(when-not (and (str/blank? new-form) (#{:insert-before :insert-after} operation))
610+
(loop [loc zloc
611+
locations []]
612+
(if-let [{:keys [after-loc edit-span-loc]}
613+
(find-and-edit-one-multi-sexp loc operation match-form new-form reindent-fn)]
614+
(recur after-loc (conj locations edit-span-loc))
615+
(when-not (empty? locations)
616+
;; this is a location after the last match
617+
;; z/root-string on this will produce the final edited form
618+
{:zloc loc
619+
:locations locations}))))))
620+
621+
(defn find-and-edit-multi-sexp* [zloc match-form new-form {:keys [operation all? reindent-fn]}]
610622
(if all?
611-
(find-and-edit-all-multi-sexp zloc operation match-form new-form)
612-
(when-let [{:keys [after-loc edit-span-loc]} (find-and-edit-one-multi-sexp zloc operation match-form new-form)]
623+
(find-and-edit-all-multi-sexp zloc operation match-form new-form reindent-fn)
624+
(when-let [{:keys [after-loc edit-span-loc]} (find-and-edit-one-multi-sexp zloc operation match-form new-form reindent-fn)]
613625
;; this is a location after the last match
614626
;; z/root-string on this will produce the final edited form
615627
{:zloc after-loc

src/clojure_mcp/tools/form_edit/pipeline.clj

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -496,18 +496,29 @@
496496
update-file-timestamp))))))
497497

498498
(defn edit-sexp
499-
[{:keys [::zloc ::match-form ::new-form ::operation ::replace-all ::_whitespace-sensitive] :as ctx}]
499+
[{:keys [::zloc ::match-form ::new-form ::operation ::replace-all ::_whitespace-sensitive ::nrepl-client-atom] :as ctx}]
500500
(try
501-
(if-let [result (core/find-and-edit-multi-sexp
502-
zloc
503-
match-form
504-
new-form
505-
(cond-> {:operation operation}
506-
replace-all (assoc :all? true)))]
507-
(-> ctx
508-
(assoc ::zloc (:zloc result)))
509-
{::error true
510-
::message (str "Could not find form: " match-form)})
501+
(let [nrepl-client-map (some-> nrepl-client-atom deref)
502+
cljfmt-setting (config/get-cljfmt nrepl-client-map)
503+
;; When partial mode, pre-format new-form at col 1 and build reindent-fn
504+
[adjusted-form reindent-fn]
505+
(if (and (= :partial cljfmt-setting) (not (str/blank? new-form)))
506+
(let [formatting-options (core/project-formatting-options nrepl-client-map)
507+
formatted (core/format-form-in-isolation new-form 1 formatting-options)]
508+
[formatted (fn [form-str col] (core/re-indent-to-column form-str col))])
509+
[new-form nil])]
510+
(if-let [result (core/find-and-edit-multi-sexp
511+
zloc
512+
match-form
513+
adjusted-form
514+
(cond-> {:operation operation}
515+
replace-all (assoc :all? true)
516+
reindent-fn (assoc :reindent-fn reindent-fn)))]
517+
(-> ctx
518+
(assoc ::zloc (:zloc result))
519+
(cond-> reindent-fn (assoc ::pre-formatted? true)))
520+
{::error true
521+
::message (str "Could not find form: " match-form)}))
511522
(catch Exception e
512523
{::error true
513524
::message (str "Error editing form: " (.getMessage e))})))

0 commit comments

Comments
 (0)