From 77814484608ca81eb227666d095c7118d6aeda9b Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Wed, 11 Mar 2020 23:50:35 -0400 Subject: [PATCH 1/4] bpo-39885: IDLE: Leave selection when right click within This exception was omitted from previous commit, 4ca060d. --- Lib/idlelib/NEWS.txt | 4 ++-- Lib/idlelib/editor.py | 15 +++++++++++---- .../IDLE/2020-03-08-14-27-36.bpo-39885.29ERiR.rst | 4 ++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 3a4873b624f1e4..14559b8466aeb2 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -6,8 +6,8 @@ Released on 2020-10-05? 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 clicking outside of a +selection, clear the selection and move the cursor. 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 b0f88b5463d1b6..c496e830bbe7a5 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -499,15 +499,23 @@ def handle_yview(self, event, *args): 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 @@ def right_menu_event(self, event): 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/Misc/NEWS.d/next/IDLE/2020-03-08-14-27-36.bpo-39885.29ERiR.rst b/Misc/NEWS.d/next/IDLE/2020-03-08-14-27-36.bpo-39885.29ERiR.rst index f0f434ad3c1f41..8062568a44dbaf 100644 --- a/Misc/NEWS.d/next/IDLE/2020-03-08-14-27-36.bpo-39885.29ERiR.rst +++ b/Misc/NEWS.d/next/IDLE/2020-03-08-14-27-36.bpo-39885.29ERiR.rst @@ -1,2 +1,2 @@ -Since clicking to get an IDLE context menu moves the cursor, -any text selection should be and now is cleared. +When a context menu is invoked by clicking outside of a selection, +clear the selection and move the cursor. From 6160e593653452e2c29c12054ff38156cc563ae4 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Mon, 16 Mar 2020 00:57:34 -0400 Subject: [PATCH 2/4] prepare for new test --- Lib/idlelib/idle_test/test_editor.py | 46 ++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 91e8ef89d1d72a..fe4eaf6f552a3b 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -5,6 +5,7 @@ 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 @@ def test_tabwidth_8(self): ) +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 @@ def tearDownClass(cls): 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 @@ def test_indent_and_newline_event(self): 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 @@ def test_indent_and_newline_event(self): # 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) From 4bb7ec529c1f867b1f3bc2c336c02e5a8fd73e7c Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Fri, 29 May 2020 17:19:14 -0400 Subject: [PATCH 3/4] whitespace --- Lib/idlelib/idle_test/test_editor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index fe4eaf6f552a3b..443dcf021679fc 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -212,7 +212,7 @@ def tearDownClass(cls): class DummyRMenu: def tk_popup(x, y): pass - def test_rclick(self): + def test_rclick(self): pass From 1ae9a203cb741b657eae93a9a0636b6341fc3a9c Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Fri, 29 May 2020 18:22:24 -0400 Subject: [PATCH 4/4] Revise NEWS.txt item; add followup blurb. --- Lib/idlelib/NEWS.txt | 5 +++-- Lib/idlelib/editor.py | 2 +- .../next/IDLE/2020-05-29-18-21-58.bpo-39885.zB_-bN.rst | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2020-05-29-18-21-58.bpo-39885.zB_-bN.rst diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 7056bda96c76a6..7982afa7d1f674 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: When a context menu is invoked by clicking outside of a -selection, clear the selection and move the cursor. +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 c496e830bbe7a5..a178eaf93c013a 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -508,7 +508,7 @@ def right_menu_event(self, event): in_selection = False if not in_selection: text.tag_remove("sel", "1.0", "end") - text.mark_set("insert", newdex) + text.mark_set("insert", newdex) if not self.rmenu: self.make_rmenu() rmenu = self.rmenu diff --git a/Misc/NEWS.d/next/IDLE/2020-05-29-18-21-58.bpo-39885.zB_-bN.rst b/Misc/NEWS.d/next/IDLE/2020-05-29-18-21-58.bpo-39885.zB_-bN.rst new file mode 100644 index 00000000000000..a847b75997117d --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2020-05-29-18-21-58.bpo-39885.zB_-bN.rst @@ -0,0 +1,2 @@ +Make context menu Cut and Copy work again when right-clicking within a +selection.