summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib
diff options
context:
space:
mode:
authorTerry Jan Reedy <tjreedy@udel.edu>2020-05-29 22:54:14 (GMT)
committerGitHub <noreply@github.com>2020-05-29 22:54:14 (GMT)
commit97e4e0f53d6690db6b942678489716a30925b8af (patch)
tree1735d0b6e1e8d0acb2f0b0ac11782f0d51e08b46 /Lib/idlelib
parent8bd216dfede9cb2d5bedb67f20a30c99844dbfb8 (diff)
downloadcpython-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.txt5
-rw-r--r--Lib/idlelib/editor.py15
-rw-r--r--Lib/idlelib/idle_test/test_editor.py46
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)