python-mode and nested indents

Bug #328775 reported by Montanaro
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
python-mode.el
Fix Released
Medium
Andreas Roehler
Components-python-mode
Fix Released
Undecided
Andreas Roehler

Bug Description

(migrated from python project, bug #587239)

Original submission:

Using Python-mode 4.6 and GNU emacs 21.2.2, I
enter the following:

 if x < 0:
     for i in range(100):
         print i
 else:
     print "x is negative"

 If I now put the cursor on the "else:" line and hit
 tab, it erroneously changes the indentation to line the
 "else" up with the "for" above it.

Followup comments:

 Date: 2002-07-26 17:40
Sender: tim_one
Logged In: YES
user_id=31435

It's up to Barry to decide (and I assigned the report
to him). I'll only add that the behavior does appear to be
as documented:

"""
The \\[indent-for-tab-command] and \\[py-newline-
and-indent] keys try to suggest plausible indentation,
based on the indentation of preceding statements.

[example snipped]

Python-mode cannot know whether that's what you
intended, or whether
\tif a > 0:
\t c = d
\t_

was your intent. In general, Python-mode either
reproduces the indentation of the (closest code or
indenting-comment) preceding statement, or adds an
extra py-indent-offset blanks if the preceding statement
has `:' as its last significant (non-whitespace and non-
comment) character. If the suggested indentation is too much,
use \\[py-electric-backspace] to reduce it.
""

That seems (to me) easy to remember and to live with.

Date: 2002-07-26 17:14
Sender: arkoenig
Logged In: YES
user_id=418174

If you really believe that hitting tab means that the
block structure isn't what you intended, then you should
also believe that hitting tab repeatedly on a line that can
legally be indented in exactly two different ways
(presumably with different meanings) should cycle
between the meanings. Which it doesn't in this case.

I am willing to accept that hitting tab should generate
the maximum legal indent, which would mean that the
behavior I described with "else:" isn't a bug. I do think,
though, that generating an illegal indent should be considered
a bug. I also think that for most cases, lining up an
"else" with the nearest preceding "if" or "elif"
rather than the nearest preceding "for" or "while" is less
surprising, though I'll admit that's a matter of taste.

Date: 2002-07-26 17:05
Sender: tim_one
Logged In: YES
user_id=31435

I agree that the second one (elif) may be considered a
bug. Afraid I can't agree about the first reason,
though: of course hitting tab in pymode can change the
meaning. When you've got

if whatever:
->x
y

and hit tab when on the line containing y, it assumes
you're hitting tab for a reason, not just to make trouble
<wink>.

I believe there's a discussion about this in the long
form of the pymode help. Since pymod can't *know* the
block structure you intend, it does its best to guess, and
hitting a "guess the block structure I intended" key is taken
as meaning, for a start, that the block structure on the
current line isn't what you intended (else why would have hit
the key? as a Python programmer, you should already
know this isn't C mode <wink>).

Date: 2002-07-26 16:49
Sender: arkoenig
Logged In: YES
user_id=418174

Frankly, I hadn't thought of that possibility!

However, I still consider the behavior a bug, for two
reasons: (1) I can type something that's syntactically
valid, hit tab, and have it change the meaning of what
I typed, and (2) It changes the indentation in the same
way if I say "elif:" instead of "else:", even though
that change is not syntactically valid. That is (using -> to indicate a
tab):

if x < 0:
->for i in range(100):
->->print i
elif x > 0:
->print x

Again, hitting tab on the "elif" line will indent the
"elif" to line up with the "for", even though the result is
syntactically invalid.

Date: 2002-07-26 16:14
Sender: tim_one
Logged In: YES
user_id=31435

Andrew, why is that erroneous? Loops in Python have
(optional) "else:" clauses too. There's no way for
pymode to guess whether you intended the else to go with the if
or the for. I expect it looks backward for the closest-
preceding construct the else-statement could "belong to", and
finds the for-loop first.

[http://sourceforge.net/tracker/index.php?func=detail&aid=783235&group_id=86916&atid=581349]

Related branches

Revision history for this message
Docwhat-users (docwhat-users) wrote :

I'm having a hard time following this bug, because the
formatting is strange in sourceforge. (Is there someplace
else I can read this that'll be easier to read?)

Anyway, I think you're talking about how I can type
something like (_==spaces):

if a:
__x
__y

If I move to y and hit tab, the indent cycles between being
indented two characters or none.

I personally hate this behaviour. I bump the tab and then
the line gets screwed up. I would really like a way to
disable this. The cases where it the best guess isn't right
is few enough that I don't really care that I have to hit
backspace after tab.

I think this was the previous behaviour, because I don't
remember this from before. :-(

So, an option to turn this off would be apprecated...

Love the mode, otherwise. :-)

Ciao!

Bryce Harrington (bryce)
description: updated
Changed in python-mode:
assignee: nobody → Andreas Roehler (a-roehler)
Changed in python-mode:
status: New → Fix Committed
Changed in python-mode:
status: Fix Committed → Confirmed
Changed in python-mode:
status: Confirmed → Fix Committed
Changed in python-mode:
status: Fix Committed → Incomplete
Revision history for this message
Andreas Roehler (a-roehler) wrote :

Hi,

the first description isn't valid IMHO, as the `for' loop
may contain a `else'-clause, so Emacs can't decide that.

(comparison corrected silently)

if x > 0:
    for i in range(100):
        print i
    else:
        print "All done"

Second example below from thread looks valid for me

if x > 0:
    for i in range(100):
        print i
    elif x < 0:
    print "x is negative"

Wrong indented `elif' is offered, which can't follow `for'.

Opinions?

Andreas

Changed in python-mode:
status: Incomplete → Fix Committed
Changed in python-mode:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.