From 1ab3cf527f7a77ea69df8ae0fdadc49f16c9cc96 Mon Sep 17 00:00:00 2001 From: Roman Rudakov Date: Sat, 21 Jun 2025 16:42:35 +0200 Subject: [PATCH] Extend completion to complete ns aliases and required symbols Completions for: - namespace aliases required with `:as` - imported functions required with `:refer` - imported Java classes --- CHANGELOG.md | 2 ++ clojure-ts-mode.el | 29 ++++++++++++++++++++++++++++- test/clojure-ts-mode-completion.el | 28 +++++++++++++++++++++++++++- test/samples/completion.clj | 7 ++++++- 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96251e7..bf5ab1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - [#113](https://github.com/clojure-emacs/clojure-ts-mode/pull/113): Fix non-working refactoring commands for Emacs-30. - [#114](https://github.com/clojure-emacs/clojure-ts-mode/pull/114): Extend built-in completion to complete keywords and local bindings in `for` and `doseq` forms. +- [#116](https://github.com/clojure-emacs/clojure-ts-mode/pull/116): Extend built-in completion to complete all imported symbols from an `ns` + form. ## 0.5.1 (2025-06-17) diff --git a/clojure-ts-mode.el b/clojure-ts-mode.el index 4802d9e..8cb38b4 100644 --- a/clojure-ts-mode.el +++ b/clojure-ts-mode.el @@ -2592,6 +2592,30 @@ before DELIM-OPEN." :anchor ((sym_lit) @defun-candidate))))) "Query that matches top-level definitions.") +(defconst clojure-ts--completion-query-ns + (treesit-query-compile + 'clojure + '(((source (list_lit + :anchor [(comment) (meta_lit) (old_meta_lit)] :* + :anchor (sym_lit name: (sym_name) @sym) + ;; require + (list_lit + :anchor ((kwd_lit) @kwd (:equal ":require" @kwd)) + (vec_lit + :anchor (sym_lit) + [(sym_lit) @ns-alias-candidate + (vec_lit (sym_lit) @defun-candidate)])))) + (:equal "ns" @sym)) + ((source (list_lit + :anchor [(comment) (meta_lit) (old_meta_lit)] :* + :anchor (sym_lit name: (sym_name) @sym) + ;; import + (((list_lit + :anchor ((kwd_lit) @kwd (:equal ":import" @kwd)) + (list_lit :anchor (sym_lit) (sym_lit) @import-candidate)))))) + (:equal "ns" @sym)))) + "Query that matches all imported symbols in a Clojure ns form.") + (defconst clojure-ts--completion-query-keywords (treesit-query-compile 'clojure '((kwd_lit) @keyword-candidate)) "Query that matches any Clojure keyword.") @@ -2634,7 +2658,9 @@ bindings vector as well as destructuring syntax.") (defconst clojure-ts--completion-annotations (list 'defun-candidate " Definition" 'local-candidate " Local variable" - 'keyword-candidate " Keyword") + 'keyword-candidate " Keyword" + 'ns-alias-candidate " Namespace alias" + 'import-candidate " Class") "Property list of completion candidate type and annotation string.") (defun clojure-ts--completion-annotation-function (candidate) @@ -2691,6 +2717,7 @@ all let bindings found along the way." (source (treesit-buffer-root-node 'clojure)) (nodes (append (treesit-query-capture source clojure-ts--completion-query-defuns) (treesit-query-capture source clojure-ts--completion-query-keywords) + (treesit-query-capture source clojure-ts--completion-query-ns) (clojure-ts--completion-fn-args-nodes) (clojure-ts--completion-let-locals-nodes)))) (list (car bounds) diff --git a/test/clojure-ts-mode-completion.el b/test/clojure-ts-mode-completion.el index ffa30df..c3adbcf 100644 --- a/test/clojure-ts-mode-completion.el +++ b/test/clojure-ts-mode-completion.el @@ -196,7 +196,33 @@ u|" (expect (nth 2 (clojure-ts-completion-at-point-function)) :to-equal '((":let" . keyword-candidate) ("digit" . local-candidate) - ("prefixed-digit" . local-candidate)))))) + ("prefixed-digit" . local-candidate))))) + + (it "should complete all imported symbols from a ns form" + (with-clojure-ts-buffer-point " +(ns completion + (:require + [clojure.string :as str] + [clojure.test :as test :refer [deftest testing is]]) + (:import + (java.time Instant LocalDate))) + +s|" + (expect (nth 2 (clojure-ts-completion-at-point-function)) + :to-equal '(("completion" . defun-candidate) + (":require" . keyword-candidate) + (":as" . keyword-candidate) + (":refer" . keyword-candidate) + (":import" . keyword-candidate) + (":require" . kwd) + ("str" . ns-alias-candidate) + ("test" . ns-alias-candidate) + ("deftest" . defun-candidate) + ("testing" . defun-candidate) + ("is" . defun-candidate) + (":import" . kwd) + ("Instant" . import-candidate) + ("LocalDate" . import-candidate)))))) (provide 'clojure-ts-mode-completion) ;;; clojure-ts-mode-completion.el ends here diff --git a/test/samples/completion.clj b/test/samples/completion.clj index 7207d7f..40d132a 100644 --- a/test/samples/completion.clj +++ b/test/samples/completion.clj @@ -1,4 +1,9 @@ -(ns completion) +(ns completion + (:require + [clojure.string :as str] + [clojure.test :as test :refer [deftest testing is]]) + (:import + (java.time Instant LocalDate))) (def my-var "Hello") (def my-another-var "World")