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:
parent
6f03b236c1
commit
6bf644ec82
|
@ -199,7 +199,8 @@ Format Paragraph
|
||||||
Strip trailing whitespace
|
Strip trailing whitespace
|
||||||
Remove trailing space and other whitespace characters after the last
|
Remove trailing space and other whitespace characters after the last
|
||||||
non-whitespace character of a line by applying str.rstrip to each line,
|
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::
|
.. index::
|
||||||
single: Run script
|
single: Run script
|
||||||
|
|
|
@ -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
|
bpo-38636: Fix IDLE Format menu tab toggle and file indent width. These
|
||||||
functions (default shortcuts Alt-T and Alt-U) were mistakenly disabled
|
functions (default shortcuts Alt-T and Alt-U) were mistakenly disabled
|
||||||
in 3.7.5 and 3.8.0.
|
in 3.7.5 and 3.8.0.
|
||||||
|
|
|
@ -408,6 +408,16 @@ class Rstrip: # 'Strip Trailing Whitespace" on "Format" menu.
|
||||||
if cut < raw:
|
if cut < raw:
|
||||||
text.delete('%i.%i' % (cur, cut), '%i.end' % cur)
|
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()
|
undo.undo_block_stop()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>IDLE — Python 3.9.0a0 documentation</title>
|
<title>IDLE — Python 3.9.0a1 documentation</title>
|
||||||
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
|
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="../_static/pygments.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>
|
<script type="text/javascript" src="../_static/sidebar.js"></script>
|
||||||
|
|
||||||
<link rel="search" type="application/opensearchdescription+xml"
|
<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"/>
|
href="../_static/opensearch.xml"/>
|
||||||
<link rel="author" title="About these documents" href="../about.html" />
|
<link rel="author" title="About these documents" href="../about.html" />
|
||||||
<link rel="index" title="Index" href="../genindex.html" />
|
<link rel="index" title="Index" href="../genindex.html" />
|
||||||
<link rel="search" title="Search" href="../search.html" />
|
<link rel="search" title="Search" href="../search.html" />
|
||||||
<link rel="copyright" title="Copyright" href="../copyright.html" />
|
<link rel="copyright" title="Copyright" href="../copyright.html" />
|
||||||
<link rel="next" title="Other Graphical User Interface Packages" href="othergui.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" />
|
<link rel="canonical" href="https://docs.python.org/3/library/idle.html" />
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
<a href="othergui.html" title="Other Graphical User Interface Packages"
|
<a href="othergui.html" title="Other Graphical User Interface Packages"
|
||||||
accesskey="N">next</a> |</li>
|
accesskey="N">next</a> |</li>
|
||||||
<li class="right" >
|
<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>
|
accesskey="P">previous</a> |</li>
|
||||||
|
|
||||||
<li><img src="../_static/py.png" alt=""
|
<li><img src="../_static/py.png" alt=""
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
|
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="../index.html">3.9.0a0 Documentation</a> »
|
<a href="../index.html">3.9.0a1 Documentation</a> »
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
|
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
|
||||||
|
@ -240,7 +240,8 @@ paragraph will be formatted to less than N columns, where N defaults to 72.</p>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Strip trailing whitespace</dt><dd><p>Remove trailing space and other whitespace characters after the last
|
<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,
|
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>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
@ -886,8 +887,8 @@ also used for testing.</p>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h4>Previous topic</h4>
|
<h4>Previous topic</h4>
|
||||||
<p class="topless"><a href="tkinter.scrolledtext.html"
|
<p class="topless"><a href="tkinter.tix.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>
|
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>
|
<h4>Next topic</h4>
|
||||||
<p class="topless"><a href="othergui.html"
|
<p class="topless"><a href="othergui.html"
|
||||||
title="next chapter">Other Graphical User Interface Packages</a></p>
|
title="next chapter">Other Graphical User Interface Packages</a></p>
|
||||||
|
@ -919,7 +920,7 @@ also used for testing.</p>
|
||||||
<a href="othergui.html" title="Other Graphical User Interface Packages"
|
<a href="othergui.html" title="Other Graphical User Interface Packages"
|
||||||
>next</a> |</li>
|
>next</a> |</li>
|
||||||
<li class="right" >
|
<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>
|
>previous</a> |</li>
|
||||||
|
|
||||||
<li><img src="../_static/py.png" alt=""
|
<li><img src="../_static/py.png" alt=""
|
||||||
|
@ -928,7 +929,7 @@ also used for testing.</p>
|
||||||
|
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="../index.html">3.9.0a0 Documentation</a> »
|
<a href="../index.html">3.9.0a1 Documentation</a> »
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
|
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
|
||||||
|
@ -959,11 +960,11 @@ also used for testing.</p>
|
||||||
<br />
|
<br />
|
||||||
<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>?
|
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
|
||||||
<br />
|
<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>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -40,8 +40,9 @@ class Func:
|
||||||
class Editor:
|
class Editor:
|
||||||
'''Minimally imitate editor.EditorWindow class.
|
'''Minimally imitate editor.EditorWindow class.
|
||||||
'''
|
'''
|
||||||
def __init__(self, flist=None, filename=None, key=None, root=None):
|
def __init__(self, flist=None, filename=None, key=None, root=None,
|
||||||
self.text = Text()
|
text=None): # Allow real Text with mock Editor.
|
||||||
|
self.text = text or Text()
|
||||||
self.undo = UndoDelegator()
|
self.undo = UndoDelegator()
|
||||||
|
|
||||||
def get_selection_indices(self):
|
def get_selection_indices(self):
|
||||||
|
|
|
@ -611,37 +611,33 @@ class IndentsTest(unittest.TestCase):
|
||||||
|
|
||||||
class RstripTest(unittest.TestCase):
|
class RstripTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_rstrip_line(self):
|
@classmethod
|
||||||
editor = MockEditor()
|
def setUpClass(cls):
|
||||||
text = editor.text
|
requires('gui')
|
||||||
do_rstrip = ft.Rstrip(editor).do_rstrip
|
cls.root = Tk()
|
||||||
eq = self.assertEqual
|
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()
|
@classmethod
|
||||||
eq(text.get('1.0', 'insert'), '')
|
def tearDownClass(cls):
|
||||||
text.insert('1.0', ' ')
|
del cls.text, cls.do_rstrip, cls.editor
|
||||||
do_rstrip()
|
cls.root.update_idletasks()
|
||||||
eq(text.get('1.0', 'insert'), '')
|
cls.root.destroy()
|
||||||
text.insert('1.0', ' \n')
|
del cls.root
|
||||||
do_rstrip()
|
|
||||||
eq(text.get('1.0', 'insert'), '\n')
|
|
||||||
|
|
||||||
def test_rstrip_multiple(self):
|
def tearDown(self):
|
||||||
editor = MockEditor()
|
self.text.delete('1.0', 'end-1c')
|
||||||
# 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 test_rstrip_lines(self):
|
||||||
original = (
|
original = (
|
||||||
"Line with an ending tab \n"
|
"Line with an ending tab \n"
|
||||||
"Line ending in 5 spaces \n"
|
"Line ending in 5 spaces \n"
|
||||||
"Linewithnospaces\n"
|
"Linewithnospaces\n"
|
||||||
" indented line\n"
|
" indented line\n"
|
||||||
" indented line with trailing space \n"
|
" indented line with trailing space \n"
|
||||||
" ")
|
" \n")
|
||||||
stripped = (
|
stripped = (
|
||||||
"Line with an ending tab\n"
|
"Line with an ending tab\n"
|
||||||
"Line ending in 5 spaces\n"
|
"Line ending in 5 spaces\n"
|
||||||
|
@ -649,9 +645,23 @@ class RstripTest(unittest.TestCase):
|
||||||
" indented line\n"
|
" indented line\n"
|
||||||
" indented line with trailing space\n")
|
" indented line with trailing space\n")
|
||||||
|
|
||||||
text.insert('1.0', original)
|
self.text.insert('1.0', original)
|
||||||
do_rstrip()
|
self.do_rstrip()
|
||||||
self.assertEqual(text.get('1.0', 'insert'), stripped)
|
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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
'Strip Trailing Whitespace' on the Format menu removes extra newlines
|
||||||
|
at the end of non-shell files.
|
Loading…
Reference in New Issue