Skip to content

Commit 1b38922

Browse files
authored
bpo-36390: Gather IDLE Format menu functions into format.py (python#14827)
Add two indent spec methods from editor and Rstrip to existing file. Tests are not added for indent methods because they need change in lights of 3.x's prohibition on mixing tabs and spaces.
1 parent 8cb65d1 commit 1b38922

File tree

6 files changed

+114
-116
lines changed

6 files changed

+114
-116
lines changed

Lib/idlelib/editor.py

+4-30
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,8 @@ class EditorWindow(object):
5353
from idlelib.autoexpand import AutoExpand
5454
from idlelib.calltip import Calltip
5555
from idlelib.codecontext import CodeContext
56-
from idlelib.format import FormatParagraph, FormatRegion
56+
from idlelib.format import FormatParagraph, FormatRegion, Indents, Rstrip
5757
from idlelib.parenmatch import ParenMatch
58-
from idlelib.rstrip import Rstrip
5958
from idlelib.squeezer import Squeezer
6059
from idlelib.zoomheight import ZoomHeight
6160

@@ -173,14 +172,15 @@ def __init__(self, flist=None, filename=None, key=None, root=None):
173172
text.bind("<<newline-and-indent>>",self.newline_and_indent_event)
174173
text.bind("<<smart-indent>>",self.smart_indent_event)
175174
self.fregion = fregion = self.FormatRegion(self)
175+
# self.fregion used in smart_indent_event to access indent_region.
176176
text.bind("<<indent-region>>", fregion.indent_region_event)
177177
text.bind("<<dedent-region>>", fregion.dedent_region_event)
178178
text.bind("<<comment-region>>", fregion.comment_region_event)
179179
text.bind("<<uncomment-region>>", fregion.uncomment_region_event)
180180
text.bind("<<tabify-region>>", fregion.tabify_region_event)
181181
text.bind("<<untabify-region>>", fregion.untabify_region_event)
182-
text.bind("<<toggle-tabs>>", self.toggle_tabs_event)
183-
text.bind("<<change-indentwidth>>",self.change_indentwidth_event)
182+
text.bind("<<toggle-tabs>>", self.Indents.toggle_tabs_event)
183+
text.bind("<<change-indentwidth>>", self.Indents.change_indentwidth_event)
184184
text.bind("<Left>", self.move_at_edge_if_selection(0))
185185
text.bind("<Right>", self.move_at_edge_if_selection(1))
186186
text.bind("<<del-word-left>>", self.del_word_left)
@@ -1424,20 +1424,6 @@ def inner(offset, _startindex=startindex,
14241424
return _icis(_startindex + "+%dc" % offset)
14251425
return inner
14261426

1427-
def toggle_tabs_event(self, event):
1428-
if self.askyesno(
1429-
"Toggle tabs",
1430-
"Turn tabs " + ("on", "off")[self.usetabs] +
1431-
"?\nIndent width " +
1432-
("will be", "remains at")[self.usetabs] + " 8." +
1433-
"\n Note: a tab is always 8 columns",
1434-
parent=self.text):
1435-
self.usetabs = not self.usetabs
1436-
# Try to prevent inconsistent indentation.
1437-
# User must change indent width manually after using tabs.
1438-
self.indentwidth = 8
1439-
return "break"
1440-
14411427
# XXX this isn't bound to anything -- see tabwidth comments
14421428
## def change_tabwidth_event(self, event):
14431429
## new = self._asktabwidth()
@@ -1446,18 +1432,6 @@ def toggle_tabs_event(self, event):
14461432
## self.set_indentation_params(0, guess=0)
14471433
## return "break"
14481434

1449-
def change_indentwidth_event(self, event):
1450-
new = self.askinteger(
1451-
"Indent width",
1452-
"New indent width (2-16)\n(Always use 8 when using tabs)",
1453-
parent=self.text,
1454-
initialvalue=self.indentwidth,
1455-
minvalue=2,
1456-
maxvalue=16)
1457-
if new and new != self.indentwidth and not self.usetabs:
1458-
self.indentwidth = new
1459-
return "break"
1460-
14611435
# Make string that displays as n leading blanks.
14621436

14631437
def _make_blanks(self, n):

Lib/idlelib/format.py

+62-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
File renamed from paragraph.py with functions added from editor.py.
77
"""
88
import re
9+
from tkinter.messagebox import askyesno
910
from tkinter.simpledialog import askinteger
1011
from idlelib.config import idleConf
1112

@@ -195,7 +196,7 @@ def get_comment_header(line):
195196
return m.group(1)
196197

197198

198-
# Copy from editor.py; importing it would cause an import cycle.
199+
# Copied from editor.py; importing it would cause an import cycle.
199200
_line_indent_re = re.compile(r'[ \t]*')
200201

201202
def get_line_indent(line, tabwidth):
@@ -209,7 +210,7 @@ def get_line_indent(line, tabwidth):
209210

210211

211212
class FormatRegion:
212-
"Format selected text."
213+
"Format selected text (region)."
213214

214215
def __init__(self, editwin):
215216
self.editwin = editwin
@@ -352,6 +353,65 @@ def _asktabwidth(self):
352353
maxvalue=16)
353354

354355

356+
# With mixed indents not allowed, these are semi-useless and not unittested.
357+
class Indents: # pragma: no cover
358+
"Change future indents."
359+
360+
def __init__(self, editwin):
361+
self.editwin = editwin
362+
363+
def toggle_tabs_event(self, event):
364+
editwin = self.editwin
365+
usetabs = editwin.usetabs
366+
if askyesno(
367+
"Toggle tabs",
368+
"Turn tabs " + ("on", "off")[usetabs] +
369+
"?\nIndent width " +
370+
("will be", "remains at")[usetabs] + " 8." +
371+
"\n Note: a tab is always 8 columns",
372+
parent=editwin.text):
373+
editwin.usetabs = not usetabs
374+
# Try to prevent inconsistent indentation.
375+
# User must change indent width manually after using tabs.
376+
editwin.indentwidth = 8
377+
return "break"
378+
379+
def change_indentwidth_event(self, event):
380+
editwin = self.editwin
381+
new = askinteger(
382+
"Indent width",
383+
"New indent width (2-16)\n(Always use 8 when using tabs)",
384+
parent=editwin.text,
385+
initialvalue=editwin.indentwidth,
386+
minvalue=2,
387+
maxvalue=16)
388+
if new and new != editwin.indentwidth and not editwin.usetabs:
389+
editwin.indentwidth = new
390+
return "break"
391+
392+
393+
class Rstrip: # 'Strip Trailing Whitespace" on "Format" menu.
394+
def __init__(self, editwin):
395+
self.editwin = editwin
396+
397+
def do_rstrip(self, event=None):
398+
text = self.editwin.text
399+
undo = self.editwin.undo
400+
undo.undo_block_start()
401+
402+
end_line = int(float(text.index('end')))
403+
for cur in range(1, end_line):
404+
txt = text.get('%i.0' % cur, '%i.end' % cur)
405+
raw = len(txt)
406+
cut = len(txt.rstrip())
407+
# Since text.delete() marks file as changed, even if not,
408+
# only call it when needed to actually delete something.
409+
if cut < raw:
410+
text.delete('%i.%i' % (cur, cut), '%i.end' % cur)
411+
412+
undo.undo_block_stop()
413+
414+
355415
if __name__ == "__main__":
356416
from unittest import main
357417
main('idlelib.idle_test.test_format', verbosity=2, exit=False)

Lib/idlelib/idle_test/test_format.py

+46
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from test.support import requires
77
from tkinter import Tk, Text
88
from idlelib.editor import EditorWindow
9+
from idlelib.idle_test.mock_idle import Editor as MockEditor
910

1011

1112
class Is_Get_Test(unittest.TestCase):
@@ -573,5 +574,50 @@ def test_ask_tabwidth(self, askinteger):
573574
self.assertEqual(ask(), 10)
574575

575576

577+
class rstripTest(unittest.TestCase):
578+
579+
def test_rstrip_line(self):
580+
editor = MockEditor()
581+
text = editor.text
582+
do_rstrip = ft.Rstrip(editor).do_rstrip
583+
eq = self.assertEqual
584+
585+
do_rstrip()
586+
eq(text.get('1.0', 'insert'), '')
587+
text.insert('1.0', ' ')
588+
do_rstrip()
589+
eq(text.get('1.0', 'insert'), '')
590+
text.insert('1.0', ' \n')
591+
do_rstrip()
592+
eq(text.get('1.0', 'insert'), '\n')
593+
594+
def test_rstrip_multiple(self):
595+
editor = MockEditor()
596+
# Comment above, uncomment 3 below to test with real Editor & Text.
597+
#from idlelib.editor import EditorWindow as Editor
598+
#from tkinter import Tk
599+
#editor = Editor(root=Tk())
600+
text = editor.text
601+
do_rstrip = ft.Rstrip(editor).do_rstrip
602+
603+
original = (
604+
"Line with an ending tab \n"
605+
"Line ending in 5 spaces \n"
606+
"Linewithnospaces\n"
607+
" indented line\n"
608+
" indented line with trailing space \n"
609+
" ")
610+
stripped = (
611+
"Line with an ending tab\n"
612+
"Line ending in 5 spaces\n"
613+
"Linewithnospaces\n"
614+
" indented line\n"
615+
" indented line with trailing space\n")
616+
617+
text.insert('1.0', original)
618+
do_rstrip()
619+
self.assertEqual(text.get('1.0', 'insert'), stripped)
620+
621+
576622
if __name__ == '__main__':
577623
unittest.main(verbosity=2, exit=2)

Lib/idlelib/idle_test/test_rstrip.py

-53
This file was deleted.

Lib/idlelib/rstrip.py

-29
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Rename paragraph.py to format.py and add region formatting methods
2-
from editor.py. Add tests for the latter.
1+
Gather Format menu functions into format.py. Combine
2+
paragraph.py, rstrip.py, and format methods from editor.py.

0 commit comments

Comments
 (0)