Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5d46ab1

Browse files
committed
Issue #16893: Replace help.txt with idle.html for Idle doc display.
The new idlelib/idle.html is copied from Doc/build/html/idle.html. It looks better than help.txt and will better document Idle as released. The tkinter html viewer that works for this file was written by Rose Roseman. The new code is in idlelib/help.py, a new file for help menu classes. The now unused EditorWindow.HelpDialog class and helt.txt file are deprecated.
1 parent 16ad5cf commit 5d46ab1

6 files changed

Lines changed: 927 additions & 12 deletions

File tree

Lib/idlelib/EditorWindow.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from idlelib.configHandler import idleConf
2222
from idlelib import aboutDialog, textView, configDialog
2323
from idlelib import macosxSupport
24+
from idlelib import help
2425

2526
# The default tab setting for a Text widget, in average-width characters.
2627
TK_TABWIDTH_DEFAULT = 8
@@ -42,6 +43,11 @@ def _sphinx_version():
4243
class HelpDialog(object):
4344

4445
def __init__(self):
46+
import warnings as w
47+
w.warn("EditorWindow.HelpDialog is no longer used by Idle.\n"
48+
"It will be removed in 3.6 or later.\n"
49+
"It has been replaced by private help.HelpWindow\n",
50+
DeprecationWarning, stacklevel=2)
4551
self.parent = None # parent of help window
4652
self.dlg = None # the help window iteself
4753

@@ -539,11 +545,13 @@ def config_extensions_dialog(self, event=None):
539545
configDialog.ConfigExtensionsDialog(self.top)
540546

541547
def help_dialog(self, event=None):
548+
"Handle help doc event."
549+
# edit maxosxSupport.overrideRootMenu.help_dialog to match
542550
if self.root:
543551
parent = self.root
544552
else:
545553
parent = self.top
546-
helpDialog.display(parent, near=self.top)
554+
help.show_idlehelp(parent)
547555

548556
def python_docs(self, event=None):
549557
if sys.platform[:3] == 'win':
@@ -1716,4 +1724,4 @@ def _editor_window(parent): # htest #
17161724

17171725
if __name__ == '__main__':
17181726
from idlelib.idle_test.htest import run
1719-
run(_help_dialog, _editor_window)
1727+
run(_editor_window)

Lib/idlelib/help.py

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
"""
2+
help.py implements the Idle help menu and is subject to change.
3+
4+
The contents are subject to revision at any time, without notice.
5+
6+
Help => About IDLE: diplay About Idle dialog
7+
8+
<to be moved here from aboutDialog.py>
9+
10+
Help => IDLE Help: display idle.html with proper formatting
11+
12+
HelpParser - Parses idle.html generated from idle.rst by Sphinx
13+
and renders to tk Text.
14+
15+
HelpText - Displays formatted idle.html.
16+
17+
HelpFrame - Contains text, scrollbar, and table-of-contents.
18+
(This will be needed for display in a future tabbed window.)
19+
20+
HelpWindow - Display idleframe in a standalone window.
21+
22+
show_idlehelp - Create HelpWindow. Called in EditorWindow.help_dialog.
23+
"""
24+
from html.parser import HTMLParser
25+
from os.path import abspath, dirname, isdir, isfile, join
26+
from tkinter import Tk, Toplevel, Frame, Text, Scrollbar, Menu, Menubutton
27+
from tkinter import font as tkfont
28+
29+
use_ttk = False # until available to import
30+
if use_ttk:
31+
from tkinter.ttk import Menubutton
32+
33+
## About IDLE ##
34+
35+
36+
## IDLE Help ##
37+
38+
class HelpParser(HTMLParser):
39+
"""Render idle.html generated by Sphinx from idle.rst.
40+
41+
The overridden handle_xyz methods handle a subset of html tags.
42+
The supplied text should have the needed tag configurations.
43+
The behavior for unsupported tags, such as table, is undefined.
44+
"""
45+
def __init__(self, text):
46+
HTMLParser.__init__(self, convert_charrefs=True)
47+
self.text = text # text widget we're rendering into
48+
self.tags = '' # current text tags to apply
49+
self.show = False # used so we exclude page navigation
50+
self.hdrlink = False # used so we don't show header links
51+
self.level = 0 # indentation level
52+
self.pre = False # displaying preformatted text
53+
self.hprefix = '' # strip e.g. '25.5' from headings
54+
self.nested_dl = False # if we're in a nested <dl>
55+
self.simplelist = False # simple list (no double spacing)
56+
self.tocid = 1 # id for table of contents entries
57+
self.contents = [] # map toc ids to section titles
58+
self.data = '' # to record data within header tags for toc
59+
60+
def indent(self, amt=1):
61+
self.level += amt
62+
self.tags = '' if self.level == 0 else 'l'+str(self.level)
63+
64+
def handle_starttag(self, tag, attrs):
65+
"Handle starttags in idle.html."
66+
class_ = ''
67+
for a, v in attrs:
68+
if a == 'class':
69+
class_ = v
70+
s = ''
71+
if tag == 'div' and class_ == 'section':
72+
self.show = True # start of main content
73+
elif tag == 'div' and class_ == 'sphinxsidebar':
74+
self.show = False # end of main content
75+
elif tag == 'p' and class_ != 'first':
76+
s = '\n\n'
77+
elif tag == 'span' and class_ == 'pre':
78+
self.tags = 'pre'
79+
elif tag == 'span' and class_ == 'versionmodified':
80+
self.tags = 'em'
81+
elif tag == 'em':
82+
self.tags = 'em'
83+
elif tag in ['ul', 'ol']:
84+
if class_.find('simple') != -1:
85+
s = '\n'
86+
self.simplelist = True
87+
else:
88+
self.simplelist = False
89+
self.indent()
90+
elif tag == 'dl':
91+
if self.level > 0:
92+
self.nested_dl = True
93+
elif tag == 'li':
94+
s = '\n* ' if self.simplelist else '\n\n* '
95+
elif tag == 'dt':
96+
s = '\n\n' if not self.nested_dl else '\n' # avoid extra line
97+
self.nested_dl = False
98+
elif tag == 'dd':
99+
self.indent()
100+
s = '\n'
101+
elif tag == 'pre':
102+
self.pre = True
103+
if self.show:
104+
self.text.insert('end', '\n\n')
105+
self.tags = 'preblock'
106+
elif tag == 'a' and class_ == 'headerlink':
107+
self.hdrlink = True
108+
elif tag == 'h1':
109+
self.text.mark_set('toc'+str(self.tocid),
110+
self.text.index('end-1line'))
111+
self.tags = tag
112+
elif tag in ['h2', 'h3']:
113+
if self.show:
114+
self.data = ''
115+
self.text.mark_set('toc'+str(self.tocid),
116+
self.text.index('end-1line'))
117+
self.text.insert('end', '\n\n')
118+
self.tags = tag
119+
if self.show:
120+
self.text.insert('end', s, self.tags)
121+
122+
def handle_endtag(self, tag):
123+
"Handle endtags in idle.html."
124+
if tag in ['h1', 'h2', 'h3', 'span', 'em']:
125+
self.indent(0) # clear tag, reset indent
126+
if self.show and tag in ['h1', 'h2', 'h3']:
127+
title = self.data
128+
self.contents.append(('toc'+str(self.tocid), title))
129+
self.tocid += 1
130+
elif tag == 'a':
131+
self.hdrlink = False
132+
elif tag == 'pre':
133+
self.pre = False
134+
self.tags = ''
135+
elif tag in ['ul', 'dd', 'ol']:
136+
self.indent(amt=-1)
137+
138+
def handle_data(self, data):
139+
"Handle date segments in idle.html."
140+
if self.show and not self.hdrlink:
141+
d = data if self.pre else data.replace('\n', ' ')
142+
if self.tags == 'h1':
143+
self.hprefix = d[0:d.index(' ')]
144+
if self.tags in ['h1', 'h2', 'h3'] and self.hprefix != '':
145+
if d[0:len(self.hprefix)] == self.hprefix:
146+
d = d[len(self.hprefix):].strip()
147+
self.data += d
148+
self.text.insert('end', d, self.tags)
149+
150+
151+
class HelpText(Text):
152+
"Display idle.html."
153+
def __init__(self, parent, filename):
154+
"Configure tags and feed file to parser."
155+
Text.__init__(self, parent, wrap='word', highlightthickness=0,
156+
padx=5, borderwidth=0)
157+
158+
normalfont = self.findfont(['TkDefaultFont', 'arial', 'helvetica'])
159+
fixedfont = self.findfont(['TkFixedFont', 'monaco', 'courier'])
160+
self['font'] = (normalfont, 12)
161+
self.tag_configure('em', font=(normalfont, 12, 'italic'))
162+
self.tag_configure('h1', font=(normalfont, 20, 'bold'))
163+
self.tag_configure('h2', font=(normalfont, 18, 'bold'))
164+
self.tag_configure('h3', font=(normalfont, 15, 'bold'))
165+
self.tag_configure('pre', font=(fixedfont, 12))
166+
self.tag_configure('preblock', font=(fixedfont, 10), lmargin1=25,
167+
borderwidth=1, relief='solid', background='#eeffcc')
168+
self.tag_configure('l1', lmargin1=25, lmargin2=25)
169+
self.tag_configure('l2', lmargin1=50, lmargin2=50)
170+
self.tag_configure('l3', lmargin1=75, lmargin2=75)
171+
self.tag_configure('l4', lmargin1=100, lmargin2=100)
172+
173+
self.parser = HelpParser(self)
174+
with open(filename, encoding='utf-8') as f:
175+
contents = f.read()
176+
self.parser.feed(contents)
177+
self['state'] = 'disabled'
178+
179+
def findfont(self, names):
180+
"Return name of first font family derived from names."
181+
for name in names:
182+
if name.lower() in (x.lower() for x in tkfont.names(root=self)):
183+
font = tkfont.Font(name=name, exists=True, root=self)
184+
return font.actual()['family']
185+
elif name.lower() in (x.lower()
186+
for x in tkfont.families(root=self)):
187+
return name
188+
189+
190+
class HelpFrame(Frame):
191+
def __init__(self, parent, filename):
192+
Frame.__init__(self, parent)
193+
text = HelpText(self, filename)
194+
self['background'] = text['background']
195+
scroll = Scrollbar(self, command=text.yview)
196+
text['yscrollcommand'] = scroll.set
197+
text.grid(column=1, row=0, sticky='nsew')
198+
scroll.grid(column=2, row=0, sticky='ns')
199+
self.grid_columnconfigure(1, weight=1)
200+
self.grid_rowconfigure(0, weight=1)
201+
toc = self.contents_widget(text)
202+
toc.grid(column=0, row=0, sticky='nw')
203+
204+
def contents_widget(self, text):
205+
toc = Menubutton(self, text='TOC')
206+
drop = Menu(toc, tearoff=False)
207+
for tag, lbl in text.parser.contents:
208+
drop.add_command(label=lbl, command=lambda mark=tag:text.see(mark))
209+
toc['menu'] = drop
210+
return toc
211+
212+
213+
class HelpWindow(Toplevel):
214+
215+
def __init__(self, parent, filename, title):
216+
Toplevel.__init__(self, parent)
217+
self.wm_title(title)
218+
self.protocol("WM_DELETE_WINDOW", self.destroy)
219+
HelpFrame(self, filename).grid(column=0, row=0, sticky='nsew')
220+
self.grid_columnconfigure(0, weight=1)
221+
self.grid_rowconfigure(0, weight=1)
222+
223+
224+
def show_idlehelp(parent):
225+
filename = join(abspath(dirname(__file__)), 'idle.html')
226+
if not isfile(filename):
227+
dirpath = join(abspath(dirname(dirname(dirname(__file__)))),
228+
'Doc', 'build', 'html', 'library')
229+
HelpWindow(parent, filename, 'IDLE Help')
230+
231+
if __name__ == '__main__':
232+
from idlelib.idle_test.htest import run
233+
run(show_idlehelp)

Lib/idlelib/help.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
This file, idlelib/help.txt is out-of-date and no longer used by Idle.
2+
It is deprecated and will be removed in the future, possibly in 3.6
3+
----------------------------------------------------------------------
4+
15
[See the end of this file for ** TIPS ** on using IDLE !!]
26

37
IDLE is the Python IDE built with the tkinter GUI toolkit.

0 commit comments

Comments
 (0)