]> git.eshelyaron.com Git - emacs.git/commitdiff
python.el: Fix mark-defun behavior (Bug#19665)
authorFabián Ezequiel Gallina <fgallina@gnu.org>
Mon, 6 Jul 2015 04:03:46 +0000 (01:03 -0300)
committerFabián Ezequiel Gallina <fgallina@gnu.org>
Mon, 6 Jul 2015 04:04:00 +0000 (01:04 -0300)
* lisp/progmodes/python.el: (python-mark-defun): New function.

* test/automated/python-tests.el (python-mark-defun-1)
(python-mark-defun-2, python-mark-defun-3): New tests.

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

index f641880428cb41886d2ef89d3c28eb6497b1459d..fbf944f9c6866f26c1c45b2f93711b625a1626e3 100644 (file)
     (define-key map [remap backward-sentence] 'python-nav-backward-block)
     (define-key map [remap forward-sentence] 'python-nav-forward-block)
     (define-key map [remap backward-up-list] 'python-nav-backward-up-list)
+    (define-key map [remap mark-defun] 'python-mark-defun)
     (define-key map "\C-c\C-j" 'imenu)
     ;; Indent specific
     (define-key map "\177" 'python-indent-dedent-line-backspace)
@@ -1250,6 +1251,21 @@ the line will be re-indented automatically if needed."
               ;; Reindent region if this is a multiline statement
               (python-indent-region dedenter-pos current-pos)))))))))
 
+\f
+;;; Mark
+
+(defun python-mark-defun (&optional allow-extend)
+  "Put mark at end of this defun, point at beginning.
+The defun marked is the one that contains point or follows point.
+
+Interactively (or with ALLOW-EXTEND non-nil), if this command is
+repeated or (in Transient Mark mode) if the mark is active, it
+marks the next defun after the ones already marked."
+  (interactive "p")
+  (when (python-info-looking-at-beginning-of-defun)
+    (end-of-line 1))
+  (mark-defun allow-extend))
+
 \f
 ;;; Navigation
 
index 4585e7f96145a1fbdcdad52afcdea697951677ef..2ed07464df66a3220e0e41d3df904f9e592af857 100644 (file)
@@ -1225,6 +1225,158 @@ this is an arbitrarily
      (should (string= (buffer-substring-no-properties (point-min) (point-max))
                       expected)))))
 
+\f
+;;; Mark
+
+(ert-deftest python-mark-defun-1 ()
+  """Test `python-mark-defun' with point at defun symbol start."""
+  (python-tests-with-temp-buffer
+   "
+def foo(x):
+    return x
+
+class A:
+   pass
+
+class B:
+
+    def __init__(self):
+       self.b = 'b'
+
+    def fun(self):
+       return self.b
+
+class C:
+   '''docstring'''
+"
+   (let ((expected-mark-beginning-position
+          (progn
+            (python-tests-look-at "class A:")
+            (1- (point))))
+         (expected-mark-end-position-1
+          (save-excursion
+            (python-tests-look-at "pass")
+            (forward-line)
+            (point)))
+         (expected-mark-end-position-2
+          (save-excursion
+            (python-tests-look-at "return self.b")
+            (forward-line)
+            (point)))
+         (expected-mark-end-position-3
+          (save-excursion
+            (python-tests-look-at "'''docstring'''")
+            (forward-line)
+            (point))))
+     ;; Select class A only, with point at bol.
+     (python-mark-defun 1)
+     (should (= (point) expected-mark-beginning-position))
+     (should (= (marker-position (mark-marker))
+                expected-mark-end-position-1))
+     ;; expand to class B, start position should remain the same.
+     (python-mark-defun 1)
+     (should (= (point) expected-mark-beginning-position))
+     (should (= (marker-position (mark-marker))
+                expected-mark-end-position-2))
+     ;; expand to class C, start position should remain the same.
+     (python-mark-defun 1)
+     (should (= (point) expected-mark-beginning-position))
+     (should (= (marker-position (mark-marker))
+                expected-mark-end-position-3)))))
+
+(ert-deftest python-mark-defun-2 ()
+  """Test `python-mark-defun' with point at nested defun symbol start."""
+  (python-tests-with-temp-buffer
+   "
+def foo(x):
+    return x
+
+class A:
+   pass
+
+class B:
+
+    def __init__(self):
+       self.b = 'b'
+
+    def fun(self):
+       return self.b
+
+class C:
+   '''docstring'''
+"
+   (let ((expected-mark-beginning-position
+          (progn
+            (python-tests-look-at "def __init__(self):")
+            (1- (line-beginning-position))))
+         (expected-mark-end-position-1
+          (save-excursion
+            (python-tests-look-at "self.b = 'b'")
+            (forward-line)
+            (point)))
+         (expected-mark-end-position-2
+          (save-excursion
+            (python-tests-look-at "return self.b")
+            (forward-line)
+            (point)))
+         (expected-mark-end-position-3
+          (save-excursion
+            (python-tests-look-at "'''docstring'''")
+            (forward-line)
+            (point))))
+     ;; Select B.__init only, with point at its start.
+     (python-mark-defun 1)
+     (should (= (point) expected-mark-beginning-position))
+     (should (= (marker-position (mark-marker))
+                expected-mark-end-position-1))
+     ;; expand to B.fun, start position should remain the same.
+     (python-mark-defun 1)
+     (should (= (point) expected-mark-beginning-position))
+     (should (= (marker-position (mark-marker))
+                expected-mark-end-position-2))
+     ;; expand to class C, start position should remain the same.
+     (python-mark-defun 1)
+     (should (= (point) expected-mark-beginning-position))
+     (should (= (marker-position (mark-marker))
+                expected-mark-end-position-3)))))
+
+(ert-deftest python-mark-defun-3 ()
+  """Test `python-mark-defun' with point inside defun symbol."""
+  (python-tests-with-temp-buffer
+   "
+def foo(x):
+    return x
+
+class A:
+   pass
+
+class B:
+
+    def __init__(self):
+       self.b = 'b'
+
+    def fun(self):
+       return self.b
+
+class C:
+   '''docstring'''
+"
+   (let ((expected-mark-beginning-position
+          (progn
+            (python-tests-look-at "def fun(self):")
+            (python-tests-look-at "(self):")
+            (1- (line-beginning-position))))
+         (expected-mark-end-position
+          (save-excursion
+            (python-tests-look-at "return self.b")
+            (forward-line)
+            (point))))
+     ;; Should select B.fun, despite point is inside the defun symbol.
+     (python-mark-defun 1)
+     (should (= (point) expected-mark-beginning-position))
+     (should (= (marker-position (mark-marker))
+                expected-mark-end-position)))))
+
 \f
 ;;; Navigation