Commit 5d46ab12 authored by Terry Jan Reedy's avatar Terry Jan Reedy

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.
parent 16ad5cfa
......@@ -21,6 +21,7 @@ from idlelib import PyParse
from idlelib.configHandler import idleConf
from idlelib import aboutDialog, textView, configDialog
from idlelib import macosxSupport
from idlelib import help
# The default tab setting for a Text widget, in average-width characters.
TK_TABWIDTH_DEFAULT = 8
......@@ -42,6 +43,11 @@ def _sphinx_version():
class HelpDialog(object):
def __init__(self):
import warnings as w
w.warn("EditorWindow.HelpDialog is no longer used by Idle.\n"
"It will be removed in 3.6 or later.\n"
"It has been replaced by private help.HelpWindow\n",
DeprecationWarning, stacklevel=2)
self.parent = None # parent of help window
self.dlg = None # the help window iteself
......@@ -539,11 +545,13 @@ class EditorWindow(object):
configDialog.ConfigExtensionsDialog(self.top)
def help_dialog(self, event=None):
"Handle help doc event."
# edit maxosxSupport.overrideRootMenu.help_dialog to match
if self.root:
parent = self.root
else:
parent = self.top
helpDialog.display(parent, near=self.top)
help.show_idlehelp(parent)
def python_docs(self, event=None):
if sys.platform[:3] == 'win':
......@@ -1716,4 +1724,4 @@ def _editor_window(parent): # htest #
if __name__ == '__main__':
from idlelib.idle_test.htest import run
run(_help_dialog, _editor_window)
run(_editor_window)
"""
help.py implements the Idle help menu and is subject to change.
The contents are subject to revision at any time, without notice.
Help => About IDLE: diplay About Idle dialog
<to be moved here from aboutDialog.py>
Help => IDLE Help: display idle.html with proper formatting
HelpParser - Parses idle.html generated from idle.rst by Sphinx
and renders to tk Text.
HelpText - Displays formatted idle.html.
HelpFrame - Contains text, scrollbar, and table-of-contents.
(This will be needed for display in a future tabbed window.)
HelpWindow - Display idleframe in a standalone window.
show_idlehelp - Create HelpWindow. Called in EditorWindow.help_dialog.
"""
from html.parser import HTMLParser
from os.path import abspath, dirname, isdir, isfile, join
from tkinter import Tk, Toplevel, Frame, Text, Scrollbar, Menu, Menubutton
from tkinter import font as tkfont
use_ttk = False # until available to import
if use_ttk:
from tkinter.ttk import Menubutton
## About IDLE ##
## IDLE Help ##
class HelpParser(HTMLParser):
"""Render idle.html generated by Sphinx from idle.rst.
The overridden handle_xyz methods handle a subset of html tags.
The supplied text should have the needed tag configurations.
The behavior for unsupported tags, such as table, is undefined.
"""
def __init__(self, text):
HTMLParser.__init__(self, convert_charrefs=True)
self.text = text # text widget we're rendering into
self.tags = '' # current text tags to apply
self.show = False # used so we exclude page navigation
self.hdrlink = False # used so we don't show header links
self.level = 0 # indentation level
self.pre = False # displaying preformatted text
self.hprefix = '' # strip e.g. '25.5' from headings
self.nested_dl = False # if we're in a nested <dl>
self.simplelist = False # simple list (no double spacing)
self.tocid = 1 # id for table of contents entries
self.contents = [] # map toc ids to section titles
self.data = '' # to record data within header tags for toc
def indent(self, amt=1):
self.level += amt
self.tags = '' if self.level == 0 else 'l'+str(self.level)
def handle_starttag(self, tag, attrs):
"Handle starttags in idle.html."
class_ = ''
for a, v in attrs:
if a == 'class':
class_ = v
s = ''
if tag == 'div' and class_ == 'section':
self.show = True # start of main content
elif tag == 'div' and class_ == 'sphinxsidebar':
self.show = False # end of main content
elif tag == 'p' and class_ != 'first':
s = '\n\n'
elif tag == 'span' and class_ == 'pre':
self.tags = 'pre'
elif tag == 'span' and class_ == 'versionmodified':
self.tags = 'em'
elif tag == 'em':
self.tags = 'em'
elif tag in ['ul', 'ol']:
if class_.find('simple') != -1:
s = '\n'
self.simplelist = True
else:
self.simplelist = False
self.indent()
elif tag == 'dl':
if self.level > 0:
self.nested_dl = True
elif tag == 'li':
s = '\n* ' if self.simplelist else '\n\n* '
elif tag == 'dt':
s = '\n\n' if not self.nested_dl else '\n' # avoid extra line
self.nested_dl = False
elif tag == 'dd':
self.indent()
s = '\n'
elif tag == 'pre':
self.pre = True
if self.show:
self.text.insert('end', '\n\n')
self.tags = 'preblock'
elif tag == 'a' and class_ == 'headerlink':
self.hdrlink = True
elif tag == 'h1':
self.text.mark_set('toc'+str(self.tocid),
self.text.index('end-1line'))
self.tags = tag
elif tag in ['h2', 'h3']:
if self.show:
self.data = ''
self.text.mark_set('toc'+str(self.tocid),
self.text.index('end-1line'))
self.text.insert('end', '\n\n')
self.tags = tag
if self.show:
self.text.insert('end', s, self.tags)
def handle_endtag(self, tag):
"Handle endtags in idle.html."
if tag in ['h1', 'h2', 'h3', 'span', 'em']:
self.indent(0) # clear tag, reset indent
if self.show and tag in ['h1', 'h2', 'h3']:
title = self.data
self.contents.append(('toc'+str(self.tocid), title))
self.tocid += 1
elif tag == 'a':
self.hdrlink = False
elif tag == 'pre':
self.pre = False
self.tags = ''
elif tag in ['ul', 'dd', 'ol']:
self.indent(amt=-1)
def handle_data(self, data):
"Handle date segments in idle.html."
if self.show and not self.hdrlink:
d = data if self.pre else data.replace('\n', ' ')
if self.tags == 'h1':
self.hprefix = d[0:d.index(' ')]
if self.tags in ['h1', 'h2', 'h3'] and self.hprefix != '':
if d[0:len(self.hprefix)] == self.hprefix:
d = d[len(self.hprefix):].strip()
self.data += d
self.text.insert('end', d, self.tags)
class HelpText(Text):
"Display idle.html."
def __init__(self, parent, filename):
"Configure tags and feed file to parser."
Text.__init__(self, parent, wrap='word', highlightthickness=0,
padx=5, borderwidth=0)
normalfont = self.findfont(['TkDefaultFont', 'arial', 'helvetica'])
fixedfont = self.findfont(['TkFixedFont', 'monaco', 'courier'])
self['font'] = (normalfont, 12)
self.tag_configure('em', font=(normalfont, 12, 'italic'))
self.tag_configure('h1', font=(normalfont, 20, 'bold'))
self.tag_configure('h2', font=(normalfont, 18, 'bold'))
self.tag_configure('h3', font=(normalfont, 15, 'bold'))
self.tag_configure('pre', font=(fixedfont, 12))
self.tag_configure('preblock', font=(fixedfont, 10), lmargin1=25,
borderwidth=1, relief='solid', background='#eeffcc')
self.tag_configure('l1', lmargin1=25, lmargin2=25)
self.tag_configure('l2', lmargin1=50, lmargin2=50)
self.tag_configure('l3', lmargin1=75, lmargin2=75)
self.tag_configure('l4', lmargin1=100, lmargin2=100)
self.parser = HelpParser(self)
with open(filename, encoding='utf-8') as f:
contents = f.read()
self.parser.feed(contents)
self['state'] = 'disabled'
def findfont(self, names):
"Return name of first font family derived from names."
for name in names:
if name.lower() in (x.lower() for x in tkfont.names(root=self)):
font = tkfont.Font(name=name, exists=True, root=self)
return font.actual()['family']
elif name.lower() in (x.lower()
for x in tkfont.families(root=self)):
return name
class HelpFrame(Frame):
def __init__(self, parent, filename):
Frame.__init__(self, parent)
text = HelpText(self, filename)
self['background'] = text['background']
scroll = Scrollbar(self, command=text.yview)
text['yscrollcommand'] = scroll.set
text.grid(column=1, row=0, sticky='nsew')
scroll.grid(column=2, row=0, sticky='ns')
self.grid_columnconfigure(1, weight=1)
self.grid_rowconfigure(0, weight=1)
toc = self.contents_widget(text)
toc.grid(column=0, row=0, sticky='nw')
def contents_widget(self, text):
toc = Menubutton(self, text='TOC')
drop = Menu(toc, tearoff=False)
for tag, lbl in text.parser.contents:
drop.add_command(label=lbl, command=lambda mark=tag:text.see(mark))
toc['menu'] = drop
return toc
class HelpWindow(Toplevel):
def __init__(self, parent, filename, title):
Toplevel.__init__(self, parent)
self.wm_title(title)
self.protocol("WM_DELETE_WINDOW", self.destroy)
HelpFrame(self, filename).grid(column=0, row=0, sticky='nsew')
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
def show_idlehelp(parent):
filename = join(abspath(dirname(__file__)), 'idle.html')
if not isfile(filename):
dirpath = join(abspath(dirname(dirname(dirname(__file__)))),
'Doc', 'build', 'html', 'library')
HelpWindow(parent, filename, 'IDLE Help')
if __name__ == '__main__':
from idlelib.idle_test.htest import run
run(show_idlehelp)
This file, idlelib/help.txt is out-of-date and no longer used by Idle.
It is deprecated and will be removed in the future, possibly in 3.6
----------------------------------------------------------------------
[See the end of this file for ** TIPS ** on using IDLE !!]
IDLE is the Python IDE built with the tkinter GUI toolkit.
......
This diff is collapsed.
......@@ -194,13 +194,6 @@ _grep_dialog_spec = {
"should open that file \nin a new EditorWindow."
}
_help_dialog_spec = {
'file': 'EditorWindow',
'kwds': {},
'msg': "If the help text displays, this works.\n"
"Text is selectable. Window is scrollable."
}
_io_binding_spec = {
'file': 'IOBinding',
'kwds': {},
......@@ -279,6 +272,13 @@ _scrolled_list_spec = {
"Right clicking an item will display a popup."
}
show_idlehelp_spec = {
'file': 'help',
'kwds': {},
'msg': "If the help text displays, this works.\n"
"Text is selectable. Window is scrollable."
}
_stack_viewer_spec = {
'file': 'StackViewer',
'kwds': {},
......
......@@ -174,9 +174,8 @@ def overrideRootMenu(root, flist):
configDialog.ConfigDialog(root, 'Settings')
def help_dialog(event=None):
from idlelib import textView
fn = path.join(path.abspath(path.dirname(__file__)), 'help.txt')
textView.view_file(root, 'Help', fn)
from idlelib import help
help.show_idlehelp(root)
root.bind('<<about-idle>>', about_dialog)
root.bind('<<open-config-dialog>>', config_dialog)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment