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.
43 IDENTCHARS
= string
.letters
+ string
.digits
+ '_'
47 identchars
= IDENTCHARS
53 doc_header
= "Documented commands (type help <topic>):"
54 misc_header
= "Miscellaneous help topics:"
55 undoc_header
= "Undocumented commands:"
56 nohelp
= "*** No help on %s"
58 def __init__(self
): pass
60 def cmdloop(self
, intro
=None):
69 line
= self
.cmdqueue
[0]
73 line
= raw_input(self
.prompt
)
76 line
= self
.precmd(line
)
77 stop
= self
.onecmd(line
)
78 stop
= self
.postcmd(stop
, line
)
81 def precmd(self
, line
):
84 def postcmd(self
, stop
, line
):
93 def onecmd(self
, line
):
94 line
= string
.strip(line
)
98 if hasattr(self
, 'do_shell'):
101 return self
.default(line
)
103 return self
.emptyline()
106 while i
< n
and line
[i
] in self
.identchars
: i
= i
+1
107 cmd
, arg
= line
[:i
], string
.strip(line
[i
:])
109 return self
.default(line
)
112 func
= getattr(self
, 'do_' + cmd
)
113 except AttributeError:
114 return self
.default(line
)
119 return self
.onecmd(self
.lastcmd
)
121 def default(self
, line
):
122 print '*** Unknown syntax:', line
124 def do_help(self
, arg
):
126 # XXX check arg syntax
128 func
= getattr(self
, 'help_' + arg
)
131 doc
=getattr(self
, 'do_' + arg
).__doc
__
137 print self
.nohelp
% (arg
,)
141 # Inheritance says we have to look in class and
142 # base classes; order is not important.
144 classes
= [self
.__class
__]
148 classes
= classes
+ list(aclass
.__bases
__)
149 names
= names
+ dir(aclass
)
155 if name
[:5] == 'help_':
158 # There can be duplicates if routines overridden
161 if name
[:3] == 'do_':
166 if help.has_key(cmd
):
169 elif getattr(self
, name
).__doc
__:
172 cmds_undoc
.append(cmd
)
173 print self
.doc_leader
174 self
.print_topics(self
.doc_header
, cmds_doc
, 15,80)
175 self
.print_topics(self
.misc_header
, help.keys(),15,80)
176 self
.print_topics(self
.undoc_header
, cmds_undoc
, 15,80)
178 def print_topics(self
, header
, cmds
, cmdlen
, maxcol
):
182 print self
.ruler
* len(header
)
183 (cmds_per_line
,junk
)=divmod(maxcol
,cmdlen
)
187 print (("%-"+`cmdlen`
+"s") % cmd
),
188 col
= (col
+1) % cmds_per_line