Skip to content

feat: add cljfmt :partial mode to format only replaced forms (#154)#155

Open
williamp44 wants to merge 1 commit intobhauman:mainfrom
williamp44:fix/cljfmt-partial-formatting
Open

feat: add cljfmt :partial mode to format only replaced forms (#154)#155
williamp44 wants to merge 1 commit intobhauman:mainfrom
williamp44:fix/cljfmt-partial-formatting

Conversation

@williamp44
Copy link

@williamp44 williamp44 commented Mar 1, 2026

Summary

Approach

Per your guidance in #154: format the replacement content in isolation, then re-indent to match the target column position.

  • Before insertion: cljfmt formats the new form string, then re-indent-to-column adjusts indentation for the target position
  • After insertion: format-source skips whole-file formatting (the form is already formatted)
  • sexp-edit-pipeline: Falls back to full-file formatting in :partial mode (no position tracking for arbitrary s-expression matching)

Changes

  • config/schema.clj:cljfmt accepts [:or :boolean [:= :partial]]
  • config.cljprocess-config preserves :partial; get-cljfmt documents 3 values
  • form_edit/core.clj — Two new pure functions: re-indent-to-column, format-form-in-isolation
  • form_edit/pipeline.clj — Two new pipeline steps: capture-form-position, format-new-source-partial; format-source updated to 3-way cond
  • CONFIG.md / PROJECT_SUMMARY.md — Documentation

Config usage

{:cljfmt :partial}  ;; format only the edited form
{:cljfmt true}      ;; full-file formatting (default, unchanged)
{:cljfmt false}     ;; no formatting (unchanged)

Test plan

  • 298 tests, 2153 assertions, 0 failures
  • Unit tests for re-indent-to-column (col 1, col > 1, blank lines, single-line)
  • Unit tests for format-form-in-isolation (success + failure fallback)
  • capture-form-position tested at col 1 and col 9 (nested reader conditional)
  • E2E: :partial + :replace — target formatted, surrounding (ns test.core) preserved
  • E2E: :partial + :before and :after — inserted form formatted, surrounding preserved
  • E2E: true mode contrast — confirms (ns test.core) gets normalized
  • sexp-edit-pipeline + :partial — falls back to full-file formatting
  • process-config round-trip — :partial survives EDN → config processing
  • Schema validates all three values

Summary by CodeRabbit

  • New Features

    • Added a :partial cljfmt mode that formats only the edited form, preserving surrounding formatting.
  • Behavior

    • Editing honors :partial, skipping full-file reformat when applicable; true remains full-file, false disables formatting. Partial edits preserve alignment and fallback safely on failure.
  • Documentation

    • Docs updated to explain true (full-file), :partial (form-only), and false (disabled).
  • Tests

    • Expanded tests covering schema acceptance, partial/full formatting, alignment, and fallback.

@coderabbitai
Copy link

coderabbitai bot commented Mar 1, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a cljfmt ":partial" mode to format only the edited form in isolation, updates docs, config, and schema to accept true/false/:partial, adds column-aware formatting helpers, captures the form column in the edit pipeline, applies isolated formatting when requested, and adds tests covering partial-format flows.

Changes

Cohort / File(s) Summary
Docs & Project Summary
CONFIG.md, PROJECT_SUMMARY.md
Replace boolean :cljfmt docs with a mode-based description accepting true, :partial, and false; update guidance about when each mode applies.
Config Processing
src/clojure_mcp/config.clj
Preserve :partial in process-config (avoid coerced boolean) and add docstring to get-cljfmt describing possible return values.
Schema
src/clojure_mcp/config/schema.clj
Change :cljfmt schema from boolean to [:or :boolean [:= :partial]] to allow the :partial literal.
Core Formatting Utilities
src/clojure_mcp/tools/form_edit/core.clj
Add re-indent-to-column and format-form-in-isolation helpers and logging import to support isolated form formatting and re-indentation.
Pipeline Orchestration
src/clojure_mcp/tools/form_edit/pipeline.clj
Add public ::form-col, capture-form-position, and format-new-source-partial; capture form column after locating the form, pre-format the new form in isolation when :cljfmt is :partial, and skip whole-file formatting in that path. Update pipeline ordering to include new steps.
Tests
test/clojure_mcp/config/schema_test.clj, test/clojure_mcp/tools/form_edit/pipeline_test.clj
Add schema tests for :partial and an extensive test suite for partial-format flows, re-indentation, isolated formatting, capture position, pipeline behavior, and edge cases.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Pipeline
    participant Finder
    participant Pos
    participant Formatter
    participant FileFormatter
    participant Editor

    Client->>Pipeline: request edit (replace/insert)
    Pipeline->>Finder: parse-source & locate form
    Finder-->>Pipeline: positioned zipper / located form
    Pipeline->>Pos: capture-form-position (compute ::form-col)
    Pos-->>Pipeline: ::form-col (maybe nil)
    alt cljfmt = :partial and ::form-col present
        Pipeline->>Formatter: format-new-source-partial (::new-source-code, ::form-col)
        Formatter->>Formatter: format-form-in-isolation and re-indent-to-column
        Formatter-->>Pipeline: updated ::new-source-code
        Pipeline->>Editor: edit-form (insert formatted form)
        Editor-->>Pipeline: source with replacement
        Pipeline->>FileFormatter: format-source (skip whole-file formatting)
        FileFormatter-->>Pipeline: unchanged surrounding formatting
    else
        Pipeline->>Editor: edit-form (no pre-format)
        Editor-->>Pipeline: source with replacement
        Pipeline->>FileFormatter: format-source (apply cljfmt to entire file)
        FileFormatter->>FileFormatter: apply cljfmt to whole file
        FileFormatter-->>Pipeline: fully formatted source
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I hopped in, nibbling spaces with care,

I formatted the form, left the rest where they were,
columns lined up like neat little rows,
no noisy diffs, just tidy repose,
a rabbit's patch — small, clever, and fair.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a :partial mode for cljfmt that formats only replaced forms, directly addressing the PR's primary objective.
Linked Issues check ✅ Passed The PR implements all coding requirements from issue #154: scoped formatting via :partial mode, configurable cljfmt behavior, fallback to full-file formatting, and supporting three cljfmt values (true, false, :partial).
Out of Scope Changes check ✅ Passed All changes directly support the linked issue #154 objective: formatting only replaced forms. Documentation updates, schema changes, helper functions, and pipeline modifications are all in scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
test/clojure_mcp/tools/form_edit/pipeline_test.clj (1)

421-453: Move temp-dir cleanup into finally blocks for failure-safe teardown.

Several tests clean temp dirs only at the end of happy-path execution. If an assertion fails earlier, temp artifacts can leak and affect later runs.

Pattern to apply
- (let [test-dir (test-utils/create-test-dir)
-       ...]
-   ...
-   (test-utils/clean-test-dir test-dir))
+ (let [test-dir (test-utils/create-test-dir)]
+   (try
+     (let [...]
+       ...)
+     (finally
+       (test-utils/clean-test-dir test-dir))))

Also applies to: 460-484, 525-553, 560-588

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/clojure_mcp/tools/form_edit/pipeline_test.clj` around lines 421 - 453,
The test creates a temp test-dir via test-utils/create-test-dir and currently
calls test-utils/clean-test-dir only at the end of the happy path; wrap the body
that uses test-dir (the let block that calls sut/edit-form-pipeline, checks
result, and reads file-path) in a try...finally and move the
test-utils/clean-test-dir call into the finally so cleanup always runs; apply
the same change to the other similar tests referenced (the blocks around lines
460-484, 525-553, 560-588) to ensure temp dirs are removed on failures as well.
src/clojure_mcp/tools/form_edit/pipeline.clj (1)

243-245: Don’t default missing position to column 1 in partial mode.

If z/position is unavailable, setting ::form-col to 1 still triggers the “already preformatted” skip path, which can suppress full-file fallback and mis-indent nested edits.

Proposed fix
 (defn capture-form-position
@@
   [ctx]
   (let [zloc (::zloc ctx)]
     (if-let [pos (z/position zloc)]
       (assoc ctx ::form-col (second pos)) ;; [row col] -> col
-      (assoc ctx ::form-col 1)))) ;; default to column 1
+      ctx))) ;; leave unset so downstream can fall back

 (defn format-new-source-partial
@@
   (let [nrepl-client-map (some-> ctx ::nrepl-client-atom deref)
         cljfmt-setting (config/get-cljfmt nrepl-client-map)]
-    (if (= :partial cljfmt-setting)
+    (if (and (= :partial cljfmt-setting) (some? (::form-col ctx)))
       (let [new-source (::new-source-code ctx)
-            target-col (or (::form-col ctx) 1)
+            target-col (::form-col ctx)
             formatting-options (core/project-formatting-options nrepl-client-map)
             formatted (core/format-form-in-isolation new-source target-col formatting-options)]
         (assoc ctx ::new-source-code formatted))
       ;; Not :partial mode, pass through
       ctx)))

Also applies to: 257-263, 320-321

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/clojure_mcp/tools/form_edit/pipeline.clj` around lines 243 - 245, The
code currently defaults ::form-col to 1 when z/position returns nil, which
incorrectly signals a column and triggers the “already preformatted” skip;
change the logic so you only assoc ::form-col when (z/position zloc) yields a
value (i.e., keep ctx unchanged when pos is nil) instead of associating 1, and
apply the same fix at the other occurrences that default to 1 (the blocks around
the other z/position uses you noted). In short: remove the fallback assoc of
::form-col 1, only assoc ::form-col (second pos) when pos exists, and ensure
downstream code relies on presence/absence of ::form-col rather than a sentinel
value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/clojure_mcp/tools/form_edit/pipeline.clj`:
- Around line 243-245: The code currently defaults ::form-col to 1 when
z/position returns nil, which incorrectly signals a column and triggers the
“already preformatted” skip; change the logic so you only assoc ::form-col when
(z/position zloc) yields a value (i.e., keep ctx unchanged when pos is nil)
instead of associating 1, and apply the same fix at the other occurrences that
default to 1 (the blocks around the other z/position uses you noted). In short:
remove the fallback assoc of ::form-col 1, only assoc ::form-col (second pos)
when pos exists, and ensure downstream code relies on presence/absence of
::form-col rather than a sentinel value.

In `@test/clojure_mcp/tools/form_edit/pipeline_test.clj`:
- Around line 421-453: The test creates a temp test-dir via
test-utils/create-test-dir and currently calls test-utils/clean-test-dir only at
the end of the happy path; wrap the body that uses test-dir (the let block that
calls sut/edit-form-pipeline, checks result, and reads file-path) in a
try...finally and move the test-utils/clean-test-dir call into the finally so
cleanup always runs; apply the same change to the other similar tests referenced
(the blocks around lines 460-484, 525-553, 560-588) to ensure temp dirs are
removed on failures as well.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 203944d and afaf190.

📒 Files selected for processing (8)
  • CONFIG.md
  • PROJECT_SUMMARY.md
  • src/clojure_mcp/config.clj
  • src/clojure_mcp/config/schema.clj
  • src/clojure_mcp/tools/form_edit/core.clj
  • src/clojure_mcp/tools/form_edit/pipeline.clj
  • test/clojure_mcp/config/schema_test.clj
  • test/clojure_mcp/tools/form_edit/pipeline_test.clj

@williamp44 williamp44 force-pushed the fix/cljfmt-partial-formatting branch from afaf190 to 23e41e1 Compare March 2, 2026 00:08
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/clojure_mcp/tools/form_edit/pipeline_test.clj (1)

421-452: Wrap temp-dir cleanup in finally to avoid test pollution on assertion failure.

A few tests clean temp dirs only on the success path. If an assertion fails early, cleanup is skipped.

Also applies to: 460-484, 491-518, 525-553, 560-588, 643-675, 690-711

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/clojure_mcp/tools/form_edit/pipeline_test.clj` around lines 421 - 452,
Tests create a temp dir via test-utils/create-test-dir and only call
test-utils/clean-test-dir on the success path, so wrap the cleanup in a finally
block to guarantee deletion even if an assertion fails: surround the setup,
pipeline execution (sut/edit-form-pipeline and sut/format-result) and assertions
with a try (or try/finally) and move the call to test-utils/clean-test-dir
test-dir into the finally clause; apply the same change to the other test blocks
that currently call test-utils/clean-test-dir only on the success path (the
other blocks using test-dir, create-and-register-test-file,
sut/edit-form-pipeline, sut/format-result).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/clojure_mcp/tools/form_edit/pipeline.clj`:
- Around line 243-245: The code currently defaults ::form-col to 1 when
z/position returns nil, which causes silent mis-indentation in :partial mode;
change the logic in the block that uses z/position and zloc so that if
z/position is nil and the operation-mode or context indicates :partial you do
not set ::form-col to 1 (leave ::form-col absent or nil on ctx) so the caller
can trigger the full-file fallback; apply the same conditional change for the
similar block around the 257-264 region—only apply the column=1 default when not
in :partial mode and explicitly set or omit ::form-col accordingly.

---

Nitpick comments:
In `@test/clojure_mcp/tools/form_edit/pipeline_test.clj`:
- Around line 421-452: Tests create a temp dir via test-utils/create-test-dir
and only call test-utils/clean-test-dir on the success path, so wrap the cleanup
in a finally block to guarantee deletion even if an assertion fails: surround
the setup, pipeline execution (sut/edit-form-pipeline and sut/format-result) and
assertions with a try (or try/finally) and move the call to
test-utils/clean-test-dir test-dir into the finally clause; apply the same
change to the other test blocks that currently call test-utils/clean-test-dir
only on the success path (the other blocks using test-dir,
create-and-register-test-file, sut/edit-form-pipeline, sut/format-result).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between afaf190 and 23e41e1.

📒 Files selected for processing (8)
  • CONFIG.md
  • PROJECT_SUMMARY.md
  • src/clojure_mcp/config.clj
  • src/clojure_mcp/config/schema.clj
  • src/clojure_mcp/tools/form_edit/core.clj
  • src/clojure_mcp/tools/form_edit/pipeline.clj
  • test/clojure_mcp/config/schema_test.clj
  • test/clojure_mcp/tools/form_edit/pipeline_test.clj
🚧 Files skipped from review as they are similar to previous changes (3)
  • test/clojure_mcp/config/schema_test.clj
  • src/clojure_mcp/config/schema.clj
  • src/clojure_mcp/config.clj

@williamp44 williamp44 force-pushed the fix/cljfmt-partial-formatting branch from 23e41e1 to 6a6a442 Compare March 2, 2026 00:31
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/clojure_mcp/tools/form_edit/pipeline.clj (1)

243-264: ⚠️ Potential issue | 🟠 Major

Don’t coerce missing form position to column 1 in :partial mode.

At Line 245, setting ::form-col to 1 when position is unavailable causes :partial flow to proceed as if tracking succeeded. Combined with Line 257 and Line 320, this can mis-indent edits and incorrectly skip full-file fallback.

Suggested fix
 (defn capture-form-position
@@
   [ctx]
   (let [zloc (::zloc ctx)]
     (if-let [pos (z/position zloc)]
       (assoc ctx ::form-col (second pos)) ;; [row col] -> col
-      (assoc ctx ::form-col 1)))) ;; default to column 1
+      ctx))) ;; keep nil/absent so downstream can fallback
 
 (defn format-new-source-partial
@@
   (let [nrepl-client-map (some-> ctx ::nrepl-client-atom deref)
         cljfmt-setting (config/get-cljfmt nrepl-client-map)]
-    (if (= :partial cljfmt-setting)
+    (if (and (= :partial cljfmt-setting) (::form-col ctx))
       (let [new-source (::new-source-code ctx)
-            target-col (or (::form-col ctx) 1)
+            target-col (::form-col ctx)
             formatting-options (core/project-formatting-options nrepl-client-map)
             formatted (core/format-form-in-isolation new-source target-col formatting-options)]
         (assoc ctx ::new-source-code formatted))
       ;; Not :partial mode, pass through
       ctx)))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/clojure_mcp/tools/form_edit/pipeline.clj` around lines 243 - 264, The
code currently defaults ::form-col to 1 and then always runs partial formatting;
instead, in format-new-source-partial only perform partial formatting when the
position is actually present: check (contains? ctx ::form-col) or that
(::form-col ctx) is non-nil before calling core/format-form-in-isolation, and if
the form column is missing return ctx unchanged (so downstream code can fall
back to full-file formatting). Update format-new-source-partial to gate the
:partial branch on the presence of ::form-col (referencing ::new-source-code,
::form-col, core/format-form-in-isolation and config/get-cljfmt) rather than
coercing a default column.
🧹 Nitpick comments (1)
test/clojure_mcp/tools/form_edit/pipeline_test.clj (1)

366-393: Add a regression test for “position unavailable” in partial mode.

Current coverage validates known columns, but not the z/position -> nil path that should trigger fallback behavior instead of treating it as column 1.

Suggested test case
 (deftest capture-form-position-test
@@
       (is (= 9 (::sut/form-col result))
           "Nested form should be at column 9"))))
+
+(deftest capture-form-position-missing-position-test
+  (testing "capture-form-position leaves ::form-col absent when position tracking is unavailable"
+    (with-redefs [z/position (fn [_] nil)]
+      (let [ctx {::sut/zloc :dummy-zloc}
+            result (sut/capture-form-position ctx)]
+        (is (nil? (::sut/form-col result)))))))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/clojure_mcp/tools/form_edit/pipeline_test.clj` around lines 366 - 393,
Add a regression test in capture-form-position-test that simulates the “position
unavailable” (z/position -> nil) scenario in partial mode and asserts the
fallback behavior instead of treating the form as column 1: call
sut/parse-source and sut/find-form as other tests do but set the context to
partial mode (include ::sut/partial true or whatever flag your parser uses to
indicate partial parsing), ensure the found node yields a nil position from
z/position, then call sut/capture-form-position and assert the returned
::sut/form-col matches the expected fallback value (or that a specific fallback
path/flag is set) and not 1; reference capture-form-position, find-form,
parse-source, ::sut/partial, and z/position when locating code to exercise.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/clojure_mcp/tools/form_edit/pipeline.clj`:
- Around line 243-264: The code currently defaults ::form-col to 1 and then
always runs partial formatting; instead, in format-new-source-partial only
perform partial formatting when the position is actually present: check
(contains? ctx ::form-col) or that (::form-col ctx) is non-nil before calling
core/format-form-in-isolation, and if the form column is missing return ctx
unchanged (so downstream code can fall back to full-file formatting). Update
format-new-source-partial to gate the :partial branch on the presence of
::form-col (referencing ::new-source-code, ::form-col,
core/format-form-in-isolation and config/get-cljfmt) rather than coercing a
default column.

---

Nitpick comments:
In `@test/clojure_mcp/tools/form_edit/pipeline_test.clj`:
- Around line 366-393: Add a regression test in capture-form-position-test that
simulates the “position unavailable” (z/position -> nil) scenario in partial
mode and asserts the fallback behavior instead of treating the form as column 1:
call sut/parse-source and sut/find-form as other tests do but set the context to
partial mode (include ::sut/partial true or whatever flag your parser uses to
indicate partial parsing), ensure the found node yields a nil position from
z/position, then call sut/capture-form-position and assert the returned
::sut/form-col matches the expected fallback value (or that a specific fallback
path/flag is set) and not 1; reference capture-form-position, find-form,
parse-source, ::sut/partial, and z/position when locating code to exercise.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 23e41e1 and 6a6a442.

📒 Files selected for processing (8)
  • CONFIG.md
  • PROJECT_SUMMARY.md
  • src/clojure_mcp/config.clj
  • src/clojure_mcp/config/schema.clj
  • src/clojure_mcp/tools/form_edit/core.clj
  • src/clojure_mcp/tools/form_edit/pipeline.clj
  • test/clojure_mcp/config/schema_test.clj
  • test/clojure_mcp/tools/form_edit/pipeline_test.clj
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/clojure_mcp/config.clj
  • PROJECT_SUMMARY.md
  • test/clojure_mcp/config/schema_test.clj
  • CONFIG.md

@williamp44 williamp44 force-pushed the fix/cljfmt-partial-formatting branch 2 times, most recently from 3dff6ef to 0c92c83 Compare March 2, 2026 18:00
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/clojure_mcp/tools/form_edit/pipeline.clj (1)

45-45: Consider tightening ::form-col to pos-int?.

Columns are 1-based; using int? allows invalid 0/negative values into context state.

Proposed spec tightening
-(s/def ::form-col int?)
+(s/def ::form-col pos-int?)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/clojure_mcp/tools/form_edit/pipeline.clj` at line 45, The ::form-col spec
currently allows any integer (int?), letting 0 and negatives through; change its
predicate to pos-int? so only positive 1-based column numbers are valid. Locate
the declaration (s/def ::form-col int?) in pipeline.clj and replace int? with
pos-int?, then run/update any callers or tests that construct context state to
ensure they supply positive integers (or add validation/conversion before
constructing the spec if needed).
test/clojure_mcp/tools/form_edit/pipeline_test.clj (1)

441-739: Consider extracting temp-file lifecycle helpers for these integration tests.

There’s repeated create/set/cleanup logic; a shared helper (or fixture wrapper) would reduce duplication and make cleanup more reliable when assertions fail mid-test.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/clojure_mcp/tools/form_edit/pipeline_test.clj` around lines 441 - 739,
The tests repeat the same temp-file lifecycle (test-utils/create-test-dir,
test-utils/create-and-register-test-file, config/set-config!, and
test-utils/clean-test-dir with try/finally) across many cases; extract a
reusable helper (e.g., with-temp-test-file or fixture wrapper) that (1) creates
the test-dir and registers the file, (2) yields the file-path and any
teardown/restore actions to the test body, and (3) guarantees cleanup and config
reset on success or failure so each test (those invoking sut/edit-form-pipeline
like edit-form-pipeline-partial-formatting-test, issue-154-e2e-test,
sexp-edit-pipeline-partial-fallback-test, etc.) can call the helper to reduce
duplication and ensure reliable cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/clojure_mcp/tools/form_edit/pipeline.clj`:
- Line 45: The ::form-col spec currently allows any integer (int?), letting 0
and negatives through; change its predicate to pos-int? so only positive 1-based
column numbers are valid. Locate the declaration (s/def ::form-col int?) in
pipeline.clj and replace int? with pos-int?, then run/update any callers or
tests that construct context state to ensure they supply positive integers (or
add validation/conversion before constructing the spec if needed).

In `@test/clojure_mcp/tools/form_edit/pipeline_test.clj`:
- Around line 441-739: The tests repeat the same temp-file lifecycle
(test-utils/create-test-dir, test-utils/create-and-register-test-file,
config/set-config!, and test-utils/clean-test-dir with try/finally) across many
cases; extract a reusable helper (e.g., with-temp-test-file or fixture wrapper)
that (1) creates the test-dir and registers the file, (2) yields the file-path
and any teardown/restore actions to the test body, and (3) guarantees cleanup
and config reset on success or failure so each test (those invoking
sut/edit-form-pipeline like edit-form-pipeline-partial-formatting-test,
issue-154-e2e-test, sexp-edit-pipeline-partial-fallback-test, etc.) can call the
helper to reduce duplication and ensure reliable cleanup.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3dff6ef and 0c92c83.

📒 Files selected for processing (8)
  • CONFIG.md
  • PROJECT_SUMMARY.md
  • src/clojure_mcp/config.clj
  • src/clojure_mcp/config/schema.clj
  • src/clojure_mcp/tools/form_edit/core.clj
  • src/clojure_mcp/tools/form_edit/pipeline.clj
  • test/clojure_mcp/config/schema_test.clj
  • test/clojure_mcp/tools/form_edit/pipeline_test.clj
🚧 Files skipped from review as they are similar to previous changes (4)
  • PROJECT_SUMMARY.md
  • src/clojure_mcp/tools/form_edit/core.clj
  • CONFIG.md
  • src/clojure_mcp/config.clj

…#154)

When :cljfmt is set to :partial in config, clojure_edit formats only the
replacement form in isolation (via cljfmt) and re-indents it to the correct
column position, rather than reformatting the entire file. This prevents
collateral formatting changes to unrelated code.

- Add re-indent-to-column and format-form-in-isolation pure functions
- Add capture-form-position and format-new-source-partial pipeline steps
- Update format-source to skip whole-file formatting when partial pre-formatting ran
- sexp-edit-pipeline falls back to full-file formatting in :partial mode
- Update schema to accept [:or :boolean [:= :partial]]
- 298 tests, 2153 assertions, 0 failures
@williamp44 williamp44 force-pushed the fix/cljfmt-partial-formatting branch from 0c92c83 to 232aea9 Compare March 2, 2026 18:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

clojure_edit replace reformats entire file via cljfmt, not just the target form causing Noisy diffs and Stale REPL vars

1 participant