Skip to content

Commit

Permalink
Implement commands for navigating over logical sexps
Browse files Browse the repository at this point in the history
  • Loading branch information
Malabarba committed Jun 30, 2015
1 parent fda8788 commit 571cb10
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## master (unreleased)

* [#302](https://github.com/clojure-emacs/clojure-mode/pull/302) Add new sexp navigation commands. `clojure-forward-logical-sexp` and `clojure-backward-logical-sexp` consider `^hints` and `#reader.macros` to be part of the sexp that follows them.

## 4.1.0 (20/06/2015)

### Changes
Expand Down
39 changes: 39 additions & 0 deletions clojure-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,45 @@ Returns a list pair, e.g. (\"defn\" \"abc\") or (\"deftest\" \"some-test\")."
(list (match-string 1)
(match-string 2))))))


;;; Sexp navigation
(defun clojure-forward-logical-sexp (&optional n)
"Move forward N logical sexps.
This will skip over sexps that don't represent objects, so that ^hints and
#reader.macros are considered part of the following sexp."
(interactive "p")
(if (< n 0)
(clojure-backward-logical-sexp (- n))
(while (> n 0)
;; Non-logical sexps.
(while (progn (forward-sexp 1)
(forward-sexp -1)
(looking-at-p "\\^\\|#[[:alpha:]]"))
(forward-sexp 1))
;; The actual sexp
(forward-sexp 1)
(setq n (1- n)))))

(defun clojure-backward-logical-sexp (&optional n)
"Move backward N logical sexps.
This will skip over sexps that don't represent objects, so that ^hints and
#reader.macros are considered part of the following sexp."
(interactive "p")
(if (< n 0)
(clojure-forward-logical-sexp (- n))
(while (> n 0)
;; The actual sexp
(backward-sexp 1)
;; Non-logical sexps.
(while (and (not (bobp))
(ignore-errors
(save-excursion
(backward-sexp 1)
(looking-at-p "\\^\\|#[[:alpha:]]"))))
(backward-sexp 1))
(setq n (1- n)))))


;;;###autoload
(progn
(add-to-list 'auto-mode-alist
Expand Down
45 changes: 45 additions & 0 deletions test/clojure-mode-sexp-test.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
;;; clojure-mode-sexp-test.el --- Clojure Mode: sexp tests -*- lexical-binding: t; -*-

;; Copyright (C) 2015 Artur Malabarba <artur@endlessparentheses.com>

;; 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 <http://www.gnu.org/licenses/>.

;;; Code:

(require 'clojure-mode)
(require 'ert)

(ert-deftest test-sexp ()
(with-temp-buffer
(insert "^String #macro ^dynamic reverse")
(clojure-mode)
(clojure-backward-logical-sexp 1)
(should (looking-at-p "\\^String \\#macro \\^dynamic reverse"))
(clojure-forward-logical-sexp 1)
(should (looking-back "\\^String \\#macro \\^dynamic reverse"))
(insert " ^String biverse inverse")
(clojure-backward-logical-sexp 1)
(should (looking-at-p "inverse"))
(clojure-backward-logical-sexp 2)
(should (looking-at-p "\\^String \\#macro \\^dynamic reverse"))
(clojure-forward-logical-sexp 2)
(should (looking-back "\\^String biverse"))
(clojure-backward-logical-sexp 1)
(should (looking-at-p "\\^String biverse"))))

(provide 'clojure-mode-sexp-test)

;;; clojure-mode-sexp-test.el ends here

0 comments on commit 571cb10

Please sign in to comment.