mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
bpo-29910: IDLE no longer deletes a character after commenting out a region (#825)
This happened because shortcut has a class binding and 'break' was not returned. Fix other potential conflicts between IDLE and default key bindings. * Add news item * Update NEWS
This commit is contained in:
parent
9a02ae3d3d
commit
213ce12adf
11 changed files with 48 additions and 16 deletions
|
@ -60,6 +60,7 @@ class AutoComplete:
|
||||||
if a function call is needed.
|
if a function call is needed.
|
||||||
"""
|
"""
|
||||||
self.open_completions(True, False, True)
|
self.open_completions(True, False, True)
|
||||||
|
return "break"
|
||||||
|
|
||||||
def try_open_completions_event(self, event):
|
def try_open_completions_event(self, event):
|
||||||
"""Happens when it would be nice to open a completion list, but not
|
"""Happens when it would be nice to open a completion list, but not
|
||||||
|
|
|
@ -89,24 +89,27 @@ class CallTip:
|
||||||
# If the event was triggered by the same event that unbinded
|
# If the event was triggered by the same event that unbinded
|
||||||
# this function, the function will be called nevertheless,
|
# this function, the function will be called nevertheless,
|
||||||
# so do nothing in this case.
|
# so do nothing in this case.
|
||||||
return
|
return None
|
||||||
curline, curcol = map(int, self.widget.index("insert").split('.'))
|
curline, curcol = map(int, self.widget.index("insert").split('.'))
|
||||||
if curline < self.parenline or \
|
if curline < self.parenline or \
|
||||||
(curline == self.parenline and curcol <= self.parencol) or \
|
(curline == self.parenline and curcol <= self.parencol) or \
|
||||||
self.widget.compare("insert", ">", MARK_RIGHT):
|
self.widget.compare("insert", ">", MARK_RIGHT):
|
||||||
self.hidetip()
|
self.hidetip()
|
||||||
|
return "break"
|
||||||
else:
|
else:
|
||||||
self.position_window()
|
self.position_window()
|
||||||
if self.checkhide_after_id is not None:
|
if self.checkhide_after_id is not None:
|
||||||
self.widget.after_cancel(self.checkhide_after_id)
|
self.widget.after_cancel(self.checkhide_after_id)
|
||||||
self.checkhide_after_id = \
|
self.checkhide_after_id = \
|
||||||
self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
|
self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
|
||||||
|
return None
|
||||||
|
|
||||||
def hide_event(self, event):
|
def hide_event(self, event):
|
||||||
if not self.tipwindow:
|
if not self.tipwindow:
|
||||||
# See the explanation in checkhide_event.
|
# See the explanation in checkhide_event.
|
||||||
return
|
return None
|
||||||
self.hidetip()
|
self.hidetip()
|
||||||
|
return "break"
|
||||||
|
|
||||||
def hidetip(self):
|
def hidetip(self):
|
||||||
if not self.tipwindow:
|
if not self.tipwindow:
|
||||||
|
|
|
@ -47,6 +47,7 @@ class CallTips:
|
||||||
def force_open_calltip_event(self, event):
|
def force_open_calltip_event(self, event):
|
||||||
"The user selected the menu entry or hotkey, open the tip."
|
"The user selected the menu entry or hotkey, open the tip."
|
||||||
self.open_calltip(True)
|
self.open_calltip(True)
|
||||||
|
return "break"
|
||||||
|
|
||||||
def try_open_calltip_event(self, event):
|
def try_open_calltip_event(self, event):
|
||||||
"""Happens when it would be nice to open a CallTip, but not really
|
"""Happens when it would be nice to open a CallTip, but not really
|
||||||
|
|
|
@ -89,6 +89,7 @@ class CodeContext:
|
||||||
idleConf.SetOption("extensions", "CodeContext", "visible",
|
idleConf.SetOption("extensions", "CodeContext", "visible",
|
||||||
str(self.label is not None))
|
str(self.label is not None))
|
||||||
idleConf.SaveUserCfgFiles()
|
idleConf.SaveUserCfgFiles()
|
||||||
|
return "break"
|
||||||
|
|
||||||
def get_line_info(self, linenum):
|
def get_line_info(self, linenum):
|
||||||
"""Get the line indent value, text, and any block start keyword
|
"""Get the line indent value, text, and any block start keyword
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import importlib
|
|
||||||
import importlib.abc
|
import importlib.abc
|
||||||
import importlib.util
|
import importlib.util
|
||||||
import os
|
import os
|
||||||
|
@ -147,7 +146,7 @@ class EditorWindow(object):
|
||||||
text.bind("<<python-docs>>", self.python_docs)
|
text.bind("<<python-docs>>", self.python_docs)
|
||||||
text.bind("<<about-idle>>", self.about_dialog)
|
text.bind("<<about-idle>>", self.about_dialog)
|
||||||
text.bind("<<open-config-dialog>>", self.config_dialog)
|
text.bind("<<open-config-dialog>>", self.config_dialog)
|
||||||
text.bind("<<open-module>>", self.open_module)
|
text.bind("<<open-module>>", self.open_module_event)
|
||||||
text.bind("<<do-nothing>>", lambda event: "break")
|
text.bind("<<do-nothing>>", lambda event: "break")
|
||||||
text.bind("<<select-all>>", self.select_all)
|
text.bind("<<select-all>>", self.select_all)
|
||||||
text.bind("<<remove-selection>>", self.remove_selection)
|
text.bind("<<remove-selection>>", self.remove_selection)
|
||||||
|
@ -294,7 +293,7 @@ class EditorWindow(object):
|
||||||
def home_callback(self, event):
|
def home_callback(self, event):
|
||||||
if (event.state & 4) != 0 and event.keysym == "Home":
|
if (event.state & 4) != 0 and event.keysym == "Home":
|
||||||
# state&4==Control. If <Control-Home>, use the Tk binding.
|
# state&4==Control. If <Control-Home>, use the Tk binding.
|
||||||
return
|
return None
|
||||||
if self.text.index("iomark") and \
|
if self.text.index("iomark") and \
|
||||||
self.text.compare("iomark", "<=", "insert lineend") and \
|
self.text.compare("iomark", "<=", "insert lineend") and \
|
||||||
self.text.compare("insert linestart", "<=", "iomark"):
|
self.text.compare("insert linestart", "<=", "iomark"):
|
||||||
|
@ -423,6 +422,7 @@ class EditorWindow(object):
|
||||||
rmenu.tk_popup(event.x_root, event.y_root)
|
rmenu.tk_popup(event.x_root, event.y_root)
|
||||||
if iswin:
|
if iswin:
|
||||||
self.text.config(cursor="ibeam")
|
self.text.config(cursor="ibeam")
|
||||||
|
return "break"
|
||||||
|
|
||||||
rmenu_specs = [
|
rmenu_specs = [
|
||||||
# ("Label", "<<virtual-event>>", "statefuncname"), ...
|
# ("Label", "<<virtual-event>>", "statefuncname"), ...
|
||||||
|
@ -464,11 +464,13 @@ class EditorWindow(object):
|
||||||
"Handle Help 'About IDLE' event."
|
"Handle Help 'About IDLE' event."
|
||||||
# Synchronize with macosx.overrideRootMenu.about_dialog.
|
# Synchronize with macosx.overrideRootMenu.about_dialog.
|
||||||
help_about.AboutDialog(self.top)
|
help_about.AboutDialog(self.top)
|
||||||
|
return "break"
|
||||||
|
|
||||||
def config_dialog(self, event=None):
|
def config_dialog(self, event=None):
|
||||||
"Handle Options 'Configure IDLE' event."
|
"Handle Options 'Configure IDLE' event."
|
||||||
# Synchronize with macosx.overrideRootMenu.config_dialog.
|
# Synchronize with macosx.overrideRootMenu.config_dialog.
|
||||||
configdialog.ConfigDialog(self.top,'Settings')
|
configdialog.ConfigDialog(self.top,'Settings')
|
||||||
|
return "break"
|
||||||
|
|
||||||
def help_dialog(self, event=None):
|
def help_dialog(self, event=None):
|
||||||
"Handle Help 'IDLE Help' event."
|
"Handle Help 'IDLE Help' event."
|
||||||
|
@ -478,6 +480,7 @@ class EditorWindow(object):
|
||||||
else:
|
else:
|
||||||
parent = self.top
|
parent = self.top
|
||||||
help.show_idlehelp(parent)
|
help.show_idlehelp(parent)
|
||||||
|
return "break"
|
||||||
|
|
||||||
def python_docs(self, event=None):
|
def python_docs(self, event=None):
|
||||||
if sys.platform[:3] == 'win':
|
if sys.platform[:3] == 'win':
|
||||||
|
@ -497,7 +500,7 @@ class EditorWindow(object):
|
||||||
def copy(self,event):
|
def copy(self,event):
|
||||||
if not self.text.tag_ranges("sel"):
|
if not self.text.tag_ranges("sel"):
|
||||||
# There is no selection, so do nothing and maybe interrupt.
|
# There is no selection, so do nothing and maybe interrupt.
|
||||||
return
|
return None
|
||||||
self.text.event_generate("<<Copy>>")
|
self.text.event_generate("<<Copy>>")
|
||||||
return "break"
|
return "break"
|
||||||
|
|
||||||
|
@ -515,6 +518,7 @@ class EditorWindow(object):
|
||||||
def remove_selection(self, event=None):
|
def remove_selection(self, event=None):
|
||||||
self.text.tag_remove("sel", "1.0", "end")
|
self.text.tag_remove("sel", "1.0", "end")
|
||||||
self.text.see("insert")
|
self.text.see("insert")
|
||||||
|
return "break"
|
||||||
|
|
||||||
def move_at_edge_if_selection(self, edge_index):
|
def move_at_edge_if_selection(self, edge_index):
|
||||||
"""Cursor move begins at start or end of selection
|
"""Cursor move begins at start or end of selection
|
||||||
|
@ -575,8 +579,9 @@ class EditorWindow(object):
|
||||||
return "break"
|
return "break"
|
||||||
text.mark_set("insert", "%d.0" % lineno)
|
text.mark_set("insert", "%d.0" % lineno)
|
||||||
text.see("insert")
|
text.see("insert")
|
||||||
|
return "break"
|
||||||
|
|
||||||
def open_module(self, event=None):
|
def open_module(self):
|
||||||
"""Get module name from user and open it.
|
"""Get module name from user and open it.
|
||||||
|
|
||||||
Return module path or None for calls by open_class_browser
|
Return module path or None for calls by open_class_browser
|
||||||
|
@ -600,21 +605,27 @@ class EditorWindow(object):
|
||||||
self.io.loadfile(file_path)
|
self.io.loadfile(file_path)
|
||||||
return file_path
|
return file_path
|
||||||
|
|
||||||
|
def open_module_event(self, event):
|
||||||
|
self.open_module()
|
||||||
|
return "break"
|
||||||
|
|
||||||
def open_class_browser(self, event=None):
|
def open_class_browser(self, event=None):
|
||||||
filename = self.io.filename
|
filename = self.io.filename
|
||||||
if not (self.__class__.__name__ == 'PyShellEditorWindow'
|
if not (self.__class__.__name__ == 'PyShellEditorWindow'
|
||||||
and filename):
|
and filename):
|
||||||
filename = self.open_module()
|
filename = self.open_module()
|
||||||
if filename is None:
|
if filename is None:
|
||||||
return
|
return "break"
|
||||||
head, tail = os.path.split(filename)
|
head, tail = os.path.split(filename)
|
||||||
base, ext = os.path.splitext(tail)
|
base, ext = os.path.splitext(tail)
|
||||||
from idlelib import browser
|
from idlelib import browser
|
||||||
browser.ClassBrowser(self.flist, base, [head])
|
browser.ClassBrowser(self.flist, base, [head])
|
||||||
|
return "break"
|
||||||
|
|
||||||
def open_path_browser(self, event=None):
|
def open_path_browser(self, event=None):
|
||||||
from idlelib import pathbrowser
|
from idlelib import pathbrowser
|
||||||
pathbrowser.PathBrowser(self.flist)
|
pathbrowser.PathBrowser(self.flist)
|
||||||
|
return "break"
|
||||||
|
|
||||||
def open_turtle_demo(self, event = None):
|
def open_turtle_demo(self, event = None):
|
||||||
import subprocess
|
import subprocess
|
||||||
|
@ -623,6 +634,7 @@ class EditorWindow(object):
|
||||||
'-c',
|
'-c',
|
||||||
'from turtledemo.__main__ import main; main()']
|
'from turtledemo.__main__ import main; main()']
|
||||||
subprocess.Popen(cmd, shell=False)
|
subprocess.Popen(cmd, shell=False)
|
||||||
|
return "break"
|
||||||
|
|
||||||
def gotoline(self, lineno):
|
def gotoline(self, lineno):
|
||||||
if lineno is not None and lineno > 0:
|
if lineno is not None and lineno > 0:
|
||||||
|
@ -879,6 +891,7 @@ class EditorWindow(object):
|
||||||
|
|
||||||
def center_insert_event(self, event):
|
def center_insert_event(self, event):
|
||||||
self.center()
|
self.center()
|
||||||
|
return "break"
|
||||||
|
|
||||||
def center(self, mark="insert"):
|
def center(self, mark="insert"):
|
||||||
text = self.text
|
text = self.text
|
||||||
|
@ -910,6 +923,7 @@ class EditorWindow(object):
|
||||||
|
|
||||||
def close_event(self, event):
|
def close_event(self, event):
|
||||||
self.close()
|
self.close()
|
||||||
|
return "break"
|
||||||
|
|
||||||
def maybesave(self):
|
def maybesave(self):
|
||||||
if self.io:
|
if self.io:
|
||||||
|
@ -1357,6 +1371,7 @@ class EditorWindow(object):
|
||||||
line = lines[pos]
|
line = lines[pos]
|
||||||
lines[pos] = '##' + line
|
lines[pos] = '##' + line
|
||||||
self.set_region(head, tail, chars, lines)
|
self.set_region(head, tail, chars, lines)
|
||||||
|
return "break"
|
||||||
|
|
||||||
def uncomment_region_event(self, event):
|
def uncomment_region_event(self, event):
|
||||||
head, tail, chars, lines = self.get_region()
|
head, tail, chars, lines = self.get_region()
|
||||||
|
@ -1370,6 +1385,7 @@ class EditorWindow(object):
|
||||||
line = line[1:]
|
line = line[1:]
|
||||||
lines[pos] = line
|
lines[pos] = line
|
||||||
self.set_region(head, tail, chars, lines)
|
self.set_region(head, tail, chars, lines)
|
||||||
|
return "break"
|
||||||
|
|
||||||
def tabify_region_event(self, event):
|
def tabify_region_event(self, event):
|
||||||
head, tail, chars, lines = self.get_region()
|
head, tail, chars, lines = self.get_region()
|
||||||
|
@ -1382,6 +1398,7 @@ class EditorWindow(object):
|
||||||
ntabs, nspaces = divmod(effective, tabwidth)
|
ntabs, nspaces = divmod(effective, tabwidth)
|
||||||
lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:]
|
lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:]
|
||||||
self.set_region(head, tail, chars, lines)
|
self.set_region(head, tail, chars, lines)
|
||||||
|
return "break"
|
||||||
|
|
||||||
def untabify_region_event(self, event):
|
def untabify_region_event(self, event):
|
||||||
head, tail, chars, lines = self.get_region()
|
head, tail, chars, lines = self.get_region()
|
||||||
|
@ -1390,6 +1407,7 @@ class EditorWindow(object):
|
||||||
for pos in range(len(lines)):
|
for pos in range(len(lines)):
|
||||||
lines[pos] = lines[pos].expandtabs(tabwidth)
|
lines[pos] = lines[pos].expandtabs(tabwidth)
|
||||||
self.set_region(head, tail, chars, lines)
|
self.set_region(head, tail, chars, lines)
|
||||||
|
return "break"
|
||||||
|
|
||||||
def toggle_tabs_event(self, event):
|
def toggle_tabs_event(self, event):
|
||||||
if self.askyesno(
|
if self.askyesno(
|
||||||
|
|
|
@ -95,14 +95,14 @@ class ParenMatchTest(unittest.TestCase):
|
||||||
pm = self.get_parenmatch()
|
pm = self.get_parenmatch()
|
||||||
|
|
||||||
text.insert('insert', '# this is a commen)')
|
text.insert('insert', '# this is a commen)')
|
||||||
self.assertIsNone(pm.paren_closed_event('event'))
|
pm.paren_closed_event('event')
|
||||||
|
|
||||||
text.insert('insert', '\ndef')
|
text.insert('insert', '\ndef')
|
||||||
self.assertIsNone(pm.flash_paren_event('event'))
|
pm.flash_paren_event('event')
|
||||||
self.assertIsNone(pm.paren_closed_event('event'))
|
pm.paren_closed_event('event')
|
||||||
|
|
||||||
text.insert('insert', ' a, *arg)')
|
text.insert('insert', ' a, *arg)')
|
||||||
self.assertIsNone(pm.paren_closed_event('event'))
|
pm.paren_closed_event('event')
|
||||||
|
|
||||||
def test_handle_restore_timer(self):
|
def test_handle_restore_timer(self):
|
||||||
pm = self.get_parenmatch()
|
pm = self.get_parenmatch()
|
||||||
|
|
|
@ -94,26 +94,28 @@ class ParenMatch:
|
||||||
.get_surrounding_brackets())
|
.get_surrounding_brackets())
|
||||||
if indices is None:
|
if indices is None:
|
||||||
self.bell()
|
self.bell()
|
||||||
return
|
return "break"
|
||||||
self.activate_restore()
|
self.activate_restore()
|
||||||
self.create_tag(indices)
|
self.create_tag(indices)
|
||||||
self.set_timeout_last()
|
self.set_timeout_last()
|
||||||
|
return "break"
|
||||||
|
|
||||||
def paren_closed_event(self, event):
|
def paren_closed_event(self, event):
|
||||||
# If it was a shortcut and not really a closing paren, quit.
|
# If it was a shortcut and not really a closing paren, quit.
|
||||||
closer = self.text.get("insert-1c")
|
closer = self.text.get("insert-1c")
|
||||||
if closer not in _openers:
|
if closer not in _openers:
|
||||||
return
|
return "break"
|
||||||
hp = HyperParser(self.editwin, "insert-1c")
|
hp = HyperParser(self.editwin, "insert-1c")
|
||||||
if not hp.is_in_code():
|
if not hp.is_in_code():
|
||||||
return
|
return "break"
|
||||||
indices = hp.get_surrounding_brackets(_openers[closer], True)
|
indices = hp.get_surrounding_brackets(_openers[closer], True)
|
||||||
if indices is None:
|
if indices is None:
|
||||||
self.bell()
|
self.bell()
|
||||||
return
|
return "break"
|
||||||
self.activate_restore()
|
self.activate_restore()
|
||||||
self.create_tag(indices)
|
self.create_tag(indices)
|
||||||
self.set_timeout()
|
self.set_timeout()
|
||||||
|
return "break"
|
||||||
|
|
||||||
def restore_event(self, event=None):
|
def restore_event(self, event=None):
|
||||||
self.text.tag_delete("paren")
|
self.text.tag_delete("paren")
|
||||||
|
|
|
@ -63,6 +63,7 @@ class ScriptBinding:
|
||||||
return 'break'
|
return 'break'
|
||||||
if not self.tabnanny(filename):
|
if not self.tabnanny(filename):
|
||||||
return 'break'
|
return 'break'
|
||||||
|
return "break"
|
||||||
|
|
||||||
def tabnanny(self, filename):
|
def tabnanny(self, filename):
|
||||||
# XXX: tabnanny should work on binary files as well
|
# XXX: tabnanny should work on binary files as well
|
||||||
|
|
|
@ -76,6 +76,7 @@ class ScrolledList:
|
||||||
index = self.listbox.index("active")
|
index = self.listbox.index("active")
|
||||||
self.select(index)
|
self.select(index)
|
||||||
menu.tk_popup(event.x_root, event.y_root)
|
menu.tk_popup(event.x_root, event.y_root)
|
||||||
|
return "break"
|
||||||
|
|
||||||
def make_menu(self):
|
def make_menu(self):
|
||||||
menu = Menu(self.listbox, tearoff=0)
|
menu = Menu(self.listbox, tearoff=0)
|
||||||
|
|
|
@ -20,6 +20,7 @@ class ZoomHeight:
|
||||||
def zoom_height_event(self, event):
|
def zoom_height_event(self, event):
|
||||||
top = self.editwin.top
|
top = self.editwin.top
|
||||||
zoom_height(top)
|
zoom_height(top)
|
||||||
|
return "break"
|
||||||
|
|
||||||
|
|
||||||
def zoom_height(top):
|
def zoom_height(top):
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
IDLE no longer deletes a character after commenting out a region by a key
|
||||||
|
shortcut. Add ``return 'break'`` for this and other potential conflicts
|
||||||
|
between IDLE and default key bindings.
|
Loading…
Add table
Add a link
Reference in a new issue