emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] trunk r116963: Make up-list and backward-up-list get out o


From: Daniel Colascione
Subject: [Emacs-diffs] trunk r116963: Make up-list and backward-up-list get out of more spots
Date: Wed, 09 Apr 2014 17:12:36 +0000
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 116963
revision-id: address@hidden
parent: address@hidden
committer: Daniel Colascione <address@hidden>
branch nick: trunk
timestamp: Wed 2014-04-09 09:58:08 -0700
message:
  Make up-list and backward-up-list get out of more spots
added:
  test/automated/syntax-tests.el 
syntaxtests.el-20140409062257-6rj0ssyhpfo3sb6y-1
modified:
  doc/lispref/ChangeLog          changelog-20091113204419-o5vbwnq5f7feedwu-6155
  doc/lispref/errors.texi        
errors.texi-20091113204419-o5vbwnq5f7feedwu-6177
  doc/lispref/positions.texi     
positions.texi-20091113204419-o5vbwnq5f7feedwu-6206
  lisp/ChangeLog                 changelog-20091113204419-o5vbwnq5f7feedwu-1432
  lisp/emacs-lisp/lisp.el        lisp.el-20091113204419-o5vbwnq5f7feedwu-131
  test/ChangeLog                 changelog-20091113204419-o5vbwnq5f7feedwu-8588
=== modified file 'doc/lispref/ChangeLog'
--- a/doc/lispref/ChangeLog     2014-04-08 10:33:48 +0000
+++ b/doc/lispref/ChangeLog     2014-04-09 16:58:08 +0000
@@ -1,3 +1,11 @@
+2014-04-09  Daniel Colascione  <address@hidden>
+
+       * errors.texi (Standard Errors): Document required error
+       parameters for `scan-error'.
+
+       * positions.texi (List Motion): Explain new `up-list' arguments.
+       Mention `backward-up-list'.
+
 2014-04-08  Daniel Colascione  <address@hidden>
 
        * minibuf.texi (Programmed Completion): Improve phrasing, remove

=== modified file 'doc/lispref/errors.texi'
--- a/doc/lispref/errors.texi   2014-01-01 07:43:34 +0000
+++ b/doc/lispref/errors.texi   2014-04-09 16:58:08 +0000
@@ -157,7 +157,10 @@
 @item scan-error
 The message is @samp{Scan error}.  This happens when certain
 syntax-parsing functions find invalid syntax or mismatched
-parentheses.  @xref{List Motion}, and @xref{Parsing Expressions}.
+parentheses.  Conventionally raised with three argument: a
+human-readable error message, the start of the obstacle that cannot be
+moved over, and the end of the obstacle.  @xref{List Motion}, and
address@hidden Expressions}.
 
 @item search-failed
 The message is @samp{Search failed}.  @xref{Searching and Matching}.

=== modified file 'doc/lispref/positions.texi'
--- a/doc/lispref/positions.texi        2014-02-06 04:27:26 +0000
+++ b/doc/lispref/positions.texi        2014-04-09 16:58:08 +0000
@@ -647,9 +647,19 @@
 quotes are ignored.)
 @end deffn
 
address@hidden Command up-list &optional arg
-This function moves forward out of @var{arg} (default 1) levels of parentheses.
-A negative argument means move backward but still to a less deep spot.
address@hidden Command up-list &optional arg escape-strings no-syntax-crossing
+This function moves forward out of @var{arg} (default 1) levels of
+parentheses.  A negative argument means move backward but still to a
+less deep spot.  If @var{escape-strings} is non-nil (as it is
+interactively), move out of enclosing strings as well. If
address@hidden is non-nil (as it is interactively), prefer
+to break out of any enclosing string instead of moving to the start of
+a list broken across multiple strings.  On error, location of point is
+unspecified.
address@hidden deffn
+
address@hidden Command backward-up-list &optional arg escape-strings 
no-syntax-crossing
+This function is just like @code{up-list}, but with a negated argument.
 @end deffn
 
 @deffn Command down-list &optional arg

=== modified file 'lisp/ChangeLog'
--- a/lisp/ChangeLog    2014-04-09 13:37:49 +0000
+++ b/lisp/ChangeLog    2014-04-09 16:58:08 +0000
@@ -1,3 +1,11 @@
+2014-04-09  Daniel Colascione  <address@hidden>
+
+       * emacs-lisp/lisp.el (backward-up-list): Add `escape-strings',
+       `no-syntax-crossing' arguments.  Forward to `up-list'.
+       (up-list): Add `escape-strings', `no-syntax-crossing' arguments.
+       Implement logic for escaping from strings.  Use narrowing to deal
+       with corner cases.
+
 2014-04-09  Leo Liu  <address@hidden>
 
        * net/rcirc.el (rcirc-connection-info): New variable.

=== modified file 'lisp/emacs-lisp/lisp.el'
--- a/lisp/emacs-lisp/lisp.el   2014-02-26 02:31:27 +0000
+++ b/lisp/emacs-lisp/lisp.el   2014-04-09 16:58:08 +0000
@@ -57,10 +57,14 @@
 
 (defun forward-sexp (&optional arg)
   "Move forward across one balanced expression (sexp).
-With ARG, do it that many times.  Negative arg -N means
-move backward across N balanced expressions.
-This command assumes point is not in a string or comment.
-Calls `forward-sexp-function' to do the work, if that is non-nil."
+With ARG, do it that many times.  Negative arg -N means move
+backward across N balanced expressions.  This command assumes
+point is not in a string or comment.  Calls
+`forward-sexp-function' to do the work, if that is non-nil.  If
+unable to move over a sexp, signal `scan-error' with three
+arguments: a message, the start of the obstacle (usually a
+parenthesis or list marker of some kind), and end of the
+obstacle."
   (interactive "^p")
   (or arg (setq arg 1))
   (if forward-sexp-function
@@ -140,38 +144,92 @@
       (goto-char (or (scan-lists (point) inc -1) (buffer-end arg)))
       (setq arg (- arg inc)))))
 
-(defun backward-up-list (&optional arg)
+(defun backward-up-list (&optional arg escape-strings no-syntax-crossing)
   "Move backward out of one level of parentheses.
 This command will also work on other parentheses-like expressions
-defined by the current language mode.
-With ARG, do this that many times.
-A negative argument means move forward but still to a less deep spot.
-This command assumes point is not in a string or comment."
-  (interactive "^p")
-  (up-list (- (or arg 1))))
+defined by the current language mode.  With ARG, do this that
+many times.  A negative argument means move forward but still to
+a less deep spot.  If ESCAPE-STRINGS is non-nil (as it is
+interactively), move out of enclosing strings as well.  If
+NO-SYNTAX-CROSSING is non-nil (as it is interactively), prefer to
+break out of any enclosing string instead of moving to the start
+of a list broken across multiple strings.  On error, location of
+point is unspecified."
+  (interactive "^p\nd\nd")
+  (up-list (- (or arg 1)) escape-strings no-syntax-crossing))
 
-(defun up-list (&optional arg)
+(defun up-list (&optional arg escape-strings no-syntax-crossing)
   "Move forward out of one level of parentheses.
 This command will also work on other parentheses-like expressions
-defined by the current language mode.
-With ARG, do this that many times.
-A negative argument means move backward but still to a less deep spot.
-This command assumes point is not in a string or comment."
-  (interactive "^p")
+defined by the current language mode.  With ARG, do this that
+many times.  A negative argument means move backward but still to
+a less deep spot.  If ESCAPE-STRINGS is non-nil (as it is
+interactively), move out of enclosing strings as well. If
+NO-SYNTAX-CROSSING is non-nil (as it is interactively), prefer to
+break out of any enclosing string instead of moving to the start
+of a list broken across multiple strings.  On error, location of
+point is unspecified."
+  (interactive "^p\nd\nd")
   (or arg (setq arg 1))
   (let ((inc (if (> arg 0) 1 -1))
-        pos)
+        (pos nil))
     (while (/= arg 0)
-      (if (null forward-sexp-function)
-          (goto-char (or (scan-lists (point) inc 1) (buffer-end arg)))
-       (condition-case err
-           (while (progn (setq pos (point))
-                         (forward-sexp inc)
-                         (/= (point) pos)))
-         (scan-error (goto-char (nth (if (> arg 0) 3 2) err))))
-       (if (= (point) pos)
-            (signal 'scan-error
-                    (list "Unbalanced parentheses" (point) (point)))))
+      (condition-case err
+          (save-restriction
+            ;; If we've been asked not to cross string boundaries
+            ;; and we're inside a string, narrow to that string so
+            ;; that scan-lists doesn't find a match in a different
+            ;; string.
+            (when no-syntax-crossing
+              (let* ((syntax (syntax-ppss))
+                     (string-comment-start (nth 8 syntax)))
+                (when string-comment-start
+                  (save-excursion
+                    (goto-char string-comment-start)
+                    (narrow-to-region
+                     (point)
+                     (if (nth 3 syntax) ; in string
+                         (condition-case nil
+                             (progn (forward-sexp) (point))
+                           (scan-error (point-max)))
+                       (forward-comment 1)
+                       (point)))))))
+            (if (null forward-sexp-function)
+                (goto-char (or (scan-lists (point) inc 1)
+                               (buffer-end arg)))
+              (condition-case err
+                  (while (progn (setq pos (point))
+                                (forward-sexp inc)
+                                (/= (point) pos)))
+                (scan-error (goto-char (nth (if (> arg 0) 3 2) err))))
+              (if (= (point) pos)
+                  (signal 'scan-error
+                          (list "Unbalanced parentheses" (point) (point))))))
+        (scan-error
+         (let ((syntax nil))
+           (or
+            ;; If we bumped up against the end of a list, see whether
+            ;; we're inside a string: if so, just go to the beginning
+            ;; or end of that string.
+            (and escape-strings
+                 (or syntax (setf syntax (syntax-ppss)))
+                 (nth 3 syntax)
+                 (goto-char (nth 8 syntax))
+                 (progn (when (> inc 0)
+                          (forward-sexp))
+                        t))
+            ;; If we narrowed to a comment above and failed to escape
+            ;; it, the error might be our fault, not an indication
+            ;; that we're out of syntax.  Try again from beginning or
+            ;; end of the comment.
+            (and no-syntax-crossing
+                 (or syntax (setf syntax (syntax-ppss)))
+                 (nth 4 syntax)
+                 (goto-char (nth 8 syntax))
+                 (or (< inc 0)
+                     (forward-comment 1))
+                 (setf arg (+ arg inc)))
+            (signal (car err) (cdr err))))))
       (setq arg (- arg inc)))))
 
 (defun kill-sexp (&optional arg)

=== modified file 'test/ChangeLog'
--- a/test/ChangeLog    2014-04-09 03:37:56 +0000
+++ b/test/ChangeLog    2014-04-09 16:58:08 +0000
@@ -1,3 +1,7 @@
+2014-04-09  Daniel Colascione  <address@hidden>
+
+       * automated/syntax-tests.el: New file.
+
 2014-04-09  Glenn Morris  <address@hidden>
 
        * automated/python-tests.el (python-triple-quote-pairing):

=== added file 'test/automated/syntax-tests.el'
--- a/test/automated/syntax-tests.el    1970-01-01 00:00:00 +0000
+++ b/test/automated/syntax-tests.el    2014-04-09 16:58:08 +0000
@@ -0,0 +1,97 @@
+;;; syntax-tests.el --- Testing syntax rules and basic movement -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2014 Free Software Foundation, Inc.
+
+;; Author: Daniel Colascione <address@hidden>
+;; Keywords:
+
+;; 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/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+(require 'ert)
+(require 'cl-lib)
+
+(defun run-up-list-test (fn data start instructions)
+  (cl-labels ((posof (thing)
+                (and (symbolp thing)
+                     (= (length (symbol-name thing)) 1)
+                     (- (aref (symbol-name thing) 0) ?a -1))))
+    (with-temp-buffer
+      (set-syntax-table (make-syntax-table))
+      ;; Use a syntax table in which single quote is a string
+      ;; character so that we can embed the test data in a lisp string
+      ;; literal.
+      (modify-syntax-entry ?\' "\"")
+      (insert data)
+      (goto-char (posof start))
+      (dolist (instruction instructions)
+        (cond ((posof instruction)
+               (funcall fn)
+               (should (eql (point) (posof instruction))))
+              ((symbolp instruction)
+               (should-error (funcall fn)
+                             :type instruction))
+              (t (cl-assert nil nil "unknown ins")))))))
+
+(defmacro define-up-list-test (name fn data start &rest expected)
+  `(ert-deftest ,name ()
+     (run-up-list-test ,fn ,data ',start ',expected)))
+
+(define-up-list-test up-list-basic
+  (lambda () (up-list))
+  (or "(1 1 (1 1) 1 (1 1) 1)")
+  ;;   abcdefghijklmnopqrstuv
+  i k v scan-error)
+
+(define-up-list-test up-list-with-forward-sexp-function
+  (lambda ()
+    (let ((forward-sexp-function
+           (lambda (&optional arg)
+             (let ((forward-sexp-function nil))
+               (forward-sexp arg)))))
+      (up-list)))
+  (or "(1 1 (1 1) 1 (1 1) 1)")
+  ;;   abcdefghijklmnopqrstuv
+  i k v scan-error)
+
+(define-up-list-test up-list-out-of-string
+  (lambda () (up-list 1 t))
+  (or "1 (1 '2 2 (2 2 2' 1) 1")
+  ;;   abcdefghijklmnopqrstuvwxy
+  o r u scan-error)
+
+(define-up-list-test up-list-cross-string
+  (lambda () (up-list 1 t))
+  (or "(1 '2 ( 2' 1 '2 ) 2' 1)")
+  ;;   abcdefghijklmnopqrstuvwxy
+  i r u x scan-error)
+
+(define-up-list-test up-list-no-cross-string
+  (lambda () (up-list 1 t t))
+  (or "(1 '2 ( 2' 1 '2 ) 2' 1)")
+  ;;   abcdefghijklmnopqrstuvwxy
+  i k x scan-error)
+
+(define-up-list-test backward-up-list-basic
+  (lambda () (backward-up-list))
+  (or "(1 1 (1 1) 1 (1 1) 1)")
+  ;;   abcdefghijklmnopqrstuv
+  i f a scan-error)
+
+(provide 'syntax-tests)
+;;; syntax-tests.el ends here


reply via email to

[Prev in Thread] Current Thread [Next in Thread]