blob: c84d889629026f2ef7632f4ecee34890ef9b03c0 [file] [log] [blame]
Guido van Rossumf06ee5f1996-11-27 19:52:01 +00001#! /usr/bin/env python
Guido van Rossumf09b7701994-07-06 21:17:21 +00002
3# Tk man page browser -- currently only shows the Tcl/Tk man pages
4
5import sys
6import os
7import string
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00008import re
Guido van Rossumf09b7701994-07-06 21:17:21 +00009from Tkinter import *
10from ManPage import ManPage
11
Guido van Rossuma2f626f1997-09-15 15:39:11 +000012MANNDIRLIST = ['/depot/sundry/man/mann','/usr/local/man/mann']
13MAN3DIRLIST = ['/depot/sundry/man/man3','/usr/local/man/man3']
14
15foundmanndir = 0
16for dir in MANNDIRLIST:
17 if os.path.exists(dir):
Tim Peters182b5ac2004-07-18 06:16:08 +000018 MANNDIR = dir
19 foundmanndir = 1
Guido van Rossuma2f626f1997-09-15 15:39:11 +000020
21foundman3dir = 0
22for dir in MAN3DIRLIST:
23 if os.path.exists(dir):
Tim Peters182b5ac2004-07-18 06:16:08 +000024 MAN3DIR = dir
25 foundman3dir = 1
Guido van Rossuma2f626f1997-09-15 15:39:11 +000026
27if not foundmanndir or not foundman3dir:
28 sys.stderr.write('\n')
29 if not foundmanndir:
Tim Peters182b5ac2004-07-18 06:16:08 +000030 msg = """\
Guido van Rossuma2f626f1997-09-15 15:39:11 +000031Failed to find mann directory.
Tim Peters182b5ac2004-07-18 06:16:08 +000032Please add the correct entry to the MANNDIRLIST
Guido van Rossuma2f626f1997-09-15 15:39:11 +000033at the top of %s script.""" % \
34sys.argv[0]
Tim Peters182b5ac2004-07-18 06:16:08 +000035 sys.stderr.write("%s\n\n" % msg)
Guido van Rossuma2f626f1997-09-15 15:39:11 +000036 if not foundman3dir:
Tim Peters182b5ac2004-07-18 06:16:08 +000037 msg = """\
Guido van Rossuma2f626f1997-09-15 15:39:11 +000038Failed to find man3 directory.
Tim Peters182b5ac2004-07-18 06:16:08 +000039Please add the correct entry to the MAN3DIRLIST
Guido van Rossuma2f626f1997-09-15 15:39:11 +000040at the top of %s script.""" % \
41sys.argv[0]
Tim Peters182b5ac2004-07-18 06:16:08 +000042 sys.stderr.write("%s\n\n" % msg)
Guido van Rossuma2f626f1997-09-15 15:39:11 +000043 sys.exit(1)
44
45del foundmanndir
46del foundman3dir
Guido van Rossumf09b7701994-07-06 21:17:21 +000047
Guido van Rossum36ea0e71994-07-11 13:15:05 +000048def listmanpages(mandir):
Tim Peters182b5ac2004-07-18 06:16:08 +000049 files = os.listdir(mandir)
50 names = []
51 for file in files:
52 if file[-2:-1] == '.' and (file[-1] in 'ln123456789'):
53 names.append(file[:-2])
54 names.sort()
55 return names
Guido van Rossumf09b7701994-07-06 21:17:21 +000056
57class SelectionBox:
58
Tim Peters182b5ac2004-07-18 06:16:08 +000059 def __init__(self, master=None):
60 self.choices = []
Guido van Rossumf09b7701994-07-06 21:17:21 +000061
Tim Peters182b5ac2004-07-18 06:16:08 +000062 self.frame = Frame(master, name="frame")
63 self.frame.pack(expand=1, fill=BOTH)
64 self.master = self.frame.master
65 self.subframe = Frame(self.frame, name="subframe")
66 self.subframe.pack(expand=0, fill=BOTH)
67 self.leftsubframe = Frame(self.subframe, name='leftsubframe')
68 self.leftsubframe.pack(side=LEFT, expand=1, fill=BOTH)
69 self.rightsubframe = Frame(self.subframe, name='rightsubframe')
70 self.rightsubframe.pack(side=RIGHT, expand=1, fill=BOTH)
71 self.chaptervar = StringVar(master)
72 self.chapter = Menubutton(self.rightsubframe, name='chapter',
73 text='Directory', relief=RAISED,
74 borderwidth=2)
75 self.chapter.pack(side=TOP)
76 self.chaptermenu = Menu(self.chapter, name='chaptermenu')
77 self.chaptermenu.add_radiobutton(label='C functions',
78 value=MAN3DIR,
79 variable=self.chaptervar,
80 command=self.newchapter)
81 self.chaptermenu.add_radiobutton(label='Tcl/Tk functions',
82 value=MANNDIR,
83 variable=self.chaptervar,
84 command=self.newchapter)
85 self.chapter['menu'] = self.chaptermenu
86 self.listbox = Listbox(self.rightsubframe, name='listbox',
87 relief=SUNKEN, borderwidth=2,
88 width=20, height=5)
89 self.listbox.pack(expand=1, fill=BOTH)
90 self.l1 = Button(self.leftsubframe, name='l1',
91 text='Display manual page named:',
92 command=self.entry_cb)
93 self.l1.pack(side=TOP)
94 self.entry = Entry(self.leftsubframe, name='entry',
95 relief=SUNKEN, borderwidth=2,
96 width=20)
97 self.entry.pack(expand=0, fill=X)
98 self.l2frame = Frame(self.leftsubframe, name='l2frame')
99 self.l2frame.pack(expand=0, fill=NONE)
100 self.l2 = Button(self.l2frame, name='l2',
101 text='Search regexp:',
102 command=self.search_cb)
103 self.l2.pack(side=LEFT)
104 self.casevar = BooleanVar()
105 self.casesense = Checkbutton(self.l2frame, name='casesense',
106 text='Case sensitive',
107 variable=self.casevar,
108 relief=FLAT)
109 self.casesense.pack(side=LEFT)
110 self.search = Entry(self.leftsubframe, name='search',
111 relief=SUNKEN, borderwidth=2,
112 width=20)
113 self.search.pack(expand=0, fill=X)
114 self.title = Label(self.leftsubframe, name='title',
115 text='(none)')
116 self.title.pack(side=BOTTOM)
117 self.text = ManPage(self.frame, name='text',
118 relief=SUNKEN, borderwidth=2,
119 wrap=NONE, width=72,
120 selectbackground='pink')
121 self.text.pack(expand=1, fill=BOTH)
Guido van Rossumf09b7701994-07-06 21:17:21 +0000122
Tim Peters182b5ac2004-07-18 06:16:08 +0000123 self.entry.bind('<Return>', self.entry_cb)
124 self.search.bind('<Return>', self.search_cb)
125 self.listbox.bind('<Double-1>', self.listbox_cb)
Guido van Rossumf09b7701994-07-06 21:17:21 +0000126
Tim Peters182b5ac2004-07-18 06:16:08 +0000127 self.entry.bind('<Tab>', self.entry_tab)
128 self.search.bind('<Tab>', self.search_tab)
129 self.text.bind('<Tab>', self.text_tab)
Guido van Rossumf09b7701994-07-06 21:17:21 +0000130
Tim Peters182b5ac2004-07-18 06:16:08 +0000131 self.entry.focus_set()
Guido van Rossumf09b7701994-07-06 21:17:21 +0000132
Tim Peters182b5ac2004-07-18 06:16:08 +0000133 self.chaptervar.set(MANNDIR)
134 self.newchapter()
Guido van Rossum36ea0e71994-07-11 13:15:05 +0000135
Tim Peters182b5ac2004-07-18 06:16:08 +0000136 def newchapter(self):
137 mandir = self.chaptervar.get()
138 self.choices = []
139 self.addlist(listmanpages(mandir))
Guido van Rossum36ea0e71994-07-11 13:15:05 +0000140
Tim Peters182b5ac2004-07-18 06:16:08 +0000141 def addchoice(self, choice):
142 if choice not in self.choices:
143 self.choices.append(choice)
144 self.choices.sort()
145 self.update()
Guido van Rossumf09b7701994-07-06 21:17:21 +0000146
Tim Peters182b5ac2004-07-18 06:16:08 +0000147 def addlist(self, list):
148 self.choices[len(self.choices):] = list
149 self.choices.sort()
150 self.update()
Guido van Rossumf09b7701994-07-06 21:17:21 +0000151
Tim Peters182b5ac2004-07-18 06:16:08 +0000152 def entry_cb(self, *e):
153 self.update()
Guido van Rossum119749b1994-07-08 14:28:38 +0000154
Tim Peters182b5ac2004-07-18 06:16:08 +0000155 def listbox_cb(self, e):
156 selection = self.listbox.curselection()
157 if selection and len(selection) == 1:
158 name = self.listbox.get(selection[0])
159 self.show_page(name)
Guido van Rossum119749b1994-07-08 14:28:38 +0000160
Tim Peters182b5ac2004-07-18 06:16:08 +0000161 def search_cb(self, *e):
162 self.search_string(self.search.get())
Guido van Rossum119749b1994-07-08 14:28:38 +0000163
Tim Peters182b5ac2004-07-18 06:16:08 +0000164 def entry_tab(self, e):
165 self.search.focus_set()
Guido van Rossum119749b1994-07-08 14:28:38 +0000166
Tim Peters182b5ac2004-07-18 06:16:08 +0000167 def search_tab(self, e):
168 self.entry.focus_set()
Guido van Rossum119749b1994-07-08 14:28:38 +0000169
Tim Peters182b5ac2004-07-18 06:16:08 +0000170 def text_tab(self, e):
171 self.entry.focus_set()
Guido van Rossum119749b1994-07-08 14:28:38 +0000172
Tim Peters182b5ac2004-07-18 06:16:08 +0000173 def updatelist(self):
174 key = self.entry.get()
Collin Winter6f2df4d2007-07-17 20:59:35 +0000175 ok = list(filter(lambda name, key=key, n=len(key): name[:n]==key,
176 self.choices))
Tim Peters182b5ac2004-07-18 06:16:08 +0000177 if not ok:
178 self.frame.bell()
179 self.listbox.delete(0, AtEnd())
180 exactmatch = 0
181 for item in ok:
182 if item == key: exactmatch = 1
183 self.listbox.insert(AtEnd(), item)
184 if exactmatch:
185 return key
186 n = self.listbox.size()
187 if n == 1:
188 return self.listbox.get(0)
189 # Else return None, meaning not a unique selection
Guido van Rossumf09b7701994-07-06 21:17:21 +0000190
Tim Peters182b5ac2004-07-18 06:16:08 +0000191 def update(self):
192 name = self.updatelist()
193 if name:
194 self.show_page(name)
195 self.entry.delete(0, AtEnd())
196 self.updatelist()
Guido van Rossumf09b7701994-07-06 21:17:21 +0000197
Tim Peters182b5ac2004-07-18 06:16:08 +0000198 def show_page(self, name):
199 file = '%s/%s.?' % (self.chaptervar.get(), name)
200 fp = os.popen('nroff -man %s | ul -i' % file, 'r')
201 self.text.kill()
202 self.title['text'] = name
203 self.text.parsefile(fp)
Guido van Rossumf09b7701994-07-06 21:17:21 +0000204
Tim Peters182b5ac2004-07-18 06:16:08 +0000205 def search_string(self, search):
206 if not search:
207 self.frame.bell()
Collin Winter6f2df4d2007-07-17 20:59:35 +0000208 print('Empty search string')
Tim Peters182b5ac2004-07-18 06:16:08 +0000209 return
210 if not self.casevar.get():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000211 map = re.IGNORECASE
Tim Peters182b5ac2004-07-18 06:16:08 +0000212 else:
213 map = None
214 try:
215 if map:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000216 prog = re.compile(search, map)
Tim Peters182b5ac2004-07-18 06:16:08 +0000217 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000218 prog = re.compile(search)
Guido van Rossumb940e112007-01-10 16:19:56 +0000219 except re.error as msg:
Tim Peters182b5ac2004-07-18 06:16:08 +0000220 self.frame.bell()
Collin Winter6f2df4d2007-07-17 20:59:35 +0000221 print('Regex error:', msg)
Tim Peters182b5ac2004-07-18 06:16:08 +0000222 return
223 here = self.text.index(AtInsert())
224 lineno = string.atoi(here[:string.find(here, '.')])
225 end = self.text.index(AtEnd())
226 endlineno = string.atoi(end[:string.find(end, '.')])
227 wraplineno = lineno
228 found = 0
229 while 1:
230 lineno = lineno + 1
231 if lineno > endlineno:
232 if wraplineno <= 0:
233 break
234 endlineno = wraplineno
235 lineno = 0
236 wraplineno = 0
237 line = self.text.get('%d.0 linestart' % lineno,
238 '%d.0 lineend' % lineno)
239 i = prog.search(line)
240 if i >= 0:
241 found = 1
242 n = max(1, len(prog.group(0)))
243 try:
244 self.text.tag_remove('sel',
245 AtSelFirst(),
246 AtSelLast())
247 except TclError:
248 pass
249 self.text.tag_add('sel',
250 '%d.%d' % (lineno, i),
251 '%d.%d' % (lineno, i+n))
252 self.text.mark_set(AtInsert(),
253 '%d.%d' % (lineno, i))
254 self.text.yview_pickplace(AtInsert())
255 break
256 if not found:
257 self.frame.bell()
Guido van Rossumf09b7701994-07-06 21:17:21 +0000258
259def main():
Tim Peters182b5ac2004-07-18 06:16:08 +0000260 root = Tk()
261 sb = SelectionBox(root)
262 if sys.argv[1:]:
263 sb.show_page(sys.argv[1])
264 root.minsize(1, 1)
265 root.mainloop()
Guido van Rossumf09b7701994-07-06 21:17:21 +0000266
267main()