From 0278430d04dd1a82c362739d9979c7aa751341b5 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sat, 23 Mar 2019 12:32:30 -0300 Subject: [PATCH] fix #518 - ns form inside strings and comments --- clojure-mode.el | 40 +++++++++++++++++++++++----------- test/clojure-mode-sexp-test.el | 17 ++++++++++++++- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/clojure-mode.el b/clojure-mode.el index b434c98c..f7af8729 100644 --- a/clojure-mode.el +++ b/clojure-mode.el @@ -1886,6 +1886,19 @@ the cached value will be updated automatically." (defvar-local clojure-cached-ns nil "A buffer ns cache used to speed up ns-related operations.") +(defun clojure--find-ns-in-direction (dir) + "Return the nearest namespace in a specific direction. +DIR is `forward' or `backward'." + (let ((candidate) + (fn (if (eq dir 'forward) + #'search-forward-regexp + #'search-backward-regexp))) + (while (and (not candidate) + (funcall fn clojure-namespace-name-regex nil t)) + (unless (or (clojure--in-string-p) (clojure--in-comment-p)) + (setq candidate (match-string-no-properties 4)))) + candidate)) + (defun clojure-find-ns () "Return the namespace of the current Clojure buffer. Return the namespace closest to point and above it. If there are @@ -1894,19 +1907,16 @@ no namespaces above point, return the first one in the buffer. The results will be cached if `clojure-cache-ns' is set to t." (if (and clojure-cache-ns clojure-cached-ns) clojure-cached-ns - (let ((ns (save-excursion - (save-restriction - (widen) - - ;; Move to top-level to avoid searching from inside ns - (ignore-errors (while t (up-list nil t t))) - - ;; The closest ns form above point. - (when (or (re-search-backward clojure-namespace-name-regex nil t) - ;; Or any form at all. - (and (goto-char (point-min)) - (re-search-forward clojure-namespace-name-regex nil t))) - (match-string-no-properties 4)))))) + (let* ((ns (save-excursion + (save-restriction + (widen) + + ;; Move to top-level to avoid searching from inside ns + (ignore-errors (while t (up-list nil t t))) + + ;; Move to closest ns form above point. + (or (clojure--find-ns-in-direction 'backward) + (clojure--find-ns-in-direction 'forward)))))) (setq clojure-cached-ns ns) ns))) @@ -2384,6 +2394,10 @@ See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-cycle-privacy" "Check whether the point is currently in a string." (nth 3 (syntax-ppss))) +(defun clojure--in-comment-p () + "Check whether the point is currently in a comment." + (nth 4 (syntax-ppss))) + (defun clojure--goto-if () "Find the first surrounding if or if-not expression." (when (clojure--in-string-p) diff --git a/test/clojure-mode-sexp-test.el b/test/clojure-mode-sexp-test.el index 801356a7..f8a97e3c 100644 --- a/test/clojure-mode-sexp-test.el +++ b/test/clojure-mode-sexp-test.el @@ -162,7 +162,22 @@ and point left there." ;; From inside second ns's name (goto-char 42) - (should (equal "baz-quux" (clojure-find-ns)))))) + (should (equal "baz-quux" (clojure-find-ns)))) + (let ((data + '(("\"\n(ns foo-bar)\"\n" "(in-ns 'baz-quux)" "baz-quux") + (";(ns foo-bar)\n" "(in-ns 'baz-quux)" "baz-quux") + ("(ns foo-bar)\n" "\"\n(in-ns 'baz-quux)\"" "foo-bar") + ("(ns foo-bar)\n" ";(in-ns 'baz-quux)" "foo-bar")))) + (pcase-dolist (`(,form1 ,form2 ,expected) data) + (with-temp-buffer + (insert form1) + (save-excursion (insert form2)) + (clojure-mode) + ;; Between the two namespaces + (should (equal expected (clojure-find-ns))) + ;; After both namespaces + (goto-char (point-max)) + (should (equal expected (clojure-find-ns)))))))) (provide 'clojure-mode-sexp-test)