Commit 82494aa6 authored by Cheryl Sabella's avatar Cheryl Sabella Committed by Terry Jan Reedy

bpo-36390: IDLE: Combine region formatting methods. (GH-12481)

Rename paragraph.py to format.py and add region formatting methods
from editor.py.  Add tests for the latter.
parent fb26504d
...@@ -29,7 +29,7 @@ from idlelib.textview import view_text ...@@ -29,7 +29,7 @@ from idlelib.textview import view_text
from idlelib.autocomplete import AutoComplete from idlelib.autocomplete import AutoComplete
from idlelib.codecontext import CodeContext from idlelib.codecontext import CodeContext
from idlelib.parenmatch import ParenMatch from idlelib.parenmatch import ParenMatch
from idlelib.paragraph import FormatParagraph from idlelib.format import FormatParagraph
from idlelib.squeezer import Squeezer from idlelib.squeezer import Squeezer
changes = ConfigChanges() changes = ConfigChanges()
......
...@@ -53,7 +53,7 @@ class EditorWindow(object): ...@@ -53,7 +53,7 @@ class EditorWindow(object):
from idlelib.autoexpand import AutoExpand from idlelib.autoexpand import AutoExpand
from idlelib.calltip import Calltip from idlelib.calltip import Calltip
from idlelib.codecontext import CodeContext from idlelib.codecontext import CodeContext
from idlelib.paragraph import FormatParagraph from idlelib.format import FormatParagraph, FormatRegion
from idlelib.parenmatch import ParenMatch from idlelib.parenmatch import ParenMatch
from idlelib.rstrip import Rstrip from idlelib.rstrip import Rstrip
from idlelib.squeezer import Squeezer from idlelib.squeezer import Squeezer
...@@ -172,13 +172,14 @@ class EditorWindow(object): ...@@ -172,13 +172,14 @@ class EditorWindow(object):
text.bind("<<smart-backspace>>",self.smart_backspace_event) text.bind("<<smart-backspace>>",self.smart_backspace_event)
text.bind("<<newline-and-indent>>",self.newline_and_indent_event) text.bind("<<newline-and-indent>>",self.newline_and_indent_event)
text.bind("<<smart-indent>>",self.smart_indent_event) text.bind("<<smart-indent>>",self.smart_indent_event)
text.bind("<<indent-region>>",self.indent_region_event) self.fregion = fregion = self.FormatRegion(self)
text.bind("<<dedent-region>>",self.dedent_region_event) text.bind("<<indent-region>>", fregion.indent_region_event)
text.bind("<<comment-region>>",self.comment_region_event) text.bind("<<dedent-region>>", fregion.dedent_region_event)
text.bind("<<uncomment-region>>",self.uncomment_region_event) text.bind("<<comment-region>>", fregion.comment_region_event)
text.bind("<<tabify-region>>",self.tabify_region_event) text.bind("<<uncomment-region>>", fregion.uncomment_region_event)
text.bind("<<untabify-region>>",self.untabify_region_event) text.bind("<<tabify-region>>", fregion.tabify_region_event)
text.bind("<<toggle-tabs>>",self.toggle_tabs_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("<<change-indentwidth>>",self.change_indentwidth_event)
text.bind("<Left>", self.move_at_edge_if_selection(0)) text.bind("<Left>", self.move_at_edge_if_selection(0))
text.bind("<Right>", self.move_at_edge_if_selection(1)) text.bind("<Right>", self.move_at_edge_if_selection(1))
...@@ -1290,7 +1291,7 @@ class EditorWindow(object): ...@@ -1290,7 +1291,7 @@ class EditorWindow(object):
try: try:
if first and last: if first and last:
if index2line(first) != index2line(last): if index2line(first) != index2line(last):
return self.indent_region_event(event) return self.fregion.indent_region_event(event)
text.delete(first, last) text.delete(first, last)
text.mark_set("insert", first) text.mark_set("insert", first)
prefix = text.get("insert linestart", "insert") prefix = text.get("insert linestart", "insert")
...@@ -1423,72 +1424,6 @@ class EditorWindow(object): ...@@ -1423,72 +1424,6 @@ class EditorWindow(object):
return _icis(_startindex + "+%dc" % offset) return _icis(_startindex + "+%dc" % offset)
return inner return inner
def indent_region_event(self, event):
head, tail, chars, lines = self.get_region()
for pos in range(len(lines)):
line = lines[pos]
if line:
raw, effective = get_line_indent(line, self.tabwidth)
effective = effective + self.indentwidth
lines[pos] = self._make_blanks(effective) + line[raw:]
self.set_region(head, tail, chars, lines)
return "break"
def dedent_region_event(self, event):
head, tail, chars, lines = self.get_region()
for pos in range(len(lines)):
line = lines[pos]
if line:
raw, effective = get_line_indent(line, self.tabwidth)
effective = max(effective - self.indentwidth, 0)
lines[pos] = self._make_blanks(effective) + line[raw:]
self.set_region(head, tail, chars, lines)
return "break"
def comment_region_event(self, event):
head, tail, chars, lines = self.get_region()
for pos in range(len(lines) - 1):
line = lines[pos]
lines[pos] = '##' + line
self.set_region(head, tail, chars, lines)
return "break"
def uncomment_region_event(self, event):
head, tail, chars, lines = self.get_region()
for pos in range(len(lines)):
line = lines[pos]
if not line:
continue
if line[:2] == '##':
line = line[2:]
elif line[:1] == '#':
line = line[1:]
lines[pos] = line
self.set_region(head, tail, chars, lines)
return "break"
def tabify_region_event(self, event):
head, tail, chars, lines = self.get_region()
tabwidth = self._asktabwidth()
if tabwidth is None: return
for pos in range(len(lines)):
line = lines[pos]
if line:
raw, effective = get_line_indent(line, tabwidth)
ntabs, nspaces = divmod(effective, tabwidth)
lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:]
self.set_region(head, tail, chars, lines)
return "break"
def untabify_region_event(self, event):
head, tail, chars, lines = self.get_region()
tabwidth = self._asktabwidth()
if tabwidth is None: return
for pos in range(len(lines)):
lines[pos] = lines[pos].expandtabs(tabwidth)
self.set_region(head, tail, chars, lines)
return "break"
def toggle_tabs_event(self, event): def toggle_tabs_event(self, event):
if self.askyesno( if self.askyesno(
"Toggle tabs", "Toggle tabs",
...@@ -1523,33 +1458,6 @@ class EditorWindow(object): ...@@ -1523,33 +1458,6 @@ class EditorWindow(object):
self.indentwidth = new self.indentwidth = new
return "break" return "break"
def get_region(self):
text = self.text
first, last = self.get_selection_indices()
if first and last:
head = text.index(first + " linestart")
tail = text.index(last + "-1c lineend +1c")
else:
head = text.index("insert linestart")
tail = text.index("insert lineend +1c")
chars = text.get(head, tail)
lines = chars.split("\n")
return head, tail, chars, lines
def set_region(self, head, tail, chars, lines):
text = self.text
newchars = "\n".join(lines)
if newchars == chars:
text.bell()
return
text.tag_remove("sel", "1.0", "end")
text.mark_set("insert", head)
text.undo_block_start()
text.delete(head, tail)
text.insert(head, newchars)
text.undo_block_stop()
text.tag_add("sel", head, "insert")
# Make string that displays as n leading blanks. # Make string that displays as n leading blanks.
def _make_blanks(self, n): def _make_blanks(self, n):
...@@ -1571,15 +1479,6 @@ class EditorWindow(object): ...@@ -1571,15 +1479,6 @@ class EditorWindow(object):
text.insert("insert", self._make_blanks(column)) text.insert("insert", self._make_blanks(column))
text.undo_block_stop() text.undo_block_stop()
def _asktabwidth(self):
return self.askinteger(
"Tab width",
"Columns per tab? (2-16)",
parent=self.text,
initialvalue=self.indentwidth,
minvalue=2,
maxvalue=16)
# Guess indentwidth from text content. # Guess indentwidth from text content.
# Return guessed indentwidth. This should not be believed unless # Return guessed indentwidth. This should not be believed unless
# it's in a reasonable range (e.g., it will be 0 if no indented # it's in a reasonable range (e.g., it will be 0 if no indented
......
"""Format a paragraph, comment block, or selection to a max width. """Format all or a selected region (line slice) of text.
Does basic, standard text formatting, and also understands Python Region formatting options: paragraph, comment block, indent, deindent,
comment blocks. Thus, for editing Python source code, this comment, uncomment, tabify, and untabify.
extension is really only suitable for reformatting these comment
blocks or triple-quoted strings. File renamed from paragraph.py with functions added from editor.py.
Known problems with comment reformatting:
* If there is a selection marked, and the first line of the
selection is not complete, the block will probably not be detected
as comments, and will have the normal "text formatting" rules
applied.
* If a comment block has leading whitespace that mixes tabs and
spaces, they will not be considered part of the same block.
* Fancy comments, like this bulleted list, aren't handled :-)
""" """
import re import re
from tkinter.simpledialog import askinteger
from idlelib.config import idleConf from idlelib.config import idleConf
class FormatParagraph: class FormatParagraph:
"""Format a paragraph, comment block, or selection to a max width.
Does basic, standard text formatting, and also understands Python
comment blocks. Thus, for editing Python source code, this
extension is really only suitable for reformatting these comment
blocks or triple-quoted strings.
Known problems with comment reformatting:
* If there is a selection marked, and the first line of the
selection is not complete, the block will probably not be detected
as comments, and will have the normal "text formatting" rules
applied.
* If a comment block has leading whitespace that mixes tabs and
spaces, they will not be considered part of the same block.
* Fancy comments, like this bulleted list, aren't handled :-)
"""
def __init__(self, editwin): def __init__(self, editwin):
self.editwin = editwin self.editwin = editwin
...@@ -189,6 +195,163 @@ def get_comment_header(line): ...@@ -189,6 +195,163 @@ def get_comment_header(line):
return m.group(1) return m.group(1)
# Copy from editor.py; importing it would cause an import cycle.
_line_indent_re = re.compile(r'[ \t]*')
def get_line_indent(line, tabwidth):
"""Return a line's indentation as (# chars, effective # of spaces).
The effective # of spaces is the length after properly "expanding"
the tabs into spaces, as done by str.expandtabs(tabwidth).
"""
m = _line_indent_re.match(line)
return m.end(), len(m.group().expandtabs(tabwidth))
class FormatRegion:
"Format selected text."
def __init__(self, editwin):
self.editwin = editwin
def get_region(self):
"""Return line information about the selected text region.
If text is selected, the first and last indices will be
for the selection. If there is no text selected, the
indices will be the current cursor location.
Return a tuple containing (first index, last index,
string representation of text, list of text lines).
"""
text = self.editwin.text
first, last = self.editwin.get_selection_indices()
if first and last:
head = text.index(first + " linestart")
tail = text.index(last + "-1c lineend +1c")
else:
head = text.index("insert linestart")
tail = text.index("insert lineend +1c")
chars = text.get(head, tail)
lines = chars.split("\n")
return head, tail, chars, lines
def set_region(self, head, tail, chars, lines):
"""Replace the text between the given indices.
Args:
head: Starting index of text to replace.
tail: Ending index of text to replace.
chars: Expected to be string of current text
between head and tail.
lines: List of new lines to insert between head
and tail.
"""
text = self.editwin.text
newchars = "\n".join(lines)
if newchars == chars:
text.bell()
return
text.tag_remove("sel", "1.0", "end")
text.mark_set("insert", head)
text.undo_block_start()
text.delete(head, tail)
text.insert(head, newchars)
text.undo_block_stop()
text.tag_add("sel", head, "insert")
def indent_region_event(self, event=None):
"Indent region by indentwidth spaces."
head, tail, chars, lines = self.get_region()
for pos in range(len(lines)):
line = lines[pos]
if line:
raw, effective = get_line_indent(line, self.editwin.tabwidth)
effective = effective + self.editwin.indentwidth
lines[pos] = self.editwin._make_blanks(effective) + line[raw:]
self.set_region(head, tail, chars, lines)
return "break"
def dedent_region_event(self, event=None):
"Dedent region by indentwidth spaces."
head, tail, chars, lines = self.get_region()
for pos in range(len(lines)):
line = lines[pos]
if line:
raw, effective = get_line_indent(line, self.editwin.tabwidth)
effective = max(effective - self.editwin.indentwidth, 0)
lines[pos] = self.editwin._make_blanks(effective) + line[raw:]
self.set_region(head, tail, chars, lines)
return "break"
def comment_region_event(self, event=None):
"""Comment out each line in region.
## is appended to the beginning of each line to comment it out.
"""
head, tail, chars, lines = self.get_region()
for pos in range(len(lines) - 1):
line = lines[pos]
lines[pos] = '##' + line
self.set_region(head, tail, chars, lines)
return "break"
def uncomment_region_event(self, event=None):
"""Uncomment each line in region.
Remove ## or # in the first positions of a line. If the comment
is not in the beginning position, this command will have no effect.
"""
head, tail, chars, lines = self.get_region()
for pos in range(len(lines)):
line = lines[pos]
if not line:
continue
if line[:2] == '##':
line = line[2:]
elif line[:1] == '#':
line = line[1:]
lines[pos] = line
self.set_region(head, tail, chars, lines)
return "break"
def tabify_region_event(self, event=None):
"Convert leading spaces to tabs for each line in selected region."
head, tail, chars, lines = self.get_region()
tabwidth = self._asktabwidth()
if tabwidth is None:
return
for pos in range(len(lines)):
line = lines[pos]
if line:
raw, effective = get_line_indent(line, tabwidth)
ntabs, nspaces = divmod(effective, tabwidth)
lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:]
self.set_region(head, tail, chars, lines)
return "break"
def untabify_region_event(self, event=None):
"Expand tabs to spaces for each line in region."
head, tail, chars, lines = self.get_region()
tabwidth = self._asktabwidth()
if tabwidth is None:
return
for pos in range(len(lines)):
lines[pos] = lines[pos].expandtabs(tabwidth)
self.set_region(head, tail, chars, lines)
return "break"
def _asktabwidth(self):
"Return value for tab width."
return askinteger(
"Tab width",
"Columns per tab? (2-16)",
parent=self.editwin.text,
initialvalue=self.editwin.indentwidth,
minvalue=2,
maxvalue=16)
if __name__ == "__main__": if __name__ == "__main__":
from unittest import main from unittest import main
main('idlelib.idle_test.test_paragraph', verbosity=2, exit=False) main('idlelib.idle_test.test_format', verbosity=2, exit=False)
"Test paragraph, coverage 76%." "Test format, coverage 99%."
from idlelib import paragraph as pg from idlelib import format as ft
import unittest import unittest
from unittest import mock
from test.support import requires from test.support import requires
from tkinter import Tk, Text from tkinter import Tk, Text
from idlelib.editor import EditorWindow from idlelib.editor import EditorWindow
...@@ -16,26 +17,26 @@ class Is_Get_Test(unittest.TestCase): ...@@ -16,26 +17,26 @@ class Is_Get_Test(unittest.TestCase):
leadingws_nocomment = ' This is not a comment' leadingws_nocomment = ' This is not a comment'
def test_is_all_white(self): def test_is_all_white(self):
self.assertTrue(pg.is_all_white('')) self.assertTrue(ft.is_all_white(''))
self.assertTrue(pg.is_all_white('\t\n\r\f\v')) self.assertTrue(ft.is_all_white('\t\n\r\f\v'))
self.assertFalse(pg.is_all_white(self.test_comment)) self.assertFalse(ft.is_all_white(self.test_comment))
def test_get_indent(self): def test_get_indent(self):
Equal = self.assertEqual Equal = self.assertEqual
Equal(pg.get_indent(self.test_comment), '') Equal(ft.get_indent(self.test_comment), '')
Equal(pg.get_indent(self.trailingws_comment), '') Equal(ft.get_indent(self.trailingws_comment), '')
Equal(pg.get_indent(self.leadingws_comment), ' ') Equal(ft.get_indent(self.leadingws_comment), ' ')
Equal(pg.get_indent(self.leadingws_nocomment), ' ') Equal(ft.get_indent(self.leadingws_nocomment), ' ')
def test_get_comment_header(self): def test_get_comment_header(self):
Equal = self.assertEqual Equal = self.assertEqual
# Test comment strings # Test comment strings
Equal(pg.get_comment_header(self.test_comment), '#') Equal(ft.get_comment_header(self.test_comment), '#')
Equal(pg.get_comment_header(self.trailingws_comment), '#') Equal(ft.get_comment_header(self.trailingws_comment), '#')
Equal(pg.get_comment_header(self.leadingws_comment), ' #') Equal(ft.get_comment_header(self.leadingws_comment), ' #')
# Test non-comment strings # Test non-comment strings
Equal(pg.get_comment_header(self.leadingws_nocomment), ' ') Equal(ft.get_comment_header(self.leadingws_nocomment), ' ')
Equal(pg.get_comment_header(self.test_nocomment), '') Equal(ft.get_comment_header(self.test_nocomment), '')
class FindTest(unittest.TestCase): class FindTest(unittest.TestCase):
...@@ -63,7 +64,7 @@ class FindTest(unittest.TestCase): ...@@ -63,7 +64,7 @@ class FindTest(unittest.TestCase):
linelength = int(text.index("%d.end" % line).split('.')[1]) linelength = int(text.index("%d.end" % line).split('.')[1])
for col in (0, linelength//2, linelength): for col in (0, linelength//2, linelength):
tempindex = "%d.%d" % (line, col) tempindex = "%d.%d" % (line, col)
self.assertEqual(pg.find_paragraph(text, tempindex), expected) self.assertEqual(ft.find_paragraph(text, tempindex), expected)
text.delete('1.0', 'end') text.delete('1.0', 'end')
def test_find_comment(self): def test_find_comment(self):
...@@ -162,7 +163,7 @@ class ReformatFunctionTest(unittest.TestCase): ...@@ -162,7 +163,7 @@ class ReformatFunctionTest(unittest.TestCase):
def test_reformat_paragraph(self): def test_reformat_paragraph(self):
Equal = self.assertEqual Equal = self.assertEqual
reform = pg.reformat_paragraph reform = ft.reformat_paragraph
hw = "O hello world" hw = "O hello world"
Equal(reform(' ', 1), ' ') Equal(reform(' ', 1), ' ')
Equal(reform("Hello world", 20), "Hello world") Equal(reform("Hello world", 20), "Hello world")
...@@ -193,7 +194,7 @@ class ReformatCommentTest(unittest.TestCase): ...@@ -193,7 +194,7 @@ class ReformatCommentTest(unittest.TestCase):
test_string = ( test_string = (
" \"\"\"this is a test of a reformat for a triple quoted string" " \"\"\"this is a test of a reformat for a triple quoted string"
" will it reformat to less than 70 characters for me?\"\"\"") " will it reformat to less than 70 characters for me?\"\"\"")
result = pg.reformat_comment(test_string, 70, " ") result = ft.reformat_comment(test_string, 70, " ")
expected = ( expected = (
" \"\"\"this is a test of a reformat for a triple quoted string will it\n" " \"\"\"this is a test of a reformat for a triple quoted string will it\n"
" reformat to less than 70 characters for me?\"\"\"") " reformat to less than 70 characters for me?\"\"\"")
...@@ -202,7 +203,7 @@ class ReformatCommentTest(unittest.TestCase): ...@@ -202,7 +203,7 @@ class ReformatCommentTest(unittest.TestCase):
test_comment = ( test_comment = (
"# this is a test of a reformat for a triple quoted string will " "# this is a test of a reformat for a triple quoted string will "
"it reformat to less than 70 characters for me?") "it reformat to less than 70 characters for me?")
result = pg.reformat_comment(test_comment, 70, "#") result = ft.reformat_comment(test_comment, 70, "#")
expected = ( expected = (
"# this is a test of a reformat for a triple quoted string will it\n" "# this is a test of a reformat for a triple quoted string will it\n"
"# reformat to less than 70 characters for me?") "# reformat to less than 70 characters for me?")
...@@ -211,7 +212,7 @@ class ReformatCommentTest(unittest.TestCase): ...@@ -211,7 +212,7 @@ class ReformatCommentTest(unittest.TestCase):
class FormatClassTest(unittest.TestCase): class FormatClassTest(unittest.TestCase):
def test_init_close(self): def test_init_close(self):
instance = pg.FormatParagraph('editor') instance = ft.FormatParagraph('editor')
self.assertEqual(instance.editwin, 'editor') self.assertEqual(instance.editwin, 'editor')
instance.close() instance.close()
self.assertEqual(instance.editwin, None) self.assertEqual(instance.editwin, None)
...@@ -273,7 +274,7 @@ class FormatEventTest(unittest.TestCase): ...@@ -273,7 +274,7 @@ class FormatEventTest(unittest.TestCase):
cls.root.withdraw() cls.root.withdraw()
editor = Editor(root=cls.root) editor = Editor(root=cls.root)
cls.text = editor.text.text # Test code does not need the wrapper. cls.text = editor.text.text # Test code does not need the wrapper.
cls.formatter = pg.FormatParagraph(editor).format_paragraph_event cls.formatter = ft.FormatParagraph(editor).format_paragraph_event
# Sets the insert mark just after the re-wrapped and inserted text. # Sets the insert mark just after the re-wrapped and inserted text.
@classmethod @classmethod
...@@ -375,5 +376,202 @@ class FormatEventTest(unittest.TestCase): ...@@ -375,5 +376,202 @@ class FormatEventTest(unittest.TestCase):
## text.delete('1.0', 'end') ## text.delete('1.0', 'end')
class DummyEditwin:
def __init__(self, root, text):
self.root = root
self.text = text
self.indentwidth = 4
self.tabwidth = 4
self.usetabs = False
self.context_use_ps1 = True
_make_blanks = EditorWindow._make_blanks
get_selection_indices = EditorWindow.get_selection_indices
class FormatRegionTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
requires('gui')
cls.root = Tk()
cls.root.withdraw()
cls.text = Text(cls.root)
cls.text.undo_block_start = mock.Mock()
cls.text.undo_block_stop = mock.Mock()
cls.editor = DummyEditwin(cls.root, cls.text)
cls.formatter = ft.FormatRegion(cls.editor)
@classmethod
def tearDownClass(cls):
del cls.text, cls.formatter, cls.editor
cls.root.update_idletasks()
cls.root.destroy()
del cls.root
def setUp(self):
self.text.insert('1.0', self.code_sample)
def tearDown(self):
self.text.delete('1.0', 'end')
code_sample = """\
class C1():
# Class comment.
def __init__(self, a, b):
self.a = a
self.b = b
def compare(self):
if a > b:
return a
elif a < b:
return b
else:
return None
"""
def test_get_region(self):
get = self.formatter.get_region
text = self.text
eq = self.assertEqual
# Add selection.
text.tag_add('sel', '7.0', '10.0')
expected_lines = ['',
' def compare(self):',
' if a > b:',
'']
eq(get(), ('7.0', '10.0', '\n'.join(expected_lines), expected_lines))
# Remove selection.
text.tag_remove('sel', '1.0', 'end')
eq(get(), ('15.0', '16.0', '\n', ['', '']))
def test_set_region(self):
set_ = self.formatter.set_region
text = self.text
eq = self.assertEqual
save_bell = text.bell
text.bell = mock.Mock()
line6 = self.code_sample.splitlines()[5]
line10 = self.code_sample.splitlines()[9]
text.tag_add('sel', '6.0', '11.0')
head, tail, chars, lines = self.formatter.get_region()
# No changes.
set_(head, tail, chars, lines)
text.bell.assert_called_once()
eq(text.get('6.0', '11.0'), chars)
eq(text.get('sel.first', 'sel.last'), chars)
text.tag_remove('sel', '1.0', 'end')
# Alter selected lines by changing lines and adding a newline.
newstring = 'added line 1\n\n\n\n'
newlines = newstring.split('\n')
set_('7.0', '10.0', chars, newlines)
# Selection changed.
eq(text.get('sel.first', 'sel.last'), newstring)
# Additional line added, so last index is changed.
eq(text.get('7.0', '11.0'), newstring)
# Before and after lines unchanged.
eq(text.get('6.0', '7.0-1c'), line6)
eq(text.get('11.0', '12.0-1c'), line10)
text.tag_remove('sel', '1.0', 'end')
text.bell = save_bell
def test_indent_region_event(self):
indent = self.formatter.indent_region_event
text = self.text
eq = self.assertEqual
text.tag_add('sel', '7.0', '10.0')
indent()
# Blank lines aren't affected by indent.
eq(text.get('7.0', '10.0'), ('\n def compare(self):\n if a > b:\n'))
def test_dedent_region_event(self):
dedent = self.formatter.dedent_region_event
text = self.text
eq = self.assertEqual
text.tag_add('sel', '7.0', '10.0')
dedent()
# Blank lines aren't affected by dedent.
eq(text.get('7.0', '10.0'), ('\ndef compare(self):\n if a > b:\n'))
def test_comment_region_event(self):
comment = self.formatter.comment_region_event
text = self.text
eq = self.assertEqual
text.tag_add('sel', '7.0', '10.0')
comment()
eq(text.get('7.0', '10.0'), ('##\n## def compare(self):\n## if a > b:\n'))
def test_uncomment_region_event(self):
comment = self.formatter.comment_region_event
uncomment = self.formatter.uncomment_region_event
text = self.text
eq = self.assertEqual
text.tag_add('sel', '7.0', '10.0')
comment()
uncomment()
eq(text.get('7.0', '10.0'), ('\n def compare(self):\n if a > b:\n'))
# Only remove comments at the beginning of a line.
text.tag_remove('sel', '1.0', 'end')
text.tag_add('sel', '3.0', '4.0')
uncomment()
eq(text.get('3.0', '3.end'), (' # Class comment.'))
self.formatter.set_region('3.0', '4.0', '', ['# Class comment.', ''])
uncomment()
eq(text.get('3.0', '3.end'), (' Class comment.'))
@mock.patch.object(ft.FormatRegion, "_asktabwidth")
def test_tabify_region_event(self, _asktabwidth):
tabify = self.formatter.tabify_region_event
text = self.text
eq = self.assertEqual
text.tag_add('sel', '7.0', '10.0')
# No tabwidth selected.
_asktabwidth.return_value = None
self.assertIsNone(tabify())
_asktabwidth.return_value = 3
self.assertIsNotNone(tabify())
eq(text.get('7.0', '10.0'), ('\n\t def compare(self):\n\t\t if a > b:\n'))
@mock.patch.object(ft.FormatRegion, "_asktabwidth")
def test_untabify_region_event(self, _asktabwidth):
untabify = self.formatter.untabify_region_event
text = self.text
eq = self.assertEqual
text.tag_add('sel', '7.0', '10.0')
# No tabwidth selected.
_asktabwidth.return_value = None
self.assertIsNone(untabify())
_asktabwidth.return_value = 2
self.formatter.tabify_region_event()
_asktabwidth.return_value = 3
self.assertIsNotNone(untabify())
eq(text.get('7.0', '10.0'), ('\n def compare(self):\n if a > b:\n'))
@mock.patch.object(ft, "askinteger")
def test_ask_tabwidth(self, askinteger):
ask = self.formatter._asktabwidth
askinteger.return_value = 10
self.assertEqual(ask(), 10)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main(verbosity=2, exit=2) unittest.main(verbosity=2, exit=2)
...@@ -60,6 +60,7 @@ menudefs = [ ...@@ -60,6 +60,7 @@ menudefs = [
]), ]),
('format', [ ('format', [
('F_ormat Paragraph', '<<format-paragraph>>'),
('_Indent Region', '<<indent-region>>'), ('_Indent Region', '<<indent-region>>'),
('_Dedent Region', '<<dedent-region>>'), ('_Dedent Region', '<<dedent-region>>'),
('Comment _Out Region', '<<comment-region>>'), ('Comment _Out Region', '<<comment-region>>'),
...@@ -68,7 +69,6 @@ menudefs = [ ...@@ -68,7 +69,6 @@ menudefs = [
('Untabify Region', '<<untabify-region>>'), ('Untabify Region', '<<untabify-region>>'),
('Toggle Tabs', '<<toggle-tabs>>'), ('Toggle Tabs', '<<toggle-tabs>>'),
('New Indent Width', '<<change-indentwidth>>'), ('New Indent Width', '<<change-indentwidth>>'),
('F_ormat Paragraph', '<<format-paragraph>>'),
('S_trip Trailing Whitespace', '<<do-rstrip>>'), ('S_trip Trailing Whitespace', '<<do-rstrip>>'),
]), ]),
......
Rename paragraph.py to format.py and add region formatting methods
from editor.py. Add tests for the latter.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment