Skip to content

Commit d6b4102

Browse files
committed
gh-94521: Copy/cut current line without selecting it
1 parent 1dd5054 commit d6b4102

3 files changed

Lines changed: 60 additions & 6 deletions

File tree

‎Doc/library/idle.rst‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,11 @@ Select All
125125

126126
Cut
127127
Copy selection into the system-wide clipboard; then delete the selection.
128+
If there is no selection, cut the current line instead.
128129

129130
Copy
130131
Copy selection into the system-wide clipboard.
132+
If there is no selection, copy the current line instead.
131133

132134
Paste
133135
Insert contents of the system-wide clipboard into the current window.
@@ -371,9 +373,11 @@ Context menus have the standard clipboard functions also on the Edit menu.
371373

372374
Cut
373375
Copy selection into the system-wide clipboard; then delete the selection.
376+
If there is no selection, cut the current line instead.
374377

375378
Copy
376379
Copy selection into the system-wide clipboard.
380+
If there is no selection, copy the current line instead.
377381

378382
Paste
379383
Insert contents of the system-wide clipboard into the current window.

‎Lib/idlelib/editor.py‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -609,16 +609,20 @@ def python_docs(self, event=None):
609609

610610
def cut(self,event):
611611
if not self.text.tag_ranges('sel'):
612-
self.text.tag_add('sel', 'insert linestart', 'insert+1l linestart')
613-
self.text.mark_set('insert', 'insert linestart')
614-
self.text.event_generate("<<Cut>>")
612+
self.copy(event)
613+
self.text.delete('insert', 'insert+1l')
614+
else:
615+
self.text.event_generate("<<Cut>>")
615616
return "break"
616617

617618
def copy(self,event):
618-
if not self.text.tag_ranges("sel"):
619-
self.text.tag_add('sel', 'insert linestart', 'insert+1l linestart')
619+
if not self.text.tag_ranges('sel'):
620620
self.text.mark_set('insert', 'insert linestart')
621-
self.text.event_generate("<<Copy>>")
621+
line = self.text.get('insert', 'insert+1l')
622+
self.text.clipboard_clear()
623+
self.text.clipboard_append(line)
624+
else:
625+
self.text.event_generate("<<Copy>>")
622626
return "break"
623627

624628
def paste(self,event):

‎Lib/idlelib/idle_test/test_editor.py‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,5 +237,51 @@ def test_rclick(self):
237237
pass
238238

239239

240+
class CopyCutLineTest(unittest.TestCase):
241+
242+
@classmethod
243+
def setUpClass(cls):
244+
requires('gui')
245+
cls.root = Tk()
246+
cls.root.withdraw()
247+
cls.window = Editor(root=cls.root)
248+
249+
@classmethod
250+
def tearDownClass(cls):
251+
cls.root.destroy()
252+
del cls.root
253+
254+
def test_copy_no_selection(self):
255+
eq = self.assertEqual
256+
text = self.window.text
257+
258+
insert(text, 'hello\nworld')
259+
text.mark_set('insert', '1.2')
260+
self.window.copy(event=None)
261+
262+
# Copy current line without being selected
263+
eq(text.clipboard_get(), 'hello\n')
264+
eq(text.tag_ranges('sel'), ())
265+
266+
# Cursor move to start of the line
267+
eq(text.index('insert'), '1.0')
268+
269+
def test_cut_no_selection(self):
270+
eq = self.assertEqual
271+
text = self.window.text
272+
273+
insert(text, 'hello\nworld')
274+
text.mark_set('insert', '1.2')
275+
self.window.cut(event=None)
276+
277+
# Copy current line and remove it
278+
eq(text.clipboard_get(), 'hello\n')
279+
eq(text.get('1.0', 'end'), 'world\n')
280+
eq(text.tag_ranges('sel'), ())
281+
282+
# Cursor move to start of the line
283+
eq(text.index('insert'), '1.0')
284+
285+
240286
if __name__ == '__main__':
241287
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)