* lisp/progmodes/python.el (python-nav--syntactically): Fix cornercases
authorFabián Ezequiel Gallina <fgallina@gnu.org>
Wed, 17 Apr 2013 22:23:13 +0000 (19:23 -0300)
committerFabián Ezequiel Gallina <fgallina@gnu.org>
Wed, 17 Apr 2013 22:23:13 +0000 (19:23 -0300)
and do not care about match data.

* test/automated/python-tests.el (python-nav-backward-defun-2)
(python-nav-backward-defun-3, python-nav-forward-defun-2)
(python-nav-forward-defun-3): New tests.

lisp/ChangeLog
lisp/progmodes/python.el
test/ChangeLog
test/automated/python-tests.el

index 4ace42a..fdb9ac2 100644 (file)
@@ -1,3 +1,8 @@
+2013-04-17  Fabián Ezequiel Gallina  <fgallina@gnu.org>
+
+       * progmodes/python.el (python-nav--syntactically): Fix cornercases
+       and do not care about match data.
+
 2013-04-17  Stefan Monnier  <monnier@iro.umontreal.ca>
 
        * emacs-lisp/lisp.el (lisp-completion-at-point): Provide specialized
index 1d7cf02..53aff94 100644 (file)
@@ -1192,28 +1192,32 @@ Returns nil if point is not in a def or class."
       ;; Ensure point moves forward.
       (and (> beg-pos (point)) (goto-char beg-pos)))))
 
-(defun python-nav--syntactically (fn poscompfn &optional pos)
-  "Move to point using FN ignoring non-code or paren context.
-FN must take no arguments and could be used to set match-data.
-POSCOMPFN is a two arguments function used to compare current and
-previous point after it is moved using FN, this is normally a
-less-than or greater-than comparison.  Optional argument POS is
-internally used in recursive calls and should not be explicitly
-passed."
-  (let* ((newpos
-          (and (funcall fn)
-               (save-match-data
-                 (and
-                  (not (python-syntax-context-type))
-                  (point-marker)))))
-         (current-match-data (match-data)))
-    (cond ((or (and (not pos) newpos)
-               (and pos newpos (funcall poscompfn newpos pos)))
-           (set-match-data current-match-data)
-           (point-marker))
-          ((and (not pos) (not newpos)) nil)
-          (t (python-nav--syntactically
-              fn poscompfn (point-marker))))))
+(defun python-nav--syntactically (fn poscompfn &optional contextfn)
+  "Move point using FN avoiding places with specific context.
+FN must take no arguments. POSCOMPFN is a two arguments function
+used to compare current and previous point after it is moved
+using FN, this is normally a less-than or greater-than
+comparison.  Optional argument CONTEXTFN defaults to
+`python-syntax-context-type' and is used for checking current
+point context, it must return a non-nil value if this point must
+be skipped."
+  (let ((contextfn (or contextfn 'python-syntax-context-type))
+        (start-pos (point-marker))
+        (prev-pos))
+    (catch 'found
+      (while t
+        (let* ((newpos
+                (and (funcall fn) (point-marker)))
+               (context (funcall contextfn)))
+          (cond ((and (not context) newpos
+                      (or (and (not prev-pos) newpos)
+                          (and prev-pos newpos
+                               (funcall poscompfn newpos prev-pos))))
+                 (throw 'found (point-marker)))
+                ((and newpos context)
+                 (setq prev-pos (point)))
+                (t (when (not newpos) (goto-char start-pos))
+                   (throw 'found nil))))))))
 
 (defun python-nav--forward-defun (arg)
   "Internal implementation of python-nav-{backward,forward}-defun.
index 7c25ad1..c8cb8ee 100644 (file)
@@ -1,3 +1,9 @@
+2013-04-17  Fabián Ezequiel Gallina  <fgallina@gnu.org>
+
+       * automated/python-tests.el (python-nav-backward-defun-2)
+       (python-nav-backward-defun-3, python-nav-forward-defun-2)
+       (python-nav-forward-defun-3): New tests.
+
 2013-04-17  Fabián Ezequiel Gallina  <fgallina@gnu.org>
 
        * automated/python-tests.el (python-nav-backward-defun-1)
index a7c7aab..15089e6 100644 (file)
@@ -718,6 +718,60 @@ class A(object): # A
               (python-tests-look-at "class A(object): # A" -1)))
    (should (not (python-nav-backward-defun)))))
 
+(ert-deftest python-nav-backward-defun-2 ()
+  (python-tests-with-temp-buffer
+   "
+def decoratorFunctionWithArguments(arg1, arg2, arg3):
+    '''print decorated function call data to stdout.
+
+    Usage:
+
+    @decoratorFunctionWithArguments('arg1', 'arg2')
+    def func(a, b, c=True):
+        pass
+    '''
+
+    def wwrap(f):
+        print 'Inside wwrap()'
+        def wrapped_f(*args):
+            print 'Inside wrapped_f()'
+            print 'Decorator arguments:', arg1, arg2, arg3
+            f(*args)
+            print 'After f(*args)'
+        return wrapped_f
+    return wwrap
+"
+   (goto-char (point-max))
+   (should (= (save-excursion (python-nav-backward-defun))
+              (python-tests-look-at "        def wrapped_f(*args):" -1)))
+   (should (= (save-excursion (python-nav-backward-defun))
+              (python-tests-look-at "    def wwrap(f):" -1)))
+   (should (= (save-excursion (python-nav-backward-defun))
+              (python-tests-look-at "def decoratorFunctionWithArguments(arg1, arg2, arg3):" -1)))
+   (should (not (python-nav-backward-defun)))))
+
+(ert-deftest python-nav-backward-defun-3 ()
+  (python-tests-with-temp-buffer
+   "
+'''
+    def u(self):
+        pass
+
+    def v(self):
+        pass
+
+    def w(self):
+        pass
+'''
+
+class A(object):
+    pass
+"
+   (goto-char (point-min))
+   (let ((point (python-tests-look-at "class A(object):")))
+     (should (not (python-nav-backward-defun)))
+     (should (= point (point))))))
+
 (ert-deftest python-nav-forward-defun-1 ()
   (python-tests-with-temp-buffer
    "
@@ -762,6 +816,60 @@ class A(object): # A
               (python-tests-look-at "(self): # c")))
    (should (not (python-nav-forward-defun)))))
 
+(ert-deftest python-nav-forward-defun-2 ()
+  (python-tests-with-temp-buffer
+   "
+def decoratorFunctionWithArguments(arg1, arg2, arg3):
+    '''print decorated function call data to stdout.
+
+    Usage:
+
+    @decoratorFunctionWithArguments('arg1', 'arg2')
+    def func(a, b, c=True):
+        pass
+    '''
+
+    def wwrap(f):
+        print 'Inside wwrap()'
+        def wrapped_f(*args):
+            print 'Inside wrapped_f()'
+            print 'Decorator arguments:', arg1, arg2, arg3
+            f(*args)
+            print 'After f(*args)'
+        return wrapped_f
+    return wwrap
+"
+   (goto-char (point-min))
+   (should (= (save-excursion (python-nav-forward-defun))
+              (python-tests-look-at "(arg1, arg2, arg3):")))
+   (should (= (save-excursion (python-nav-forward-defun))
+              (python-tests-look-at "(f):")))
+   (should (= (save-excursion (python-nav-forward-defun))
+              (python-tests-look-at "(*args):")))
+   (should (not (python-nav-forward-defun)))))
+
+(ert-deftest python-nav-forward-defun-3 ()
+  (python-tests-with-temp-buffer
+   "
+class A(object):
+    pass
+
+'''
+    def u(self):
+        pass
+
+    def v(self):
+        pass
+
+    def w(self):
+        pass
+'''
+"
+   (goto-char (point-min))
+   (let ((point (python-tests-look-at "(object):")))
+     (should (not (python-nav-forward-defun)))
+     (should (= point (point))))))
+
 (ert-deftest python-nav-beginning-of-statement-1 ()
   (python-tests-with-temp-buffer
    "