Skip to content

Commit

Permalink
bpo-38862: IDLE Strip Trailing Whitespace fixes end newlines (GH-17366)
Browse files Browse the repository at this point in the history
Extra newlines are removed at the end of non-shell files. If the file only has newlines after stripping other trailing whitespace, all are removed, as is done by patchcheck.py.
  • Loading branch information
terryjreedy committed Nov 24, 2019
1 parent 6f03b23 commit 6bf644e
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 41 deletions.
3 changes: 2 additions & 1 deletion Doc/library/idle.rst
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ Format Paragraph
Strip trailing whitespace
Remove trailing space and other whitespace characters after the last
non-whitespace character of a line by applying str.rstrip to each line,
including lines within multiline strings.
including lines within multiline strings. Except for Shell windows,
remove extra newlines at the end of the file.

.. index::
single: Run script
Expand Down
3 changes: 3 additions & 0 deletions Lib/idlelib/NEWS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ Released on 2020-10-05?
======================================


bpo-38862: 'Strip Trailing Whitespace' on the Format menu removes extra
newlines at the end of non-shell files.

bpo-38636: Fix IDLE Format menu tab toggle and file indent width. These
functions (default shortcuts Alt-T and Alt-U) were mistakenly disabled
in 3.7.5 and 3.8.0.
Expand Down
10 changes: 10 additions & 0 deletions Lib/idlelib/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,16 @@ def do_rstrip(self, event=None):
if cut < raw:
text.delete('%i.%i' % (cur, cut), '%i.end' % cur)

if (text.get('end-2c') == '\n' # File ends with at least 1 newline;
and not hasattr(self.editwin, 'interp')): # & is not Shell.
# Delete extra user endlines.
while (text.index('end-1c') > '1.0' # Stop if file empty.
and text.get('end-3c') == '\n'):
text.delete('end-3c')
# Because tk indexes are slice indexes and never raise,
# a file with only newlines will be emptied.
# patchcheck.py does the same.

undo.undo_block_stop()


Expand Down
25 changes: 13 additions & 12 deletions Lib/idlelib/help.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>IDLE &#8212; Python 3.9.0a0 documentation</title>
<title>IDLE &#8212; Python 3.9.0a1 documentation</title>
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />

Expand All @@ -17,14 +17,14 @@
<script type="text/javascript" src="../_static/sidebar.js"></script>

<link rel="search" type="application/opensearchdescription+xml"
title="Search within Python 3.9.0a0 documentation"
title="Search within Python 3.9.0a1 documentation"
href="../_static/opensearch.xml"/>
<link rel="author" title="About these documents" href="../about.html" />
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="copyright" title="Copyright" href="../copyright.html" />
<link rel="next" title="Other Graphical User Interface Packages" href="othergui.html" />
<link rel="prev" title="tkinter.scrolledtextScrolled Text Widget" href="tkinter.scrolledtext.html" />
<link rel="prev" title="tkinter.tixExtension widgets for Tk" href="tkinter.tix.html" />
<link rel="canonical" href="https://docs.python.org/3/library/idle.html" />


Expand Down Expand Up @@ -62,7 +62,7 @@ <h3>Navigation</h3>
<a href="othergui.html" title="Other Graphical User Interface Packages"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="tkinter.scrolledtext.html" title="tkinter.scrolledtextScrolled Text Widget"
<a href="tkinter.tix.html" title="tkinter.tixExtension widgets for Tk"
accesskey="P">previous</a> |</li>

<li><img src="../_static/py.png" alt=""
Expand All @@ -71,7 +71,7 @@ <h3>Navigation</h3>


<li>
<a href="../index.html">3.9.0a0 Documentation</a> &#187;
<a href="../index.html">3.9.0a1 Documentation</a> &#187;
</li>

<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> &#187;</li>
Expand Down Expand Up @@ -240,7 +240,8 @@ <h3>Edit menu (Shell and Editor)<a class="headerlink" href="#edit-menu-shell-and
</dd>
<dt>Strip trailing whitespace</dt><dd><p>Remove trailing space and other whitespace characters after the last
non-whitespace character of a line by applying str.rstrip to each line,
including lines within multiline strings.</p>
including lines within multiline strings. Except for Shell windows,
remove extra newlines at the end of the file.</p>
</dd>
</dl>
</div>
Expand Down Expand Up @@ -886,8 +887,8 @@ <h3><a href="../contents.html">Table of Contents</a></h3>
</ul>

<h4>Previous topic</h4>
<p class="topless"><a href="tkinter.scrolledtext.html"
title="previous chapter"><code class="xref py py-mod docutils literal notranslate"><span class="pre">tkinter.scrolledtext</span></code>Scrolled Text Widget</a></p>
<p class="topless"><a href="tkinter.tix.html"
title="previous chapter"><code class="xref py py-mod docutils literal notranslate"><span class="pre">tkinter.tix</span></code>Extension widgets for Tk</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="othergui.html"
title="next chapter">Other Graphical User Interface Packages</a></p>
Expand Down Expand Up @@ -919,7 +920,7 @@ <h3>Navigation</h3>
<a href="othergui.html" title="Other Graphical User Interface Packages"
>next</a> |</li>
<li class="right" >
<a href="tkinter.scrolledtext.html" title="tkinter.scrolledtextScrolled Text Widget"
<a href="tkinter.tix.html" title="tkinter.tixExtension widgets for Tk"
>previous</a> |</li>

<li><img src="../_static/py.png" alt=""
Expand All @@ -928,7 +929,7 @@ <h3>Navigation</h3>


<li>
<a href="../index.html">3.9.0a0 Documentation</a> &#187;
<a href="../index.html">3.9.0a1 Documentation</a> &#187;
</li>

<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> &#187;</li>
Expand Down Expand Up @@ -959,11 +960,11 @@ <h3>Navigation</h3>
<br />
<br />

Last updated on Sep 01, 2019.
Last updated on Nov 24, 2019.
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
<br />

Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 2.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 2.1.1.
</div>

</body>
Expand Down
5 changes: 3 additions & 2 deletions Lib/idlelib/idle_test/mock_idle.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ def __call__(self, *args, **kwds):
class Editor:
'''Minimally imitate editor.EditorWindow class.
'''
def __init__(self, flist=None, filename=None, key=None, root=None):
self.text = Text()
def __init__(self, flist=None, filename=None, key=None, root=None,
text=None): # Allow real Text with mock Editor.
self.text = text or Text()
self.undo = UndoDelegator()

def get_selection_indices(self):
Expand Down
62 changes: 36 additions & 26 deletions Lib/idlelib/idle_test/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,47 +611,57 @@ def test_change_indentwidth(self, askinteger):

class RstripTest(unittest.TestCase):

def test_rstrip_line(self):
editor = MockEditor()
text = editor.text
do_rstrip = ft.Rstrip(editor).do_rstrip
eq = self.assertEqual
@classmethod
def setUpClass(cls):
requires('gui')
cls.root = Tk()
cls.root.withdraw()
cls.text = Text(cls.root)
cls.editor = MockEditor(text=cls.text)
cls.do_rstrip = ft.Rstrip(cls.editor).do_rstrip

@classmethod
def tearDownClass(cls):
del cls.text, cls.do_rstrip, cls.editor
cls.root.update_idletasks()
cls.root.destroy()
del cls.root

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
def tearDown(self):
self.text.delete('1.0', 'end-1c')

def test_rstrip_lines(self):
original = (
"Line with an ending tab \n"
"Line ending in 5 spaces \n"
"Linewithnospaces\n"
" indented line\n"
" indented line with trailing space \n"
" ")
" \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)
self.text.insert('1.0', original)
self.do_rstrip()
self.assertEqual(self.text.get('1.0', 'insert'), stripped)

def test_rstrip_end(self):
text = self.text
for code in ('', '\n', '\n\n\n'):
with self.subTest(code=code):
text.insert('1.0', code)
self.do_rstrip()
self.assertEqual(text.get('1.0','end-1c'), '')
for code in ('a\n', 'a\n\n', 'a\n\n\n'):
with self.subTest(code=code):
text.delete('1.0', 'end-1c')
text.insert('1.0', code)
self.do_rstrip()
self.assertEqual(text.get('1.0','end-1c'), 'a\n')


if __name__ == '__main__':
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'Strip Trailing Whitespace' on the Format menu removes extra newlines
at the end of non-shell files.

0 comments on commit 6bf644e

Please sign in to comment.