Skip to content

bpo-37903: IDLE: Shell sidebar with prompts #15474

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 42 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
7adb9ad
initial working shell sidebar
taleinat Aug 5, 2019
26bbaec
fix recall and handling of prompt and input lines
taleinat Aug 23, 2019
9076da5
update only as needed during editing, accounting for line wrapping
taleinat Aug 23, 2019
cad2cd1
properly insert delegators into their proper place in the percolator
taleinat Aug 24, 2019
4040e26
move non-syntax tag highlighting out of ColorDelegator
taleinat Aug 24, 2019
9b31031
replace shell sidebar prompt and input line recognition method
taleinat Aug 24, 2019
37a0db3
minor code cleanup
taleinat Aug 24, 2019
c766822
remove unnecessary .replace() delegator method
taleinat Aug 24, 2019
50bd082
fix inverted condition in deciding whether to update sidebar (oops!)
taleinat Aug 24, 2019
6f186f0
fix "stdin" tag removed when undo-ing a deletion
taleinat Aug 24, 2019
f7f3de9
fix sidebar update on new prompt
taleinat Aug 24, 2019
e929ea7
add a NEWS entry
taleinat Aug 24, 2019
d04bfa3
fix recall handling with multiple successive statements
taleinat Aug 24, 2019
81f4852
remove a dead line
taleinat Aug 24, 2019
46be85e
remove commented out initial attempt
taleinat Aug 24, 2019
1fc4bcb
update shell sidebar font upon font config changes
taleinat Aug 25, 2019
6f1c975
update sidebar text colors upon highlight config changes
taleinat Sep 17, 2020
083fede
use the prompt ("console") foreground color for the shell sidebar text
taleinat Sep 17, 2020
4ad72a1
show continuation prompts ("...") for multi-line history recall
taleinat Sep 17, 2020
009e08d
show continuation prompts ("...") after multi-line replace in the shell
taleinat Sep 17, 2020
e524cce
show continuation prompts ("...") after multi-line undo/redo in the s…
taleinat Sep 17, 2020
3ea2986
don't show continuation prompts ("...") for print() outputs
taleinat Sep 17, 2020
7f9182f
allow deleting ">>> " at the beginning of a line in shell windows
taleinat Sep 17, 2020
10aaf1d
update shell sidebar on shell output squeeze/unsqueeze
taleinat Sep 17, 2020
7c91901
remove failing editor window test that is no longer relevant
taleinat Sep 17, 2020
50ca9c6
add several tests for the shell sidebar
taleinat Sep 18, 2020
23c218f
reduce shell sidebar test run time by reusing the PyShell
taleinat Sep 18, 2020
6cef0a9
revert removal of the "hit" tag from Colorizer.tag_defs
taleinat Oct 11, 2020
a018135
hide unnecessary extra "root" Tk window in tests
taleinat Oct 11, 2020
525fe44
fix test method names
taleinat Oct 11, 2020
7b8913d
fix test comments according to pep-8 style
taleinat Oct 11, 2020
8c8d0c0
rename sidebar test class according to convention
taleinat Oct 11, 2020
7ecc843
re-word doc-strings for BaseSideBar and EndLineDelegator
taleinat Oct 12, 2020
bedb1cb
re-word doc-strings for get_lineno and get_end_linenumber
taleinat Oct 12, 2020
eee0453
optimize tests and make them more robust
taleinat Oct 12, 2020
7afcb57
handle mouse buttons except for button 1 (left-click)
taleinat Oct 12, 2020
8a7dd60
add tests for text font and color configs
taleinat Oct 12, 2020
6efb968
remove show/hide_sidebar from the shell sidebar
taleinat Oct 12, 2020
cc37924
add more test cases
taleinat Oct 12, 2020
97576da
update coverage percentage
taleinat Oct 12, 2020
2aa4e1a
re-word squeeze_current_text() doc-string
taleinat Oct 12, 2020
71f343e
update coverage percentage
taleinat Oct 13, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions Lib/idlelib/colorizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,15 @@ def LoadTagDefs(self):
"BUILTIN": idleConf.GetHighlight(theme, "builtin"),
"STRING": idleConf.GetHighlight(theme, "string"),
"DEFINITION": idleConf.GetHighlight(theme, "definition"),
"SYNC": {'background':None,'foreground':None},
"TODO": {'background':None,'foreground':None},
"SYNC": {'background': None, 'foreground': None},
"TODO": {'background': None, 'foreground': None},
"ERROR": idleConf.GetHighlight(theme, "error"),
# The following is used by ReplaceDialog:
# "hit" is used by ReplaceDialog to mark matches. It shouldn't be changed by Colorizer, but
# that currently isn't technically possible. This should be moved elsewhere in the future
# when fixing the "hit" tag's visibility, or when the replace dialog is replaced with a
# non-modal alternative.
"hit": idleConf.GetHighlight(theme, "hit"),
}
}

if DEBUG: print('tagdefs',self.tagdefs)

Expand Down
2 changes: 1 addition & 1 deletion Lib/idlelib/configdialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ def activate_config_changes(self):
"""
win_instances = self.parent.instance_dict.keys()
for instance in win_instances:
instance.ResetColorizer()
instance.update_colors()
instance.ResetFont()
instance.set_notabs_indentwidth()
instance.ApplyKeybindings()
Expand Down
45 changes: 26 additions & 19 deletions Lib/idlelib/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,14 @@ class EditorWindow(object):
from idlelib.sidebar import LineNumbers
from idlelib.format import FormatParagraph, FormatRegion, Indents, Rstrip
from idlelib.parenmatch import ParenMatch
from idlelib.squeezer import Squeezer
from idlelib.zoomheight import ZoomHeight

filesystemencoding = sys.getfilesystemencoding() # for file names
help_url = None

allow_code_context = True
allow_line_numbers = True
user_input_insert_tags = None

def __init__(self, flist=None, filename=None, key=None, root=None):
# Delay import: runscript imports pyshell imports EditorWindow.
Expand Down Expand Up @@ -266,7 +266,7 @@ def __init__(self, flist=None, filename=None, key=None, root=None):
io.set_filename_change_hook(self.filename_change_hook)
self.good_load = False
self.set_indentation_params(False)
self.color = None # initialized below in self.ResetColorizer
self.color = None # initialized below in self.update_colors()
self.code_context = None # optionally initialized later below
self.line_numbers = None # optionally initialized later below
if filename:
Expand All @@ -279,7 +279,7 @@ def __init__(self, flist=None, filename=None, key=None, root=None):
io.set_filename(filename)
self.good_load = True

self.ResetColorizer()
self.update_colors()
self.saved_change_hook()
self.update_recent_files_list()
self.load_extensions()
Expand Down Expand Up @@ -782,9 +782,7 @@ def _addcolorizer(self):
self.color = self.ColorDelegator()
# can add more colorizers here...
if self.color:
self.per.removefilter(self.undo)
self.per.insertfilter(self.color)
self.per.insertfilter(self.undo)
self.per.insertfilterafter(filter=self.color, after=self.undo)

def _rmcolorizer(self):
if not self.color:
Expand All @@ -794,12 +792,23 @@ def _rmcolorizer(self):
self.color = None

def ResetColorizer(self):
"Update the color theme"
# Called from self.filename_change_hook and from configdialog.py
"""Reset the syntax colorizer.

For example, this is called after filename changes, since the file
type can affect the highlighting.
"""
self._rmcolorizer()
self._addcolorizer()

def update_colors(self):
"""Update the color theme.

For example, this is called after highlighting config changes.
"""
EditorWindow.color_config(self.text)

self.ResetColorizer()

if self.code_context is not None:
self.code_context.update_highlight_colors()

Expand Down Expand Up @@ -1301,8 +1310,6 @@ def smart_backspace_event(self, event):
# Debug prompt is multilined....
ncharsdeleted = 0
while 1:
if chars == self.prompt_last_line: # '' unless PyShell
break
chars = chars[:-1]
ncharsdeleted = ncharsdeleted + 1
have = len(chars.expandtabs(tabwidth))
Expand All @@ -1311,7 +1318,7 @@ def smart_backspace_event(self, event):
text.undo_block_start()
text.delete("insert-%dc" % ncharsdeleted, "insert")
if have < want:
text.insert("insert", ' ' * (want - have))
text.insert("insert", ' ' * (want - have), self.user_input_insert_tags)
text.undo_block_stop()
return "break"

Expand Down Expand Up @@ -1344,7 +1351,7 @@ def smart_indent_event(self, event):
effective = len(prefix.expandtabs(self.tabwidth))
n = self.indentwidth
pad = ' ' * (n - effective % n)
text.insert("insert", pad)
text.insert("insert", pad, self.user_input_insert_tags)
text.see("insert")
return "break"
finally:
Expand Down Expand Up @@ -1375,13 +1382,13 @@ def newline_and_indent_event(self, event):
if i == n:
# The cursor is in or at leading indentation in a continuation
# line; just inject an empty line at the start.
text.insert("insert linestart", '\n')
text.insert("insert linestart", '\n', self.user_input_insert_tags)
return "break"
indent = line[:i]

# Strip whitespace before insert point unless it's in the prompt.
i = 0
while line and line[-1] in " \t" and line != self.prompt_last_line:
while line and line[-1] in " \t":
line = line[:-1]
i += 1
if i:
Expand All @@ -1392,7 +1399,7 @@ def newline_and_indent_event(self, event):
text.delete("insert")

# Insert new line.
text.insert("insert", '\n')
text.insert("insert", '\n', self.user_input_insert_tags)

# Adjust indentation for continuations and block open/close.
# First need to find the last statement.
Expand Down Expand Up @@ -1428,7 +1435,7 @@ def newline_and_indent_event(self, event):
elif c == pyparse.C_STRING_NEXT_LINES:
# Inside a string which started before this line;
# just mimic the current indent.
text.insert("insert", indent)
text.insert("insert", indent, self.user_input_insert_tags)
elif c == pyparse.C_BRACKET:
# Line up with the first (if any) element of the
# last open bracket structure; else indent one
Expand All @@ -1442,7 +1449,7 @@ def newline_and_indent_event(self, event):
# beyond leftmost =; else to beyond first chunk of
# non-whitespace on initial line.
if y.get_num_lines_in_stmt() > 1:
text.insert("insert", indent)
text.insert("insert", indent, self.user_input_insert_tags)
else:
self.reindent_to(y.compute_backslash_indent())
else:
Expand All @@ -1453,7 +1460,7 @@ def newline_and_indent_event(self, event):
# indentation of initial line of closest preceding
# interesting statement.
indent = y.get_base_indent_string()
text.insert("insert", indent)
text.insert("insert", indent, self.user_input_insert_tags)
if y.is_block_opener():
self.smart_indent_event(event)
elif indent and y.is_block_closer():
Expand Down Expand Up @@ -1500,7 +1507,7 @@ def reindent_to(self, column):
if text.compare("insert linestart", "!=", "insert"):
text.delete("insert linestart", "insert")
if column:
text.insert("insert", self._make_blanks(column))
text.insert("insert", self._make_blanks(column), self.user_input_insert_tags)
text.undo_block_stop()

# Guess indentwidth from text content.
Expand Down
4 changes: 2 additions & 2 deletions Lib/idlelib/history.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ def fetch(self, reverse):
else:
if self.text.get("iomark", "end-1c") != prefix:
self.text.delete("iomark", "end-1c")
self.text.insert("iomark", prefix)
self.text.insert("iomark", prefix, "stdin")
pointer = prefix = None
break
item = self.history[pointer]
if item[:nprefix] == prefix and len(item) > nprefix:
self.text.delete("iomark", "end-1c")
self.text.insert("iomark", item)
self.text.insert("iomark", item, "stdin")
break
self.text.see("insert")
self.text.tag_remove("sel", "1.0", "end")
Expand Down
8 changes: 0 additions & 8 deletions Lib/idlelib/idle_test/test_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ def test_indent_and_newline_event(self):
'2.end'),
)

w.prompt_last_line = ''
for test in tests:
with self.subTest(label=test.label):
insert(text, test.text)
Expand All @@ -182,13 +181,6 @@ def test_indent_and_newline_event(self):
# Deletes selected text before adding new line.
eq(get('1.0', 'end'), ' def f1(self, a,\n \n return a + b\n')

# Preserves the whitespace in shell prompt.
w.prompt_last_line = '>>> '
insert(text, '>>> \t\ta =')
text.mark_set('insert', '1.5')
nl(None)
eq(get('1.0', 'end'), '>>> \na =\n')


class RMenuTest(unittest.TestCase):

Expand Down
Loading