Skip to content

Fix dynamic completion clobbering *1/*2/*3 and re-requiring per request#60

Open
bbatsov wants to merge 3 commits into
masterfrom
preserve-repl-history
Open

Fix dynamic completion clobbering *1/*2/*3 and re-requiring per request#60
bbatsov wants to merge 3 commits into
masterfrom
preserve-repl-history

Conversation

@bbatsov

@bbatsov bbatsov commented Jul 12, 2026

Copy link
Copy Markdown
Member

Two fixes to the dynamic (JS interop) completion path.

Fixes #5 - completion clobbered *1/*2/*3. Dynamic completion evaluates a probe in your REPL to introspect the object, and cljs.repl's default eval wrapper rotates the history vars after every eval - so each completion request overwrote *1 with the introspection result. cljs-eval now evaluates with a :wrap that skips that rotation (reusing cljs.repl/init-wrap-fn, which is exactly this). New test that establishes *1, completes, and asserts *1 survived.

Fixes #6 - re-required the introspection ns on every keystroke. js-properties-of-object required suitable.js-introspection on every completion request. The default path already loads it once via ensure-suitable-cljs-is-loaded, so that was a wasted eval round-trip per keystroke; the shadow path relied on it, so it now loads the ns once from its ensure-loaded step (guarded by a session flag) instead. Verified against both the Node and shadow-cljs integration tests.

Heads up: the Node integration test is a bit flaky (it occasionally fails to spawn the node process); unrelated to these changes, but a re-run clears it.

  • The commits are consistent with the contribution guidelines
  • You've added tests to cover your change(s)
  • All tests are passing
  • The new code is not generating reflection warnings
  • You've updated the changelog (if adding/changing user-visible functionality)

bbatsov added 3 commits July 12, 2026 14:08
Dynamic completion evaluates a probe in the user's REPL to introspect the
object. cljs.repl's default eval wrapper rotates the history vars after
every eval - (set! *3 *2) (set! *2 *1) (set! *1 ret) - so each completion
request overwrote *1 with the introspection result.

cljs-eval now passes a :wrap that evaluates without the history rotation
(reusing cljs.repl/init-wrap-fn, which is exactly that), so completion
leaves *1/*2/*3 alone.
js-properties-of-object required suitable.js-introspection on every single
completion request. The default path already loads it once via
ensure-suitable-cljs-is-loaded, so that require was a wasted eval
round-trip per keystroke; the shadow path relied on it, so it now loads
the namespace once from its ensure-loaded step (guarded by a session
flag) instead.

Verified against both the Node and shadow-cljs integration tests.
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.

goog.require emitted for every complete request Auto-complete destroys *1 *2 *3 special bindings

1 participant