Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Lib/idlelib/config-extensions.def
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ enable=True
enable_shell=False
enable_editor=True

[TrimExtension]
enable=True
enable_trim_on_save=True

[ScriptBinding]
enable=True
enable_shell=False
Expand Down
1 change: 1 addition & 0 deletions Lib/idlelib/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,7 @@ def get_standard_extension_names(self):
'ParenMatch': 'parenmatch',
'RstripExtension': 'rstrip',
'ScriptBinding': 'runscript',
'TrimExtension': 'trim',
'ZoomHeight': 'zoomheight',
}

Expand Down
4 changes: 4 additions & 0 deletions Lib/idlelib/idle_test/mock_tk.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ def _decode(self, index, endflag=0):
return lastline, len(self.data[lastline]) - 1
elif index == 'end':
return self._endex(endflag)
elif index.startswith('end-'):
a, b = index.split()
a = int(a[4: -1])
index = '%d.0' % (a + 1)

line, char = index.split('.')
line = int(line)
Expand Down
53 changes: 53 additions & 0 deletions Lib/idlelib/idle_test/test_trim.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import unittest
import idlelib.trim as trim
from test.support import requires
requires('gui')
from idlelib.editor import EditorWindow as Editor
from tkinter import Tk


class trimTest(unittest.TestCase):

def test_trim_line(self):
editor = Editor(root=Tk())
text = editor.text
do_trim = trim.TrimExtension(editor).do_trim

do_trim()
self.assertEqual(text.get('1.0', 'insert'), '')
text.insert('1.0', ' ')
do_trim()
self.assertEqual(text.get('1.0', 'insert'), '')
text.insert('1.0', ' \n')
do_trim()
self.assertEqual(text.get('1.0', 'insert'), '')

def test_trim_multiple(self):
editor = Editor(root=Tk())
text = editor.text
do_trim = trim.TrimExtension(editor).do_trim

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


if __name__ == '__main__':
unittest.main(verbosity=2, exit=False)
13 changes: 13 additions & 0 deletions Lib/idlelib/iomenu.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@ def coding_spec(data):
return name


def strip_trailing_whitespace_and_blankline(f):
def _strip(self, event, *args, **kwargs):
if idleConf.GetOption('extensions', 'TrimExtension',
'enable_trim_on_save',
type='bool', default=False):
self.editwin.text.event_generate('<<do-trim>>')
return f(self, event, *args, **kwargs)
return _strip


class IOBinding:
# One instance per editor Window so methods know which to save, close.
# Open returns focus to self.editwin if aborted.
Expand Down Expand Up @@ -340,6 +350,7 @@ def maybesave(self):
self.text.focus_set()
return reply

@strip_trailing_whitespace_and_blankline
def save(self, event):
if not self.filename:
self.save_as(event)
Expand All @@ -353,6 +364,7 @@ def save(self, event):
self.text.focus_set()
return "break"

@strip_trailing_whitespace_and_blankline
def save_as(self, event):
filename = self.asksavefile()
if filename:
Expand All @@ -367,6 +379,7 @@ def save_as(self, event):
self.updaterecentfileslist(filename)
return "break"

@strip_trailing_whitespace_and_blankline
def save_a_copy(self, event):
filename = self.asksavefile()
if filename:
Expand Down
40 changes: 40 additions & 0 deletions Lib/idlelib/trim.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'Provides "Trim trailing whitespace and blank line" option'


class TrimExtension:

def __init__(self, editwin):
self.editwin = editwin
self.editwin.text.bind('<<do-trim>>', self.do_trim)

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

undo.undo_block_start()

last = 0
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())

# Get the last non-blank line of code
if cut:
last = cur

# 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)

# Trim trailing blank line
text.delete('end-%ic linestart' % (end_line - last - 1), 'end')

undo.undo_block_stop()


if __name__ == "__main__":
import unittest
unittest.main('idlelib.idle_test.test_trim', verbosity=2, exit=False)