Skip to content

Commit

Permalink
[Fix #518] Ignore ns forms inside strings in clojure-find-ns (#519)
Browse files Browse the repository at this point in the history
  • Loading branch information
Malabarba authored and bbatsov committed Mar 25, 2019
1 parent 4387cb8 commit e898a94
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* [#508](https://github.com/clojure-emacs/clojure-mode/issues/508): Fix font lock for namespaces with metadata
* [#506](https://github.com/clojure-emacs/clojure-mode/issues/506): `clojure-mode-display-version` correctly displays the package's version
* [#445](https://github.com/clojure-emacs/clojure-mode/issues/445), [#405](https://github.com/clojure-emacs/clojure-mode/issues/405), [#469](https://github.com/clojure-emacs/clojure-mode/issues/469): Correct font-lock on string definitions with docstrings, e.g: `(def foo "doc" "value")`. Correct indentation as well.
* [#518](https://github.com/clojure-emacs/clojure-mode/issues/518): Fix clojure-find-ns when there's an `ns` form inside a string

## 5.10.0 (2019-01-05)

Expand Down
25 changes: 19 additions & 6 deletions clojure-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -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 (direction)
"Return the nearest namespace in a specific DIRECTION.
DIRECTION is `forward' or `backward'."
(let ((candidate)
(fn (if (eq direction '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
Expand All @@ -1901,12 +1914,8 @@ The results will be cached if `clojure-cache-ns' is set to t."
;; 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))))))
(or (clojure--find-ns-in-direction 'backward)
(clojure--find-ns-in-direction 'forward))))))
(setq clojure-cached-ns ns)
ns)))

Expand Down Expand Up @@ -2384,6 +2393,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)
Expand Down
49 changes: 32 additions & 17 deletions test/clojure-mode-sexp-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -146,23 +146,38 @@ and point left there."
;; we should not cache the results of `clojure-find-ns' here
(let ((clojure-cache-ns nil))
(with-temp-buffer
(insert "(ns ^{:doc \"Some docs\"}\nfoo-bar)")
(newline)
(newline)
(insert "(in-ns 'baz-quux)")
(clojure-mode)

;; From inside docstring of first ns
(goto-char 18)
(should (equal "foo-bar" (clojure-find-ns)))

;; From inside first ns's name, on its own line
(goto-char 29)
(should (equal "foo-bar" (clojure-find-ns)))

;; From inside second ns's name
(goto-char 42)
(should (equal "baz-quux" (clojure-find-ns))))))
(insert "(ns ^{:doc \"Some docs\"}\nfoo-bar)")
(newline)
(newline)
(insert "(in-ns 'baz-quux)")
(clojure-mode)

;; From inside docstring of first ns
(goto-char 18)
(should (equal "foo-bar" (clojure-find-ns)))

;; From inside first ns's name, on its own line
(goto-char 29)
(should (equal "foo-bar" (clojure-find-ns)))

;; From inside second ns's name
(goto-char 42)
(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)

Expand Down

0 comments on commit e898a94

Please sign in to comment.