Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
e5f4daa
apply Saimadhav's patch v3 (linenumber-text-widget-v3.diff)
taleinat Jun 12, 2019
5cda90d
updated into first working version
taleinat Jun 12, 2019
d35acd0
some refactoring
taleinat Jun 12, 2019
89feac0
fix integration with undo/redo
taleinat Jun 12, 2019
dd11796
give get_end a better name and a doc-string
taleinat Jun 12, 2019
62ce5db
fix buggy insertion of a delegator into the middle of the percolator
taleinat Jun 12, 2019
bd942da
fix bug where BaseSideBar.show_sidebar() ignored the given side
taleinat Jun 12, 2019
954d122
add a NEWS entry
taleinat Jun 12, 2019
5f21e7f
update line numbers immediately upon highlighting config changes
taleinat Jul 5, 2019
776aa4e
optimize and improve scrolling
taleinat Jul 5, 2019
86ebf06
add a separate configuration setting for line number colors
taleinat Jul 5, 2019
1cdfa27
remove double- and triple- click conversion to single clicks
taleinat Jul 5, 2019
083689e
replace hack to make font changes take effect immediately
taleinat Jul 5, 2019
8f02e7b
refactor and expand tests, also fixing test_delete
taleinat Jul 6, 2019
b7faf1f
attempt to fix tests failing on Linux
taleinat Jul 7, 2019
bbba1ea
remove sidebar text widget border on macOS
taleinat Jul 9, 2019
5cade34
mouse click and drag now select entire lines
taleinat Jul 9, 2019
351c205
fix layout when showing both line numbers and code context
taleinat Jul 9, 2019
7251403
fix test_toggle_linenumbering
taleinat Jul 9, 2019
335b78e
fix code context tests after pack->grid change
taleinat Jul 9, 2019
38cdf79
Merge remote-tracking branch 'origin/master' into pr_14030
terryjreedy Jul 10, 2019
76a1551
10. Make text_frame resizeable.
terryjreedy Jul 10, 2019
83220c0
Remove unneeded addition to config-extensions.def.
terryjreedy Jul 10, 2019
5ea1326
1. Skip warning for new theme elements.
terryjreedy Jul 10, 2019
857d536
Remane linenumbers.py to sidebar.py.
terryjreedy Jul 10, 2019
53abdb4
Rename test_linenumbers to test_sidebar, fix import.
terryjreedy Jul 10, 2019
3bccd46
rename test class
taleinat Jul 10, 2019
2c90d7a
forward double- and triple-clicks events as normal click events
taleinat Jul 10, 2019
0fad84f
line numbers off by default and set separately per window
taleinat Jul 10, 2019
c2fb8f9
configurable default for whether to show line numbers in new windows
taleinat Jul 10, 2019
5cd21f4
fix state of menu option when opening IDLE with line numbers shown
taleinat Jul 10, 2019
d246688
fix and improve show_sidebar() and hide_sidebar() and their tests
taleinat Jul 11, 2019
cc294e9
add tests for click and drag selections
taleinat Jul 11, 2019
bd8fc82
add a test for scrolling
taleinat Jul 11, 2019
f267df9
add an htest for drag-scrolling on the line numbers
taleinat Jul 11, 2019
7728110
fix string formatting in htest
taleinat Jul 11, 2019
8c13379
fix skipping warning for missing line number highlight config
taleinat Jul 11, 2019
8d2b924
fix skipping warning for missing line number highlight config
taleinat Jul 11, 2019
a90e9f7
fix click and drag selection
taleinat Jul 11, 2019
59a0011
Merge branch 'master' into bpo-17535/IDLE-line-numbers
taleinat Jul 17, 2019
ed0ebac
Merge branch 'master' into bpo-17535/IDLE-line-numbers
terryjreedy Jul 20, 2019
7c822b6
Move line numbers down a pixel.
terryjreedy Jul 20, 2019
46935c9
properly ensure correct Y-axis padding of the sidebar widget
taleinat Jul 22, 2019
6e937be
fix line numbers update upon font config changes
taleinat Jul 22, 2019
ab69da5
fix fragile tests in test_sidebar
taleinat Jul 22, 2019
60e1132
Update test_sidebar docstring.
terryjreedy Jul 23, 2019
da95809
Touchup docs.
terryjreedy Jul 23, 2019
bb2a08c
fix locally
terryjreedy Jul 23, 2019
4f01c1f
Merge branch 'bpo-17535/IDLE-line-numbers' of https://github.com/tale…
terryjreedy Jul 23, 2019
18dcbc9
more doc touch-ups: consistency, wording, typo
taleinat Jul 23, 2019
af4473b
add tests for font and color updates for line numbers
taleinat Jul 23, 2019
2a493ea
ensure font consistency in line numbers htest
taleinat Jul 23, 2019
86d420e
add "What's New" entries
taleinat Jul 23, 2019
27e741f
revert 3.9 "what's New" entry
taleinat Jul 23, 2019
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
4 changes: 4 additions & 0 deletions Doc/library/idle.rst
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,10 @@ Zoom/Restore Height
defaults to 40 lines by 80 chars unless changed on the General tab of the
Configure IDLE dialog.

Line Numbers (Editor Window only)
Open a column to the left of the edit window which shows the linenumber
of each line of text.

Window menu (Shell and Editor)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
10 changes: 10 additions & 0 deletions Lib/idlelib/config-extensions.def
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ style= expression
flash-delay= 500
bell= True

# [LineNumber]
# enable=1
# enable_editor=1
# # Should LineNumbering be visible on EditorWindow startup?
# visible=0
# bgcolor=Gray
# fgcolor=Black
# [LineNumber_bindings]
# toggle-line-numbers=

# IDLE reads several config files to determine user preferences. This
# file is the default configuration file for IDLE extensions settings.
#
Expand Down
14 changes: 10 additions & 4 deletions Lib/idlelib/config-highlight.def
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ hit-foreground= #ffffff
hit-background= #000000
error-foreground= #000000
error-background= #ff7777
context-foreground= #000000
context-background= lightgray
linenumber-foreground= gray
linenumber-background= #ffffff
#cursor (only foreground can be set, restart IDLE)
cursor-foreground= black
#shell window
Expand All @@ -31,8 +35,6 @@ stderr-foreground= red
stderr-background= #ffffff
console-foreground= #770000
console-background= #ffffff
context-foreground= #000000
context-background= lightgray

[IDLE New]
normal-foreground= #000000
Expand All @@ -55,6 +57,10 @@ hit-foreground= #ffffff
hit-background= #000000
error-foreground= #000000
error-background= #ff7777
context-foreground= #000000
context-background= lightgray
linenumber-foreground= gray
linenumber-background= #ffffff
#cursor (only foreground can be set, restart IDLE)
cursor-foreground= black
#shell window
Expand All @@ -64,8 +70,6 @@ stderr-foreground= red
stderr-background= #ffffff
console-foreground= #770000
console-background= #ffffff
context-foreground= #000000
context-background= lightgray

[IDLE Dark]
comment-foreground = #dd0000
Expand Down Expand Up @@ -97,3 +101,5 @@ comment-background = #002240
break-foreground = #FFFFFF
context-foreground= #ffffff
context-background= #454545
linenumber-foreground= gray
linenumber-background= #002240
6 changes: 4 additions & 2 deletions Lib/idlelib/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,10 @@ def GetThemeDict(self, type, themeName):
'hit-background':'#000000',
'error-foreground':'#ffffff',
'error-background':'#000000',
'context-foreground':'#000000',
'context-background':'#ffffff',
'linenumber-foreground':'#000000',
'linenumber-background':'#ffffff',
#cursor (only foreground can be set)
'cursor-foreground':'#000000',
#shell window
Expand All @@ -345,8 +349,6 @@ def GetThemeDict(self, type, themeName):
'stderr-background':'#ffffff',
'console-foreground':'#000000',
'console-background':'#ffffff',
'context-foreground':'#000000',
'context-background':'#ffffff',
}
for element in theme:
if not cfgParser.has_option(themeName, element):
Expand Down
6 changes: 6 additions & 0 deletions Lib/idlelib/configdialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,7 @@ def create_page_highlight(self):
'Shell Error Text': ('error', '12'),
'Shell Stdout Text': ('stdout', '13'),
'Shell Stderr Text': ('stderr', '14'),
'Line Number': ('linenumber', '16'),
}
self.builtin_name = tracers.add(
StringVar(self), self.var_changed_builtin_name)
Expand Down Expand Up @@ -864,6 +865,11 @@ def create_page_highlight(self):
('stderr', 'stderr'), ('\n\n', 'normal'))
for texttag in text_and_tags:
text.insert(END, texttag[0], texttag[1])
n_lines = len(text.get('1.0', END).splitlines())
for lineno in range(1, n_lines + 1):
text.insert(f'{lineno}.0',
f'{lineno:{len(str(n_lines))}d} ',
'linenumber')
for element in self.theme_elements:
def tem(event, elem=element):
# event.widget.winfo_top_level().highlight_target.set(elem)
Expand Down
24 changes: 22 additions & 2 deletions Lib/idlelib/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class EditorWindow(object):
from idlelib.calltip import Calltip
from idlelib.codecontext import CodeContext
from idlelib.paragraph import FormatParagraph
from idlelib.linenumbers import LineNumbers
from idlelib.parenmatch import ParenMatch
from idlelib.rstrip import Rstrip
from idlelib.squeezer import Squeezer
Expand All @@ -62,6 +63,9 @@ class EditorWindow(object):
filesystemencoding = sys.getfilesystemencoding() # for file names
help_url = None

allow_code_context = True
allow_line_numbers = True

def __init__(self, flist=None, filename=None, key=None, root=None):
# Delay import: runscript imports pyshell imports EditorWindow.
from idlelib.runscript import ScriptBinding
Expand Down Expand Up @@ -247,6 +251,7 @@ def __init__(self, flist=None, filename=None, key=None, root=None):
self.good_load = False
self.set_indentation_params(False)
self.color = None # initialized below in self.ResetColorizer
self.line_numbers = None # optionally initialized later below
if filename:
if os.path.exists(filename) and not os.path.isdir(filename):
if io.loadfile(filename):
Expand Down Expand Up @@ -311,8 +316,19 @@ def __init__(self, flist=None, filename=None, key=None, root=None):
text.bind("<<refresh-calltip>>", ctip.refresh_calltip_event)
text.bind("<<force-open-calltip>>", ctip.force_open_calltip_event)
text.bind("<<zoom-height>>", self.ZoomHeight(self).zoom_height_event)
text.bind("<<toggle-code-context>>",
self.CodeContext(self).toggle_code_context_event)
if self.allow_code_context:
code_context = self.CodeContext(self)
text.bind("<<toggle-code-context>>",
code_context.toggle_code_context_event)
else:
self.update_menu_state('options', '*Code Context', 'disabled')
if self.allow_line_numbers:
self.line_numbers = self.LineNumbers(self)
text.bind("<<toggle-line-numbers>>",
self.line_numbers.toggle_line_numbers_event)
pass
else:
self.update_menu_state('options', '*Line Numbers', 'disabled')

def _filename_to_unicode(self, filename):
"""Return filename as BMP unicode so displayable in Tk."""
Expand Down Expand Up @@ -771,6 +787,8 @@ def ResetColorizer(self):
self._rmcolorizer()
self._addcolorizer()
EditorWindow.color_config(self.text)
if self.line_numbers is not None:
self.line_numbers.update_sidebar_text_font()

IDENTCHARS = string.ascii_letters + string.digits + "_"

Expand All @@ -790,6 +808,8 @@ def ResetFont(self):
# Called from configdialog.py

self.text['font'] = idleConf.GetFont(self.root, 'main','EditorWindow')
if self.line_numbers is not None:
self.line_numbers.update_sidebar_text_font()

def RemoveKeybindings(self):
"Remove the keybindings before they are changed."
Expand Down
197 changes: 197 additions & 0 deletions Lib/idlelib/idle_test/test_linenumbers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
"""Unittest for idlelib.LineNumber"""
from itertools import chain
import unittest
from test.support import requires
import tkinter as tk

from idlelib.delegator import Delegator
from idlelib.percolator import Percolator
from idlelib.linenumbers import LineNumbers


class Dummy_editwin:
def __init__(self, text):
self.text = text
self.text_frame = self.text.master
self.per = Percolator(text)
self.undo = Delegator()
self.per.insertfilter(self.undo)

def setvar(self, name, value):
pass


class LineNumberTest(unittest.TestCase):

@classmethod
def setUpClass(cls):
requires('gui')
cls.root = tk.Tk()
cls.text = tk.Text(cls.root)
cls.editwin = Dummy_editwin(cls.text)
cls.editwin.vbar = tk.Scrollbar(cls.root)

@classmethod
def tearDownClass(cls):
cls.editwin.per.close()
cls.text.destroy()
cls.root.destroy()
del cls.text, cls.editwin, cls.root

def setUp(self):
self.linenumber = LineNumbers(self.editwin)

def tearDown(self):
self.text.delete('1.0', 'end')

def assert_state_disabled(self):
state = self.linenumber.sidebar_text.config()['state']
self.assertEqual(state[-1], tk.DISABLED)

def get_sidebar_text_contents(self):
return self.linenumber.sidebar_text.get('1.0', tk.END)

def assert_sidebar_n_lines(self, n_lines):
expected = '\n'.join(chain(map(str, range(1, n_lines + 1)), ['']))
self.assertEqual(self.get_sidebar_text_contents(), expected)

def assert_text_equals(self, expected):
return self.assertEqual(self.text.get('1.0', 'end'), expected)

def test_init_empty(self):
self.assert_sidebar_n_lines(1)

def test_init_not_empty(self):
self.text.insert('insert', 'foo bar\n'*3)
self.assert_text_equals('foo bar\n'*3 + '\n')
self.assert_sidebar_n_lines(4)

def test_toggle_linenumbering(self):
self.assertEqual(self.linenumber.side, tk.LEFT)
self.linenumber.toggle_line_numbers_event(None)
self.assertEqual(self.linenumber.side, None)
self.linenumber.toggle_line_numbers_event(None)
self.assertEqual(self.linenumber.side, tk.LEFT)

def test_insert(self):
self.text.insert('insert', 'foobar')
self.assert_text_equals('foobar\n')
self.assert_sidebar_n_lines(1)
self.assert_state_disabled()

self.text.insert('insert', '\nfoo')
self.assert_text_equals('foobar\nfoo\n')
self.assert_sidebar_n_lines(2)
self.assert_state_disabled()

self.text.insert('insert', 'hello\n'*2)
self.assert_text_equals('foobar\nfoohello\nhello\n\n')
self.assert_sidebar_n_lines(4)
self.assert_state_disabled()

self.text.insert('insert', '\nworld')
self.assert_text_equals('foobar\nfoohello\nhello\n\nworld\n')
self.assert_sidebar_n_lines(5)
self.assert_state_disabled()

def test_delete(self):
self.text.insert('insert', 'foobar')
self.assert_text_equals('foobar\n')
self.text.delete('1.1', '1.3')
self.assert_text_equals('fbar\n')
self.assert_sidebar_n_lines(1)
self.assert_state_disabled()

self.text.insert('insert', 'foo\n'*2)
self.assert_text_equals('fbarfoo\nfoo\n\n')
self.assert_sidebar_n_lines(3)
self.assert_state_disabled()

# note: deleting up to "2.end" doesn't delete the final newline
self.text.delete('2.0', '2.end')
self.assert_text_equals('fbarfoo\n\n\n')
self.assert_sidebar_n_lines(3)
self.assert_state_disabled()

self.text.delete('1.3', 'end')
self.assert_text_equals('fba\n')
self.assert_sidebar_n_lines(1)
self.assert_state_disabled()

# note: Text widgets always keep a single '\n' character at the end
self.text.delete('1.0', 'end')
self.assert_text_equals('\n')
self.assert_sidebar_n_lines(1)
self.assert_state_disabled()

def test_sidebar_text_width(self):
"""
Test that linenumber text widget is always at the minimum
width
"""
def get_width():
return self.linenumber.sidebar_text.config()['width'][-1]

self.assert_sidebar_n_lines(1)
self.assertEqual(get_width(), 1)

self.text.insert('insert', 'foo')
self.assert_sidebar_n_lines(1)
self.assertEqual(get_width(), 1)

self.text.insert('insert', 'foo\n'*8)
self.assert_sidebar_n_lines(9)
self.assertEqual(get_width(), 1)

self.text.insert('insert', 'foo\n')
self.assert_sidebar_n_lines(10)
self.assertEqual(get_width(), 2)

self.text.insert('insert', 'foo\n')
self.assert_sidebar_n_lines(11)
self.assertEqual(get_width(), 2)

self.text.delete('insert -1l linestart', 'insert linestart')
self.assert_sidebar_n_lines(10)
self.assertEqual(get_width(), 2)

self.text.delete('insert -1l linestart', 'insert linestart')
self.assert_sidebar_n_lines(9)
self.assertEqual(get_width(), 1)

self.text.insert('insert', 'foo\n'*90)
self.assert_sidebar_n_lines(99)
self.assertEqual(get_width(), 2)

self.text.insert('insert', 'foo\n')
self.assert_sidebar_n_lines(100)
self.assertEqual(get_width(), 3)

self.text.insert('insert', 'foo\n')
self.assert_sidebar_n_lines(101)
self.assertEqual(get_width(), 3)

self.text.delete('insert -1l linestart', 'insert linestart')
self.assert_sidebar_n_lines(100)
self.assertEqual(get_width(), 3)

self.text.delete('insert -1l linestart', 'insert linestart')
self.assert_sidebar_n_lines(99)
self.assertEqual(get_width(), 2)

self.text.delete('50.0 -1c', 'end -1c')
self.assert_sidebar_n_lines(49)
self.assertEqual(get_width(), 2)

self.text.delete('5.0 -1c', 'end -1c')
self.assert_sidebar_n_lines(4)
self.assertEqual(get_width(), 1)

# note: Text widgets always keep a single '\n' character at the end
self.text.delete('1.0', 'end -1c')
self.assert_sidebar_n_lines(1)
self.assertEqual(get_width(), 1)


if __name__ == '__main__':
unittest.main(verbosity=2)
Loading