blob: f20c1bb7aa7296ec0610bccdcebd14947b5d5fe9 [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:
112 line = self.cmdqueue[0]
113 del self.cmdqueue[0]
114 else:
Guido van Rossumbfb91842001-03-22 21:59:20 +0000115 if self.use_rawinput:
116 try:
117 line = raw_input(self.prompt)
118 except EOFError:
119 line = 'EOF'
120 else:
121 sys.stdout.write(self.prompt)
Neil Schemenauerd03c3422002-03-23 20:43:59 +0000122 sys.stdout.flush()
Guido van Rossumbfb91842001-03-22 21:59:20 +0000123 line = sys.stdin.readline()
124 if not len(line):
125 line = 'EOF'
126 else:
127 line = line[:-1] # chop \n
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000128 line = self.precmd(line)
129 stop = self.onecmd(line)
130 stop = self.postcmd(stop, line)
131 self.postloop()
Guido van Rossum80884071998-06-29 17:58:55 +0000132
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000133 def precmd(self, line):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000134 """Hook method executed just before the command line is
135 interpreted, but after the input prompt is generated and issued.
136
137 """
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000138 return line
Guido van Rossum80884071998-06-29 17:58:55 +0000139
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000140 def postcmd(self, stop, line):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000141 """Hook method executed just after a command dispatch is finished."""
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000142 return stop
Guido van Rossum80884071998-06-29 17:58:55 +0000143
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000144 def preloop(self):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000145 """Hook method executed once when the cmdloop() method is called."""
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000146 pass
Guido van Rossum80884071998-06-29 17:58:55 +0000147
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000148 def postloop(self):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000149 """Hook method executed once when the cmdloop() method is about to
150 return.
151
152 """
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000153 pass
Guido van Rossumb53e6781992-01-24 01:12:17 +0000154
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000155 def parseline(self, line):
Eric S. Raymond20e44232001-02-09 04:52:11 +0000156 line = line.strip()
Eric S. Raymond5f1b2702000-07-11 13:03:55 +0000157 if not line:
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000158 return None, None, line
Eric S. Raymond5f1b2702000-07-11 13:03:55 +0000159 elif line[0] == '?':
160 line = 'help ' + line[1:]
161 elif line[0] == '!':
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000162 if hasattr(self, 'do_shell'):
Eric S. Raymond5f1b2702000-07-11 13:03:55 +0000163 line = 'shell ' + line[1:]
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000164 else:
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000165 return None, None, line
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000166 i, n = 0, len(line)
167 while i < n and line[i] in self.identchars: i = i+1
Eric S. Raymond20e44232001-02-09 04:52:11 +0000168 cmd, arg = line[:i], line[i:].strip()
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000169 return cmd, arg, line
Tim Petersab9ba272001-08-09 21:40:30 +0000170
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000171 def onecmd(self, line):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000172 """Interpret the argument as though it had been typed in response
173 to the prompt.
174
175 This may be overridden, but should not normally need to be;
176 see the precmd() and postcmd() methods for useful execution hooks.
177 The return value is a flag indicating whether interpretation of
178 commands by the interpreter should stop.
179
180 """
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000181 cmd, arg, line = self.parseline(line)
182 if not line:
183 return self.emptyline()
184 if cmd is None:
185 return self.default(line)
186 self.lastcmd = line
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000187 if cmd == '':
188 return self.default(line)
189 else:
190 try:
191 func = getattr(self, 'do_' + cmd)
192 except AttributeError:
193 return self.default(line)
194 return func(arg)
Guido van Rossumb53e6781992-01-24 01:12:17 +0000195
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000196 def emptyline(self):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000197 """Called when an empty line is entered in response to the prompt.
198
199 If this method is not overridden, it repeats the last nonempty
200 command entered.
201
202 """
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000203 if self.lastcmd:
204 return self.onecmd(self.lastcmd)
Guido van Rossum80884071998-06-29 17:58:55 +0000205
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000206 def default(self, line):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000207 """Called on an input line when the command prefix is not recognized.
208
209 If this method is not overridden, it prints an error message and
210 returns.
211
212 """
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000213 print '*** Unknown syntax:', line
Guido van Rossumb53e6781992-01-24 01:12:17 +0000214
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000215 def completedefault(self, *ignored):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000216 """Method called to complete an input line when no command-specific
217 complete_*() method is available.
218
219 By default, it returns an empty list.
220
221 """
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000222 return []
223
224 def completenames(self, text, *ignored):
225 dotext = 'do_'+text
226 return [a[3:] for a in self.get_names() if a.startswith(dotext)]
227
228 def complete(self, text, state):
229 """Return the next possible completion for 'text'.
230
231 If a command has not been entered, then complete against command list.
232 Otherwise try to call complete_<command> to get list of completions.
233 """
234 if state == 0:
235 import readline
236 origline = readline.get_line_buffer()
237 line = origline.lstrip()
238 stripped = len(origline) - len(line)
239 begidx = readline.get_begidx() - stripped
240 endidx = readline.get_endidx() - stripped
241 if begidx>0:
242 cmd, args, foo = self.parseline(line)
243 if cmd == '':
244 compfunc = self.completedefault
245 else:
246 try:
247 compfunc = getattr(self, 'complete_' + cmd)
248 except AttributeError:
249 compfunc = self.completedefault
250 else:
251 compfunc = self.completenames
252 self.completion_matches = compfunc(text, line, begidx, endidx)
253 try:
254 return self.completion_matches[state]
255 except IndexError:
256 return None
Tim Petersab9ba272001-08-09 21:40:30 +0000257
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000258 def get_names(self):
259 # Inheritance says we have to look in class and
260 # base classes; order is not important.
261 names = []
262 classes = [self.__class__]
263 while classes:
264 aclass = classes[0]
265 if aclass.__bases__:
266 classes = classes + list(aclass.__bases__)
267 names = names + dir(aclass)
268 del classes[0]
269 return names
270
271 def complete_help(self, *args):
272 return self.completenames(*args)
273
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000274 def do_help(self, arg):
275 if arg:
276 # XXX check arg syntax
277 try:
278 func = getattr(self, 'help_' + arg)
Skip Montanaro1ce00732002-03-24 16:34:21 +0000279 except AttributeError:
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000280 try:
281 doc=getattr(self, 'do_' + arg).__doc__
282 if doc:
283 print doc
284 return
Skip Montanaro1ce00732002-03-24 16:34:21 +0000285 except AttributeError:
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000286 pass
287 print self.nohelp % (arg,)
288 return
289 func()
290 else:
Martin v. Löwis66b6e192001-07-28 14:44:03 +0000291 names = self.get_names()
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000292 cmds_doc = []
293 cmds_undoc = []
294 help = {}
295 for name in names:
296 if name[:5] == 'help_':
297 help[name[5:]]=1
298 names.sort()
299 # There can be duplicates if routines overridden
300 prevname = ''
301 for name in names:
302 if name[:3] == 'do_':
303 if name == prevname:
304 continue
305 prevname = name
306 cmd=name[3:]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000307 if cmd in help:
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000308 cmds_doc.append(cmd)
309 del help[cmd]
310 elif getattr(self, name).__doc__:
311 cmds_doc.append(cmd)
312 else:
313 cmds_undoc.append(cmd)
314 print self.doc_leader
315 self.print_topics(self.doc_header, cmds_doc, 15,80)
316 self.print_topics(self.misc_header, help.keys(),15,80)
317 self.print_topics(self.undoc_header, cmds_undoc, 15,80)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000318
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000319 def print_topics(self, header, cmds, cmdlen, maxcol):
320 if cmds:
Jeremy Hyltond30e5872001-01-26 17:15:18 +0000321 print header
Guido van Rossum4acc25b2000-02-02 15:10:15 +0000322 if self.ruler:
323 print self.ruler * len(header)
324 (cmds_per_line,junk)=divmod(maxcol,cmdlen)
325 col=cmds_per_line
326 for cmd in cmds:
327 if col==0: print
328 print (("%-"+`cmdlen`+"s") % cmd),
329 col = (col+1) % cmds_per_line
330 print "\n"