1 """Command line interface helper classes.
2
3 It provides some default commands, a help system, a default readline
4 configuration with completion and persistent history.
5
6 Example::
7
8 class BookShell(CLIHelper):
9
10 def __init__(self):
11 # quit and help are builtins
12 # CMD_MAP keys are commands, values are topics
13 self.CMD_MAP['pionce'] = _("Sommeil")
14 self.CMD_MAP['ronfle'] = _("Sommeil")
15 CLIHelper.__init__(self)
16
17 help_do_pionce = ("pionce", "pionce duree", _("met ton corps en veille"))
18 def do_pionce(self):
19 print 'nap is good'
20
21 help_do_ronfle = ("ronfle", "ronfle volume", _("met les autres en veille"))
22 def do_ronfle(self):
23 print 'fuuuuuuuuuuuu rhhhhhrhrhrrh'
24
25 cl = BookShell()
26
27 :copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
28 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
29 :license: General Public License version 2 - http://www.gnu.org/licenses
30 """
31 __docformat__ = "restructuredtext en"
32
33 import __builtin__
34 if not hasattr(__builtin__, '_'):
35 __builtin__._ = str
36
37
39 """Init the readline library if available."""
40 try:
41 import readline
42 readline.parse_and_bind("tab: complete")
43 readline.set_completer(complete_method)
44 string = readline.get_completer_delims().replace(':', '')
45 readline.set_completer_delims(string)
46 if histfile is not None:
47 try:
48 readline.read_history_file(histfile)
49 except IOError:
50 pass
51 import atexit
52 atexit.register(readline.write_history_file, histfile)
53 except:
54 print 'readline is not available :-('
55
56
58 """Readline completer."""
59
62
64 """Hook called by readline when <tab> is pressed."""
65 n = len(text)
66 matches = []
67 for cmd in self.list :
68 if cmd[:n] == text :
69 matches.append(cmd)
70 try:
71 return matches[state]
72 except IndexError:
73 return None
74
75
77 """An abstract command line interface client which recognize commands
78 and provide an help system.
79 """
80
81 CMD_MAP = {'help' : _("Others"),
82 'quit' : _("Others"),
83 }
84 CMD_PREFIX = ''
85
87 self._topics = {}
88 self.commands = None
89 self._completer = Completer(self._register_commands())
90 init_readline(self._completer.complete, histfile)
91
93 """loop on user input, exit on EOF"""
94 while 1:
95 try:
96 line = raw_input('>>> ')
97 except EOFError:
98 print
99 break
100 s_line = line.strip()
101 if not s_line:
102 continue
103 args = s_line.split()
104 if args[0] in self.commands:
105 try:
106 cmd = 'do_%s' % self.commands[args[0]]
107 getattr(self, cmd)(*args[1:])
108 except EOFError:
109 break
110 except:
111 import traceback
112 traceback.print_exc()
113 else:
114 try:
115 self.handle_line(s_line)
116 except:
117 import traceback
118 traceback.print_exc()
119
121 """Method to overload in the concrete class (should handle
122 lines which are not commands).
123 """
124 raise NotImplementedError()
125
126
127
128
130 """ register available commands method and return the list of
131 commands name
132 """
133 self.commands = {}
134 self._command_help = {}
135 commands = [attr[3:] for attr in dir(self) if attr[:3] == 'do_']
136 for command in commands:
137 topic = self.CMD_MAP[command]
138 help_method = getattr(self, 'help_do_%s' % command)
139 self._topics.setdefault(topic, []).append(help_method)
140 self.commands[self.CMD_PREFIX + command] = command
141 self._command_help[command] = help_method
142 return self.commands.keys()
143
145 print _('Command %s') % cmd
146 print _('Syntax: %s') % syntax
147 print '\t', explanation
148 print
149
150
151
152
154 """base input of the help system"""
155 if command in self._command_help:
156 self._print_help(*self._command_help[command])
157 elif command is None or command not in self._topics:
158 print _("Use help <topic> or help <command>.")
159 print _("Available topics are:")
160 topics = self._topics.keys()
161 topics.sort()
162 for topic in topics:
163 print '\t', topic
164 print
165 print _("Available commands are:")
166 commands = self.commands.keys()
167 commands.sort()
168 for command in commands:
169 print '\t', command[len(self.CMD_PREFIX):]
170
171 else:
172 print _('Available commands about %s:') % command
173 print
174 for command_help_method in self._topics[command]:
175 try:
176 if callable(command_help_method):
177 self._print_help(*command_help_method())
178 else:
179 self._print_help(*command_help_method)
180 except:
181 import traceback
182 traceback.print_exc()
183 print 'ERROR in help method %s'% (
184 command_help_method.func_name)
185
186 help_do_help = ("help", "help [topic|command]",
187 _("print help message for the given topic/command or \
188 available topics when no argument"))
189
191 """quit the CLI"""
192 raise EOFError()
193
195 return ("quit", "quit", _("quit the application"))
196