Subject: Re: bug#39598: 26.3; Emacs is extremely unresponsive on a trivial python file

From: Noam Postavsky <[email-masked]>
Date: Thu, 12 Mar 2020 23:00:09 -0400

Eli Zaretskii <[email-masked]> writes:

>> From: Ivan Oreshnikov <[email-masked]>
>> Date: Fri, 14 Feb 2020 17:31:48 +0100
>> Cc: [email-masked]
>> 
>> Ok, here's the full expansion of the relevant part of the profiler report:
>
> Looks like this part of python-nav--forward-sexp needs some
> optimizations:

Actually, it seems the main problem is a bit higher up.
python-info-docstring-p calls python-nav-backward-sexp repeatedly, until
it hits a non-string sexp.  Even though it's only checking for two sexp
strings.

    (let ((counter 1)
      ...
             ;; Allow up to two consecutive docstrings only.
             (>=
              2
              (let (last-backward-sexp-point)
                (while (save-excursion
                         (python-nav-backward-sexp)
                         (setq backward-sexp-point (point))
                         (and (= indentation (current-indentation))
                              ...
                              (looking-at-p
                               (concat "[uU]?[rR]?"
                                       (python-rx string-delimiter)))))
                  ;; Previous sexp was a string, restore point.
                  (goto-char backward-sexp-point)
                  (cl-incf counter))
                counter)))

So any repetitions of the while loop after the second one are useless.
The patch (generated with --ignore-all-space) below fixes it:

--- c/lisp/progmodes/python.el
+++ i/lisp/progmodes/python.el
@@ -5135,7 +5135,8 @@ python-info-docstring-p
              (>=
               2
               (let (last-backward-sexp-point)
-                (while (save-excursion
+                (while (and (<= counter 2)
+                            (save-excursion
                               (python-nav-backward-sexp)
                               (setq backward-sexp-point (point))
                               (and (= indentation (current-indentation))
@@ -5149,7 +5150,7 @@ python-info-docstring-p
                                            backward-sexp-point))
                                    (looking-at-p
                                     (concat "[uU]?[rR]?"
-                                       (python-rx string-delimiter)))))
+                                            (python-rx string-delimiter))))))
                   ;; Previous sexp was a string, restore point.
                   (goto-char backward-sexp-point)
                   (cl-incf counter))