class Console: """ Main class used for handling the actually input/output of the program. TODO: - More commands/finish current commands. - Read settings from a configuration file. Preferably JSON. """ colors = Color() cursor = ">" current_module = None module = None ostream = sys.stdout istream = sys.stdin def __init__(self, **kwargs): """ Constructor for the console. Only accepts 'cursor', 'ostream' and 'istream' kwargs. """ for key, value in kwargs.items(): if key in ["cursor", "ostream", "istream"]: setattr(self, key, value) else: raise ConsoleError("unexpected keyword argument '%s'" % key) if not self.ostream is sys.stdout: self.colors.disable() self.stack = CommandStack(self) def write(self, output): self.ostream.write(output) def writeln(self, output): self.write(output + "\n") def set_color(self, color): try: newcolor = getattr(self.colors, color) except AttributeError: raise ConsoleError("invalid color '%s'" % color) else: self.write(newcolor) def disable_colors(self): self.colors.disable() def enable_colors(self): self.colors.enable() def prompt(self): """ Prints the cursor, as well as the currently loaded module if available, and then waits for input. """ self.set_color("blue") self.write(self.cursor + " ") if self.current_module: self.set_color("bold") self.write("(%s) " % self.current_module) self.set_color("white") def get_input(self): """ Reads user input from istream, and then returns the input """ user_input = self.istream.readline() return user_input def parse_input(self, user_input): """ Checks if a command is valid - if not, prints an error. Else, pop all other arguments to a list and then call the command with the given args """ for arg in user_input.split(): self.stack.push(arg) command = self.stack.pop() arguments = [] if not command in commands_list.keys(): #don't crash if the user accidentally presses enter if command==None: self.error("please write a command.") else: self.error("command '%s' not found." % command) self.writeln("Enter 'help' or '?' to get a list of commands") while not self.stack.is_empty(): self.stack.pop() return while not self.stack.is_empty(): arguments.append(self.stack.pop()) self.call(command, arguments) def error(self, error): """ Used for quickly/simply writing an error to ostream. """ self.set_color("red") self.write("[-] error: ") self.set_color("white") self.writeln(error) def warn(self, message): """ Used for quickly/simply writing a warning to ostream. """ self.set_color("cyan") self.write("[-] warning: ") self.set_color("white") self.writeln(message) def debug(self, message): """ Used for quickly/simply writing a debug statement to ostream. """ self.set_color("dark_blue") self.write("[*] debug: ") self.set_color("white") self.writeln(message) def info(self, message): """ Used for quickly/simply writing an info statement to ostream. """ self.set_color("green") self.write("[+] ") self.set_color("white") self.writeln(message) def call(self, command, arguments): """ Execute's the callback funcion for the given command, passing along arguments. """ commands_list[command](self)._callback(*arguments) def set_module(self, new_module): name = new_module.split("/")[-1] # Replace /'s with .'s mod_path = new_module.replace("/", ".") # Strip the first "." mod_path = mod_path.lstrip('.') # Load the actual module class file try: module = __import__(mod_path, fromlist=[name]) except SyntaxError, e: self.error("module contains a syntax error and cannot be loaded") traceback.print_exc(e) return try: name = getattr(module, '__module__') except AttributeError: name = name.title() klass = getattr(module, name) self.module = klass(self) self.current_module = new_module