unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: kobarity <kobarity@gmail.com>
To: 55702@debbugs.gnu.org
Subject: bug#55702: 29.0.50; python-mark-defun does not handle backslash escaped newline
Date: Sun, 3 Jul 2022 17:56:56 +0900	[thread overview]
Message-ID: <CAMQkrSoj5r_3C13T8HsKftX+8N3cNVJi1a2UNmt6hHXkZcEgoQ@mail.gmail.com> (raw)
In-Reply-To: <CAMQkrSpKpZ_+0NFD_=7t5GJAygGUyq8+=EWHyS-9_UwQ1BrcNg@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1951 bytes --]

Hello,

I wrote:
> When the following steps are performed, the first line "def \" will
> not be included in the region.
>
> 1. emacs -Q
> 2. Load the following Python file using M-x find-file
>
> #+begin_src python
> def \
>         foo(x):
>     return x
> #+end_src
>
> 3. M-x forward-line (Move point to the line "foo(x):".)
> 4. M-x python-mark-defun

In fact, this is not only the issue in python-mark-defun, but also the
issue in python-nav-beginning-of-defun. In the example above,
python-nav-beginning-of-defun does not move the point if the point is
located at the beginning of the line "foo(x):". My previous patch was
not sufficient to solve the issue in python-nav-beginning-of-defun. So
I attach the revised patch.

On the other hand, I'm wondering if it is worth supporting such rarely
used forms, as there seems to be some more issues regarding the line
continuation using backslash. Is it better to leave such rarely used
forms unsupported and keep the code simple?

Below is the explanation of my patch:

> Sorry, it may not be good to change the behavior of
> python-info-looking-at-beginning-of-defun.  I will reconsider the fix.

Instead of changing the default behavior of
python-info-looking-at-beginning-of-defun, I added an argument to
change the behavior. When CHECK-STATEMENT is non-nil, the current
statement is checked instead of the current physical line.

This argument is used in python-nav--beginning-of-defun to be able
to recognize the defun with line continuation using backslash. When
ARG is positive, the point is moved to the end of the statement if the
point is located at the continuation line. This is necessary for
re-search-backward to find the defun regexp.

If the defun is found when ARG is negative, it is necessary to move
point to the beginning of the statement, because the point is at the
end of the defun regexp which may be in the different line from the
beginning of the statement.

Best Regards,

[-- Attachment #2: fix-55702.patch --]
[-- Type: application/octet-stream, Size: 7284 bytes --]

commit de745b4a395d79e0cba915593c228345d7862d59
Author: kobarity <kobarity@gmail.com>
Date:   Sun Jul 3 17:14:48 2022 +0900

    Make `python-nav-beginning-of-defun' handle line continuation using backslash
    
    * lisp/progmodes/python.el (python-nav--beginning-of-defun): Allow
    line continuation using backslash in defuns (bug#55702).
    (python-info-looking-at-beginning-of-defun): Add CHECK-STATEMENT
    argument.

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 16cdf58611..7a626ae35e 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -1472,15 +1472,17 @@ python-nav--beginning-of-defun
                      0))))
          (found
           (progn
-            (when (and (python-info-looking-at-beginning-of-defun)
+            (when (and (python-info-looking-at-beginning-of-defun nil t)
                        (or (< arg 0)
                            ;; If looking at beginning of defun, and if
                            ;; pos is > line-content-start, ensure a
                            ;; backward re search match this defun by
                            ;; going to end of line before calling
                            ;; re-search-fn bug#40563
-                           (and (> arg 0) (> pos line-content-start))))
-              (end-of-line 1))
+                           (and (> arg 0)
+                                (or (python-info-continuation-line-p)
+                                    (> pos line-content-start)))))
+              (python-nav-end-of-statement))
 
             (while (and (funcall re-search-fn
                                  python-nav-beginning-of-defun-regexp nil t)
@@ -1490,14 +1492,18 @@ python-nav--beginning-of-defun
                             (and (> arg 0)
                                  (not (= (current-indentation) 0))
                                  (>= (current-indentation) body-indentation)))))
-            (and (python-info-looking-at-beginning-of-defun)
+            (and (python-info-looking-at-beginning-of-defun nil t)
                  (or (not (= (line-number-at-pos pos)
                              (line-number-at-pos)))
                      (and (>= (point) line-beg-pos)
                           (<= (point) line-content-start)
                           (> pos line-content-start)))))))
     (if found
-        (or (beginning-of-line 1) t)
+        (progn
+          (when (< arg 0)
+            (python-nav-beginning-of-statement))
+          (beginning-of-line 1)
+          t)
       (and (goto-char pos) nil))))
 
 (defun python-nav-beginning-of-defun (&optional arg)
@@ -5299,10 +5305,15 @@ python-info-assignment-continuation-line-p
       (forward-line -1)
       (python-info-assignment-statement-p t))))
 
-(defun python-info-looking-at-beginning-of-defun (&optional syntax-ppss)
-  "Check if point is at `beginning-of-defun' using SYNTAX-PPSS."
+(defun python-info-looking-at-beginning-of-defun (&optional syntax-ppss
+                                                            check-statement)
+  "Check if point is at `beginning-of-defun' using SYNTAX-PPSS.
+When CHECK-STATEMENT is non-nil, the current statement is checked
+instead of the current physical line."
   (and (not (python-syntax-context-type (or syntax-ppss (syntax-ppss))))
        (save-excursion
+         (when check-statement
+           (python-nav-beginning-of-statement))
          (beginning-of-line 1)
          (looking-at python-nav-beginning-of-defun-regexp))))
 
diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el
index c59a2e7953..d7b3c102f2 100644
--- a/test/lisp/progmodes/python-tests.el
+++ b/test/lisp/progmodes/python-tests.el
@@ -1757,6 +1757,36 @@ python-mark-defun-4
      (should (= (marker-position (mark-marker))
                 expected-mark-end-position)))))
 
+(ert-deftest python-mark-defun-5 ()
+  "Test `python-mark-defun' with point inside backslash escaped defun."
+  (python-tests-with-temp-buffer
+   "
+def \\
+        foo(x):
+    return x
+"
+   (let ((transient-mark-mode t)
+         (expected-mark-beginning-position
+          (progn
+            (python-tests-look-at "def ")
+            (1- (line-beginning-position))))
+         (expected-mark-end-position
+          (save-excursion
+            (python-tests-look-at "return x")
+            (forward-line)
+            (point))))
+     (python-tests-look-at "def ")
+     (python-mark-defun 1)
+     (should (= (point) expected-mark-beginning-position))
+     (should (= (marker-position (mark-marker))
+                expected-mark-end-position))
+     (deactivate-mark)
+     (python-tests-look-at "foo(x)")
+     (python-mark-defun 1)
+     (should (= (point) expected-mark-beginning-position))
+     (should (= (marker-position (mark-marker))
+                expected-mark-end-position)))))
+
 \f
 ;;; Navigation
 
@@ -1905,17 +1935,47 @@ python-nav-beginning-of-defun-3
 (ert-deftest python-nav-beginning-of-defun-4 ()
   (python-tests-with-temp-buffer
    "
+def a():
+    pass
+
 def \\
-        a():
+        b():
     return 0
+
+def c():
+    pass
 "
-   (python-tests-look-at "return 0")
+   (python-tests-look-at "def c():")
+   (should (= (save-excursion
+                (python-nav-beginning-of-defun)
+                (point))
+              (save-excursion
+                (python-tests-look-at "def \\" -1)
+                (beginning-of-line)
+                (point))))
+   (python-tests-look-at "return 0" -1)
    (should (= (save-excursion
                 (python-nav-beginning-of-defun)
                 (point))
               (save-excursion
                 (python-tests-look-at "def \\" -1)
                 (beginning-of-line)
+                (point))))
+   (python-tests-look-at "b():" -1)
+   (should (= (save-excursion
+                (python-nav-beginning-of-defun)
+                (point))
+              (save-excursion
+                (python-tests-look-at "def \\" -1)
+                (beginning-of-line)
+                (point))))
+   (python-tests-look-at "def a():" -1)
+   (should (= (save-excursion
+                (python-nav-beginning-of-defun -1)
+                (point))
+              (save-excursion
+                (python-tests-look-at "def \\")
+                (beginning-of-line)
                 (point))))))
 
 (ert-deftest python-nav-end-of-defun-1 ()
@@ -5242,6 +5302,23 @@ python-info-looking-at-beginning-of-defun-1
    (python-tests-look-at "deff()")
    (should (not (python-info-looking-at-beginning-of-defun)))))
 
+(ert-deftest python-info-looking-at-beginning-of-defun-2 ()
+  (python-tests-with-temp-buffer
+   "
+def \\
+        foo(arg):
+    pass
+"
+   (python-tests-look-at "def \\")
+   (should (python-info-looking-at-beginning-of-defun))
+   (should (python-info-looking-at-beginning-of-defun nil t))
+   (python-tests-look-at "foo(arg):")
+   (should (not (python-info-looking-at-beginning-of-defun)))
+   (should (python-info-looking-at-beginning-of-defun nil t))
+   (python-tests-look-at "pass")
+   (should (not (python-info-looking-at-beginning-of-defun)))
+   (should (not (python-info-looking-at-beginning-of-defun nil t)))))
+
 (ert-deftest python-info-current-line-comment-p-1 ()
   (python-tests-with-temp-buffer
    "

  parent reply	other threads:[~2022-07-03  8:56 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-29 12:22 bug#55702: 29.0.50; python-mark-defun does not handle backslash escaped newline kobarity
2022-05-29 12:27 ` kobarity
2022-05-29 13:11 ` kobarity
2022-07-03  8:56 ` kobarity [this message]
2022-07-03 12:23   ` Lars Ingebrigtsen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAMQkrSoj5r_3C13T8HsKftX+8N3cNVJi1a2UNmt6hHXkZcEgoQ@mail.gmail.com \
    --to=kobarity@gmail.com \
    --cc=55702@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).