aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Colascione2014-04-09 09:58:08 -0700
committerDaniel Colascione2014-04-09 09:58:08 -0700
commit3f63a9f7de4f252a0309c2143e6d916d734ffe22 (patch)
tree01a53bee941983edfc24944f9774741eafa87c81
parent6c971fb0f44169d7f77a9575301a4935106c0360 (diff)
downloademacs-3f63a9f7de4f252a0309c2143e6d916d734ffe22.tar.gz
emacs-3f63a9f7de4f252a0309c2143e6d916d734ffe22.zip
Make up-list and backward-up-list get out of more spots
-rw-r--r--doc/lispref/ChangeLog8
-rw-r--r--doc/lispref/errors.texi5
-rw-r--r--doc/lispref/positions.texi16
-rw-r--r--lisp/ChangeLog8
-rw-r--r--lisp/emacs-lisp/lisp.el116
-rw-r--r--test/ChangeLog4
-rw-r--r--test/automated/syntax-tests.el97
7 files changed, 221 insertions, 33 deletions
diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog
index 2ae1faffc4e..25fa8ca4946 100644
--- a/doc/lispref/ChangeLog
+++ b/doc/lispref/ChangeLog
@@ -1,3 +1,11 @@
12014-04-09 Daniel Colascione <dancol@dancol.org>
2
3 * errors.texi (Standard Errors): Document required error
4 parameters for `scan-error'.
5
6 * positions.texi (List Motion): Explain new `up-list' arguments.
7 Mention `backward-up-list'.
8
12014-04-08 Daniel Colascione <dancol@dancol.org> 92014-04-08 Daniel Colascione <dancol@dancol.org>
2 10
3 * minibuf.texi (Programmed Completion): Improve phrasing, remove 11 * minibuf.texi (Programmed Completion): Improve phrasing, remove
diff --git a/doc/lispref/errors.texi b/doc/lispref/errors.texi
index e00496e3478..dba8d219774 100644
--- a/doc/lispref/errors.texi
+++ b/doc/lispref/errors.texi
@@ -157,7 +157,10 @@ The message is @samp{Attempt to modify a protected file}.
157@item scan-error 157@item scan-error
158The message is @samp{Scan error}. This happens when certain 158The message is @samp{Scan error}. This happens when certain
159syntax-parsing functions find invalid syntax or mismatched 159syntax-parsing functions find invalid syntax or mismatched
160parentheses. @xref{List Motion}, and @xref{Parsing Expressions}. 160parentheses. Conventionally raised with three argument: a
161human-readable error message, the start of the obstacle that cannot be
162moved over, and the end of the obstacle. @xref{List Motion}, and
163@xref{Parsing Expressions}.
161 164
162@item search-failed 165@item search-failed
163The message is @samp{Search failed}. @xref{Searching and Matching}. 166The message is @samp{Search failed}. @xref{Searching and Matching}.
diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi
index f83173e2038..5a77b37e7e1 100644
--- a/doc/lispref/positions.texi
+++ b/doc/lispref/positions.texi
@@ -647,9 +647,19 @@ parentheses. (Other syntactic entities such as words or paired string
647quotes are ignored.) 647quotes are ignored.)
648@end deffn 648@end deffn
649 649
650@deffn Command up-list &optional arg 650@deffn Command up-list &optional arg escape-strings no-syntax-crossing
651This function moves forward out of @var{arg} (default 1) levels of parentheses. 651This function moves forward out of @var{arg} (default 1) levels of
652A negative argument means move backward but still to a less deep spot. 652parentheses. A negative argument means move backward but still to a
653less deep spot. If @var{escape-strings} is non-nil (as it is
654interactively), move out of enclosing strings as well. If
655@var{no-syntax-crossing} is non-nil (as it is interactively), prefer
656to break out of any enclosing string instead of moving to the start of
657a list broken across multiple strings. On error, location of point is
658unspecified.
659@end deffn
660
661@deffn Command backward-up-list &optional arg escape-strings no-syntax-crossing
662This function is just like @code{up-list}, but with a negated argument.
653@end deffn 663@end deffn
654 664
655@deffn Command down-list &optional arg 665@deffn Command down-list &optional arg
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 8f27ffbf636..bab1edaffda 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,11 @@
12014-04-09 Daniel Colascione <dancol@dancol.org>
2
3 * emacs-lisp/lisp.el (backward-up-list): Add `escape-strings',
4 `no-syntax-crossing' arguments. Forward to `up-list'.
5 (up-list): Add `escape-strings', `no-syntax-crossing' arguments.
6 Implement logic for escaping from strings. Use narrowing to deal
7 with corner cases.
8
12014-04-09 Leo Liu <sdl.web@gmail.com> 92014-04-09 Leo Liu <sdl.web@gmail.com>
2 10
3 * net/rcirc.el (rcirc-connection-info): New variable. 11 * net/rcirc.el (rcirc-connection-info): New variable.
diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el
index 0487515a142..3ff65ff11cd 100644
--- a/lisp/emacs-lisp/lisp.el
+++ b/lisp/emacs-lisp/lisp.el
@@ -57,10 +57,14 @@ Should take the same arguments and behave similarly to `forward-sexp'.")
57 57
58(defun forward-sexp (&optional arg) 58(defun forward-sexp (&optional arg)
59 "Move forward across one balanced expression (sexp). 59 "Move forward across one balanced expression (sexp).
60With ARG, do it that many times. Negative arg -N means 60With ARG, do it that many times. Negative arg -N means move
61move backward across N balanced expressions. 61backward across N balanced expressions. This command assumes
62This command assumes point is not in a string or comment. 62point is not in a string or comment. Calls
63Calls `forward-sexp-function' to do the work, if that is non-nil." 63`forward-sexp-function' to do the work, if that is non-nil. If
64unable to move over a sexp, signal `scan-error' with three
65arguments: a message, the start of the obstacle (usually a
66parenthesis or list marker of some kind), and end of the
67obstacle."
64 (interactive "^p") 68 (interactive "^p")
65 (or arg (setq arg 1)) 69 (or arg (setq arg 1))
66 (if forward-sexp-function 70 (if forward-sexp-function
@@ -140,38 +144,92 @@ This command assumes point is not in a string or comment."
140 (goto-char (or (scan-lists (point) inc -1) (buffer-end arg))) 144 (goto-char (or (scan-lists (point) inc -1) (buffer-end arg)))
141 (setq arg (- arg inc))))) 145 (setq arg (- arg inc)))))
142 146
143(defun backward-up-list (&optional arg) 147(defun backward-up-list (&optional arg escape-strings no-syntax-crossing)
144 "Move backward out of one level of parentheses. 148 "Move backward out of one level of parentheses.
145This command will also work on other parentheses-like expressions 149This command will also work on other parentheses-like expressions
146defined by the current language mode. 150defined by the current language mode. With ARG, do this that
147With ARG, do this that many times. 151many times. A negative argument means move forward but still to
148A negative argument means move forward but still to a less deep spot. 152a less deep spot. If ESCAPE-STRINGS is non-nil (as it is
149This command assumes point is not in a string or comment." 153interactively), move out of enclosing strings as well. If
150 (interactive "^p") 154NO-SYNTAX-CROSSING is non-nil (as it is interactively), prefer to
151 (up-list (- (or arg 1)))) 155break out of any enclosing string instead of moving to the start
152 156of a list broken across multiple strings. On error, location of
153(defun up-list (&optional arg) 157point is unspecified."
158 (interactive "^p\nd\nd")
159 (up-list (- (or arg 1)) escape-strings no-syntax-crossing))
160
161(defun up-list (&optional arg escape-strings no-syntax-crossing)
154 "Move forward out of one level of parentheses. 162 "Move forward out of one level of parentheses.
155This command will also work on other parentheses-like expressions 163This command will also work on other parentheses-like expressions
156defined by the current language mode. 164defined by the current language mode. With ARG, do this that
157With ARG, do this that many times. 165many times. A negative argument means move backward but still to
158A negative argument means move backward but still to a less deep spot. 166a less deep spot. If ESCAPE-STRINGS is non-nil (as it is
159This command assumes point is not in a string or comment." 167interactively), move out of enclosing strings as well. If
160 (interactive "^p") 168NO-SYNTAX-CROSSING is non-nil (as it is interactively), prefer to
169break out of any enclosing string instead of moving to the start
170of a list broken across multiple strings. On error, location of
171point is unspecified."
172 (interactive "^p\nd\nd")
161 (or arg (setq arg 1)) 173 (or arg (setq arg 1))
162 (let ((inc (if (> arg 0) 1 -1)) 174 (let ((inc (if (> arg 0) 1 -1))
163 pos) 175 (pos nil))
164 (while (/= arg 0) 176 (while (/= arg 0)
165 (if (null forward-sexp-function) 177 (condition-case err
166 (goto-char (or (scan-lists (point) inc 1) (buffer-end arg))) 178 (save-restriction
167 (condition-case err 179 ;; If we've been asked not to cross string boundaries
168 (while (progn (setq pos (point)) 180 ;; and we're inside a string, narrow to that string so
169 (forward-sexp inc) 181 ;; that scan-lists doesn't find a match in a different
170 (/= (point) pos))) 182 ;; string.
171 (scan-error (goto-char (nth (if (> arg 0) 3 2) err)))) 183 (when no-syntax-crossing
172 (if (= (point) pos) 184 (let* ((syntax (syntax-ppss))
173 (signal 'scan-error 185 (string-comment-start (nth 8 syntax)))
174 (list "Unbalanced parentheses" (point) (point))))) 186 (when string-comment-start
187 (save-excursion
188 (goto-char string-comment-start)
189 (narrow-to-region
190 (point)
191 (if (nth 3 syntax) ; in string
192 (condition-case nil
193 (progn (forward-sexp) (point))
194 (scan-error (point-max)))
195 (forward-comment 1)
196 (point)))))))
197 (if (null forward-sexp-function)
198 (goto-char (or (scan-lists (point) inc 1)
199 (buffer-end arg)))
200 (condition-case err
201 (while (progn (setq pos (point))
202 (forward-sexp inc)
203 (/= (point) pos)))
204 (scan-error (goto-char (nth (if (> arg 0) 3 2) err))))
205 (if (= (point) pos)
206 (signal 'scan-error
207 (list "Unbalanced parentheses" (point) (point))))))
208 (scan-error
209 (let ((syntax nil))
210 (or
211 ;; If we bumped up against the end of a list, see whether
212 ;; we're inside a string: if so, just go to the beginning
213 ;; or end of that string.
214 (and escape-strings
215 (or syntax (setf syntax (syntax-ppss)))
216 (nth 3 syntax)
217 (goto-char (nth 8 syntax))
218 (progn (when (> inc 0)
219 (forward-sexp))
220 t))
221 ;; If we narrowed to a comment above and failed to escape
222 ;; it, the error might be our fault, not an indication
223 ;; that we're out of syntax. Try again from beginning or
224 ;; end of the comment.
225 (and no-syntax-crossing
226 (or syntax (setf syntax (syntax-ppss)))
227 (nth 4 syntax)
228 (goto-char (nth 8 syntax))
229 (or (< inc 0)
230 (forward-comment 1))
231 (setf arg (+ arg inc)))
232 (signal (car err) (cdr err))))))
175 (setq arg (- arg inc))))) 233 (setq arg (- arg inc)))))
176 234
177(defun kill-sexp (&optional arg) 235(defun kill-sexp (&optional arg)
diff --git a/test/ChangeLog b/test/ChangeLog
index c27b9b5f437..ebba4f01e93 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,7 @@
12014-04-09 Daniel Colascione <dancol@dancol.org>
2
3 * automated/syntax-tests.el: New file.
4
12014-04-09 Glenn Morris <rgm@gnu.org> 52014-04-09 Glenn Morris <rgm@gnu.org>
2 6
3 * automated/python-tests.el (python-triple-quote-pairing): 7 * automated/python-tests.el (python-triple-quote-pairing):
diff --git a/test/automated/syntax-tests.el b/test/automated/syntax-tests.el
new file mode 100644
index 00000000000..9b97001a14e
--- /dev/null
+++ b/test/automated/syntax-tests.el
@@ -0,0 +1,97 @@
1;;; syntax-tests.el --- Testing syntax rules and basic movement -*- lexical-binding: t -*-
2
3;; Copyright (C) 2014 Free Software Foundation, Inc.
4
5;; Author: Daniel Colascione <dancol@dancol.org>
6;; Keywords:
7
8;; This program is free software; you can redistribute it and/or modify
9;; it under the terms of the GNU General Public License as published by
10;; the Free Software Foundation, either version 3 of the License, or
11;; (at your option) any later version.
12
13;; This program is distributed in the hope that it will be useful,
14;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;; GNU General Public License for more details.
17
18;; You should have received a copy of the GNU General Public License
19;; along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21;;; Commentary:
22
23;;
24
25;;; Code:
26(require 'ert)
27(require 'cl-lib)
28
29(defun run-up-list-test (fn data start instructions)
30 (cl-labels ((posof (thing)
31 (and (symbolp thing)
32 (= (length (symbol-name thing)) 1)
33 (- (aref (symbol-name thing) 0) ?a -1))))
34 (with-temp-buffer
35 (set-syntax-table (make-syntax-table))
36 ;; Use a syntax table in which single quote is a string
37 ;; character so that we can embed the test data in a lisp string
38 ;; literal.
39 (modify-syntax-entry ?\' "\"")
40 (insert data)
41 (goto-char (posof start))
42 (dolist (instruction instructions)
43 (cond ((posof instruction)
44 (funcall fn)
45 (should (eql (point) (posof instruction))))
46 ((symbolp instruction)
47 (should-error (funcall fn)
48 :type instruction))
49 (t (cl-assert nil nil "unknown ins")))))))
50
51(defmacro define-up-list-test (name fn data start &rest expected)
52 `(ert-deftest ,name ()
53 (run-up-list-test ,fn ,data ',start ',expected)))
54
55(define-up-list-test up-list-basic
56 (lambda () (up-list))
57 (or "(1 1 (1 1) 1 (1 1) 1)")
58 ;; abcdefghijklmnopqrstuv
59 i k v scan-error)
60
61(define-up-list-test up-list-with-forward-sexp-function
62 (lambda ()
63 (let ((forward-sexp-function
64 (lambda (&optional arg)
65 (let ((forward-sexp-function nil))
66 (forward-sexp arg)))))
67 (up-list)))
68 (or "(1 1 (1 1) 1 (1 1) 1)")
69 ;; abcdefghijklmnopqrstuv
70 i k v scan-error)
71
72(define-up-list-test up-list-out-of-string
73 (lambda () (up-list 1 t))
74 (or "1 (1 '2 2 (2 2 2' 1) 1")
75 ;; abcdefghijklmnopqrstuvwxy
76 o r u scan-error)
77
78(define-up-list-test up-list-cross-string
79 (lambda () (up-list 1 t))
80 (or "(1 '2 ( 2' 1 '2 ) 2' 1)")
81 ;; abcdefghijklmnopqrstuvwxy
82 i r u x scan-error)
83
84(define-up-list-test up-list-no-cross-string
85 (lambda () (up-list 1 t t))
86 (or "(1 '2 ( 2' 1 '2 ) 2' 1)")
87 ;; abcdefghijklmnopqrstuvwxy
88 i k x scan-error)
89
90(define-up-list-test backward-up-list-basic
91 (lambda () (backward-up-list))
92 (or "(1 1 (1 1) 1 (1 1) 1)")
93 ;; abcdefghijklmnopqrstuv
94 i f a scan-error)
95
96(provide 'syntax-tests)
97;;; syntax-tests.el ends here