1 # A generic class to build line-oriented command interpreters
3 # Interpreters constructed with this class obey the following conventions:
5 # 1. End of file on input is processed as the command 'EOF'.
6 # 2. A command is parsed out of each line by collecting the prefix composed
7 # of characters in the identchars member.
8 # 3. 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.
10 # 4. Typing an empty line repeats the last command. (Actually, it calls the
11 # method `emptyline', which may be overridden in a subclass.)
12 # 5. 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.
16 # 6. The command '?' is a synonym for `help'. The command '!' is a synonym
17 # for `shell', if a do_shell method exists.
19 # The `default' method may be overridden to intercept commands for which there
22 # The data member `self.ruler' sets the character used to draw separator lines
23 # in the help messages. If empty, no ruler line is drawn. It defaults to "=".
25 # If the value of `self.intro' is nonempty when the cmdloop method is called,
26 # it is printed out on interpreter startup. This value may be overridden
27 # via an optional argument to the cmdloop() method.
29 # The data members `self.doc_header', `self.misc_header', and
30 # `self.undoc_header' set the headers used for the help function's
31 # listings of documented functions, miscellaneous topics, and undocumented
32 # functions respectively.
34 # These interpreters use raw_input; thus, if the readline module is loaded,
35 # they automatically support Emacs-like command history and editing features.
41 IDENTCHARS
= string
.letters
+ string
.digits
+ '_'
45 identchars
= IDENTCHARS
51 doc_header
= "Documented commands (type help <topic>):"
52 misc_header
= "Miscellaneous help topics:"
53 undoc_header
= "Undocumented commands:"
54 nohelp
= "*** No help on %s"
56 def __init__(self
): pass
58 def cmdloop(self
, intro
=None):
67 line
= self
.cmdqueue
[0]
71 line
= raw_input(self
.prompt
)
74 line
= self
.precmd(line
)
75 stop
= self
.onecmd(line
)
76 stop
= self
.postcmd(stop
, line
)
79 def precmd(self
, line
):
82 def postcmd(self
, stop
, line
):
91 def onecmd(self
, line
):
92 line
= string
.strip(line
)
96 if hasattr(self
, 'do_shell'):
99 return self
.default(line
)
101 return self
.emptyline()
104 while i
< n
and line
[i
] in self
.identchars
: i
= i
+1
105 cmd
, arg
= line
[:i
], string
.strip(line
[i
:])
107 return self
.default(line
)
110 func
= getattr(self
, 'do_' + cmd
)
111 except AttributeError:
112 return self
.default(line
)
117 return self
.onecmd(self
.lastcmd
)
119 def default(self
, line
):
120 print '*** Unknown syntax:', line
122 def do_help(self
, arg
):
124 # XXX check arg syntax
126 func
= getattr(self
, 'help_' + arg
)
129 doc
=getattr(self
, 'do_' + arg
).__doc
__
135 print self
.nohelp
% (arg
,)
139 # Inheritance says we have to look in class and
140 # base classes; order is not important.
142 classes
= [self
.__class
__]
146 classes
= classes
+ list(aclass
.__bases
__)
147 names
= names
+ dir(aclass
)
153 if name
[:5] == 'help_':
156 # There can be duplicates if routines overridden
159 if name
[:3] == 'do_':
164 if help.has_key(cmd
):
167 elif getattr(self
, name
).__doc
__:
170 cmds_undoc
.append(cmd
)
171 print self
.doc_leader
172 self
.print_topics(self
.doc_header
, cmds_doc
, 15,80)
173 self
.print_topics(self
.misc_header
, help.keys(),15,80)
174 self
.print_topics(self
.undoc_header
, cmds_undoc
, 15,80)
176 def print_topics(self
, header
, cmds
, cmdlen
, maxcol
):
180 print self
.ruler
* len(header
)
181 (cmds_per_line
,junk
)=divmod(maxcol
,cmdlen
)
185 print (("%-"+`cmdlen`
+"s") % cmd
),
186 col
= (col
+1) % cmds_per_line