You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
IDLE already provides quick block indenting, by
selecting one or more lines and pressing Tab. So, it
would make sense to have Shift+Tab to do the opposite
work. While there's already Alt+[ (and Alt+] to indent),
Shift+Tab is more intuitive, especially to those who are
used to other Windows developer tools, like Visual
Studio or TextPad.
What I'd really like is smart tabs like python-mode, where a tab
(re)indents the line to the correct point based on the syntax,
and a backspace backs up to the previous level.
Since IDLE already knows how to indent I'm hoping that that
won't be to difficult to implement.
gpolo commented on Mar 29, 2009
gpolomannequin
Mannequin
More actions
Patch added for allowing, and defining, Shift-Tab as the default binding
for dedenting.
The problem is that dedent-region may do more than one would expect.
changed the title [-]Dedenting with Shift+Tab[/-][+]IDLE: Dedenting with Shift+Tab[/+]on Aug 9, 2010
serwy commented on Dec 22, 2011
serwymannequin
Mannequin
More actions
I applied the patch and encountered a problem. MultiCall.py is replacing "<Shift-Key-Tab>" with "<Shift-KeyPress-Tab>". When this happens, the logic for rebinding "<<PrevWindow>>" fails.
Was the existing default binding of Ctrl-[ removed on purpose in Lib/idlelib/configHandler.py? According to the same patch, in the config files it is still there along-side the new Shift-Tab binding. At the least, these should be consistent.
In the code re-binding the <<Prev-Window>> event in EditorWindow.py, shouldn't there be a "break" at the end of the "if" clause inside the "for" loop?
The fact that Tab indents regions as well as lines seems not be documented. This should be added to Automatic Indentation (which should just be Indentation) with BackTab doc addition if not sooner.
On Windows, 3.4.1, shift-tab is the same as tab. The same is true in Notepad (not a model to follow), but Notepad++ dedents. Doing the same in Idle, within the editor, seems like a reasonable request.
The unplanned and strange OSX behavior should be fixed.
From the patch, I would gather that the problem is that tk hard-codes shift-Tab to <<prev-window (and, I would expect, tab to <<next-window>>). (This works but is currently useless in the dialogs.) If that is so, why do they currently act the same (for me) in the editor? Does tk automatically rebind Tab to indent-region in a text widget?
Tal: option 2 seems like something to try. If Shift-Tab is user configurable (and I think baked-in like Tab would be ok), then it should be *added* in both places. You might be right about break, except this is a moot point if the code is wrong.
<<PrevWindow>> is a predefined virtual event. https://www.tcl.tk/man/tcl8.6/TkCmd/event.htm
I can't find <<NextWindow>> listed there. I don't remember if I actually saw it before mentioning it. While I like mimicking smart_indent, I don't know if we can dismiss Roger Serwy's concern in msg150059.
Tk on Ubuntu may report key name ISO_Left_Tab msg150059, but it is not cross-platform. On Win 10 with either tk 8.5.15 (2.7) or 8.6.6 (3.6):
_tkinter.TclError: bad event type or keysym "ISO_Left_Tab"
I don't think we need to use the only sometimes valid synonym.
As Sean Wolfe reported msg212906, Shift-Tab already dedents a single line by treating it as a region. This issue is about removing the extra behavior we don't want, and blocking Control-[ from doing simplefied non-region single line dedents. Smart_indent does this by intercepting Tab (which I believe need not be bound to <<indent-region>>.
When there is a selection within a line, smart_indent does not call dedent_region but deletes the selection and insert \t or spaces, but in the latter case, the cursor may not be left on a multiple of indent spaces. This does not seem very useful. It is even less so because if the selection is within a word, tab invokes autocomplete instead of smart_indent. This needs discussion on another issue.
---
Text editing tests: how to we do them both thoroughly and efficiently (in terms of both human writing and machine execution time)?
White box approach: Set up a class test fixture that defines cls.text = <MultiCall(Text) instance>; put text in known state (content, cursor position, selection); call edit function (smart_indent, proposed smart dedent, etc); check resulting state (content, cursor, selection. Repeat for multiple input state - output state pairs. These tests break if the function name is changed and only test the function, which is, however, the main thing to be tested.
Gray-box approach: Replace function calls with pseudoevents generated on the text widget. Such tests would survive function name changes, break on pseudoevent name changes, and add a test of pseudoevent -- function binding. A black-box approach replaces pseudoevents with concrete events -- simulated key presses, mouse clicks, and menu selections. These tests survive pseudoevent name changes and add a test of concrete -- pseudo event linkage. They should only break if we change the user visible interface, which we seldom do.
I think we should use all approaches in two sets of tests. The first set would test multiple before and after states in subtests with a function call. This would define and test the intended behavior of the function. The second set would test one before and after state successively with a function call, pseudoevent generation, and concrete event generations, in this order. (If the function call fails, the event tests are bound to fail.) This would test the user interface and the links to the underlying function.
There are over 30 editing functions to test, and writing the above for all would be tedious. After writing tests for a couple, we should write helper functions that embody the repetitive boilerplate.
An additional factor: The text edit functions, properly bound with a pseudoevent to the text instance, are not methods of the text instance (though they should be), but of the EditorWindow that also contains a Toplevel; Menu hierarchy; and a Frame that contains Scrollbars and a StatusBar, along with, finally, the MultiCall(Text) instance. So the fixture setup must also provide provide an attribute for the method container. Let us call it cls.widget.
In order to put EditFrames (a new subclass of Frame) on tabs, the Text methods will have to at least be transferred to the EditFrame. It would be even better to transfer them to an IdleText subclass of MultiCall(Text) or possibly of Text. (See Mark Roseman's suggestion of a MultiCall alternative in msg272070.) After the setup code is changed to assign the new method container to cls.widget, the test methods should still run as they are.
What do you think about this @terryjreedy? The open PR for this (with a few small modifications) works pretty well. (It does not however allow for de-denting after code.) Making Shift-Tab the same as Ctrl-bracket would be wrong as as Tab has different behavior to its ctrl-bracket counterpart.
"(It does not however allow for de-denting after code.)" Tab does not indent unless before any code, so ??
Making Shift-Tab the same as Ctrl-bracket would be wrong as as Tab has different behavior to its ctrl-bracket counterpart.
We have to be specific, given what other keys do (when 4 spaces is the indent).
A. Before code, Tab inserts 4 spaces before the cursor without selecting the line or otherwise moving the cursor.
It does this regardless of its position in the current indent, so it always maintains valid 4n indents once present.
^] selects the line if no or partial selection present, and moves the cursor to the next line, where it would be if one
selects complete lines, and indents 4 spaces; ^[ does same except that it dedents.
To be parallel to Tab, Shift-Tab should just remove 4 spaces to the left. I
Note that backspace removes virtual tab, so it removes a variable number of spaces to end up at a 4n position.
If this is what the patch does, I want to change it.
B. Within and after code, ^] and ^[ do the same as before.
Tab either pops up a completion box or adds spaces to the next 4n tab stop. ShiftTab could 1) do nothing,
2) delete blanks back to the first nonbland or 4n tab, or 3) move left to the first 4n tab stop.
Not sure what the underspecified patch does.
This is a nasty issue: possible conflict with tk, undocumented behavior, OS variations, hard to test, unclear spec, and involves multicall (which I do undestand well enough and which is over -generalized for IDLE needs). The patch seems to ignore the tk and multicall issues, so I am a bit sceptical.
On Linux, if my cursor is after an expression (e.g. if 1: pass), pressing tab indents by 2 (!) spaces on the first press, and 4 after that (this seems like a bug). With the patch, after code shift+tab is a NO-OP. If being allowed to indent after code with tab is a bug, then the current behaviour of shift+tab in the patch is correct for this case.
Activity
kamek commentedon Feb 27, 2003
IDLE already provides quick block indenting, by
selecting one or more lines and pressing Tab. So, it
would make sense to have Shift+Tab to do the opposite
work. While there's already Alt+[ (and Alt+] to indent),
Shift+Tab is more intuitive, especially to those who are
used to other Windows developer tools, like Visual
Studio or TextPad.
rhettinger commentedon Jul 20, 2003
Logged In: YES
user_id=80475
While you get used to it quickly, I've bumped in to this also.
It is nice to have the control keys work the same across
applications.
kamek commentedon Jan 1, 2004
Logged In: YES
user_id=539453
This can be considered solved in the newest IDLE versions,
as you can set custom shortcuts.
rhettinger commentedon Jan 1, 2004
Logged In: YES
user_id=80475
Evenso, it may be better to have it work right out of the box.
kbkaiser commentedon Jan 2, 2004
Logged In: YES
user_id=149084
What I'd really like is smart tabs like python-mode, where a tab
(re)indents the line to the correct point based on the syntax,
and a backspace backs up to the previous level.
Since IDLE already knows how to indent I'm hoping that that
won't be to difficult to implement.
gpolo commentedon Mar 29, 2009
Patch added for allowing, and defining, Shift-Tab as the default binding
for dedenting.
The problem is that dedent-region may do more than one would expect.
[-]Dedenting with Shift+Tab[/-][+]IDLE: Dedenting with Shift+Tab[/+]serwy commentedon Dec 22, 2011
I applied the patch and encountered a problem. MultiCall.py is replacing "<Shift-Key-Tab>" with "<Shift-KeyPress-Tab>". When this happens, the logic for rebinding "<<PrevWindow>>" fails.
event_info('<<PrevWindow>>') returns ('<Key-ISO_Left_Tab>', '<Key-hpBackTab>', '<Shift-Key-Tab>')
event_info('<<dedent-region>>') returns ('<Control-KeyPress-bracketleft>', '<Shift-KeyPress-Tab>')
This is with 3.3a0 on Ubuntu 11.04.
SeanWolfe commentedon Mar 7, 2014
I did a couple tests and the shift-tab and tab work pretty much as expected. There's a small quirk for a single-line edit:
--> the text indents as expected
--> the entire line is highlighted
--> the cursor now appears beneath the line
--> subsequent typing however affects the highlighted line
For the single-line case, it would be cleaner to have it stay on the same line without highlighting.
This is OSX 10.9, python 2.7.6+ and 3.4.rc1+
taleinat commentedon Jun 10, 2014
Regarding Roger Serwy's comment, we could either:
I suggest #2.
Regarding the patch itself:
Was the existing default binding of Ctrl-[ removed on purpose in Lib/idlelib/configHandler.py? According to the same patch, in the config files it is still there along-side the new Shift-Tab binding. At the least, these should be consistent.
In the code re-binding the <<Prev-Window>> event in EditorWindow.py, shouldn't there be a "break" at the end of the "if" clause inside the "for" loop?
terryjreedy commentedon Jun 10, 2014
The fact that Tab indents regions as well as lines seems not be documented. This should be added to Automatic Indentation (which should just be Indentation) with BackTab doc addition if not sooner.
On Windows, 3.4.1, shift-tab is the same as tab. The same is true in Notepad (not a model to follow), but Notepad++ dedents. Doing the same in Idle, within the editor, seems like a reasonable request.
The unplanned and strange OSX behavior should be fixed.
From the patch, I would gather that the problem is that tk hard-codes shift-Tab to <<prev-window (and, I would expect, tab to <<next-window>>). (This works but is currently useless in the dialogs.) If that is so, why do they currently act the same (for me) in the editor? Does tk automatically rebind Tab to indent-region in a text widget?
Tal: option 2 seems like something to try. If Shift-Tab is user configurable (and I think baked-in like Tab would be ok), then it should be *added* in both places. You might be right about break, except this is a moot point if the code is wrong.
mlouielu commentedon Jun 15, 2017
PR 2210 add the smart-dedent to shift-tab in Windows, macOS, Linux.
I can't saw <<prev-window>> nor <<next-window>> in 3.7 (master) source code, so I'll take it as removed in IDLE somewhere else.
terryjreedy commentedon Jun 16, 2017
<<PrevWindow>> is a predefined virtual event.
https://www.tcl.tk/man/tcl8.6/TkCmd/event.htm
I can't find <<NextWindow>> listed there. I don't remember if I actually saw it before mentioning it. While I like mimicking smart_indent, I don't know if we can dismiss Roger Serwy's concern in msg150059.
Tk on Ubuntu may report key name ISO_Left_Tab msg150059, but it is not cross-platform. On Win 10 with either tk 8.5.15 (2.7) or 8.6.6 (3.6):
_tkinter.TclError: bad event type or keysym "ISO_Left_Tab"
I don't think we need to use the only sometimes valid synonym.
As Sean Wolfe reported msg212906, Shift-Tab already dedents a single line by treating it as a region. This issue is about removing the extra behavior we don't want, and blocking Control-[ from doing simplefied non-region single line dedents. Smart_indent does this by intercepting Tab (which I believe need not be bound to <<indent-region>>.
When there is a selection within a line, smart_indent does not call dedent_region but deletes the selection and insert \t or spaces, but in the latter case, the cursor may not be left on a multiple of indent spaces. This does not seem very useful. It is even less so because if the selection is within a word, tab invokes autocomplete instead of smart_indent. This needs discussion on another issue.
---
Text editing tests: how to we do them both thoroughly and efficiently (in terms of both human writing and machine execution time)?
White box approach: Set up a class test fixture that defines cls.text = <MultiCall(Text) instance>; put text in known state (content, cursor position, selection); call edit function (smart_indent, proposed smart dedent, etc); check resulting state (content, cursor, selection. Repeat for multiple input state - output state pairs. These tests break if the function name is changed and only test the function, which is, however, the main thing to be tested.
Gray-box approach: Replace function calls with pseudoevents generated on the text widget. Such tests would survive function name changes, break on pseudoevent name changes, and add a test of pseudoevent -- function binding. A black-box approach replaces pseudoevents with concrete events -- simulated key presses, mouse clicks, and menu selections. These tests survive pseudoevent name changes and add a test of concrete -- pseudo event linkage. They should only break if we change the user visible interface, which we seldom do.
I think we should use all approaches in two sets of tests. The first set would test multiple before and after states in subtests with a function call. This would define and test the intended behavior of the function. The second set would test one before and after state successively with a function call, pseudoevent generation, and concrete event generations, in this order. (If the function call fails, the event tests are bound to fail.) This would test the user interface and the links to the underlying function.
There are over 30 editing functions to test, and writing the above for all would be tedious. After writing tests for a couple, we should write helper functions that embody the repetitive boilerplate.
An additional factor: The text edit functions, properly bound with a pseudoevent to the text instance, are not methods of the text instance (though they should be), but of the EditorWindow that also contains a Toplevel; Menu hierarchy; and a Frame that contains Scrollbars and a StatusBar, along with, finally, the MultiCall(Text) instance. So the fixture setup must also provide provide an attribute for the method container. Let us call it cls.widget.
In order to put EditFrames (a new subclass of Frame) on tabs, the Text methods will have to at least be transferred to the EditFrame. It would be even better to transfer them to an IdleText subclass of MultiCall(Text) or possibly of Text. (See Mark Roseman's suggestion of a MultiCall alternative in msg272070.) After the setup code is changed to assign the new method container to cls.widget, the test methods should still run as they are.
StanFromIreland commentedon Feb 5, 2025
What do you think about this @terryjreedy? The open PR for this (with a few small modifications) works pretty well. (It does not however allow for de-denting after code.) Making Shift-Tab the same as Ctrl-bracket would be wrong as as Tab has different behavior to its ctrl-bracket counterpart.
terryjreedy commentedon Oct 12, 2025
@StanFromIreland Can you clarify two things?
"(It does not however allow for de-denting after code.)" Tab does not indent unless before any code, so ??
Making Shift-Tab the same as Ctrl-bracket would be wrong as as Tab has different behavior to its ctrl-bracket counterpart.
We have to be specific, given what other keys do (when 4 spaces is the indent).
A. Before code, Tab inserts 4 spaces before the cursor without selecting the line or otherwise moving the cursor.
It does this regardless of its position in the current indent, so it always maintains valid 4n indents once present.
^] selects the line if no or partial selection present, and moves the cursor to the next line, where it would be if one
selects complete lines, and indents 4 spaces; ^[ does same except that it dedents.
To be parallel to Tab, Shift-Tab should just remove 4 spaces to the left. I
Note that backspace removes virtual tab, so it removes a variable number of spaces to end up at a 4n position.
If this is what the patch does, I want to change it.
B. Within and after code, ^] and ^[ do the same as before.
Tab either pops up a completion box or adds spaces to the next 4n tab stop. ShiftTab could 1) do nothing,
2) delete blanks back to the first nonbland or 4n tab, or 3) move left to the first 4n tab stop.
Not sure what the underspecified patch does.
This is a nasty issue: possible conflict with tk, undocumented behavior, OS variations, hard to test, unclear spec, and involves multicall (which I do undestand well enough and which is over -generalized for IDLE needs). The patch seems to ignore the tk and multicall issues, so I am a bit sceptical.
StanFromIreland commentedon Oct 12, 2025
On Linux, if my cursor is after an expression (e.g.
if 1: pass), pressing tab indents by 2 (!) spaces on the first press, and 4 after that (this seems like a bug). With the patch, after code shift+tab is a NO-OP. If being allowed to indent after code with tab is a bug, then the current behaviour of shift+tab in the patch is correct for this case.terryjreedy commentedon Oct 12, 2025
Do you mean that is adds spaces before 'if' rather than after 'pass'? That would strike me as a bug. The latter is what I see on Windows.
StanFromIreland commentedon Oct 12, 2025
After the
pass.