Skip to content

Commit

Permalink
bpo-36390: Gather IDLE Format menu functions into format.py (pythonGH…
Browse files Browse the repository at this point in the history
…-14827) (pythonGH-14829)

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.
(cherry picked from commit 1b38922)

Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
  • Loading branch information
miss-islington and terryjreedy committed Jul 18, 2019
1 parent 6357433 commit 028f1d2
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 116 deletions.
34 changes: 4 additions & 30 deletions Lib/idlelib/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,8 @@ class EditorWindow(object):
from idlelib.autoexpand import AutoExpand
from idlelib.calltip import Calltip
from idlelib.codecontext import CodeContext
from idlelib.format import FormatParagraph, FormatRegion
from idlelib.format import FormatParagraph, FormatRegion, Indents, Rstrip
from idlelib.parenmatch import ParenMatch
from idlelib.rstrip import Rstrip
from idlelib.squeezer import Squeezer
from idlelib.zoomheight import ZoomHeight

Expand Down Expand Up @@ -173,14 +172,15 @@ def __init__(self, flist=None, filename=None, key=None, root=None):
text.bind("<<newline-and-indent>>",self.newline_and_indent_event)
text.bind("<<smart-indent>>",self.smart_indent_event)
self.fregion = fregion = self.FormatRegion(self)
# self.fregion used in smart_indent_event to access indent_region.
text.bind("<<indent-region>>", fregion.indent_region_event)
text.bind("<<dedent-region>>", fregion.dedent_region_event)
text.bind("<<comment-region>>", fregion.comment_region_event)
text.bind("<<uncomment-region>>", fregion.uncomment_region_event)
text.bind("<<tabify-region>>", fregion.tabify_region_event)
text.bind("<<untabify-region>>", fregion.untabify_region_event)
text.bind("<<toggle-tabs>>", self.toggle_tabs_event)
text.bind("<<change-indentwidth>>",self.change_indentwidth_event)
text.bind("<<toggle-tabs>>", self.Indents.toggle_tabs_event)
text.bind("<<change-indentwidth>>", self.Indents.change_indentwidth_event)
text.bind("<Left>", self.move_at_edge_if_selection(0))
text.bind("<Right>", self.move_at_edge_if_selection(1))
text.bind("<<del-word-left>>", self.del_word_left)
Expand Down Expand Up @@ -1424,20 +1424,6 @@ def inner(offset, _startindex=startindex,
return _icis(_startindex + "+%dc" % offset)
return inner

def toggle_tabs_event(self, event):
if self.askyesno(
"Toggle tabs",
"Turn tabs " + ("on", "off")[self.usetabs] +
"?\nIndent width " +
("will be", "remains at")[self.usetabs] + " 8." +
"\n Note: a tab is always 8 columns",
parent=self.text):
self.usetabs = not self.usetabs
# Try to prevent inconsistent indentation.
# User must change indent width manually after using tabs.
self.indentwidth = 8
return "break"

# XXX this isn't bound to anything -- see tabwidth comments
## def change_tabwidth_event(self, event):
## new = self._asktabwidth()
Expand All @@ -1446,18 +1432,6 @@ def toggle_tabs_event(self, event):
## self.set_indentation_params(0, guess=0)
## return "break"

def change_indentwidth_event(self, event):
new = self.askinteger(
"Indent width",
"New indent width (2-16)\n(Always use 8 when using tabs)",
parent=self.text,
initialvalue=self.indentwidth,
minvalue=2,
maxvalue=16)
if new and new != self.indentwidth and not self.usetabs:
self.indentwidth = new
return "break"

# Make string that displays as n leading blanks.

def _make_blanks(self, n):
Expand Down
64 changes: 62 additions & 2 deletions Lib/idlelib/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
File renamed from paragraph.py with functions added from editor.py.
"""
import re
from tkinter.messagebox import askyesno
from tkinter.simpledialog import askinteger
from idlelib.config import idleConf

Expand Down Expand Up @@ -195,7 +196,7 @@ def get_comment_header(line):
return m.group(1)


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

def get_line_indent(line, tabwidth):
Expand All @@ -209,7 +210,7 @@ def get_line_indent(line, tabwidth):


class FormatRegion:
"Format selected text."
"Format selected text (region)."

def __init__(self, editwin):
self.editwin = editwin
Expand Down Expand Up @@ -352,6 +353,65 @@ def _asktabwidth(self):
maxvalue=16)


# With mixed indents not allowed, these are semi-useless and not unittested.
class Indents: # pragma: no cover
"Change future indents."

def __init__(self, editwin):
self.editwin = editwin

def toggle_tabs_event(self, event):
editwin = self.editwin
usetabs = editwin.usetabs
if askyesno(
"Toggle tabs",
"Turn tabs " + ("on", "off")[usetabs] +
"?\nIndent width " +
("will be", "remains at")[usetabs] + " 8." +
"\n Note: a tab is always 8 columns",
parent=editwin.text):
editwin.usetabs = not usetabs
# Try to prevent inconsistent indentation.
# User must change indent width manually after using tabs.
editwin.indentwidth = 8
return "break"

def change_indentwidth_event(self, event):
editwin = self.editwin
new = askinteger(
"Indent width",
"New indent width (2-16)\n(Always use 8 when using tabs)",
parent=editwin.text,
initialvalue=editwin.indentwidth,
minvalue=2,
maxvalue=16)
if new and new != editwin.indentwidth and not editwin.usetabs:
editwin.indentwidth = new
return "break"


class Rstrip: # 'Strip Trailing Whitespace" on "Format" menu.
def __init__(self, editwin):
self.editwin = editwin

def do_rstrip(self, event=None):
text = self.editwin.text
undo = self.editwin.undo
undo.undo_block_start()

end_line = int(float(text.index('end')))
for cur in range(1, end_line):
txt = text.get('%i.0' % cur, '%i.end' % cur)
raw = len(txt)
cut = len(txt.rstrip())
# Since text.delete() marks file as changed, even if not,
# only call it when needed to actually delete something.
if cut < raw:
text.delete('%i.%i' % (cur, cut), '%i.end' % cur)

undo.undo_block_stop()


if __name__ == "__main__":
from unittest import main
main('idlelib.idle_test.test_format', verbosity=2, exit=False)
46 changes: 46 additions & 0 deletions Lib/idlelib/idle_test/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from test.support import requires
from tkinter import Tk, Text
from idlelib.editor import EditorWindow
from idlelib.idle_test.mock_idle import Editor as MockEditor


class Is_Get_Test(unittest.TestCase):
Expand Down Expand Up @@ -573,5 +574,50 @@ def test_ask_tabwidth(self, askinteger):
self.assertEqual(ask(), 10)


class rstripTest(unittest.TestCase):

def test_rstrip_line(self):
editor = MockEditor()
text = editor.text
do_rstrip = ft.Rstrip(editor).do_rstrip
eq = self.assertEqual

do_rstrip()
eq(text.get('1.0', 'insert'), '')
text.insert('1.0', ' ')
do_rstrip()
eq(text.get('1.0', 'insert'), '')
text.insert('1.0', ' \n')
do_rstrip()
eq(text.get('1.0', 'insert'), '\n')

def test_rstrip_multiple(self):
editor = MockEditor()
# Comment above, uncomment 3 below to test with real Editor & Text.
#from idlelib.editor import EditorWindow as Editor
#from tkinter import Tk
#editor = Editor(root=Tk())
text = editor.text
do_rstrip = ft.Rstrip(editor).do_rstrip

original = (
"Line with an ending tab \n"
"Line ending in 5 spaces \n"
"Linewithnospaces\n"
" indented line\n"
" indented line with trailing space \n"
" ")
stripped = (
"Line with an ending tab\n"
"Line ending in 5 spaces\n"
"Linewithnospaces\n"
" indented line\n"
" indented line with trailing space\n")

text.insert('1.0', original)
do_rstrip()
self.assertEqual(text.get('1.0', 'insert'), stripped)


if __name__ == '__main__':
unittest.main(verbosity=2, exit=2)
53 changes: 0 additions & 53 deletions Lib/idlelib/idle_test/test_rstrip.py

This file was deleted.

29 changes: 0 additions & 29 deletions Lib/idlelib/rstrip.py

This file was deleted.

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

0 comments on commit 028f1d2

Please sign in to comment.