blob: bd4e3cb06efe5c3c97763dbcff129cec9e5de10f [file] [log] [blame]
Guido van Rossum4acc25b2000-02-02 15:10:15 +00001"""A generic class to build line-oriented command interpreters.
2
3Interpreters constructed with this class obey the following conventions:
4
51. End of file on input is processed as the command 'EOF'.
62. A command is parsed out of each line by collecting the prefix composed
7 of characters in the identchars member.
83. A command `foo' is dispatched to a method 'do_foo()'; the do_ method
9 is passed a single argument consisting of the remainder of the line.
104. Typing an empty line repeats the last command. (Actually, it calls the
11 method `emptyline', which may be overridden in a subclass.)
125. There is a predefined `help' method. Given an argument `topic', it
13 calls the command `help_topic'. With no arguments, it lists all topics
14 with defined help_ functions, broken into up to three topics; documented
15 commands, miscellaneous help topics, and undocumented commands.
166. The command '?' is a synonym for `help'. The command '!' is a synonym
17 for `shell', if a do_shell method exists.
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000187. If completion is enabled, completing commands will be done automatically,
19 and completing of commands args is done by calling complete_foo() with
20 arguments text, line, begidx, endidx. text is string we are matching
21 against, all returned matches must begin with it. line is the current
22 input line (lstripped), begidx and endidx are the beginning and end
Tim Petersab9ba272001-08-09 21:40:30 +000023 indexes of the text being matched, which could be used to provide
Martin v. Löwis66b6e192001-07-28 14:44:03 +000024 different completion depending upon which position the argument is in.
Guido van Rossum4acc25b2000-02-02 15:10:15 +000025
26The `default' method may be overridden to intercept commands for which there
27is no do_ method.
28
Martin v. Löwis66b6e192001-07-28 14:44:03 +000029The `completedefault' method may be overridden to intercept completions for
Tim Petersab9ba272001-08-09 21:40:30 +000030commands that have no complete_ method.
Martin v. Löwis66b6e192001-07-28 14:44:03 +000031
Guido van Rossum4acc25b2000-02-02 15:10:15 +000032The data member `self.ruler' sets the character used to draw separator lines
33in the help messages. If empty, no ruler line is drawn. It defaults to "=".
34
35If the value of `self.intro' is nonempty when the cmdloop method is called,
36it is printed out on interpreter startup. This value may be overridden
37via an optional argument to the cmdloop() method.
38
39The data members `self.doc_header', `self.misc_header', and
40`self.undoc_header' set the headers used for the help function's
41listings of documented functions, miscellaneous topics, and undocumented
42functions respectively.
43
44These interpreters use raw_input; thus, if the readline module is loaded,
45they automatically support Emacs-like command history and editing features.
46"""
Guido van Rossumb53e6781992-01-24 01:12:17 +000047
Guido van Rossumbfb91842001-03-22 21:59:20 +000048import string, sys
Guido van Rossumb53e6781992-01-24 01:12:17 +000049
Skip Montanaroe99d5ea2001-01-20 19:54:20 +000050__all__ = ["Cmd"]
51
Guido van Rossumb53e6781992-01-24 01:12:17 +000052PROMPT = '(Cmd) '
Fred Drake79e75e12001-07-20 19:05:50 +000053IDENTCHARS = string.ascii_letters + string.digits + '_'
Guido van Rossumb53e6781992-01-24 01:12:17 +000054
55class Cmd:
Raymond Hettingeraef22fb2002-05-29 16:18:42 +000056 """A simple framework for writing line-oriented command interpreters.
57
58 These are often useful for test harnesses, administrative tools, and
59 prototypes that will later be wrapped in a more sophisticated interface.
60
61 A Cmd instance or subclass instance is a line-oriented interpreter
62 framework. There is no good reason to instantiate Cmd itself; rather,
63 it's useful as a superclass of an interpreter class you define yourself
64 in order to inherit Cmd's methods and encapsulate action methods.
65
66 """
Guido van Rossum4acc25b2000-02-02 15:10:15 +000067 prompt = PROMPT
68 identchars = IDENTCHARS
69 ruler = '='
70 lastcmd = ''
71 cmdqueue = []
72 intro = None
73 doc_leader = ""
74 doc_header = "Documented commands (type help <topic>):"
75 misc_header = "Miscellaneous help topics:"
76 undoc_header = "Undocumented commands:"
77 nohelp = "*** No help on %s"
Guido van Rossumbfb91842001-03-22 21:59:20 +000078 use_rawinput = 1
Guido van Rossum9b3bc711993-06-20 21:02:22 +000079
Tim Petersab9ba272001-08-09 21:40:30 +000080 def __init__(self, completekey='tab'):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +000081 """Instantiate a line-oriented interpreter framework.
82
83 The optional argument is the readline name of a completion key;
84 it defaults to the Tab key. If completekey is not None and the
85 readline module is available, command completion is done
86 automatically.
87
88 """
Martin v. Löwis66b6e192001-07-28 14:44:03 +000089 if completekey:
90 try:
91 import readline
92 readline.set_completer(self.complete)
93 readline.parse_and_bind(completekey+": complete")
94 except ImportError:
95 pass
Guido van Rossum030eb111998-07-01 22:53:04 +000096
Guido van Rossum4acc25b2000-02-02 15:10:15 +000097 def cmdloop(self, intro=None):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +000098 """Repeatedly issue a prompt, accept input, parse an initial prefix
99 off the received input, and dispatch to action methods, passing them
100 the remainder of the line as argument.
101
102 """
103
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000104 self.preloop()
Fred Drake8152d322000-12-12 23:20:45 +0000105 if intro is not None:
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000106 self.intro = intro
107 if self.intro:
108 print self.intro
109 stop = None
110 while not stop:
111 if self.cmdqueue:
Raymond Hettinger46ac8eb2002-06-30 03:39:14 +0000112 line = self.cmdqueue.pop(0)
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000113 else:
Guido van Rossumbfb91842001-03-22 21:59:20 +0000114 if self.use_rawinput:
115 try:
116 line = raw_input(self.prompt)
117 except EOFError:
118 line = 'EOF'
119 else:
120 sys.stdout.write(self.prompt)
Neil Schemenauerd03c3422002-03-23 20:43:59 +0000121 sys.stdout.flush()
Guido van Rossumbfb91842001-03-22 21:59:20 +0000122 line = sys.stdin.readline()
123 if not len(line):
124 line = 'EOF'
125 else:
126 line = line[:-1] # chop \n
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000127 line = self.precmd(line)
128 stop = self.onecmd(line)
129 stop = self.postcmd(stop, line)
130 self.postloop()
Guido van Rossum80884071998-06-29 17:58:55 +0000131
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000132 def precmd(self, line):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000133 """Hook method executed just before the command line is
134 interpreted, but after the input prompt is generated and issued.
135
136 """
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000137 return line
Guido van Rossum80884071998-06-29 17:58:55 +0000138
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000139 def postcmd(self, stop, line):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000140 """Hook method executed just after a command dispatch is finished."""
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000141 return stop
Guido van Rossum80884071998-06-29 17:58:55 +0000142
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000143 def preloop(self):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000144 """Hook method executed once when the cmdloop() method is called."""
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000145 pass
Guido van Rossum80884071998-06-29 17:58:55 +0000146
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000147 def postloop(self):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000148 """Hook method executed once when the cmdloop() method is about to
149 return.
150
151 """
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000152 pass
Guido van Rossumb53e6781992-01-24 01:12:17 +0000153
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000154 def parseline(self, line):
Eric S. Raymond20e44232001-02-09 04:52:11 +0000155 line = line.strip()
Eric S. Raymond5f1b2702000-07-11 13:03:55 +0000156 if not line:
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000157 return None, None, line
Eric S. Raymond5f1b2702000-07-11 13:03:55 +0000158 elif line[0] == '?':
159 line = 'help ' + line[1:]
160 elif line[0] == '!':
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000161 if hasattr(self, 'do_shell'):
Eric S. Raymond5f1b2702000-07-11 13:03:55 +0000162 line = 'shell ' + line[1:]
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000163 else:
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000164 return None, None, line
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000165 i, n = 0, len(line)
166 while i < n and line[i] in self.identchars: i = i+1
Eric S. Raymond20e44232001-02-09 04:52:11 +0000167 cmd, arg = line[:i], line[i:].strip()
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000168 return cmd, arg, line
Tim Petersab9ba272001-08-09 21:40:30 +0000169
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000170 def onecmd(self, line):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000171 """Interpret the argument as though it had been typed in response
172 to the prompt.
173
174 This may be overridden, but should not normally need to be;
175 see the precmd() and postcmd() methods for useful execution hooks.
176 The return value is a flag indicating whether interpretation of
177 commands by the interpreter should stop.
178
179 """
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000180 cmd, arg, line = self.parseline(line)
181 if not line:
182 return self.emptyline()
183 if cmd is None:
184 return self.default(line)
185 self.lastcmd = line
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000186 if cmd == '':
187 return self.default(line)
188 else:
189 try:
190 func = getattr(self, 'do_' + cmd)
191 except AttributeError:
192 return self.default(line)
193 return func(arg)
Guido van Rossumb53e6781992-01-24 01:12:17 +0000194
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000195 def emptyline(self):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000196 """Called when an empty line is entered in response to the prompt.
197
198 If this method is not overridden, it repeats the last nonempty
199 command entered.
200
201 """
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000202 if self.lastcmd:
203 return self.onecmd(self.lastcmd)
Guido van Rossum80884071998-06-29 17:58:55 +0000204
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000205 def default(self, line):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000206 """Called on an input line when the command prefix is not recognized.
207
208 If this method is not overridden, it prints an error message and
209 returns.
210
211 """
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000212 print '*** Unknown syntax:', line
Guido van Rossumb53e6781992-01-24 01:12:17 +0000213
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000214 def completedefault(self, *ignored):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000215 """Method called to complete an input line when no command-specific
216 complete_*() method is available.
217
218 By default, it returns an empty list.
219
220 """
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000221 return []
222
223 def completenames(self, text, *ignored):
224 dotext = 'do_'+text
225 return [a[3:] for a in self.get_names() if a.startswith(dotext)]
226
227 def complete(self, text, state):
228 """Return the next possible completion for 'text'.
229
230 If a command has not been entered, then complete against command list.
231 Otherwise try to call complete_<command> to get list of completions.
232 """
233 if state == 0:
234 import readline
235 origline = readline.get_line_buffer()
236 line = origline.lstrip()
237 stripped = len(origline) - len(line)
238 begidx = readline.get_begidx() - stripped
239 endidx = readline.get_endidx() - stripped
240 if begidx>0:
241 cmd, args, foo = self.parseline(line)
242 if cmd == '':
243 compfunc = self.completedefault
244 else:
245 try:
246 compfunc = getattr(self, 'complete_' + cmd)
247 except AttributeError:
248 compfunc = self.completedefault
249 else:
250 compfunc = self.completenames
251 self.completion_matches = compfunc(text, line, begidx, endidx)
252 try:
253 return self.completion_matches[state]
254 except IndexError:
255 return None
Tim Petersab9ba272001-08-09 21:40:30 +0000256
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000257 def get_names(self):
258 # Inheritance says we have to look in class and
259 # base classes; order is not important.
260 names = []
261 classes = [self.__class__]
262 while classes:
Raymond Hettinger46ac8eb2002-06-30 03:39:14 +0000263 aclass = classes.pop(0)
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000264 if aclass.__bases__:
265 classes = classes + list(aclass.__bases__)
266 names = names + dir(aclass)
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000267 return names
268
269 def complete_help(self, *args):
270 return self.completenames(*args)
271
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000272 def do_help(self, arg):
273 if arg:
274 # XXX check arg syntax
275 try:
276 func = getattr(self, 'help_' + arg)
Skip Montanaro1ce00732002-03-24 16:34:21 +0000277 except AttributeError:
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000278 try:
279 doc=getattr(self, 'do_' + arg).__doc__
280 if doc:
281 print doc
282 return
Skip Montanaro1ce00732002-03-24 16:34:21 +0000283 except AttributeError:
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000284 pass
285 print self.nohelp % (arg,)
286 return
287 func()
288 else:
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000289 names = self.get_names()
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000290 cmds_doc = []
291 cmds_undoc = []
292 help = {}
293 for name in names:
294 if name[:5] == 'help_':
295 help[name[5:]]=1
296 names.sort()
297 # There can be duplicates if routines overridden
298 prevname = ''
299 for name in names:
300 if name[:3] == 'do_':
301 if name == prevname:
302 continue
303 prevname = name
304 cmd=name[3:]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000305 if cmd in help:
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000306 cmds_doc.append(cmd)
307 del help[cmd]
308 elif getattr(self, name).__doc__:
309 cmds_doc.append(cmd)
310 else:
311 cmds_undoc.append(cmd)
312 print self.doc_leader
313 self.print_topics(self.doc_header, cmds_doc, 15,80)
314 self.print_topics(self.misc_header, help.keys(),15,80)
315 self.print_topics(self.undoc_header, cmds_undoc, 15,80)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000316
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000317 def print_topics(self, header, cmds, cmdlen, maxcol):
318 if cmds:
Jeremy Hyltond30e5872001-01-26 17:15:18 +0000319 print header
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000320 if self.ruler:
321 print self.ruler * len(header)
Guido van Rossumc706c282002-12-02 13:08:53 +0000322 self.columnize(cmds, maxcol-1)
323 print
324
325 def columnize(self, list, displaywidth=80):
326 """Display a list of strings as a compact set of columns.
327
328 Each column is only as wide as necessary.
329 Columns are separated by two spaces (one was not legible enough).
330 """
331 if not list:
332 print "<empty>"
333 return
334 nonstrings = [i for i in range(len(list))
335 if not isinstance(list[i], str)]
336 if nonstrings:
337 raise TypeError, ("list[i] not a string for i in %s" %
338 ", ".join(map(str, nonstrings)))
339 size = len(list)
340 if size == 1:
341 print list[0]
342 return
343 # Try every row count from 1 upwards
344 for nrows in range(1, len(list)):
345 ncols = (size+nrows-1) // nrows
346 colwidths = []
347 totwidth = -2
348 for col in range(ncols):
349 colwidth = 0
350 for row in range(nrows):
351 i = row + nrows*col
352 if i >= size:
353 break
354 x = list[i]
355 colwidth = max(colwidth, len(x))
356 colwidths.append(colwidth)
357 totwidth += colwidth + 2
358 if totwidth > displaywidth:
359 break
360 if totwidth <= displaywidth:
361 break
362 else:
363 nrows = len(list)
364 ncols = 1
365 colwidths = [0]
366 for row in range(nrows):
367 texts = []
368 for col in range(ncols):
369 i = row + nrows*col
370 if i >= size:
371 x = ""
372 else:
373 x = list[i]
374 texts.append(x)
375 while texts and not texts[-1]:
376 del texts[-1]
377 for col in range(len(texts)):
378 texts[col] = texts[col].ljust(colwidths[col])
379 print " ".join(texts)