blob: c6610f8d2c7dadf8968840e9141cad5445da29df [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
12MANDIR = '/usr/local/man/mann'
13
14def listmanpages(mandir = MANDIR):
15 files = os.listdir(mandir)
16 names = []
17 for file in files:
18 if file[-2:] == '.n':
19 names.append(file[:-2])
20 names.sort()
21 return names
22
23class SelectionBox:
24
25 def __init__(self, master=None):
26 self.choices = []
27
28 self.frame = Frame(master, {
29 Pack: {'expand': 1, 'fill': 'both'}})
30 self.master = self.frame.master
31 self.subframe = Frame(self.frame, {
32 Pack: {'expand': 0, 'fill': 'both'}})
33 self.listbox = Listbox(self.subframe,
34 {'relief': 'sunken', 'bd': 2,
35 'geometry': '20x6',
36 Pack: {'side': 'right',
37 'expand': 1, 'fill': 'both'}})
38 self.subsubframe = Frame(self.subframe, {
39 Pack: {'side': 'left', 'expand': 1, 'fill': 'both'}})
40 self.l1 = Label(self.subsubframe,
41 {'text': 'Display manual page named:',
42 Pack: {'side': 'top'}})
43 self.entry = Entry(self.subsubframe,
44 {'relief': 'sunken', 'bd': 2,
45 'width': 20,
46 Pack: {'side': 'top',
47 'expand': 0, 'fill': 'x'}})
48 self.l2 = Label(self.subsubframe,
49 {'text': 'Search (regexp, case insensitive):',
50 Pack: {'side': 'top'}})
51 self.search = Entry(self.subsubframe,
52 {'relief': 'sunken', 'bd': 2,
53 'width': 20,
54 Pack: {'side': 'top',
55 'expand': 0, 'fill': 'x'}})
56 self.title = Label(self.subsubframe,
57 {'text': '(none)',
58 Pack: {'side': 'bottom'}})
59 self.text = ManPage(self.frame,
60 {'relief': 'sunken', 'bd': 2,
61 'wrap': 'none', 'width': 72,
62 Pack: {'expand': 1, 'fill': 'both'}})
63
64 self.entry.bind('<Return>', self.entry_cb)
65 self.search.bind('<Return>', self.search_cb)
66 self.listbox.bind('<Double-1>', self.listbox_cb)
67
68 self.entry.focus_set()
69
70 self.showing = None
71
72 def addchoice(self, choice):
73 if choice not in self.choices:
74 self.choices.append(choice)
75 self.choices.sort()
76 self.update()
77
78 def addlist(self, list):
79 self.choices[len(self.choices):] = list
80 self.choices.sort()
81 self.update()
82
83 def updatelist(self):
84 key = self.entry.get()
85 ok = filter(lambda name, key=key, n=len(key): name[:n]==key,
86 self.choices)
87 self.listbox.delete(0, AtEnd())
88 exactmatch = 0
89 for item in ok:
90 if item == key: exactmatch = 1
91 self.listbox.insert(AtEnd(), item)
92 if exactmatch:
93 return key
94 elif self.listbox.size() == 1:
95 return self.listbox.get(0)
96
97 def entry_cb(self, e):
98 self.update()
99
100 def update(self):
101 self.show_page(self.updatelist())
102
103 def show_page(self, name):
104 if not name:
105 return
106 if name == self.showing:
107 print 'show_page: already showing'
108 return
109 name = '%s/%s.n' % (MANDIR, name)
110 fp = os.popen('nroff -man %s | ul -i' % name, 'r')
111 self.text.delete('1.0', AtEnd())
112 frame_cursor = self.frame['cursor']
113 entry_cursor = self.entry['cursor']
114 self.entry['cursor'] = 'watch'
115 self.search['cursor'] = 'watch'
116 self.frame['cursor'] = 'watch'
117 self.text.parsefile(fp)
118 self.search['cursor'] = entry_cursor
119 self.entry['cursor'] = entry_cursor
120 self.frame['cursor'] = frame_cursor
121 self.entry.delete(0, AtEnd())
122 self.updatelist()
123
124 def listbox_cb(self, e):
125 selection = self.listbox.curselection()
126 if selection and len(selection) == 1:
127 which = self.listbox.get(selection[0])
128 self.show_page(which)
129
130 def search_cb(self, e):
131 self.search_string(self.search.get())
132
133 def search_string(self, search):
134 if not search:
135 print 'Empty search string'
136 return
137 try:
138 prog = regex.compile(search, regex.casefold)
139 except regex.error, msg:
140 print 'Regex error:', msg
141 return
142 here = self.text.index(AtInsert())
143 lineno = string.atoi(here[:string.find(here, '.')])
144 end = self.text.index(AtEnd())
145 endlineno = string.atoi(end[:string.find(end, '.')])
146 wraplineno = lineno
147 while 1:
148 lineno = lineno + 1
149 if lineno > endlineno:
150 if wraplineno <= 0:
151 break
152 endlineno = wraplineno
153 lineno = 0
154 wraplineno = 0
155 line = self.text.get('%d.0 linestart' % lineno,
156 '%d.0 lineend' % lineno)
157 i = prog.search(line)
158 if i >= 0:
159 n = max(1, len(prog.group(0)))
160 try:
161 self.text.tag_remove('sel',
162 AtSelFirst(),
163 AtSelLast())
164 except TclError:
165 pass
166 self.text.tag_add('sel',
167 '%d.%d' % (lineno, i),
168 '%d.%d' % (lineno, i+n))
169 self.text.mark_set(AtInsert(),
170 '%d.%d' % (lineno, i))
171 self.text.yview_pickplace(AtInsert())
172 break
173
174def main():
175 root = Tk()
176 sb = SelectionBox(root)
177 sb.addlist(listmanpages())
178 if sys.argv[1:]:
179 sb.show_page(sys.argv[1])
180 root.minsize(1, 1)
181 root.mainloop()
182
183main()