History bug fix.
[AurShell.git] / aur-shell.py
blob0ec69f153e05e9057ffee0a2e6d9ac226982fdf1
1 #!/usr/bin/python
2 # -*- coding: utf-8-*-
4 """Aur Shell is simple shell framework.
6 To use it, write some plugins that Aur Shell would use.
7 """
9 import cmd
10 import string
11 import sys
12 import os
13 import os.path
14 import types
15 import readline
17 import conf
18 import plugload
19 from showinfo import Put
21 __version__ = "0.1"
24 class AurShell(cmd.Cmd):
25 """Interactive shell framework.
26 To use it, write some modules, becouse by default it's very poor shell.
27 """
28 def __init__(self, init_message=""):
29 cmd.Cmd.__init__(self)
30 self.put = Put()
31 self.prompt = conf.shell_prompt
32 if init_message:
33 self.intro = init_message
34 else:
35 self.intro = "\n\tWelcome to aurShell v%(__version__)s\n" % globals()
36 self.commands = plugload.load(conf.modules_path)
37 # load history, create empty file if history doesn't exist
38 if not os.path.isfile(conf.history_file):
39 open(conf.history_file, "w").close()
40 readline.read_history_file(conf.history_file)
41 readline.set_history_length(conf.history_length)
43 def default(self, cmd=None):
44 """Run commands.
46 cmd = (<class>, [method], [arg1], [arg2], ...)
47 """
48 # cmd[0] should be class name
49 # cmd[1] should be method name (or arugmet if class is callable)
50 # cmd[1] can be empty
51 # cmd[2:] should be method argumments, can be empty
52 cmd = cmd.split()
53 # check if alias exists and if so, replace command
54 if cmd[0] in conf.alias.keys():
55 cmd[0] = conf.alias[cmd[0]]
56 self.onecmd(" ".join(cmd))
57 # operations for single command with no arguments
58 elif len(cmd) == 1:
59 # if there's no such command (or plugin class)
60 if not cmd[0] in self.commands.keys():
61 self.put("%s : command not found." % cmd[0])
62 # for only one argument, try to run __call__() method with
63 # no arguments
64 elif "__call__" in dir(self.commands[cmd[0]]):
65 a = self.put(getattr(self.commands[cmd[0]], "__call__")())
66 if a:
67 self.put(a)
68 else:
69 self.put("%s : bad usege. Try to run help." % cmd[0])
70 # if command was called with arguments
71 elif len(cmd) > 1:
72 if not cmd[0] in self.commands.keys():
73 self.put("%s : command not found." % cmd[0])
74 # if method named arg[1] exist in class arg[0],
75 # then try to run in
76 elif cmd[1] in dir(self.commands[cmd[0]]):
77 a = self.put(getattr(self.commands[cmd[0]], cmd[1])(cmd[2:]))
78 if a:
79 self.put(a)
80 # if there's no such method arg[1] in class arg[0],
81 # try to run class.__call__(args..)
82 else:
83 try:
84 a = self.commands[cmd[0]](*cmd[1:])
85 if a:
86 self.put(a)
87 except TypeError:
88 # object is not callable
89 self.put("%s : bad usage" % cmd[0])
91 def completenames(self, text, *ignored):
92 """Complete commands"""
93 dotext = 'do_'+text
94 # local methods
95 local_cmd_list = [a[3:] + " " for a in self.get_names() if a.startswith(dotext)]
96 # + all metrods from modules
97 module_cmd_list = [a + " " for a in self.commands.keys() if a.startswith(text)]
98 return local_cmd_list + module_cmd_list
100 def completedefault(self, text, line, begidx, endidx):
101 """Complete commands argument"""
102 line = line.split()
103 # if only commands was given
104 if len(line) == 1:
105 cmds = [a + " " for a in dir(self.commands[line[0]]) if not
106 a.startswith("__")]
107 return cmds
108 # if command and argument begin was given
109 elif len(line) == 2:
110 return [a + " " for a in dir(self.commands[line[0]]) if
111 a.startswith(line[1])]
112 # else don't complete (or should I?)
113 else:
114 return []
116 def do_help(self, arg):
117 """Show help for commands"""
118 arg = arg.split()
119 if not arg:
120 self.put("Usage: help <command>")
121 else:
122 try:
123 # try to run help() method
124 self.put(getattr(self.commands[arg[0]], "help")())
125 except AttributeError:
126 # try to show __doc__
127 if self.commands[arg[0]].__doc__:
128 self.put(self.commands[arg[0]].__doc__)
129 else:
130 self.put("No help found.")
131 except KeyError:
132 self.put("No help found.")
134 def do_clear(self, *ignored):
135 """Clear the screen"""
136 # TODO 2008-02-09 20:44:50
137 self.put("Todo, sorry")
139 def do_history(self, hnumb=None, *ignored):
140 """Show the history"""
141 # TODO better history listing
142 # 2008-01-27 18:51:22
143 # print whole history
144 if not hnumb:
145 for number in range(1, conf.history_length):
146 cmd = readline.get_history_item(number)
147 if not cmd:
148 break
149 self.put("%6d %s" % (number, cmd))
150 # for history range 12-22 or -22 or 22-
151 else:
152 try:
153 if "-" in hnumb:
154 if hnumb[-1] == "-" or hnumb[0] == "-":
155 start = int(hnumb.replace("-", " "))
156 end = conf.history_length
157 else:
158 start, end = hnumb.split("-")
159 start = int(start)
160 end = int(end) + 1
161 for number in range(start, end):
162 cmd = readline.get_history_item(number)
163 if not cmd:
164 break
165 self.put("%6d %s" % (number, cmd))
166 else:
167 hnumb = int(hnumb)
168 self.put(readline.get_history_item(hnumb))
169 except ValueError:
170 self.put("""Bad value.
171 Usage: history <number or range>
172 history 11-20 -> from 11 to 20
173 history 22- -> from 22 fo the end of history file
174 history -22 -> same as 22-""")
176 def do_quit(self, *ignored):
177 """Quit from shell"""
178 if conf.history_length:
179 readline.write_history_file(conf.history_file)
180 print ""
181 sys.exit(1)
183 # function aliases
184 do_EOF = do_quit
185 do_exit = do_quit
187 if __name__ == "__main__":
188 shell = AurShell()
189 try:
190 shell.cmdloop()
191 except KeyboardInterrupt:
192 # TODO 2008-01-27 16:56:31
193 sys.exit(shell.do_quit())