From 083850a6a195c5d536bd4cd344b5917b225597cc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fabi=C3=A1n=20Ezequiel=20Gallina?= Date: Wed, 17 Apr 2013 02:08:20 -0300 Subject: [PATCH] New defun movement commands. * lisp/progmodes/python.el (python-nav--syntactically) (python-nav--forward-defun, python-nav-backward-defun) (python-nav-forward-defun): New functions. * test/automated/python-tests.el (python-nav-backward-defun-1) (python-nav-forward-defun-1): New tests. --- lisp/ChangeLog | 7 +++ lisp/progmodes/python.el | 60 +++++++++++++++++++++++ test/ChangeLog | 5 ++ test/automated/python-tests.el | 87 ++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index cbb63e3ff8..11666c60c7 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,10 @@ +2013-04-17 Fabián Ezequiel Gallina + + New defun movement commands. + * progmodes/python.el (python-nav--syntactically) + (python-nav--forward-defun, python-nav-backward-defun) + (python-nav-forward-defun): New functions. + 2013-04-17 Fabián Ezequiel Gallina * progmodes/python.el (python-syntax--context-compiler-macro): New defun. diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index b0c00a309e..1d7cf02ca5 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -1192,6 +1192,66 @@ 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--forward-defun (arg) + "Internal implementation of python-nav-{backward,forward}-defun. +Uses ARG to define which function to call, and how many times +repeat it." + (let ((found)) + (while (and (> arg 0) + (setq found + (python-nav--syntactically + (lambda () + (re-search-forward + python-nav-beginning-of-defun-regexp nil t)) + '>))) + (setq arg (1- arg))) + (while (and (< arg 0) + (setq found + (python-nav--syntactically + (lambda () + (re-search-backward + python-nav-beginning-of-defun-regexp nil t)) + '<))) + (setq arg (1+ arg))) + found)) + +(defun python-nav-backward-defun (&optional arg) + "Navigate to closer defun backward ARG times. +Unlikely `python-nav-beginning-of-defun' this doesn't care about +nested definitions." + (interactive "^p") + (python-nav--forward-defun (- (or arg 1)))) + +(defun python-nav-forward-defun (&optional arg) + "Navigate to closer defun forward ARG times. +Unlikely `python-nav-beginning-of-defun' this doesn't care about +nested definitions." + (interactive "^p") + (python-nav--forward-defun (or arg 1))) + (defun python-nav-beginning-of-statement () "Move to start of current statement." (interactive "^") diff --git a/test/ChangeLog b/test/ChangeLog index bf68984e9e..7c25ad1a80 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,8 @@ +2013-04-17 Fabián Ezequiel Gallina + + * automated/python-tests.el (python-nav-backward-defun-1) + (python-nav-forward-defun-1): New tests. + 2013-04-09 Masatake YAMATO * automated/add-log-tests.el: New file. (Bug#14112) diff --git a/test/automated/python-tests.el b/test/automated/python-tests.el index 1a741b45d8..a7c7aab646 100644 --- a/test/automated/python-tests.el +++ b/test/automated/python-tests.el @@ -674,6 +674,93 @@ def decoratorFunctionWithArguments(arg1, arg2, arg3): (python-tests-look-at "return wrapped_f") (line-beginning-position)))))) +(ert-deftest python-nav-backward-defun-1 () + (python-tests-with-temp-buffer + " +class A(object): # A + + def a(self): # a + pass + + def b(self): # b + pass + + class B(object): # B + + class C(object): # C + + def d(self): # d + pass + + # def e(self): # e + # pass + + def c(self): # c + pass + + # def d(self): # d + # pass +" + (goto-char (point-max)) + (should (= (save-excursion (python-nav-backward-defun)) + (python-tests-look-at " def c(self): # c" -1))) + (should (= (save-excursion (python-nav-backward-defun)) + (python-tests-look-at " def d(self): # d" -1))) + (should (= (save-excursion (python-nav-backward-defun)) + (python-tests-look-at " class C(object): # C" -1))) + (should (= (save-excursion (python-nav-backward-defun)) + (python-tests-look-at " class B(object): # B" -1))) + (should (= (save-excursion (python-nav-backward-defun)) + (python-tests-look-at " def b(self): # b" -1))) + (should (= (save-excursion (python-nav-backward-defun)) + (python-tests-look-at " def a(self): # a" -1))) + (should (= (save-excursion (python-nav-backward-defun)) + (python-tests-look-at "class A(object): # A" -1))) + (should (not (python-nav-backward-defun))))) + +(ert-deftest python-nav-forward-defun-1 () + (python-tests-with-temp-buffer + " +class A(object): # A + + def a(self): # a + pass + + def b(self): # b + pass + + class B(object): # B + + class C(object): # C + + def d(self): # d + pass + + # def e(self): # e + # pass + + def c(self): # c + pass + + # def d(self): # d + # pass +" + (goto-char (point-min)) + (should (= (save-excursion (python-nav-forward-defun)) + (python-tests-look-at "(object): # A"))) + (should (= (save-excursion (python-nav-forward-defun)) + (python-tests-look-at "(self): # a"))) + (should (= (save-excursion (python-nav-forward-defun)) + (python-tests-look-at "(self): # b"))) + (should (= (save-excursion (python-nav-forward-defun)) + (python-tests-look-at "(object): # B"))) + (should (= (save-excursion (python-nav-forward-defun)) + (python-tests-look-at "(object): # C"))) + (should (= (save-excursion (python-nav-forward-defun)) + (python-tests-look-at "(self): # d"))) + (should (= (save-excursion (python-nav-forward-defun)) + (python-tests-look-at "(self): # c"))) + (should (not (python-nav-forward-defun))))) (ert-deftest python-nav-beginning-of-statement-1 () (python-tests-with-temp-buffer -- 2.20.1