bpo-38862: IDLE Strip Trailing Whitespace fixes end newlines (GH-17366)

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.
This commit is contained in:
Terry Jan Reedy 2019-11-24 16:29:29 -05:00 committed by GitHub
parent 6f03b236c1
commit 6bf644ec82
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 68 additions and 40 deletions

View file

@ -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

View file

@ -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.

View file

@ -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()

View file

@ -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" />
@ -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.scrolledtext — Scrolled Text Widget" href="tkinter.scrolledtext.html" />
<link rel="prev" title="tkinter.tix — Extension widgets for Tk" href="tkinter.tix.html" />
<link rel="canonical" href="https://docs.python.org/3/library/idle.html" />
@ -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.scrolledtext — Scrolled Text Widget"
<a href="tkinter.tix.html" title="tkinter.tix — Extension widgets for Tk"
accesskey="P">previous</a> |</li>
<li><img src="../_static/py.png" alt=""
@ -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>
@ -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>
@ -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>
@ -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.scrolledtext — Scrolled Text Widget"
<a href="tkinter.tix.html" title="tkinter.tix — Extension widgets for Tk"
>previous</a> |</li>
<li><img src="../_static/py.png" alt=""
@ -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>
@ -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>

View file

@ -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):

View file

@ -611,37 +611,33 @@ 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
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')
@classmethod
def tearDownClass(cls):
del cls.text, cls.do_rstrip, cls.editor
cls.root.update_idletasks()
cls.root.destroy()
del cls.root
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"
@ -649,9 +645,23 @@ def test_rstrip_multiple(self):
" 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__':

View file

@ -0,0 +1,2 @@
'Strip Trailing Whitespace' on the Format menu removes extra newlines
at the end of non-shell files.