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
)
130 print self
.nohelp
% (arg
,)
134 # Inheritance says we have to look in class and
135 # base classes; order is not important.
137 classes
= [self
.__class
__]
141 classes
= classes
+ list(aclass
.__bases
__)
142 names
= names
+ dir(aclass
)
148 if name
[:5] == 'help_':
151 # There can be duplicates if routines overridden
154 if name
[:3] == 'do_':
159 if help.has_key(cmd
):
163 cmds_undoc
.append(cmd
)
164 print self
.doc_leader
165 self
.print_topics(self
.doc_header
, cmds_doc
, 15,80)
166 self
.print_topics(self
.misc_header
, help.keys(),15,80)
167 self
.print_topics(self
.undoc_header
, cmds_undoc
, 15,80)
169 def print_topics(self
, header
, cmds
, cmdlen
, maxcol
):
173 print self
.ruler
* len(header
)
174 (cmds_per_line
,junk
)=divmod(maxcol
,cmdlen
)
178 print (("%-"+`cmdlen`
+"s") % cmd
),
179 col
= (col
+1) % cmds_per_line