Subject: bug#56635: 29.0.50; [PATCH] hide-show in python-mode supports ONLY function and class blocks

From: Dima Kogan <[email-masked]>
Date: Mon, 18 Jul 2022 15:20:30 -0700

Hi. I'm using hide-show mode to visually collapse blocks while coding.
This is very helpful, and works great in C-like modes. hide-show mode
currently supports Python in a limited fashion: only def: and class:
blocks are hidden. Other kinds of blocks (if, else, for, while, ...) are
not supported. A simple patch that mostly adds support for all other
kinds of blocks is:

  diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
  index 1c99937c4b9..b63d2bc0690 100644
  --- a/lisp/progmodes/python.el
  +++ b/lisp/progmodes/python.el
  @@ -4819,7 +4819,7 @@ python-describe-at-point
   (defun python-hideshow-forward-sexp-function (_arg)
     "Python specific `forward-sexp' function for `hs-minor-mode'.
   Argument ARG is ignored."
  -  (python-nav-end-of-defun)
  +  (python-nav-end-of-block)
     (unless (python-info-current-line-empty-p)
       (backward-char)))

  @@ -5766,8 +5766,8 @@ python-mode

     (add-to-list
      'hs-special-modes-alist
  -   '(python-mode
  -     "\\s-*\\_<\\(?:def\\|class\\)\\_>"
  +   `(python-mode
  +     ,(python-rx block-start)
        ;; Use the empty string as end regexp so it doesn't default to
        ;; "\\s)".  This way parens at end of defun are properly hidden.
        ""

I say "mostly" because this isn't doable with regular expressions, as is
required by hide-show mode. So this patch can confuse the parser: some
bits of code will look like they begin a block, while in reality they do
not. hide-show would then collapse lines that it should ignore. Some
Python code that shows this failure:

  if 0:

      aaa
      l = [ i for i in range(5) \
            if i < 3 ]
      ccc
      abc = o.match(1,2,3)
      ddd

Here the "for" and "if" in the list comprehension both trigger the block
hiding. And the "match" function call triggers it too. python-mode has
functions to move between blocks (python-nav-...), but they're not
completely regex-based, so they can't be baked into hide-show.
Suggestions?

Obvious options:

  1. Leave the code as it is, don't support other blocks

  2. Take this patch, with the understanding that it'll collapse some
     stuff that it shouldn't

  3. Patch hide-show to potentially accept non-regex logic

I've been dogfooding the patch for a few days now, and it's behaving 99%
properly for me, so I'm inclined to suggest option 2. Making hide-show
smarter (option 3) doesn't feel worth the effort to fix THIS problem.

Thanks!