blob: fecf962202b8f4c72ff5fed8ee128157c1039238 [file] [log] [blame]
Guido van Rossumf09b7701994-07-06 21:17:21 +00001#! /ufs/guido/bin/sgi/tkpython
2
3# Tk man page browser -- currently only shows the Tcl/Tk man pages
4
5import sys
6import os
7import string
8import regex
9from Tkinter import *
10from ManPage import ManPage
11
Guido van Rossum36ea0e71994-07-11 13:15:05 +000012MANNDIR = '/usr/local/man/mann'
13MAN3DIR = '/usr/local/man/man3'
Guido van Rossumf09b7701994-07-06 21:17:21 +000014
Guido van Rossum36ea0e71994-07-11 13:15:05 +000015def listmanpages(mandir):
Guido van Rossumf09b7701994-07-06 21:17:21 +000016 files = os.listdir(mandir)
17 names = []
18 for file in files:
Guido van Rossum36ea0e71994-07-11 13:15:05 +000019 if file[-2:-1] == '.' and (file[-1] in 'ln123456789'):
Guido van Rossumf09b7701994-07-06 21:17:21 +000020 names.append(file[:-2])
21 names.sort()
22 return names
23
24class SelectionBox:
25
26 def __init__(self, master=None):
27 self.choices = []
28
29 self.frame = Frame(master, {
Guido van Rossum3e4f1821994-07-12 16:35:35 +000030 'name': 'frame',
Guido van Rossumf09b7701994-07-06 21:17:21 +000031 Pack: {'expand': 1, 'fill': 'both'}})
32 self.master = self.frame.master
33 self.subframe = Frame(self.frame, {
Guido van Rossum3e4f1821994-07-12 16:35:35 +000034 'name': 'subframe',
Guido van Rossumf09b7701994-07-06 21:17:21 +000035 Pack: {'expand': 0, 'fill': 'both'}})
Guido van Rossum36ea0e71994-07-11 13:15:05 +000036 self.leftsubframe = Frame(self.subframe, {
Guido van Rossum3e4f1821994-07-12 16:35:35 +000037 'name': 'leftsubframe',
Guido van Rossumf09b7701994-07-06 21:17:21 +000038 Pack: {'side': 'left', 'expand': 1, 'fill': 'both'}})
Guido van Rossum36ea0e71994-07-11 13:15:05 +000039 self.rightsubframe = Frame(self.subframe, {
Guido van Rossum3e4f1821994-07-12 16:35:35 +000040 'name': 'rightsubframe',
Guido van Rossum36ea0e71994-07-11 13:15:05 +000041 Pack: {'side': 'right', 'expand': 1, 'fill': 'both'}})
42 self.chaptervar = StringVar(master)
43 self.chapter = Menubutton(self.rightsubframe,
Guido van Rossum3e4f1821994-07-12 16:35:35 +000044 {'name': 'chapter',
45 'text': 'Directory',
Guido van Rossum36ea0e71994-07-11 13:15:05 +000046 'relief': 'raised', 'bd': 2,
47 Pack: {'side': 'top'}})
Guido van Rossum3e4f1821994-07-12 16:35:35 +000048 self.chaptermenu = Menu(self.chapter, {'name': 'chaptermenu'})
Guido van Rossum36ea0e71994-07-11 13:15:05 +000049 self.chaptermenu.add_radiobutton({'label': 'C functions',
50 'value': MAN3DIR,
51 'variable': self.chaptervar,
52 'command': self.newchapter})
53 self.chaptermenu.add_radiobutton({'label': 'Tcl/Tk functions',
54 'value': MANNDIR,
55 'variable': self.chaptervar,
56 'command': self.newchapter})
57 self.chapter['menu'] = self.chaptermenu
58 self.listbox = Listbox(self.rightsubframe,
Guido van Rossum3e4f1821994-07-12 16:35:35 +000059 {'name': 'listbox',
60 'relief': 'sunken', 'bd': 2,
Guido van Rossum36ea0e71994-07-11 13:15:05 +000061 'geometry': '20x5',
62 Pack: {'expand': 1, 'fill': 'both'}})
63 self.l1 = Button(self.leftsubframe,
Guido van Rossum3e4f1821994-07-12 16:35:35 +000064 {'name': 'l1',
65 'text': 'Display manual page named:',
Guido van Rossum119749b1994-07-08 14:28:38 +000066 'command': self.entry_cb,
Guido van Rossumf09b7701994-07-06 21:17:21 +000067 Pack: {'side': 'top'}})
Guido van Rossum36ea0e71994-07-11 13:15:05 +000068 self.entry = Entry(self.leftsubframe,
Guido van Rossum3e4f1821994-07-12 16:35:35 +000069 {'name': 'entry',
70 'relief': 'sunken', 'bd': 2,
Guido van Rossumf09b7701994-07-06 21:17:21 +000071 'width': 20,
72 Pack: {'side': 'top',
73 'expand': 0, 'fill': 'x'}})
Guido van Rossum3e4f1821994-07-12 16:35:35 +000074 self.l2frame = Frame(self.leftsubframe,
75 {'name': 'l2frame',
76 Pack: {'expand': 0, 'fill': 'none'}})
Guido van Rossum119749b1994-07-08 14:28:38 +000077 self.l2 = Button(self.l2frame,
Guido van Rossum3e4f1821994-07-12 16:35:35 +000078 {'name': 'l2',
79 'text': 'Search regexp:',
Guido van Rossum119749b1994-07-08 14:28:38 +000080 'command': self.search_cb,
81 Pack: {'side': 'left'}})
82 self.casesense = Checkbutton(self.l2frame,
Guido van Rossum3e4f1821994-07-12 16:35:35 +000083 {'name': 'casesense',
84 'text': 'Case sensitive',
Guido van Rossum119749b1994-07-08 14:28:38 +000085 'variable': 'casesense',
86 'relief': 'flat',
87 Pack: {'side': 'left'}})
Guido van Rossum36ea0e71994-07-11 13:15:05 +000088 self.search = Entry(self.leftsubframe,
Guido van Rossum3e4f1821994-07-12 16:35:35 +000089 {'name': 'search',
90 'relief': 'sunken', 'bd': 2,
Guido van Rossumf09b7701994-07-06 21:17:21 +000091 'width': 20,
92 Pack: {'side': 'top',
93 'expand': 0, 'fill': 'x'}})
Guido van Rossum36ea0e71994-07-11 13:15:05 +000094 self.title = Label(self.leftsubframe,
Guido van Rossum3e4f1821994-07-12 16:35:35 +000095 {'name': 'title',
96 'text': '(none)',
Guido van Rossumf09b7701994-07-06 21:17:21 +000097 Pack: {'side': 'bottom'}})
98 self.text = ManPage(self.frame,
Guido van Rossum3e4f1821994-07-12 16:35:35 +000099 {'name': 'text',
100 'relief': 'sunken', 'bd': 2,
Guido van Rossumf09b7701994-07-06 21:17:21 +0000101 'wrap': 'none', 'width': 72,
102 Pack: {'expand': 1, 'fill': 'both'}})
103
104 self.entry.bind('<Return>', self.entry_cb)
105 self.search.bind('<Return>', self.search_cb)
106 self.listbox.bind('<Double-1>', self.listbox_cb)
107
Guido van Rossum119749b1994-07-08 14:28:38 +0000108 self.entry.bind('<Tab>', self.entry_tab)
109 self.search.bind('<Tab>', self.search_tab)
110 self.text.bind('<Tab>', self.text_tab)
Guido van Rossumf09b7701994-07-06 21:17:21 +0000111
Guido van Rossum119749b1994-07-08 14:28:38 +0000112 self.entry.focus_set()
Guido van Rossumf09b7701994-07-06 21:17:21 +0000113
Guido van Rossum36ea0e71994-07-11 13:15:05 +0000114 self.chaptervar.set(MANNDIR)
115 self.newchapter()
116
117 def newchapter(self):
118 mandir = self.chaptervar.get()
119 self.choices = []
120 self.addlist(listmanpages(mandir))
121
Guido van Rossumf09b7701994-07-06 21:17:21 +0000122 def addchoice(self, choice):
123 if choice not in self.choices:
124 self.choices.append(choice)
125 self.choices.sort()
126 self.update()
127
128 def addlist(self, list):
129 self.choices[len(self.choices):] = list
130 self.choices.sort()
131 self.update()
132
Guido van Rossum119749b1994-07-08 14:28:38 +0000133 def entry_cb(self, *e):
134 self.update()
135
136 def listbox_cb(self, e):
137 selection = self.listbox.curselection()
138 if selection and len(selection) == 1:
139 name = self.listbox.get(selection[0])
140 self.show_page(name)
141
142 def search_cb(self, *e):
143 self.search_string(self.search.get())
144
145 def entry_tab(self, e):
146 self.search.focus_set()
147
148 def search_tab(self, e):
149 self.entry.focus_set()
150
151 def text_tab(self, e):
152 self.entry.focus_set()
153
Guido van Rossumf09b7701994-07-06 21:17:21 +0000154 def updatelist(self):
155 key = self.entry.get()
156 ok = filter(lambda name, key=key, n=len(key): name[:n]==key,
157 self.choices)
158 self.listbox.delete(0, AtEnd())
159 exactmatch = 0
160 for item in ok:
161 if item == key: exactmatch = 1
162 self.listbox.insert(AtEnd(), item)
163 if exactmatch:
164 return key
165 elif self.listbox.size() == 1:
166 return self.listbox.get(0)
Guido van Rossum119749b1994-07-08 14:28:38 +0000167 # Else return None, meaning not a unique selection
Guido van Rossumf09b7701994-07-06 21:17:21 +0000168
169 def update(self):
Guido van Rossum119749b1994-07-08 14:28:38 +0000170 name = self.updatelist()
171 if name:
172 self.show_page(name)
173 self.entry.delete(0, AtEnd())
174 self.updatelist()
Guido van Rossumf09b7701994-07-06 21:17:21 +0000175
176 def show_page(self, name):
Guido van Rossum36ea0e71994-07-11 13:15:05 +0000177 file = '%s/%s.?' % (self.chaptervar.get(), name)
Guido van Rossum119749b1994-07-08 14:28:38 +0000178 fp = os.popen('nroff -man %s | ul -i' % file, 'r')
179 self.text.kill()
180 self.title['text'] = name
Guido van Rossumf09b7701994-07-06 21:17:21 +0000181 self.text.parsefile(fp)
Guido van Rossumf09b7701994-07-06 21:17:21 +0000182
183 def search_string(self, search):
184 if not search:
185 print 'Empty search string'
186 return
Guido van Rossum119749b1994-07-08 14:28:38 +0000187 if self.frame.tk.getvar('casesense') != '1':
188 map = regex.casefold
189 else:
190 map = None
Guido van Rossumf09b7701994-07-06 21:17:21 +0000191 try:
Guido van Rossum119749b1994-07-08 14:28:38 +0000192 if map:
193 prog = regex.compile(search, map)
194 else:
195 prog = regex.compile(search)
Guido van Rossumf09b7701994-07-06 21:17:21 +0000196 except regex.error, msg:
197 print 'Regex error:', msg
198 return
199 here = self.text.index(AtInsert())
200 lineno = string.atoi(here[:string.find(here, '.')])
201 end = self.text.index(AtEnd())
202 endlineno = string.atoi(end[:string.find(end, '.')])
203 wraplineno = lineno
204 while 1:
205 lineno = lineno + 1
206 if lineno > endlineno:
207 if wraplineno <= 0:
208 break
209 endlineno = wraplineno
210 lineno = 0
211 wraplineno = 0
212 line = self.text.get('%d.0 linestart' % lineno,
213 '%d.0 lineend' % lineno)
214 i = prog.search(line)
215 if i >= 0:
216 n = max(1, len(prog.group(0)))
217 try:
218 self.text.tag_remove('sel',
219 AtSelFirst(),
220 AtSelLast())
221 except TclError:
222 pass
223 self.text.tag_add('sel',
224 '%d.%d' % (lineno, i),
225 '%d.%d' % (lineno, i+n))
226 self.text.mark_set(AtInsert(),
227 '%d.%d' % (lineno, i))
228 self.text.yview_pickplace(AtInsert())
229 break
230
231def main():
232 root = Tk()
233 sb = SelectionBox(root)
Guido van Rossumf09b7701994-07-06 21:17:21 +0000234 if sys.argv[1:]:
235 sb.show_page(sys.argv[1])
236 root.minsize(1, 1)
237 root.mainloop()
238
239main()