blob: 64b376011fd1884e7efeef03cfca7a83343e302a [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, {
30 Pack: {'expand': 1, 'fill': 'both'}})
31 self.master = self.frame.master
32 self.subframe = Frame(self.frame, {
33 Pack: {'expand': 0, 'fill': 'both'}})
Guido van Rossum36ea0e71994-07-11 13:15:05 +000034 self.leftsubframe = Frame(self.subframe, {
Guido van Rossumf09b7701994-07-06 21:17:21 +000035 Pack: {'side': 'left', 'expand': 1, 'fill': 'both'}})
Guido van Rossum36ea0e71994-07-11 13:15:05 +000036 self.rightsubframe = Frame(self.subframe, {
37 Pack: {'side': 'right', 'expand': 1, 'fill': 'both'}})
38 self.chaptervar = StringVar(master)
39 self.chapter = Menubutton(self.rightsubframe,
40 {'text': 'Directory',
41 'relief': 'raised', 'bd': 2,
42 Pack: {'side': 'top'}})
43 self.chaptermenu = Menu(self.chapter)
44 self.chaptermenu.add_radiobutton({'label': 'C functions',
45 'value': MAN3DIR,
46 'variable': self.chaptervar,
47 'command': self.newchapter})
48 self.chaptermenu.add_radiobutton({'label': 'Tcl/Tk functions',
49 'value': MANNDIR,
50 'variable': self.chaptervar,
51 'command': self.newchapter})
52 self.chapter['menu'] = self.chaptermenu
53 self.listbox = Listbox(self.rightsubframe,
54 {'relief': 'sunken', 'bd': 2,
55 'geometry': '20x5',
56 Pack: {'expand': 1, 'fill': 'both'}})
57 self.l1 = Button(self.leftsubframe,
Guido van Rossumf09b7701994-07-06 21:17:21 +000058 {'text': 'Display manual page named:',
Guido van Rossum119749b1994-07-08 14:28:38 +000059 'command': self.entry_cb,
Guido van Rossumf09b7701994-07-06 21:17:21 +000060 Pack: {'side': 'top'}})
Guido van Rossum36ea0e71994-07-11 13:15:05 +000061 self.entry = Entry(self.leftsubframe,
Guido van Rossumf09b7701994-07-06 21:17:21 +000062 {'relief': 'sunken', 'bd': 2,
63 'width': 20,
64 Pack: {'side': 'top',
65 'expand': 0, 'fill': 'x'}})
Guido van Rossum36ea0e71994-07-11 13:15:05 +000066 self.l2frame = Frame(self.leftsubframe, {
Guido van Rossum119749b1994-07-08 14:28:38 +000067 Pack: {'expand': 0, 'fill': 'none'}})
68 self.l2 = Button(self.l2frame,
69 {'text': 'Search regexp:',
70 'command': self.search_cb,
71 Pack: {'side': 'left'}})
72 self.casesense = Checkbutton(self.l2frame,
73 {'text': 'Case sensitive',
74 'variable': 'casesense',
75 'relief': 'flat',
76 Pack: {'side': 'left'}})
Guido van Rossum36ea0e71994-07-11 13:15:05 +000077 self.search = Entry(self.leftsubframe,
Guido van Rossumf09b7701994-07-06 21:17:21 +000078 {'relief': 'sunken', 'bd': 2,
79 'width': 20,
80 Pack: {'side': 'top',
81 'expand': 0, 'fill': 'x'}})
Guido van Rossum36ea0e71994-07-11 13:15:05 +000082 self.title = Label(self.leftsubframe,
Guido van Rossumf09b7701994-07-06 21:17:21 +000083 {'text': '(none)',
84 Pack: {'side': 'bottom'}})
85 self.text = ManPage(self.frame,
86 {'relief': 'sunken', 'bd': 2,
87 'wrap': 'none', 'width': 72,
88 Pack: {'expand': 1, 'fill': 'both'}})
89
90 self.entry.bind('<Return>', self.entry_cb)
91 self.search.bind('<Return>', self.search_cb)
92 self.listbox.bind('<Double-1>', self.listbox_cb)
93
Guido van Rossum119749b1994-07-08 14:28:38 +000094 self.entry.bind('<Tab>', self.entry_tab)
95 self.search.bind('<Tab>', self.search_tab)
96 self.text.bind('<Tab>', self.text_tab)
Guido van Rossumf09b7701994-07-06 21:17:21 +000097
Guido van Rossum119749b1994-07-08 14:28:38 +000098 self.entry.focus_set()
Guido van Rossumf09b7701994-07-06 21:17:21 +000099
Guido van Rossum36ea0e71994-07-11 13:15:05 +0000100 self.chaptervar.set(MANNDIR)
101 self.newchapter()
102
103 def newchapter(self):
104 mandir = self.chaptervar.get()
105 self.choices = []
106 self.addlist(listmanpages(mandir))
107
Guido van Rossumf09b7701994-07-06 21:17:21 +0000108 def addchoice(self, choice):
109 if choice not in self.choices:
110 self.choices.append(choice)
111 self.choices.sort()
112 self.update()
113
114 def addlist(self, list):
115 self.choices[len(self.choices):] = list
116 self.choices.sort()
117 self.update()
118
Guido van Rossum119749b1994-07-08 14:28:38 +0000119 def entry_cb(self, *e):
120 self.update()
121
122 def listbox_cb(self, e):
123 selection = self.listbox.curselection()
124 if selection and len(selection) == 1:
125 name = self.listbox.get(selection[0])
126 self.show_page(name)
127
128 def search_cb(self, *e):
129 self.search_string(self.search.get())
130
131 def entry_tab(self, e):
132 self.search.focus_set()
133
134 def search_tab(self, e):
135 self.entry.focus_set()
136
137 def text_tab(self, e):
138 self.entry.focus_set()
139
Guido van Rossumf09b7701994-07-06 21:17:21 +0000140 def updatelist(self):
141 key = self.entry.get()
142 ok = filter(lambda name, key=key, n=len(key): name[:n]==key,
143 self.choices)
144 self.listbox.delete(0, AtEnd())
145 exactmatch = 0
146 for item in ok:
147 if item == key: exactmatch = 1
148 self.listbox.insert(AtEnd(), item)
149 if exactmatch:
150 return key
151 elif self.listbox.size() == 1:
152 return self.listbox.get(0)
Guido van Rossum119749b1994-07-08 14:28:38 +0000153 # Else return None, meaning not a unique selection
Guido van Rossumf09b7701994-07-06 21:17:21 +0000154
155 def update(self):
Guido van Rossum119749b1994-07-08 14:28:38 +0000156 name = self.updatelist()
157 if name:
158 self.show_page(name)
159 self.entry.delete(0, AtEnd())
160 self.updatelist()
Guido van Rossumf09b7701994-07-06 21:17:21 +0000161
162 def show_page(self, name):
Guido van Rossum36ea0e71994-07-11 13:15:05 +0000163 file = '%s/%s.?' % (self.chaptervar.get(), name)
Guido van Rossum119749b1994-07-08 14:28:38 +0000164 fp = os.popen('nroff -man %s | ul -i' % file, 'r')
165 self.text.kill()
166 self.title['text'] = name
Guido van Rossumf09b7701994-07-06 21:17:21 +0000167 self.text.parsefile(fp)
Guido van Rossumf09b7701994-07-06 21:17:21 +0000168
169 def search_string(self, search):
170 if not search:
171 print 'Empty search string'
172 return
Guido van Rossum119749b1994-07-08 14:28:38 +0000173 if self.frame.tk.getvar('casesense') != '1':
174 map = regex.casefold
175 else:
176 map = None
Guido van Rossumf09b7701994-07-06 21:17:21 +0000177 try:
Guido van Rossum119749b1994-07-08 14:28:38 +0000178 if map:
179 prog = regex.compile(search, map)
180 else:
181 prog = regex.compile(search)
Guido van Rossumf09b7701994-07-06 21:17:21 +0000182 except regex.error, msg:
183 print 'Regex error:', msg
184 return
185 here = self.text.index(AtInsert())
186 lineno = string.atoi(here[:string.find(here, '.')])
187 end = self.text.index(AtEnd())
188 endlineno = string.atoi(end[:string.find(end, '.')])
189 wraplineno = lineno
190 while 1:
191 lineno = lineno + 1
192 if lineno > endlineno:
193 if wraplineno <= 0:
194 break
195 endlineno = wraplineno
196 lineno = 0
197 wraplineno = 0
198 line = self.text.get('%d.0 linestart' % lineno,
199 '%d.0 lineend' % lineno)
200 i = prog.search(line)
201 if i >= 0:
202 n = max(1, len(prog.group(0)))
203 try:
204 self.text.tag_remove('sel',
205 AtSelFirst(),
206 AtSelLast())
207 except TclError:
208 pass
209 self.text.tag_add('sel',
210 '%d.%d' % (lineno, i),
211 '%d.%d' % (lineno, i+n))
212 self.text.mark_set(AtInsert(),
213 '%d.%d' % (lineno, i))
214 self.text.yview_pickplace(AtInsert())
215 break
216
217def main():
218 root = Tk()
219 sb = SelectionBox(root)
Guido van Rossumf09b7701994-07-06 21:17:21 +0000220 if sys.argv[1:]:
221 sb.show_page(sys.argv[1])
222 root.minsize(1, 1)
223 root.mainloop()
224
225main()