8000 bpo-39885: Make IDLE context menu cut and copy work again (GH-18951) · python/cpython@80b6a05 · GitHub
[go: up one dir, main page]

Skip to content

Commit 80b6a05

Browse files
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. (cherry picked from commit 97e4e0f) Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
1 parent 5aa40e5 commit 80b6a05

File tree

4 files changed

+52
-16
lines changed

4 files changed

+52
-16
lines changed

Lib/idlelib/NEWS.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ Released on 2020-03-10
1717
bpo-27115: For 'Go to Line', use a Query entry box subclass with
1818
IDLE standard behavior and improved error checking.
1919

20-
bpo-39885: Since clicking to get an IDLE context menu moves the
21-
cursor, any text selection should be and now is cleared.
20+
bpo-39885: When a context menu is invoked by right-clicking outside
21+
of a selection, clear the selection and move the cursor. Cut and
22+
Copy require that the click be within the selection.
2223

2324
bpo-39852: Edit "Go to line" now clears any selection, preventing
2425
accidental deletion. It also updates Ln and Col on the status bar.

Lib/idlelib/editor.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -499,15 +499,23 @@ def handle_yview(self, event, *args):
499499
rmenu = None
500500

501501
def right_menu_event(self, event):
502-
self.text.tag_remove("sel", "1.0", "end")
503-
self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
502+
text = self.text
503+
newdex = text.index(f'@{event.x},{event.y}')
504+
try:
505+
in_selection = (text.compare('sel.first', '<=', newdex) and
506+
text.compare(newdex, '<=', 'sel.last'))
507+
except TclError:
508+
in_selection = False
509+
if not in_selection:
510+
text.tag_remove("sel", "1.0", "end")
511+
text.mark_set("insert", newdex)
504512
if not self.rmenu:
505513
self.make_rmenu()
506514
rmenu = self.rmenu
507515
self.event = event
508516
iswin = sys.platform[:3] == 'win'
509517
if iswin:
510-
self.text.config(cursor="arrow")
518+
text.config(cursor="arrow")
511519

512520
for item in self.rmenu_specs:
513521
try:
@@ -520,7 +528,6 @@ def right_menu_event(self, event):
520528
state = getattr(self, verify_state)()
521529
rmenu.entryconfigure(label, state=state)
522530

523-
524531
rmenu.tk_popup(event.x_root, event.y_root)
525532
if iswin:
526533
self.text.config(cursor="ibeam")

Lib/idlelib/idle_test/test_editor.py

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from collections import namedtuple
66
from test.support import requires
77
from tkinter import Tk
8+
from idlelib.idle_test.mock_idle import Func
89

910
Editor = editor.EditorWindow
1011

@@ -92,6 +93,12 @@ def test_tabwidth_8(self):
9293
)
9394

9495

96+
def insert(text, string):
97+
text.delete('1.0', 'end')
98+
text.insert('end', string)
99+
text.update() # Force update for colorizer to finish.
100+
101+
95102
class IndentAndNewlineTest(unittest.TestCase):
96103

97104
@classmethod
@@ -113,13 +120,6 @@ def tearDownClass(cls):
113120
cls.root.destroy()
114121
del cls.root
115122

116-
def insert(self, text):
117-
t = self.window.text
118-
t.delete('1.0', 'end')
119-
t.insert('end', text)
120-
# Force update for colorizer to finish.
121-
t.update()
122-
123123
def test_indent_and_newline_event(self):
124124
eq = self.assertEqual
125125
w = self.window
@@ -170,25 +170,51 @@ def test_indent_and_newline_event(self):
170170
w.prompt_last_line = ''
171171
for test in tests:
172172
with self.subTest(label=test.label):
173-
self.insert(test.text)
173+
insert(text, test.text)
174174
text.mark_set('insert', test.mark)
175175
nl(event=None)
176176
eq(get('1.0', 'end'), test.expected)
177177

178178
# Selected text.
179-
self.insert(' def f1(self, a, b):\n return a + b')
179+
insert(text, ' def f1(self, a, b):\n return a + b')
180180
text.tag_add('sel', '1.17', '1.end')
181181
nl(None)
182182
# Deletes selected text before adding new line.
183183
eq(get('1.0', 'end'), ' def f1(self, a,\n \n return a + b\n')
184184

185185
# Preserves the whitespace in shell prompt.
186186
w.prompt_last_line = '>>> '
187-
self.insert('>>> \t\ta =')
187+
insert(text, '>>> \t\ta =')
188188
text.mark_set('insert', '1.5')
189189
nl(None)
190190
eq(get('1.0', 'end'), '>>> \na =\n')
191191

192192

193+
class RMenuTest(unittest.TestCase):
194+
195+
@classmethod
196+
def setUpClass(cls):
197+
requires('gui')
198+
cls.root = Tk()
199+
cls.root.withdraw()
200+
cls.window = Editor(root=cls.root)
201+
202+
@classmethod
203+
def tearDownClass(cls):
204+
cls.window._close()
205+
del cls.window
206+
cls.root.update_idletasks()
207+
for id in cls.root.tk.call('after', 'info'):
208+
cls.root.after_cancel(id)
209+
cls.root.destroy()
210+
del cls.root
211+
212+
class DummyRMenu:
213+
def tk_popup(x, y): pass
214+
215+
def test_rclick(self):
216+
pass
217+
218+
193219
if __name__ == '__main__':
194220
unittest.main(verbosity=2)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Make context menu Cut and Copy work again when right-clicking within a
2+
selection.

0 commit comments

Comments
 (0)
0