diff --git a/CHANGELOG.md b/CHANGELOG.md index c669d0e..743d6b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [#46]: Fix missing `comment-add` variable in `clojure-ts-mode-variables` mentioned in [#26] - Add imenu support for `deftest` definitions. - [#53]: Let `clojure-ts-mode` derive from `clojure-mode` for Emacs 30+. +- [#42]: Fix imenu support for definitions with metadata. ## 0.2.2 (2024-02-16) diff --git a/clojure-ts-mode.el b/clojure-ts-mode.el index 8a68839..a562f03 100644 --- a/clojure-ts-mode.el +++ b/clojure-ts-mode.el @@ -520,6 +520,10 @@ with the markdown_inline grammar." "Return non-nil if NODE is a Clojure keyword." (string-equal "kwd_lit" (treesit-node-type node))) +(defun clojure-ts--metadata-node-p (node) + "Return non-nil if NODE is a Clojure metadata node." + (string-equal "meta_lit" (treesit-node-type node))) + (defun clojure-ts--named-node-text (node) "Gets the name of a symbol or keyword NODE. This does not include the NODE's namespace." @@ -530,6 +534,11 @@ This does not include the NODE's namespace." (and (clojure-ts--symbol-node-p node) (string-equal expected-symbol-name (clojure-ts--named-node-text node)))) +(defun clojure-ts--node-child-skip-metadata (node n) + "Return the Nth child of NODE like `treesit-node-child`, skipping the optional metadata node at pos 0 if present." + (let ((first-child (treesit-node-child node 0 t))) + (treesit-node-child node (if (clojure-ts--metadata-node-p first-child) (1+ n) n) t))) + (defun clojure-ts--symbol-matches-p (symbol-regexp node) "Return non-nil if NODE is a symbol that matches SYMBOL-REGEXP." (and (clojure-ts--symbol-node-p node) @@ -550,7 +559,7 @@ like \"defn\". See `clojure-ts--definition-node-p' when an exact match is possible." (and (clojure-ts--list-node-p node) - (let* ((child (treesit-node-child node 0 t)) + (let* ((child (clojure-ts--node-child-skip-metadata node 0)) (child-txt (clojure-ts--named-node-text child))) (and (clojure-ts--symbol-node-p child) (string-match-p definition-type-regexp child-txt))))) @@ -565,8 +574,8 @@ that a node is a definition is intended to be done elsewhere. Can be called directly, but intended for use as `treesit-defun-name-function'." (when (and (clojure-ts--list-node-p node) - (clojure-ts--symbol-node-p (treesit-node-child node 0 t))) - (let ((sym (treesit-node-child node 1 t))) + (clojure-ts--symbol-node-p (clojure-ts--node-child-skip-metadata node 0))) + (let ((sym (clojure-ts--node-child-skip-metadata node 1))) (when (clojure-ts--symbol-node-p sym) ;; Extracts ns and name, and recreates the full var name. ;; We can't just get the node-text of the full symbol because diff --git a/test/clojure-ts-mode-imenu-test.el b/test/clojure-ts-mode-imenu-test.el new file mode 100644 index 0000000..1dbe71c --- /dev/null +++ b/test/clojure-ts-mode-imenu-test.el @@ -0,0 +1,38 @@ +;;; clojure-ts-mode-util-test.el --- Clojure TS Mode: util test suite -*- lexical-binding: t; -*- + +;; Copyright © 2022-2024 Danny Freeman + +;; This file is not part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; The unit test suite of Clojure TS Mode + +(require 'clojure-ts-mode) +(require 'buttercup) +(require 'imenu) + + +(describe "clojure-ts-mode imenu integration" + (it "should index def with meta data" + (with-clojure-ts-buffer "^{:foo 1}(def a 1)" + (expect (imenu--in-alist "a" (imenu--make-index-alist)) + :not :to-be nil))) + + (it "should index defn with meta data" + (with-clojure-ts-buffer "^{:foo 1}(defn a [])" + (expect (imenu--in-alist "a" (imenu--make-index-alist)) + :not :to-be nil))))