branch: elpa/inf-clojure
commit d6a23b658f1eb6a8abdc835de8a811e9b3a039bc
Author: Bozhidar Batsov <[email protected]>
Commit: Bozhidar Batsov <[email protected]>
Deduplicate Clojure-family REPL feature definitions
The clojure, babashka, node-babashka, and lein-clr entries in
inf-clojure-repl-features were near-identical copies differing
only in their arglists catch clause. Extract the shared features
into inf-clojure--clojure-repl-base-features and derive each
variant via inf-clojure--merge-repl-features, overriding only
arglists. node-babashka is now a true alias for babashka.
The resulting runtime data structure is identical, so all existing
feature lookup and update code works unchanged.
---
inf-clojure.el | 87 +++++++++++++++++++++++------------------------
test/inf-clojure-tests.el | 31 +++++++++++++++++
2 files changed, 73 insertions(+), 45 deletions(-)
diff --git a/inf-clojure.el b/inf-clojure.el
index 498b9c0d03..c0d20a5d15 100644
--- a/inf-clojure.el
+++ b/inf-clojure.el
@@ -82,8 +82,29 @@
(babashka . "bb")
(joker . "joker")))
+(defun inf-clojure--merge-repl-features (base overrides)
+ "Return a new feature alist by merging OVERRIDES onto BASE.
+Keys in OVERRIDES take precedence over those in BASE."
+ (append overrides
+ (cl-remove-if (lambda (entry)
+ (assq (car entry) overrides))
+ base)))
+
+(defvar inf-clojure--clojure-repl-base-features
+ '((load . "(clojure.core/load-file \"%s\")")
+ (doc . "(clojure.repl/doc %s)")
+ (source . "(clojure.repl/source %s)")
+ (apropos . "(doseq [var (sort (clojure.repl/apropos \"%s\"))] (println
(str var)))")
+ (ns-vars . "(clojure.repl/dir %s)")
+ (set-ns . "(clojure.core/in-ns '%s)")
+ (macroexpand . "(clojure.core/macroexpand '%s)")
+ (macroexpand-1 . "(clojure.core/macroexpand-1 '%s)"))
+ "Base feature forms shared by Clojure-family REPLs.
+Individual REPL types override specific entries (typically `arglists')
+via `inf-clojure--merge-repl-features'.")
+
(defvar inf-clojure-repl-features
- '((cljs . ((doc . "(cljs.repl/doc %s)")
+ `((cljs . ((doc . "(cljs.repl/doc %s)")
(source . "(cljs.repl/source %s)")
(arglists . "(try (->> '%s cljs.core/resolve cljs.core/meta
:arglists) (catch :default _ nil))")
(apropos . "(cljs.repl/apropos \"%s\")")
@@ -113,58 +134,34 @@
(set-ns . "(in-ns '%s)")
(macroexpand . "(macroexpand '%s)")
(macroexpand-1 . "(macroexpand-1 '%s)")))
- (babashka . ((load . "(clojure.core/load-file \"%s\")")
- (doc . "(clojure.repl/doc %s)")
- (source . "(clojure.repl/source %s)")
- (arglists .
- "(try (-> '%s clojure.core/resolve
clojure.core/meta :arglists)
- (catch Throwable e nil))")
- (apropos . "(doseq [var (sort (clojure.repl/apropos \"%s\"))]
(println (str var)))")
- (ns-vars . "(clojure.repl/dir %s)")
- (set-ns . "(clojure.core/in-ns '%s)")
- (macroexpand . "(clojure.core/macroexpand '%s)")
- (macroexpand-1 . "(clojure.core/macroexpand-1 '%s)")))
- (node-babashka . ((load . "(clojure.core/load-file \"%s\")")
- (doc . "(clojure.repl/doc %s)")
- (source . "(clojure.repl/source %s)")
- (arglists .
- "(try (-> '%s clojure.core/resolve
clojure.core/meta :arglists)
- (catch Throwable e nil))")
- (apropos . "(doseq [var (sort (clojure.repl/apropos \"%s\"))]
(println (str var)))")
- (ns-vars . "(clojure.repl/dir %s)")
- (set-ns . "(clojure.core/in-ns '%s)")
- (macroexpand . "(clojure.core/macroexpand '%s)")
- (macroexpand-1 . "(clojure.core/macroexpand-1 '%s)")))
- (clojure . ((load . "(clojure.core/load-file \"%s\")")
- (doc . "(clojure.repl/doc %s)")
- (source . "(clojure.repl/source %s)")
- (arglists .
- "(try
+ (babashka . ,(inf-clojure--merge-repl-features
+ inf-clojure--clojure-repl-base-features
+ '((arglists .
+ "(try (-> '%s clojure.core/resolve
clojure.core/meta :arglists)
+ (catch Throwable e nil))"))))
+ (node-babashka . ,(inf-clojure--merge-repl-features
+ inf-clojure--clojure-repl-base-features
+ '((arglists .
+ "(try (-> '%s clojure.core/resolve
clojure.core/meta :arglists)
+ (catch Throwable e nil))"))))
+ (clojure . ,(inf-clojure--merge-repl-features
+ inf-clojure--clojure-repl-base-features
+ '((arglists .
+ "(try
(:arglists
(clojure.core/meta
(clojure.core/resolve
(clojure.core/read-string \"%s\"))))
- (catch #?(:clj Throwable :cljr Exception) e nil))")
- (apropos . "(doseq [var (sort (clojure.repl/apropos \"%s\"))]
(println (str var)))")
- (ns-vars . "(clojure.repl/dir %s)")
- (set-ns . "(clojure.core/in-ns '%s)")
- (macroexpand . "(clojure.core/macroexpand '%s)")
- (macroexpand-1 . "(clojure.core/macroexpand-1 '%s)")))
- (lein-clr . ((load . "(clojure.core/load-file \"%s\")")
- (doc . "(clojure.repl/doc %s)")
- (source . "(clojure.repl/source %s)")
- (arglists .
- "(try
+ (catch #?(:clj Throwable :cljr Exception) e
nil))"))))
+ (lein-clr . ,(inf-clojure--merge-repl-features
+ inf-clojure--clojure-repl-base-features
+ '((arglists .
+ "(try
(:arglists
(clojure.core/meta
(clojure.core/resolve
(clojure.core/read-string \"%s\"))))
- (catch Exception e nil))")
- (apropos . "(doseq [var (sort (clojure.repl/apropos \"%s\"))]
(println (str var)))")
- (ns-vars . "(clojure.repl/dir %s)")
- (set-ns . "(clojure.core/in-ns '%s)")
- (macroexpand . "(clojure.core/macroexpand '%s)")
- (macroexpand-1 . "(clojure.core/macroexpand-1 '%s)")))))
+ (catch Exception e nil))"))))))
(defvar-local inf-clojure-repl-type nil
"Symbol to define your REPL type.
diff --git a/test/inf-clojure-tests.el b/test/inf-clojure-tests.el
index af6dea905a..c1327a0b03 100644
--- a/test/inf-clojure-tests.el
+++ b/test/inf-clojure-tests.el
@@ -158,4 +158,35 @@ is a string\")
(expect (inf-clojure--update-feature 'not-found 'doc "new doc")
:to-throw))))
+(describe "inf-clojure--merge-repl-features"
+ (it "merges overrides onto a base alist"
+ (let ((base '((a . "base-a") (b . "base-b") (c . "base-c")))
+ (overrides '((b . "override-b"))))
+ (expect (inf-clojure--merge-repl-features base overrides)
+ :to-equal '((b . "override-b") (a . "base-a") (c . "base-c")))))
+ (it "preserves the base when overrides are empty"
+ (let ((base '((a . "base-a") (b . "base-b"))))
+ (expect (inf-clojure--merge-repl-features base nil)
+ :to-equal base))))
+
+(describe "inf-clojure-repl-features"
+ (it "provides all base features for clojure-family REPL types"
+ (let ((base-features '(load doc source apropos ns-vars set-ns
+ macroexpand macroexpand-1 arglists)))
+ (dolist (repl-type '(clojure babashka node-babashka lein-clr))
+ (dolist (feature base-features)
+ (expect (inf-clojure--get-feature repl-type feature nil)
+ :not :to-be nil)))))
+ (it "gives node-babashka the same features as babashka"
+ (let ((bb-features (alist-get 'babashka inf-clojure-repl-features))
+ (nbb-features (alist-get 'node-babashka inf-clojure-repl-features)))
+ (expect bb-features :to-equal nbb-features)))
+ (it "differentiates arglists across clojure-family REPL types"
+ (let ((clj-arglists (inf-clojure--get-feature 'clojure 'arglists nil))
+ (bb-arglists (inf-clojure--get-feature 'babashka 'arglists nil))
+ (clr-arglists (inf-clojure--get-feature 'lein-clr 'arglists nil)))
+ (expect clj-arglists :not :to-equal bb-arglists)
+ (expect clj-arglists :not :to-equal clr-arglists)
+ (expect bb-arglists :not :to-equal clr-arglists))))
+
;;; inf-clojure-tests.el ends here