From: Fabián Ezequiel Gallina Date: Wed, 17 Apr 2013 22:23:13 +0000 (-0300) Subject: * lisp/progmodes/python.el (python-nav--syntactically): Fix cornercases X-Git-Tag: emacs-24.3.90~173^2^2~42^2~45^2~387^2~2026^2~436 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=04754d3612ea2f09440604c571814e0795511fa3;p=emacs.git * lisp/progmodes/python.el (python-nav--syntactically): Fix cornercases 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. --- diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 4ace42afa09..fdb9ac2acab 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,8 @@ +2013-04-17 Fabián Ezequiel Gallina + + * progmodes/python.el (python-nav--syntactically): Fix cornercases + and do not care about match data. + 2013-04-17 Stefan Monnier * emacs-lisp/lisp.el (lisp-completion-at-point): Provide specialized diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 1d7cf02ca5a..53aff94ae0e 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -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. diff --git a/test/ChangeLog b/test/ChangeLog index 7c25ad1a804..c8cb8ee3b54 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,9 @@ +2013-04-17 Fabián Ezequiel Gallina + + * 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 * automated/python-tests.el (python-nav-backward-defun-1) diff --git a/test/automated/python-tests.el b/test/automated/python-tests.el index a7c7aab6464..15089e6b393 100644 --- a/test/automated/python-tests.el +++ b/test/automated/python-tests.el @@ -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 "