diff options
author | Terry Jan Reedy <tjreedy@udel.edu> | 2020-05-29 22:54:14 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-29 22:54:14 (GMT) |
commit | 97e4e0f53d6690db6b942678489716a30925b8af (patch) | |
tree | 1735d0b6e1e8d0acb2f0b0ac11782f0d51e08b46 /Lib/idlelib | |
parent | 8bd216dfede9cb2d5bedb67f20a30c99844dbfb8 (diff) | |
download | cpython-97e4e0f53d6690db6b942678489716a30925b8af.zip cpython-97e4e0f53d6690db6b942678489716a30925b8af.tar.gz cpython-97e4e0f53d6690db6b942678489716a30925b8af.tar.bz2 |
bpo-39885: Make IDLE context menu cut and copy work again (GH-18951)
Leave selection when right click within. This exception to clearing selections when right-clicking was omitted from the previous commit, 4ca060d. I did not realize that this completely disabled the context menu entries, and I should have merged a minimal fix immediately. An automated test should follow.
Diffstat (limited to 'Lib/idlelib')
-rw-r--r-- | Lib/idlelib/NEWS.txt | 5 | ||||
-rw-r--r-- | Lib/idlelib/editor.py | 15 | ||||
-rw-r--r-- | Lib/idlelib/idle_test/test_editor.py | 46 |
3 files changed, 50 insertions, 16 deletions
diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 709008f..7982afa 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -12,8 +12,9 @@ when fetching a calltip. bpo-27115: For 'Go to Line', use a Query entry box subclass with IDLE standard behavior and improved error checking. -bpo-39885: Since clicking to get an IDLE context menu moves the -cursor, any text selection should be and now is cleared. +bpo-39885: When a context menu is invoked by right-clicking outside +of a selection, clear the selection and move the cursor. Cut and +Copy require that the click be within the selection. bpo-39852: Edit "Go to line" now clears any selection, preventing accidental deletion. It also updates Ln and Col on the status bar. diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index b0f88b5..a178eaf 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -499,15 +499,23 @@ class EditorWindow(object): rmenu = None def right_menu_event(self, event): - self.text.tag_remove("sel", "1.0", "end") - self.text.mark_set("insert", "@%d,%d" % (event.x, event.y)) + text = self.text + newdex = text.index(f'@{event.x},{event.y}') + try: + in_selection = (text.compare('sel.first', '<=', newdex) and + text.compare(newdex, '<=', 'sel.last')) + except TclError: + in_selection = False + if not in_selection: + text.tag_remove("sel", "1.0", "end") + text.mark_set("insert", newdex) if not self.rmenu: self.make_rmenu() rmenu = self.rmenu self.event = event iswin = sys.platform[:3] == 'win' if iswin: - self.text.config(cursor="arrow") + text.config(cursor="arrow") for item in self.rmenu_specs: try: @@ -520,7 +528,6 @@ class EditorWindow(object): state = getattr(self, verify_state)() rmenu.entryconfigure(label, state=state) - rmenu.tk_popup(event.x_root, event.y_root) if iswin: self.text.config(cursor="ibeam") diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 91e8ef8..443dcf0 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -5,6 +5,7 @@ import unittest from collections import namedtuple from test.support import requires from tkinter import Tk +from idlelib.idle_test.mock_idle import Func Editor = editor.EditorWindow @@ -92,6 +93,12 @@ class TestGetLineIndent(unittest.TestCase): ) +def insert(text, string): + text.delete('1.0', 'end') + text.insert('end', string) + text.update() # Force update for colorizer to finish. + + class IndentAndNewlineTest(unittest.TestCase): @classmethod @@ -113,13 +120,6 @@ class IndentAndNewlineTest(unittest.TestCase): cls.root.destroy() del cls.root - def insert(self, text): - t = self.window.text - t.delete('1.0', 'end') - t.insert('end', text) - # Force update for colorizer to finish. - t.update() - def test_indent_and_newline_event(self): eq = self.assertEqual w = self.window @@ -170,13 +170,13 @@ class IndentAndNewlineTest(unittest.TestCase): w.prompt_last_line = '' for test in tests: with self.subTest(label=test.label): - self.insert(test.text) + insert(text, test.text) text.mark_set('insert', test.mark) nl(event=None) eq(get('1.0', 'end'), test.expected) # Selected text. - self.insert(' def f1(self, a, b):\n return a + b') + insert(text, ' def f1(self, a, b):\n return a + b') text.tag_add('sel', '1.17', '1.end') nl(None) # Deletes selected text before adding new line. @@ -184,11 +184,37 @@ class IndentAndNewlineTest(unittest.TestCase): # Preserves the whitespace in shell prompt. w.prompt_last_line = '>>> ' - self.insert('>>> \t\ta =') + insert(text, '>>> \t\ta =') text.mark_set('insert', '1.5') nl(None) eq(get('1.0', 'end'), '>>> \na =\n') +class RMenuTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + cls.root = Tk() + cls.root.withdraw() + cls.window = Editor(root=cls.root) + + @classmethod + def tearDownClass(cls): + cls.window._close() + del cls.window + cls.root.update_idletasks() + for id in cls.root.tk.call('after', 'info'): + cls.root.after_cancel(id) + cls.root.destroy() + del cls.root + + class DummyRMenu: + def tk_popup(x, y): pass + + def test_rclick(self): + pass + + if __name__ == '__main__': unittest.main(verbosity=2) |