class ClassicPythonShell(Shell, ConsoleProgressBarMixin): """Classic Python shell interface. This class allows igraph to be embedded in Python's shell.""" def __init__(self): """Constructor. Imports Python's classic shell""" Shell.__init__(self) self._shell = None try: self.__class__.progress_bar = ProgressBar(TerminalController()) except ValueError: # Terminal is not capable enough, disable progress handler del self.__class__._progress_handler def __call__(self): """Starts the embedded shell.""" if self._shell is None: from code import InteractiveConsole self._shell = InteractiveConsole() print >> sys.stderr, "igraph %s running inside " % __version__, self._shell.runsource("from igraph import *") self._shell.interact()
def interactive_client(file, address, cache_size, readonly, repair, startup): if file: storage = FileStorage(file, readonly=readonly, repair=repair) description = file else: socket_address = SocketAddress.new(address) wait_for_server(address=socket_address) storage = ClientStorage(address=socket_address) description = socket_address connection = Connection(storage, cache_size=cache_size) console_module = ModuleType('__console__') sys.modules['__console__'] = console_module namespace = {'connection': connection, 'root': connection.get_root(), 'get': connection.get, 'sys': sys, 'os': os, 'int8_to_str': int8_to_str, 'str_to_int8': str_to_int8, 'pp': pprint} vars(console_module).update(namespace) configure_readline( vars(console_module), os.path.expanduser("~/.durushistory")) console = InteractiveConsole(vars(console_module)) if startup: src = '''with open('{fn}', 'rb') as _: _ = compile(_.read(), '{fn}', 'exec') exec(globals().pop('_')) '''.format(fn = os.path.expanduser(startup)).rstrip() console.runsource(src, '-stub-', 'exec') help = (' connection -> the Connection\n' ' root -> the root instance') console.interact('Durus %s\n%s' % (description, help))
def interactive_client(file, host, port, cache_size, readonly, repair, startup): if file: storage = FileStorage(file, readonly=readonly, repair=repair) description = file else: wait_for_server(host, port) storage = ClientStorage(host=host, port=port) description = "%s:%s" % (host, port) connection = Connection(storage, cache_size=cache_size) namespace = {'connection': connection, 'root': connection.get(0), 'get': connection.get, 'sys': sys, 'os': os, 'p64': p64, 'u64': u64, 'pp': pprint} configure_readline(namespace, os.path.expanduser("~/.durushistory")) console = InteractiveConsole(namespace) if startup: console.runsource('execfile("%s")' % os.path.expanduser(startup)) help = (' connection -> the connection\n' ' root -> get(0)\n' ' get(oid) -> get an object\n' ' pp(object) -> pretty-print') console.interact('Durus (%s)\n%s' % (description, help))
def interactive_client(file, address, cache_size, readonly, repair, startup, storage_class=None): if file: storage = get_storage(file, storage_class=storage_class, readonly=readonly, repair=repair) description = file else: socket_address = SocketAddress.new(address) wait_for_server(address=socket_address) storage = ClientStorage(address=socket_address) description = socket_address connection = Connection(storage, cache_size=cache_size) console_module = ModuleType('__console__') sys.modules['__console__'] = console_module namespace = {'connection': connection, 'root': connection.get_root(), 'get': connection.get, 'sys': sys, 'os': os, 'int8_to_str': int8_to_str, 'str_to_int8': str_to_int8, 'pp': pprint} vars(console_module).update(namespace) configure_readline( vars(console_module), os.path.expanduser("~/.durushistory")) console = InteractiveConsole(vars(console_module)) if startup: console.runsource('execfile("%s")' % os.path.expanduser(startup)) help = (' connection -> the Connection\n' ' root -> the root instance') console.interact('Durus %s\n%s' % (description, help))
def runsource(self, source, filename="<input>", symbol="single"): try: # do some special pretty printing if the source is an expression code = self.compile(source, filename, "eval") eval_expression = True except (OverflowError, SyntaxError, ValueError): eval_expression = False if eval_expression: if code is None: return True try: result = eval(code, self.locals) self.pretty_print(result) except SystemExit: raise except: self.showtraceback() else: if softspace(sys.stdout, 0): print return False else: # fall back to default behavior return InteractiveConsole.runsource(self, source, filename, symbol)
def push(self,line, mode='single', name='auto'): self.last_op = datetime.now() self.accept_output() signal.setitimer(signal.ITIMER_VIRTUAL,10) ret = InteractiveConsole.runsource(self,line,'<'+name+'>',mode) signal.setitimer(signal.ITIMER_VIRTUAL,0) self.return_output() return ret
def runsource(self, source, filename="<stdin>", symbol="single"): if not self.compiler: from pysoc import compiler self.compiler = compiler source = self.compiler.compile(source) try: return InteractiveConsole.runsource(self, source, filename, symbol) except SystemExit, e: sys.exit(0)
def runsource(self, source, filename="<stdin>", symbol="single"): if not self.compiler: from pysoc import compiler self.compiler = compiler source = self.compiler.compile(source) try : return InteractiveConsole.runsource(self, source, filename, symbol) except SystemExit, e: sys.exit(0)
def runsource(self, source, filename="<input>", symbol="single"): """ THis function ... :param source: :param filename: :param symbol: :return: """ #if self.remote is not None: #if self.remote_session is not None: if self.locals["session"] is not None: if "Frame.from_file" in source: variable_name = source.split("=")[0].strip() #print(variable_name) #print(source.split("Frame(")[1]) arguments = source.split("from_file(")[1].split(")")[0].split( ",") path = arguments[0] #print(arguments) source = variable_name + " = RemoteFrame.from_file(" + path + ", session)" #print(source) #source = source.replace("Image.from_file(", "RemoteImage") #source = source.replace("DataCube.from_file", "RemoteDataCube") #print(source) # Run the code InteractiveConsole.runsource(self, source, filename=filename, symbol=symbol)
class ClassicPythonShell(Shell, ConsoleProgressBarMixin): """Classic Python shell interface. This class allows igraph to be embedded in Python's shell.""" def __init__(self): """Constructor. Imports Python's classic shell""" Shell.__init__(self) ConsoleProgressBarMixin.__init__(self) self._shell = None def __call__(self): """Starts the embedded shell.""" if self._shell is None: from code import InteractiveConsole self._shell = InteractiveConsole() print >> sys.stderr, "igraph %s running inside " % __version__, self._shell.runsource("from igraph import *") self._shell.interact()
def simple_repl(user_ns={}): if iswindows: setup_pyreadline() else: try: import rlcompleter # noqa import readline # noqa readline.parse_and_bind("tab: complete") except ImportError: pass user_ns = user_ns or {} import sys, re # noqa for x in ('os', 'sys', 're'): user_ns[x] = user_ns.get(x, globals().get(x, locals().get(x))) user_ns['exit'] = Exit() user_ns['help'] = Helper() from code import InteractiveConsole console = InteractiveConsole(user_ns) console.runsource('from __future__ import (unicode_literals, division, absolute_import, print_function)') console.interact(BANNER + 'Use exit to quit')
def runsource(self,source,filename="<input>",symbol="single"): old_stdout = sys.stdout old_stderr = sys.stderr sys.stdout = sys.stderr = collector = MyStringIO(self) try: more = _InteractiveConsole.runsource(self,source,filename,symbol) finally: if sys.stdout is collector: sys.stdout = old_stdout if sys.stderr is collector: sys.stderr = old_stderr return more
def runsource(self,source,filename="<input>",symbol="single"): old_stdout = sys.stdout old_stderr = sys.stderr sys.stdout = sys.stderr = collector = StringIO() try: more = _InteractiveConsole.runsource(self,source,filename,symbol) finally: if sys.stdout is collector: sys.stdout = old_stdout if sys.stderr is collector: sys.stderr = old_stderr self.write(collector.getvalue()) return more
class ClassicPythonShell(Shell): """Classic Python shell interface. This class allows igraph to be embedded in Python's shell.""" def __init__(self): """Constructor. Imports Python's classic shell""" from code import InteractiveConsole try: self.__class__.progress_bar = ProgressBar(TerminalController()) except ValueError: # Terminal is not capable enough, disable progress handler del self.__class__._progress_handler def __call__(self, namespace=None): """Starts the embedded shell. @param namespace: global namespace to use""" from code import InteractiveConsole self._shell = InteractiveConsole(locals=namespace) print >>sys.stderr, "igraph %s running inside " % __version__, self._shell.runsource("from igraph import *") self._shell.interact() def _progress_handler(message, percentage): """Progress bar handler, called when C{igraph} reports the progress of an operation @param message: message provided by C{igraph} @param percentage: percentage provided by C{igraph} """ if percentage >= 100: ClassicPythonShell.progress_bar.clear() else: ClassicPythonShell.progress_bar.update(percentage, message) _progress_handler = staticmethod(_progress_handler)
def runsource(self, source, *args): # load the source # if there is Vivaldi function definition # function_code_dict will be updated new_function_code_dict = load_common(code=source) function_code_dict.update(new_function_code_dict) from Vivaldi_translator_layer import read_as_main source = read_as_main(source) #MARK : debug #print "source :" #print repr(source) src_list = source.split('\n') src_body = '\n'.join(src_list[:-1]) src_tail = src_list[-1] # 2-1. block input if InteractiveConsole.runsource(self,src_body,*args): return InteractiveConsole.runsource(self,source,*args) # 2-2. single line else : return InteractiveConsole.runsource(self,src_tail,*args)
def runsource(self, source, filename="<input>", symbol="single"): """Do the same thing as any InteractiveConsole, except if we run into a completed statement, we first run the decoration code for envdraw on it before passing it off to the execute part of the REPL. """ try: if compile_command(source, filename, symbol): tree = ast.parse(source, filename, symbol) new_tree = ast.fix_missing_locations(AddFuncCall().visit( AddFuncReturn().visit( AddFuncDef().visit(tree)))) compiled_code = compile(new_tree, filename, symbol) self.runcode(compiled_code) TRACKER.insert_global_bindings(self.locals) return False else: return InteractiveConsole.runsource(self, source, filename, symbol) except (SyntaxError, OverflowError): self.showsyntaxerror(filename) return False
class Console: def __init__(self, screen, rect, functions={}, key_calls={}, vars={}, syntax={}): if not pygame.display.get_init(): raise pygame.error, "Display not initialized. Initialize the display before creating a Console" if not pygame.font.get_init(): pygame.font.init() self.parent_screen = screen self.rect = pygame.Rect(rect) self.size = self.rect.size self.user_vars = vars self.user_syntax = syntax self.user_namespace = {} self.variables = {\ "bg_alpha":int,\ "bg_color": list,\ "txt_color_i": list,\ "txt_color_o": list,\ "ps1": str,\ "ps2": str,\ "ps3": str,\ "active": bool,\ "repeat_rate": list,\ "preserve_events":bool,\ "python_mode":bool,\ "motd":list } self.load_cfg() self.set_interpreter() pygame.key.set_repeat(*self.repeat_rate) self.bg_layer = pygame.Surface(self.size) self.bg_layer.set_alpha(self.bg_alpha) self.txt_layer = pygame.Surface(self.size) self.txt_layer.set_colorkey(self.bg_color) try: self.font = pygame.font.Font( os.path.join(font_path, "default.ttf"), 14) except IOError: self.font = pygame.font.SysFont("monospace", 14) self.font_height = self.font.get_linesize() self.max_lines = (self.size[HEIGHT] / self.font_height) - 1 self.max_chars = ( self.size[WIDTH] / (self.font.size(ascii_letters)[WIDTH] / len(ascii_letters))) - 1 self.txt_wrapper = textwrap.TextWrapper() self.c_out = self.motd self.c_hist = [""] self.c_hist_pos = 0 self.c_in = "" self.c_pos = 0 self.c_draw_pos = 0 self.c_scroll = 0 self.changed = True self.func_calls = {} self.key_calls = {} self.add_func_calls({ "echo": self.output, "clear": self.clear, "help": self.help }) self.add_func_calls(functions) self.add_key_calls({ "l": self.clear, "c": self.clear_input, "w": self.set_active }) self.add_key_calls(key_calls) ################## #-Initialization-# def load_cfg(self): '''\ Loads the config file path/pygame-console.cfg\ All variables are initialized to their defaults,\ then new values will be loaded from the config file if it exists. ''' self.init_default_cfg() if os.path.exists(cfg_path): for line in file(cfg_path): tokens = self.tokenize(line) if re_is_comment.match(line): continue elif len(tokens) != 2: continue self.safe_set_attr(tokens[0], tokens[1]) def init_default_cfg(self): self.bg_alpha = 255 self.bg_color = [0x0, 0x0, 0x0] self.txt_color_i = [0xFF, 0xFF, 0xFF] self.txt_color_o = [0xCC, 0xCC, 0xCC] self.ps1 = "] " self.ps2 = ">>> " self.ps3 = "... " self.active = False self.repeat_rate = [500, 30] self.python_mode = False self.preserve_events = False self.motd = ["[PyConsole 0.5]"] def safe_set_attr(self, name, value): '''\ Safely set the console variables ''' if name in self.variables: if isinstance(value, self.variables[name]) or not self.variables[name]: self.__dict__[name] = value def add_func_calls(self, functions): '''\ Add functions to the func_calls dictionary. Arguments: functions -- dictionary of functions to add. ''' if isinstance(functions, dict): self.func_calls.update(functions) self.user_namespace.update(self.func_calls) def add_key_calls(self, functions): '''\ Add functions to the key_calls dictionary. Arguments: functions -- dictionary of key_calls to add. ''' if isinstance(functions, dict): self.key_calls.update(functions) def output(self, text): '''\ Prepare text to be displayed Arguments: text -- Text to be displayed ''' if not str(text): return try: self.changed = True if not isinstance(text, str): text = str(text) text = text.expandtabs() text = text.splitlines() self.txt_wrapper.width = self.max_chars for line in text: for w in self.txt_wrapper.wrap(line): self.c_out.append(w) except: pass def set_active(self, b=None): '''\ Activate or Deactivate the console Arguments: b -- Optional boolean argument, True=Activate False=Deactivate ''' if not b: self.active = not self.active else: self.active = b def format_input_line(self): '''\ Format input line to be displayed ''' # The \v here is sort of a hack, it's just a character that isn't recognized by the font engine text = self.c_in[:self.c_pos] + "\v" + self.c_in[self.c_pos + 1:] n_max = self.max_chars - len(self.c_ps) vis_range = self.c_draw_pos, self.c_draw_pos + n_max return self.c_ps + text[vis_range[0]:vis_range[1]] def draw(self): '''\ Draw the console to the parent screen ''' if not self.active: return if self.changed: self.changed = False # Draw Output self.txt_layer.fill(self.bg_color) lines = self.c_out[-(self.max_lines + self.c_scroll):len(self.c_out) - self.c_scroll] y_pos = self.size[HEIGHT] - (self.font_height * (len(lines) + 1)) for line in lines: tmp_surf = self.font.render(line, True, self.txt_color_o) self.txt_layer.blit(tmp_surf, (1, y_pos, 0, 0)) y_pos += self.font_height # Draw Input tmp_surf = self.font.render(self.format_input_line(), True, self.txt_color_i) self.txt_layer.blit( tmp_surf, (1, self.size[HEIGHT] - self.font_height, 0, 0)) # Clear background and blit text to it self.bg_layer.fill(self.bg_color) self.bg_layer.blit(self.txt_layer, (0, 0, 0, 0)) # Draw console to parent screen # self.parent_screen.fill(self.txt_color_i, (self.rect.x-1, self.rect.y-1, self.size[WIDTH]+2, self.size[HEIGHT]+2)) pygame.draw.rect(self.parent_screen, self.txt_color_i, (self.rect.x - 1, self.rect.y - 1, self.size[WIDTH] + 2, self.size[HEIGHT] + 2), 1) self.parent_screen.blit(self.bg_layer, self.rect) ####################################################################### # Functions to communicate with the console and the python interpreter# def set_interpreter(self): if self.python_mode: self.output("Entering Python mode") self.python_mode = True self.python_interpreter = InteractiveConsole() self.tmp_fds = [] self.py_fds = [Writable() for i in range(3)] self.c_ps = self.ps2 else: self.output("Entering Pyconsole mode") self.python_mode = False self.c_ps = self.ps1 def catch_output(self): if not self.tmp_fds: self.tmp_fds = [sys.stdout, sys.stdin, sys.stderr] sys.stdout, sys.stdin, sys.stderr = self.py_fds def release_output(self): if self.tmp_fds: sys.stdout, sys.stdin, sys.stderr = self.tmp_fds self.tmp_fds = [] [fd.reset() for fd in self.py_fds] def submit_input(self, text): '''\ Submit input 1) Move input to output 2) Evaluate input 3) Clear input line ''' self.clear_input() self.output(self.c_ps + text) self.c_scroll = 0 if self.python_mode: self.send_python(text) else: self.send_pyconsole(text) def send_python(self, text): '''\ Sends input the the python interpreter in effect giving the user the ability to do anything python can. ''' self.c_ps = self.ps2 self.catch_output() if text: self.add_to_history(text) r = self.python_interpreter.push(text) if r: self.c_ps = self.ps3 else: code = "".join(self.py_fds[OUT]) self.python_interpreter.push("\n") self.python_interpreter.runsource(code) for i in self.py_fds[OUT] + self.py_fds[ERR]: self.output(i) self.release_output() def send_pyconsole(self, text): '''\ Sends input to pyconsole to be interpreted ''' if not text: # Output a blank row if nothing is entered self.output("") return self.add_to_history(text) #Determine if the statement is an assignment assign = re_is_assign.match(text) try: #If it is tokenize only the "value" part of $name = value if assign: tokens = self.tokenize(assign.group('value')) else: tokens = self.tokenize(text) except ParseError, e: self.output(r'At Token: "%s"' % e.at_token()) return if tokens == None: return #Evaluate try: out = None # A variable alone on a line if (len(tokens) is 1) and re_is_var.match(text) and not assign: out = tokens[0] # Statement in the form $name = value elif (len(tokens) is 1) and assign: self.setvar(assign.group('name'), tokens[0]) else: # Function out = self.func_calls[tokens[0]](*tokens[1:]) # Assignment from function's return value if assign: self.setvar(assign.group('name'), out) if not out == None: self.output(out) except (KeyError, TypeError): self.output("Unknown Command: " + str(tokens[0])) self.output(r'Type "help" for a list of commands.')
class Console: def __init__(self, screen, rect, functions={}, key_calls={}, vars={}, syntax={}): if not pygame.display.get_init(): raise pygame.error("Display not initialized. Initialize the \ display before creating a Console") if not pygame.font.get_init(): pygame.font.init() self.parent_screen = screen self.rect = pygame.Rect(rect) self.size = self.rect.size self.user_vars = vars self.user_syntax = syntax self.user_namespace = {} self.variables = { "bg_alpha": int, "bg_color": list, "txt_color_i": list, "txt_color_o": list, "ps1": str, "ps2": str, "ps3": str, "active": bool, "repeat_rate": list, "preserve_events": bool, "python_mode": bool, "motd": list } self.load_cfg() self.set_interpreter() # pygame.key.set_repeat(*self.repeat_rate) self.bg_layer = pygame.Surface(self.size) self.bg_layer.set_alpha(self.bg_alpha) self.txt_layer = pygame.Surface(self.size) self.txt_layer.set_colorkey(self.bg_color) try: self.font = pygame.font.Font( os.path.join(font_path, "default.ttf"), 14) except IOError: self.font = pygame.font.SysFont("monospace", 14) self.font_height = self.font.get_linesize() self.max_lines = (self.size[HEIGHT] / self.font_height) - 1 self.max_chars = ( self.size[WIDTH] / (self.font.size(ascii_letters)[WIDTH] / len(ascii_letters))) - 1 self.txt_wrapper = textwrap.TextWrapper() self.c_out = self.motd self.c_hist = [""] self.c_hist_pos = 0 self.c_in = "" self.c_pos = 0 self.c_draw_pos = 0 self.c_scroll = 0 self.changed = True self.func_calls = {} self.key_calls = {} self.add_func_calls({ "echo": self.output, "clear": self.clear, "help": self.help }) self.add_func_calls(functions) self.add_key_calls({ "l": self.clear, "c": self.clear_input, "w": self.set_active }) self.add_key_calls(key_calls) ################## # -Initialization-# def load_cfg(self): '''\ Loads the config file path/pygame-console.cfg\ All variables are initialized to their defaults,\ then new values will be loaded from the config file if it exists. ''' self.init_default_cfg() if os.path.exists(cfg_path): for line in file(cfg_path): tokens = self.tokenize(line) if re_is_comment.match(line): continue elif len(tokens) != 2: continue self.safe_set_attr(tokens[0], tokens[1]) def init_default_cfg(self): self.bg_alpha = 255 self.bg_color = [0x0, 0x0, 0x0] self.txt_color_i = [0xFF, 0xFF, 0xFF] self.txt_color_o = [0xCC, 0xCC, 0xCC] self.ps1 = "] " self.ps2 = ">>> " self.ps3 = "... " self.active = False self.repeat_rate = [500, 30] self.python_mode = False self.preserve_events = False self.motd = ["[PyConsole 0.5]"] def safe_set_attr(self, name, value): '''\ Safely set the console variables ''' if name in self.variables: if isinstance(value, self.variables[name]) or not self.variables[name]: self.__dict__[name] = value def add_func_calls(self, functions): '''\ Add functions to the func_calls dictionary. Arguments: functions -- dictionary of functions to add. ''' if isinstance(functions, dict): self.func_calls.update(functions) self.user_namespace.update(self.func_calls) def add_key_calls(self, functions): '''\ Add functions to the key_calls dictionary. Arguments: functions -- dictionary of key_calls to add. ''' if isinstance(functions, dict): self.key_calls.update(functions) def output(self, text): '''\ Prepare text to be displayed Arguments: text -- Text to be displayed ''' if not str(text): return try: self.changed = True if not isinstance(text, str): text = str(text) text = text.expandtabs() text = text.splitlines() self.txt_wrapper.width = self.max_chars for line in text: for w in self.txt_wrapper.wrap(line): self.c_out.append(w) except BaseException: pass def set_active(self, b=None): '''\ Activate or Deactivate the console Arguments: b -- Optional boolean argument, True=Activate False=Deactivate ''' if not b: self.active = not self.active else: self.active = b def format_input_line(self): '''\ Format input line to be displayed ''' # The \v here is sort of a hack, it's just a character that isn't # recognized by the font engine text = self.c_in[:self.c_pos] + "\v" + self.c_in[self.c_pos + 1:] n_max = self.max_chars - len(self.c_ps) vis_range = self.c_draw_pos, self.c_draw_pos + n_max return self.c_ps + text[vis_range[0]:vis_range[1]] def draw(self): '''\ Draw the console to the parent screen ''' if not self.active: return if self.changed: self.changed = False # Draw Output self.txt_layer.fill(self.bg_color) lines = self.c_out[-(self.max_lines + self.c_scroll):len(self.c_out) - self.c_scroll] y_pos = self.size[HEIGHT] - (self.font_height * (len(lines) + 1)) for line in lines: tmp_surf = self.font.render(line, True, self.txt_color_o) self.txt_layer.blit(tmp_surf, (1, y_pos, 0, 0)) y_pos += self.font_height # Draw Input tmp_surf = self.font.render(self.format_input_line(), True, self.txt_color_i) self.txt_layer.blit( tmp_surf, (1, self.size[HEIGHT] - self.font_height, 0, 0)) # Clear background and blit text to it self.bg_layer.fill(self.bg_color) self.bg_layer.blit(self.txt_layer, (0, 0, 0, 0)) # Draw console to parent screen # self.parent_screen.fill(self.txt_color_i, \ # (self.rect.x-1, self.rect.y-1, self.size[WIDTH]+2,\ # self.size[HEIGHT]+2)) pygame.draw.rect(self.parent_screen, self.txt_color_i, (self.rect.x - 1, self.rect.y - 1, self.size[WIDTH] + 2, self.size[HEIGHT] + 2), 1) self.parent_screen.blit(self.bg_layer, self.rect) ####################################################################### # Functions to communicate with the console and the python interpreter# def set_interpreter(self): if self.python_mode: self.output("Entering Python mode") self.python_mode = True self.python_interpreter = InteractiveConsole() self.tmp_fds = [] self.py_fds = [Writable() for i in range(3)] self.c_ps = self.ps2 else: self.output("Entering Pyconsole mode") self.python_mode = False self.c_ps = self.ps1 def catch_output(self): if not self.tmp_fds: self.tmp_fds = [sys.stdout, sys.stdin, sys.stderr] sys.stdout, sys.stdin, sys.stderr = self.py_fds def release_output(self): if self.tmp_fds: sys.stdout, sys.stdin, sys.stderr = self.tmp_fds self.tmp_fds = [] [fd.reset() for fd in self.py_fds] def submit_input(self, text): '''\ Submit input 1) Move input to output 2) Evaluate input 3) Clear input line ''' self.clear_input() self.output(self.c_ps + text) self.c_scroll = 0 if self.python_mode: self.send_python(text) else: self.send_pyconsole(text) def send_python(self, text): '''\ Sends input the the python interpreter in effect giving the user the ability to do anything python can. ''' self.c_ps = self.ps2 self.catch_output() if text: self.add_to_history(text) r = self.python_interpreter.push(text) if r: self.c_ps = self.ps3 else: code = "".join(self.py_fds[OUT]) self.python_interpreter.push("\n") self.python_interpreter.runsource(code) for i in self.py_fds[OUT] + self.py_fds[ERR]: self.output(i) self.release_output() def send_pyconsole(self, text): '''\ Sends input to pyconsole to be interpreted ''' if not text: # Output a blank row if nothing is entered self.output("") return self.add_to_history(text) # Determine if the statement is an assignment assign = re_is_assign.match(text) try: # If it is tokenize only the "value" part of $name = value if assign: tokens = self.tokenize(assign.group('value')) else: tokens = self.tokenize(text) except ParseError as e: self.output(r'At Token: "%s"' % e.at_token()) return if tokens is None: return # Evaluate try: out = None # A variable alone on a line if (len(tokens) == 1) and re_is_var.match(text) and not assign: out = tokens[0] # Statement in the form $name = value elif (len(tokens) == 1) and assign: self.setvar(assign.group('name'), tokens[0]) else: # Function out = self.func_calls[tokens[0]](*tokens[1:]) # Assignment from function's return value if assign: self.setvar(assign.group('name'), out) if out is not None: self.output(out) except (KeyError, TypeError): self.output("Unknown Command: " + str(tokens[0])) self.output(r'Type "help" for a list of commands.') #################################################### # -Functions for sharing variables with the console-# def setvar(self, name, value): '''\ Sets the value of a variable ''' if name in self.user_vars or name not in self.__dict__: self.user_vars.update({name: value}) self.user_namespace.update(self.user_vars) elif name in self.__dict__: self.__dict__.update({name: value}) def getvar(self, name): '''\ Gets the value of a variable, this is useful for people that want to access console variables from within their game ''' if name in self.user_vars or name not in self.__dict__: return self.user_vars[name] elif name in self.__dict__: return self.__dict__[name] def setvars(self, vars): try: self.user_vars.update(vars) self.user_namespace.update(self.user_vars) except TypeError: self.output("setvars requires a dictionary") def getvars(self, opt_dict=None): if opt_dict: opt_dict.update(self.user_vars) else: return self.user_vars def add_to_history(self, text): '''\ Add specified text to the history ''' self.c_hist.insert(-1, text) self.c_hist_pos = len(self.c_hist) - 1 def clear_input(self): '''\ Clear input line and reset cursor position ''' self.c_in = "" self.c_pos = 0 self.c_draw_pos = 0 def set_pos(self, newpos): '''\ Moves cursor safely ''' self.c_pos = newpos if (self.c_pos - self.c_draw_pos) >= (self.max_chars - len(self.c_ps)): self.c_draw_pos = max( 0, self.c_pos - (self.max_chars - len(self.c_ps))) elif self.c_draw_pos > self.c_pos: self.c_draw_pos = self.c_pos - (self.max_chars / 2) if self.c_draw_pos < 0: self.c_draw_pos = 0 self.c_pos = 0 def str_insert(self, text, strn): '''\ Insert characters at the current cursor position ''' foo = text[:self.c_pos] + strn + text[self.c_pos:] self.set_pos(self.c_pos + len(strn)) return foo def process_input(self, event): '''\ Loop through pygame events and evaluate them ''' if not self.active: return False if event.type == KEYDOWN: self.changed = True # Special Character Manipulation if event.key == K_TAB: self.c_in = self.str_insert(self.c_in, " ") elif event.key == K_BACKSPACE: if self.c_pos > 0: self.c_in = self.c_in[:self.c_pos - 1] + self.c_in[self.c_pos:] self.set_pos(self.c_pos - 1) elif event.key == K_DELETE: if self.c_pos < len(self.c_in): self.c_in = self.c_in[:self.c_pos] + \ self.c_in[self.c_pos + 1:] elif event.key == K_RETURN or event.key == 271: self.submit_input(self.c_in) # Changing Cursor Position elif event.key == K_LEFT: if self.c_pos > 0: self.set_pos(self.c_pos - 1) elif event.key == K_RIGHT: if self.c_pos < len(self.c_in): self.set_pos(self.c_pos + 1) elif event.key == K_HOME: self.set_pos(0) elif event.key == K_END: self.set_pos(len(self.c_in)) # History Navigation elif event.key == K_UP: if len(self.c_out): if self.c_hist_pos > 0: self.c_hist_pos -= 1 self.c_in = self.c_hist[self.c_hist_pos] self.set_pos(len(self.c_in)) elif event.key == K_DOWN: if len(self.c_out): if self.c_hist_pos < len(self.c_hist) - 1: self.c_hist_pos += 1 self.c_in = self.c_hist[self.c_hist_pos] self.set_pos(len(self.c_in)) # Scrolling elif event.key == K_PAGEUP: if self.c_scroll < len(self.c_out) - 1: self.c_scroll += 1 elif event.key == K_PAGEDOWN: if self.c_scroll > 0: self.c_scroll -= 1 # Normal character printing elif event.key >= 32: mods = pygame.key.get_mods() if mods & KMOD_CTRL: if event.key in range(256) and chr( event.key) in self.key_calls: self.key_calls[chr(event.key)]() else: char = str(event.str) self.c_in = self.str_insert(self.c_in, char) return True def convert_token(self, tok): '''\ Convert a token to its proper type ''' tok = tok.strip("$") try: tmp = eval(tok, self.__dict__, self.user_namespace) except SyntaxError as strerror: self.output("SyntaxError: " + str(strerror)) raise ParseError(tok) except TypeError as strerror: self.output("TypeError: " + str(strerror)) raise ParseError(tok) except NameError as strerror: self.output("NameError: " + str(strerror)) except BaseException: self.output("Error:") raise ParseError(tok) else: return tmp def tokenize(self, s): '''\ Tokenize input line, convert tokens to proper types ''' if re_is_comment.match(s): return [s] for x in self.user_syntax: group = x.match(s) if group: self.user_syntax[x](self, group) return tokens = re_token.findall(s) tokens = [i.strip("\"") for i in tokens] cmd = [] i = 0 while i < len(tokens): t_count = 0 val = tokens[i] if re_is_number.match(val): cmd.append(self.convert_token(val)) elif re_is_var.match(val): cmd.append(self.convert_token(val)) elif val == "True": cmd.append(True) elif val == "False": cmd.append(False) elif re_is_list.match(val): while not balanced(val) and (i + t_count) < len(tokens) - 1: t_count += 1 val += tokens[i + t_count] else: if (i + t_count) < len(tokens): cmd.append(self.convert_token(val)) else: raise ParseError(val) else: cmd.append(val) i += t_count + 1 return cmd ########################## # -Some Builtin functions-# def clear(self): '''\ Clear the Screen ''' self.c_out = ["[Screen Cleared]"] self.c_scroll = 0 def help(self, *args): '''\ Output information about functions Arguments: args -- arbitrary argument list of function names |- No Args - A list of available functions will be displayed |- One or more Args - Docstring of each function will be displayed ''' if args: items = [(i, self.func_calls[i]) for i in args if i in self.func_calls] for i, v in items: out = i + ": Takes %d arguments. " % ( v.__code__.co_argcount - (v.__code__.co_varnames[0] == "self")) doc = v.__doc__ if doc: out += textwrap.dedent(doc) tmp_indent = self.txt_wrapper.subsequent_indent self.txt_wrapper.subsequent_indent = " " * (len(i) + 2) self.output(out) self.txt_wrapper.subsequent_indent = tmp_indent else: out = "Available commands: " + \ str(list(self.func_calls.keys())).strip("[]") self.output(out) self.output(r'Type "help command-name" for more\ information on that command')
def runsource(self, source, *args): self.last_buffer = [source.encode('utf-8')] return InteractiveConsole.runsource(self, source, *args)
class Console(object): def __init__(self, screen, rect, functions={}, key_calls={}, vars={}, syntax={}): if not pygame.display.get_init(): raise pygame.error, "Display not initialized. Initialize the display before creating a Console" if not pygame.font.get_init(): pygame.font.init() self.parent_screen = screen self.rect = pygame.Rect(rect) self.size = self.rect.size self.user_vars = vars self.user_syntax = syntax self.user_namespace = {} self.variables = {\ "bg_alpha":int,\ "bg_color": list,\ "txt_color_i": list,\ "txt_color_o": list,\ "ps1": str,\ "ps2": str,\ "ps3": str,\ "active": bool,\ "repeat_rate": list,\ "preserve_events":bool,\ "python_mode":bool,\ "motd":list } self.load_cfg() self.set_interpreter() pygame.key.set_repeat(*self.repeat_rate) self.bg_layer = pygame.Surface(self.size) self.bg_layer.set_alpha(self.bg_alpha) self.txt_layer = pygame.Surface(self.size) self.txt_layer.set_colorkey(self.bg_color) try: self.font = pygame.font.Font(os.path.join(font_path,"default.ttf"), 14) except IOError: self.font = pygame.font.SysFont("monospace", 14) self.font_height = self.font.get_linesize() self.max_lines = (self.size[HEIGHT] / self.font_height) - 1 self.max_chars = (self.size[WIDTH]/(self.font.size(ascii_letters)[WIDTH]/len(ascii_letters))) - 1 self.txt_wrapper = textwrap.TextWrapper() self.c_out = self.motd self.c_hist = [""] self.c_hist_pos = 0 self.c_in = "" self.c_pos = 0 self.c_draw_pos = 0 self.c_scroll = 0 self.changed = True self.func_calls = {} self.key_calls = {} self.add_func_calls({"echo":self.output, "clear": self.clear, "help":self.help}) self.add_func_calls(functions) self.add_key_calls({"l":self.clear, "c":self.clear_input, "w":self.set_active}) self.add_key_calls(key_calls) ################## #-Initialization-# def load_cfg(self): '''\ Loads the config file path/pygame-console.cfg\ All variables are initialized to their defaults,\ then new values will be loaded from the config file if it exists. ''' self.init_default_cfg() if os.path.exists(cfg_path): for line in file(cfg_path): tokens = self.tokenize(line) if re_is_comment.match(line): continue elif len(tokens) != 2: continue self.safe_set_attr(tokens[0],tokens[1]) def init_default_cfg(self): self.bg_alpha = 255 self.bg_color = [0x0,0x0,0x0] self.txt_color_i = [0xFF,0xFF,0xFF] self.txt_color_o = [0xCC,0xCC,0xCC] self.ps1 = "] " self.ps2 = ">>> " self.ps3 = "... " self.active = False self.repeat_rate = [500,30] self.python_mode = False self.preserve_events = False self.motd = ["[PyConsole 0.5]"] def safe_set_attr(self, name, value): '''\ Safely set the console variables ''' if name in self.variables: if isinstance(value, self.variables[name]) or not self.variables[name]: self.__dict__[name] = value def add_func_calls(self, functions): '''\ Add functions to the func_calls dictionary. Arguments: functions -- dictionary of functions to add. ''' if isinstance(functions,dict): self.func_calls.update(functions) self.user_namespace.update(self.func_calls) def add_key_calls(self, functions): '''\ Add functions to the key_calls dictionary. Arguments: functions -- dictionary of key_calls to add. ''' if isinstance(functions,dict): self.key_calls.update(functions) def output(self, text): '''\ Prepare text to be displayed Arguments: text -- Text to be displayed ''' if not str(text): return; try: self.changed = True if not isinstance(text,str): text = str(text) text = text.expandtabs() text = text.splitlines() self.txt_wrapper.width = self.max_chars for line in text: for w in self.txt_wrapper.wrap(line): self.c_out.append(w) except: pass def toggle_active(self): self.active = not self.active def set_active(self,b=None): '''\ Activate or Deactivate the console Arguments: b -- Optional boolean argument, True=Activate False=Deactivate ''' # ??? if not b: self.active = not self.active else: self.active = b def format_input_line(self): '''\ Format input line to be displayed ''' # The \v here is sort of a hack, it's just a character that isn't recognized by the font engine text = self.c_in[:self.c_pos] + "\v" + self.c_in[self.c_pos+1:] n_max = self.max_chars - len(self.c_ps) vis_range = self.c_draw_pos, self.c_draw_pos + n_max return self.c_ps + text[vis_range[0]:vis_range[1]] def draw(self): '''\ Draw the console to the parent screen ''' if not self.active: return; if self.changed: self.changed = False # Draw Output self.txt_layer.fill(self.bg_color) lines = self.c_out[-(self.max_lines+self.c_scroll):len(self.c_out)-self.c_scroll] y_pos = self.size[HEIGHT]-(self.font_height*(len(lines)+1)) for line in lines: tmp_surf = self.font.render(line, True, self.txt_color_o) self.txt_layer.blit(tmp_surf, (1, y_pos, 0, 0)) y_pos += self.font_height # Draw Input tmp_surf = self.font.render(self.format_input_line(), True, self.txt_color_i) self.txt_layer.blit(tmp_surf, (1,self.size[HEIGHT]-self.font_height,0,0)) # Clear background and blit text to it self.bg_layer.fill(self.bg_color) self.bg_layer.blit(self.txt_layer,(0,0,0,0)) # Draw console to parent screen # self.parent_screen.fill(self.txt_color_i, (self.rect.x-1, self.rect.y-1, self.size[WIDTH]+2, self.size[HEIGHT]+2)) pygame.draw.rect(self.parent_screen, self.txt_color_i, (self.rect.x-1, self.rect.y-1, self.size[WIDTH]+2, self.size[HEIGHT]+2), 1) self.parent_screen.blit(self.bg_layer,self.rect) ####################################################################### # Functions to communicate with the console and the python interpreter# def set_interpreter(self): if self.python_mode: self.output("Entering Python mode") self.python_mode = True self.python_interpreter = InteractiveConsole() self.tmp_fds = [] self.py_fds = [Writable() for i in range(3)] self.c_ps = self.ps2 else: self.output("Entering Pyconsole mode") self.python_mode = False self.c_ps = self.ps1 def catch_output(self): if not self.tmp_fds: self.tmp_fds = [sys.stdout, sys.stdin, sys.stderr] sys.stdout, sys.stdin, sys.stderr = self.py_fds def release_output(self): if self.tmp_fds: sys.stdout, sys.stdin, sys.stderr = self.tmp_fds self.tmp_fds = [] [fd.reset() for fd in self.py_fds] def submit_input(self, text): '''\ Submit input 1) Move input to output 2) Evaluate input 3) Clear input line ''' self.clear_input() self.output(self.c_ps + text) self.c_scroll = 0 if self.python_mode: self.send_python(text) else: self.send_pyconsole(text) def send_python(self, text): '''\ Sends input the the python interpreter in effect giving the user the ability to do anything python can. ''' self.c_ps = self.ps2 self.catch_output() if text: self.add_to_history(text) r = self.python_interpreter.push(text) if r: self.c_ps = self.ps3 else: code = "".join(self.py_fds[OUT]) self.python_interpreter.push("\n") self.python_interpreter.runsource(code) for i in self.py_fds[OUT]+self.py_fds[ERR]: self.output(i) self.release_output() def send_pyconsole(self, text): '''\ Sends input to pyconsole to be interpreted ''' if not text: # Output a blank row if nothing is entered self.output("") return; self.add_to_history(text) #Determine if the statement is an assignment assign = re_is_assign.match(text) try: #If it is tokenize only the "value" part of $name = value if assign: tokens = self.tokenize(assign.group('value')) else: tokens = self.tokenize(text) except ParseError, e: self.output(r'At Token: "%s"' % e.at_token()) return; if tokens == None: return #Evaluate try: out = None # A variable alone on a line if (len(tokens) is 1) and re_is_var.match(text) and not assign: out = tokens[0] # Statement in the form $name = value elif (len(tokens) is 1) and assign: self.setvar(assign.group('name'), tokens[0]) else: # Function out = self.func_calls[tokens[0]](*tokens[1:]) # Assignment from function's return value if assign: self.setvar(assign.group('name'), out) if not out == None: self.output(out) except (KeyError,TypeError): self.output("Unknown Command: " + str(tokens[0])) self.output(r'Type "help" for a list of commands.')
class Console: def __init__(self, screen, rect, functions={}, key_calls={}, vars={}, syntax={}): if not pygame.display.get_init(): raise pygame.error, "Display not initialized. Initialize the display before creating a Console" if not pygame.font.get_init(): pygame.font.init() self.parent_screen = screen self.rect = pygame.Rect(rect) self.size = self.rect.size self.user_vars = vars self.user_syntax = syntax self.user_namespace = {} self.variables = {\ "bg_alpha":int,\ "bg_color": list,\ "txt_color_i": list,\ "txt_color_o": list,\ "ps1": str,\ "ps2": str,\ "ps3": str,\ "active": bool,\ "repeat_rate": list,\ "preserve_events":bool,\ "python_mode":bool,\ "motd":list } self.init_default_cfg() pygame.key.set_repeat(*self.repeat_rate) self.bg_layer = pygame.Surface(self.size) self.bg_layer.set_alpha(self.bg_alpha) self.txt_layer = pygame.Surface(self.size) self.txt_layer.set_colorkey(self.bg_color) self.font = pygame.font.Font('views/DroidSansMono.ttf', 12) self.font_height = self.font.get_linesize() self.max_lines = (self.size[HEIGHT] / self.font_height) - 1 self.max_chars = (self.size[WIDTH]/(self.font.size(ascii_letters)[WIDTH]/len(ascii_letters))) - 1 self.txt_wrapper = textwrap.TextWrapper() self.c_out = self.motd self.c_hist = [""] self.c_hist_pos = 0 self.c_in = "" self.c_pos = 0 self.c_draw_pos = 0 self.c_scroll = 0 self.changed = True self.func_calls = {} self.key_calls = {} self.add_func_calls({"echo":self.output, "clear": self.clear, "help":self.help}) self.add_func_calls(functions) self.add_key_calls({"l":self.clear, "c":self.clear_input, "w":self.set_active}) self.add_key_calls(key_calls) self.set_interpreter() ################## #-Initialization-# def init_default_cfg(self): self.bg_alpha = 175 self.bg_color = [0x0,0x44,0xAA] self.txt_color_i = [0xFF,0xFF,0xFF] self.txt_color_o = [0xEE,0xEE,0xEE] self.ps1 = "] " self.ps2 = ">>> " self.ps3 = "... " self.active = True self.repeat_rate = [500,30] self.python_mode = False self.preserve_events = False self.motd = ["Press Ctrl_w to hide the console","One day this will have more to say"] def add_func_calls(self, functions): '''\ Add functions to the func_calls dictionary. Arguments: functions -- dictionary of functions to add. ''' if isinstance(functions,dict): self.func_calls.update(functions) self.user_namespace.update(self.func_calls) def add_key_calls(self, functions): '''\ Add functions to the key_calls dictionary. Arguments: functions -- dictionary of key_calls to add. ''' if isinstance(functions,dict): self.key_calls.update(functions) def output(self, text): '''\ Prepare text to be displayed Arguments: text -- Text to be displayed ''' if not str(text): return; try: self.changed = True if not isinstance(text,str): text = str(text) text = text.expandtabs() text = text.splitlines() self.txt_wrapper.width = self.max_chars for line in text: for w in self.txt_wrapper.wrap(line): self.c_out.append(w) except: raise def set_active(self,b=None): '''\ Activate or Deactivate the console Arguments: b -- Optional boolean argument, True=Activate False=Deactivate ''' if not b: self.active = not self.active else: self.active = b def format_input_line(self): '''\ Format input line to be displayed ''' # The \v here is sort of a hack, it's just a character that isn't recognized by the font engine text = self.c_in[:self.c_pos] + "\v" + self.c_in[self.c_pos+1:] n_max = self.max_chars - len(self.c_ps) vis_range = self.c_draw_pos, self.c_draw_pos + n_max return self.c_ps + text[vis_range[0]:vis_range[1]] def draw(self): '''\ Draw the console to the parent screen ''' if not self.active: return; if self.changed: self.changed = False # Draw Output self.txt_layer.fill(self.bg_color) lines = self.c_out[-(self.max_lines+self.c_scroll):len(self.c_out)-self.c_scroll] y_pos = self.size[HEIGHT]-(self.font_height*(len(lines)+1)) for line in lines: tmp_surf = self.font.render(line, True, self.txt_color_o) self.txt_layer.blit(tmp_surf, (1, y_pos, 0, 0)) y_pos += self.font_height # Draw Input tmp_surf = self.font.render(self.format_input_line(), True, self.txt_color_i) self.txt_layer.blit(tmp_surf, (1,self.size[HEIGHT]-self.font_height,0,0)) # Clear background and blit text to it self.bg_layer.fill(self.bg_color) self.bg_layer.blit(self.txt_layer,(0,0,0,0)) # Draw console to parent screen pygame.draw.rect(self.parent_screen, self.txt_color_i, (self.rect.x-1, self.rect.y-1, self.size[WIDTH]+2, self.size[HEIGHT]+2), 1) self.parent_screen.blit(self.bg_layer,self.rect) ####################################################################### # Functions to communicate with the console and the python interpreter# def set_interpreter(self): #self.output("Entering Python mode") self.python_interpreter = InteractiveConsole() self.tmp_fds = [] self.py_fds = [Writable() for i in range(3)] self.c_ps = self.ps2 def catch_output(self): if not self.tmp_fds: self.tmp_fds = [sys.stdout, sys.stdin, sys.stderr] sys.stdout, sys.stdin, sys.stderr = self.py_fds def release_output(self): if self.tmp_fds: sys.stdout, sys.stdin, sys.stderr = self.tmp_fds self.tmp_fds = [] [fd.reset() for fd in self.py_fds] def submit_input(self, text): '''\ Submit input 1) Move input to output 2) Evaluate input 3) Clear input line ''' self.clear_input() self.output(self.c_ps + text) self.c_scroll = 0 self.send_python(text) def send_python(self, text): '''\ Sends input the the python interpreter in effect giving the user the ability to do anything python can. ''' self.c_ps = self.ps2 self.catch_output() if text: self.add_to_history(text) r = self.python_interpreter.push(text) if r: self.c_ps = self.ps3 else: code = "".join(self.py_fds[OUT]) self.python_interpreter.push("\n") self.python_interpreter.runsource(code) for i in self.py_fds[OUT]+self.py_fds[ERR]: self.output(i) self.release_output() #################################################### #-Functions for sharing variables with the console-# def setvar(self, name, value): '''\ Sets the value of a variable ''' if self.user_vars.has_key(name) or not self.__dict__.has_key(name): self.user_vars.update({name:value}) self.user_namespace.update(self.user_vars) elif self.__dict__.has_key(name): self.__dict__.update({name:value}) def getvar(self, name): '''\ Gets the value of a variable, this is useful for people that want to access console variables from within their game ''' if self.user_vars.has_key(name) or not self.__dict__.has_key(name): return self.user_vars[name] elif self.__dict__.has_key(name): return self.__dict__[name] def setvars(self, vars): try: self.user_vars.update(vars) self.user_namespace.update(self.user_vars) except TypeError: self.output("setvars requires a dictionary") def getvars(self, opt_dict=None): if opt_dict: opt_dict.update(self.user_vars) else: return self.user_vars def add_to_history(self, text): '''\ Add specified text to the history ''' self.c_hist.insert(-1,text) self.c_hist_pos = len(self.c_hist)-1 def clear_input(self): '''\ Clear input line and reset cursor position ''' self.c_in = "" self.c_pos = 0 self.c_draw_pos = 0 def set_pos(self, newpos): '''\ Moves cursor safely ''' self.c_pos = newpos if (self.c_pos - self.c_draw_pos) >= (self.max_chars - len(self.c_ps)): self.c_draw_pos = max(0, self.c_pos - (self.max_chars - len(self.c_ps))) elif self.c_draw_pos > self.c_pos: self.c_draw_pos = self.c_pos - (self.max_chars/2) if self.c_draw_pos < 0: self.c_draw_pos = 0 self.c_pos = 0 def str_insert(self, text, strn): '''\ Insert characters at the current cursor position ''' foo = text[:self.c_pos] + strn + text[self.c_pos:] self.set_pos(self.c_pos + len(strn)) return foo def process_input(self): '''\ Loop through pygame events and evaluate them ''' if not self.active: return; if self.preserve_events: eventlist = pygame.event.get(KEYDOWN) else: eventlist = pygame.event.get() for event in eventlist: if event.type == KEYDOWN: self.changed = True ## Special Character Manipulation if event.key == K_TAB: self.c_in = self.str_insert(self.c_in, " ") elif event.key == K_BACKSPACE: if self.c_pos > 0: self.c_in = self.c_in[:self.c_pos-1] + self.c_in[self.c_pos:] self.set_pos(self.c_pos-1) elif event.key == K_DELETE: if self.c_pos < len(self.c_in): self.c_in = self.c_in[:self.c_pos] + self.c_in[self.c_pos+1:] elif event.key == K_RETURN or event.key == 271: self.submit_input(self.c_in) ## Changing Cursor Position elif event.key == K_LEFT: if self.c_pos > 0: self.set_pos(self.c_pos-1) elif event.key == K_RIGHT: if self.c_pos < len(self.c_in): self.set_pos(self.c_pos+1) elif event.key == K_HOME: self.set_pos(0) elif event.key == K_END: self.set_pos(len(self.c_in)) ## History Navigation elif event.key == K_UP: if len(self.c_out): if self.c_hist_pos > 0: self.c_hist_pos -= 1 self.c_in = self.c_hist[self.c_hist_pos] self.set_pos(len(self.c_in)) elif event.key == K_DOWN: if len(self.c_out): if self.c_hist_pos < len(self.c_hist)-1: self.c_hist_pos += 1 self.c_in = self.c_hist[self.c_hist_pos] self.set_pos(len(self.c_in)) ## Scrolling elif event.key == K_PAGEUP: if self.c_scroll < len(self.c_out)-1: self.c_scroll += 1 elif event.key == K_PAGEDOWN: if self.c_scroll > 0: self.c_scroll -= 1 ## Normal character printing elif event.key >= 32: mods = pygame.key.get_mods() if mods & KMOD_CTRL: if event.key in range(256) and chr(event.key) in self.key_calls: self.key_calls[chr(event.key)]() else: char = str(event.unicode) self.c_in = self.str_insert(self.c_in, char) ########################## #-Some Builtin functions-# def clear(self): '''\ Clear the Screen ''' self.c_out = ["[Screen Cleared]"] self.c_scroll = 0 def help(self, *args): '''\ Output information about functions Arguments: args -- arbitrary argument list of function names |- No Args - A list of available functions will be displayed |- One or more Args - Docstring of each function will be displayed ''' if args: items = [(i,self.func_calls[i]) for i in args if i in self.func_calls] for i,v in items: out = i + ": Takes %d arguments. " % (v.func_code.co_argcount - (v.func_code.co_varnames[0] is "self")) doc = v.func_doc if doc: out += textwrap.dedent(doc) tmp_indent = self.txt_wrapper.subsequent_indent self.txt_wrapper.subsequent_indent = " "*(len(i)+2) self.output(out) self.txt_wrapper.subsequent_indent = tmp_indent else: out = "Available commands: " + str(self.func_calls.keys()).strip("[]") self.output(out) self.output(r'Type "help command-name" for more information on that command')
class Console: def __init__(self, screen, rect, functions={}, key_calls={}, vars={}): if not pygame.display.get_init(): raise pygame.error, "Display not initialized. Initialize the display before creating a Console" if not pygame.font.get_init(): pygame.font.init() self.parent_screen = screen self.rect = pygame.Rect(rect) self.size = self.rect.size self.user_vars = vars self.variables = {\ "bg_alpha":int,\ "bg_color": list,\ "txt_color_i": list,\ "txt_color_o": list,\ "ps1": str,\ "ps2": str,\ "ps3": str,\ "active": bool,\ "repeat_rate": list,\ "preserve_events":bool,\ "python_mode":bool,\ "motd":list } self.load_cfg() self.set_interpreter() pygame.key.set_repeat(*self.repeat_rate) self.bg_layer = pygame.Surface(self.size) self.bg_layer.set_alpha(self.bg_alpha) self.txt_layer = pygame.Surface(self.size) self.txt_layer.set_colorkey(self.bg_color) self.font = pygame.font.Font("../gfx/fixed_width.ttf",14) self.font_height = self.font.get_linesize() self.max_lines = (self.size[HEIGHT] / self.font_height) - 1 self.max_chars = (self.size[WIDTH]/self.font.size("#")[WIDTH]) - 1 self.txt_wrapper = textwrap.TextWrapper() self.c_out = self.motd self.c_hist = [""] self.c_hist_pos = 0 self.c_in = "" self.c_pos = 0 self.c_draw_pos = 0 self.c_scroll = 0 # if self.python_mode: # self.c_ps = self.ps2 # else: # self.c_ps = self.ps1 self.changed = True self.func_calls = {} self.key_calls = {} self.add_func_calls({"echo":self.output, "clear": self.clear, "help":self.help}) self.add_func_calls(functions) self.add_key_calls({"l":self.clear, "c":self.clear_input, "w":self.set_active}) self.add_key_calls(key_calls) def safe_set_attr(self, name, value): """Safely set the console variables""" if name in self.variables: if isinstance(value, self.variables[name]) or not self.variables[name]: self.__dict__[name] = value def add_func_calls(self, functions): """Add functions to the func_calls dictionary. functions -- dictionary of functions to add""" if isinstance(functions,dict): self.func_calls.update(functions) def add_key_calls(self, functions): """Add functions to the key_calls dictionary. functions -- dictionary of key_calls to add""" if isinstance(functions,dict): self.key_calls.update(functions) def clear(self): """Clear the Screen""" self.c_out = ["[Screen Cleared]"] self.c_scroll = 0 def help(self, *args): """Output information about functions args -- arbitrary argument list of function names No Args - A list of available functions will be displayed One or more Args - Docstring of each function will be displayed""" if args: items=[(i,self.func_calls[i]) for i in args if i in self.func_calls] for i,v in items: out=i + ": Takes %d arguments. " % (v.func_code.co_argcount - (v.func_code.co_varnames[0] is "self")) # TODO: function doc get funny formatting, so need to fiddle here doc=v.func_doc if doc: out+=textwrap.dedent(doc) tmp_indent=self.txt_wrapper.subsequent_indent self.txt_wrapper.subsequent_indent=" "*(len(i)+2) self.output(out) self.txt_wrapper.subsequent_indent=tmp_indent else: out = "Available commands: " + str(self.func_calls.keys()).strip("[]") self.output(out) self.output(r'Type "help command-name" for more information on that command') def output(self, text): """Prepare text to be displayed text -- Text to be displayed""" if not str(text): return; try: self.changed = True if not isinstance(text,str): text = str(text) text = text.expandtabs() text = text.splitlines() self.txt_wrapper.width = self.max_chars for line in text: for w in self.txt_wrapper.wrap(line): self.c_out.append(w) except: print text def set_active(self,b=None): """Activate or Deactivate the console. Pass with b- Optional boolean argument, True=Activate False=Deactivate""" if not b: self.active = not self.active else: self.active = b def set_interpreter(self): if self.python_mode: # spqr tries to reduce console ouput,but we can still # have some debugging info if(SPQR.DEBUG_MODE==True): self.output("Entering Python mode") self.python_mode = True self.python_interpreter = InteractiveConsole() self.tmp_fds = [] self.py_fds = [Writable() for i in range(3)] self.c_ps = self.ps2 else: if(SPQR.DEBUG_MODE==True): self.output("Entering Pyconsole mode") self.python_mode=False self.c_ps=self.ps1 def catch_output(self): if not self.tmp_fds: self.tmp_fds = [sys.stdout, sys.stdin, sys.stderr] sys.stdout, sys.stdin, sys.stderr = self.py_fds def release_output(self): if self.tmp_fds: sys.stdout, sys.stdin, sys.stderr = self.tmp_fds self.tmp_fds = [] [fd.reset() for fd in self.py_fds] def format_input_line(self): '''\ Format input line to be displayed ''' text = self.c_in[:self.c_pos] + "|" + self.c_in[self.c_pos:] n_max = self.max_chars - len(self.c_ps) vis_range = self.c_draw_pos, self.c_draw_pos + n_max return self.c_ps + text[vis_range[0]:vis_range[1]] def draw(self): '''\ Draw the console to the parent screen ''' if not self.active: return; if self.changed: self.changed = False # Draw Output self.txt_layer.fill(self.bg_color) lines = self.c_out[-(self.max_lines+self.c_scroll):len(self.c_out)-self.c_scroll] y_pos = self.size[HEIGHT]-(self.font_height*(len(lines)+1)) for line in lines: tmp_surf = self.font.render(line, True, self.txt_color_o) self.txt_layer.blit(tmp_surf, (1, y_pos, 0, 0)) y_pos += self.font_height # Draw Input tmp_surf = self.font.render(self.format_input_line(), True, self.txt_color_i) self.txt_layer.blit(tmp_surf, (1,self.size[HEIGHT]-self.font_height,0,0)) # Clear background and blit text to it self.bg_layer.fill(self.bg_color) self.bg_layer.blit(self.txt_layer,(0,0,0,0)) # Draw console to parent screen #self.parent_screen.fill(self.txt_color_i, (self.rect.x-1, self.rect.y-1, self.size[WIDTH]+2, self.size[HEIGHT]+2)) pygame.draw.rect(self.parent_screen, self.txt_color_i, (self.rect.x-1, self.rect.y-1, self.size[WIDTH]+2, self.size[HEIGHT]+2), 1) self.parent_screen.blit(self.bg_layer,self.rect) def submit_input(self, text): """Submit input: 1) Move input to output, 2) Evaluate input, 3) Clear input line""" self.clear_input() self.output(self.c_ps + text) self.c_scroll = 0 if self.python_mode: self.send_python(text) else: self.send_pyconsole(text) def send_python(self, text): """Sends input to the python interpreter giving the user the ability to do anything python can""" self.c_ps = self.ps2 self.catch_output() if text: self.add_to_history(text) r = self.python_interpreter.push(text) if r: self.c_ps = self.ps3 else: code = "".join(self.py_fds[OUT]) self.python_interpreter.push("\n") self.python_interpreter.runsource(code) for i in self.py_fds[OUT]+self.py_fds[ERR]: self.output(i) self.release_output() def send_pyconsole(self, text): """Sends input to pyconsole to be interpreted""" # Output a blank row if nothing is entered if not text: self.output("") return; self.add_to_history(text) # Check if the text is in the form: name = value assign = re_is_assign.match(text) try: if assign: tokens = self.tokenize(assign.group('value')) else: tokens = self.tokenize(text) except ParseError, e: self.output(r'At Token: "%s"' % e.at_token()) return; try: if (len(tokens) is 1) and re_is_var.match(text) and not assign: out = tokens[0] else: out = self.func_calls[tokens[0]](*tokens[1:]) except (KeyError,TypeError): if (len(tokens) is 1) and assign: self.setvar(assign.group('name'), tokens[0]) else: self.output("Unknown Command: " + str(tokens[0])) self.output(r'Type "help" for a list of commands.') else: self.output(out)
def runsource(self, source, *args): from Vivaldi_translator_layer import line_translator source = line_translator(source, data_package_list) self.last_buffer = [ source.encode('latin-1') ] return InteractiveConsole.runsource(self, source, *args)
class Console: def __init__(self, screen, rect, functions={}, key_calls={}, vars={}, syntax={}): if not pygame.display.get_init(): raise pygame.error if not pygame.font.get_init(): pygame.font.init() self.parent_screen = screen self.rect = pygame.Rect(rect) self.size = self.rect.size self.user_vars = vars self.user_syntax = syntax self.user_namespace = {} self.variables = {\ "bg_alpha":int,\ "bg_color": list,\ "txt_color_i": list,\ "txt_color_o": list,\ "ps1": str,\ "ps2": str,\ "ps3": str,\ "active": bool,\ "repeat_rate": list,\ "preserve_events":bool,\ "python_mode":bool,\ "motd":list } self.load_cfg() self.set_interpreter() pygame.key.set_repeat(*self.repeat_rate) self.bg_layer = pygame.Surface(self.size) self.bg_layer.set_alpha(self.bg_alpha) self.txt_layer = pygame.Surface(self.size) self.txt_layer.set_colorkey(self.bg_color) try: self.font = pygame.font.Font(os.path.join(font_path,"default.ttf"), 14) except IOError: self.font = pygame.font.SysFont("monospace", 14) self.font_height = self.font.get_linesize() self.max_lines = (self.size[HEIGHT] / self.font_height) - 1 self.max_chars = (self.size[WIDTH]/(self.font.size(ascii_letters)[WIDTH]/len(ascii_letters))) - 1 self.txt_wrapper = textwrap.TextWrapper() self.c_out = self.motd self.c_hist = [""] self.c_hist_pos = 0 self.c_in = "" self.c_pos = 0 self.c_draw_pos = 0 self.c_scroll = 0 self.changed = True self.func_calls = {} self.key_calls = {} self.add_func_calls({"echo":self.output, "clear": self.clear, "help":self.help}) self.add_func_calls(functions) self.add_key_calls({"l":self.clear, "c":self.clear_input, "w":self.set_active}) self.add_key_calls(key_calls) ################## #-Initialization-# def load_cfg(self): '''\ Loads the config file path/pygame-console.cfg\ All variables are initialized to their defaults,\ then new values will be loaded from the config file if it exists. ''' self.init_default_cfg() if os.path.exists(cfg_path): for line in open(cfg_path): tokens = self.tokenize(line) if re_is_comment.match(line): continue elif len(tokens) != 2: continue self.safe_set_attr(tokens[0],tokens[1]) def init_default_cfg(self): self.bg_alpha = 200 self.bg_color = [0x0,0x44,0xAA] self.txt_color_i = [0xFF,0xFF,0xFF] self.txt_color_o = [0xEE,0xEE,0xEE] self.ps1 = "] " self.ps2 = ">>> " self.ps3 = "... " self.active = True self.repeat_rate = [500,30] self.python_mode = False self.preserve_events = True self.motd = ["|DarkNet|", "Type help for a list of commands","Press Ctrl_w to hide the console"] def safe_set_attr(self, name, value): '''\ Safely set the console variables ''' if name in self.variables: if isinstance(value, self.variables[name]) or not self.variables[name]: self.__dict__[name] = value def add_func_calls(self, functions): '''\ Add functions to the func_calls dictionary. Arguments: functions -- dictionary of functions to add. ''' if isinstance(functions,dict): self.func_calls.update(functions) self.user_namespace.update(self.func_calls) def add_key_calls(self, functions): '''\ Add functions to the key_calls dictionary. Arguments: functions -- dictionary of key_calls to add. ''' if isinstance(functions,dict): self.key_calls.update(functions) def output(self, text): '''\ Prepare text to be displayed Arguments: text -- Text to be displayed ''' if not str(text): return; try: self.changed = True if not isinstance(text,str): text = str(text) text = text.expandtabs() text = text.splitlines() self.txt_wrapper.width = self.max_chars for line in text: for w in self.txt_wrapper.wrap(line): self.c_out.append(w) except: pass def set_active(self,b=None): '''\ Activate or Deactivate the console Arguments: b -- Optional boolean argument, True=Activate False=Deactivate ''' if not b: self.active = not self.active else: self.active = b def format_input_line(self): '''\ Format input line to be displayed ''' # The \v here is sort of a hack, it's just a character that isn't recognized by the font engine text = self.c_in[:self.c_pos] + "\v" + self.c_in[self.c_pos+1:] n_max = self.max_chars - len(self.c_ps) vis_range = self.c_draw_pos, self.c_draw_pos + n_max return self.c_ps + text[vis_range[0]:int(vis_range[1])] def draw(self): '''\ Draw the console to the parent screen ''' if not self.active: return; if self.changed: self.changed = False # Draw Output self.txt_layer.fill(self.bg_color) lines = self.c_out[-(int(self.max_lines) + self.c_scroll):len(self.c_out) - self.c_scroll] y_pos = self.size[HEIGHT]-(self.font_height*(len(lines)+1)) for line in lines: tmp_surf = self.font.render(line, True, self.txt_color_o) self.txt_layer.blit(tmp_surf, (1, y_pos, 0, 0)) y_pos += self.font_height # Draw Input tmp_surf = self.font.render(self.format_input_line(), True, self.txt_color_i) self.txt_layer.blit(tmp_surf, (1,self.size[HEIGHT]-self.font_height,0,0)) # Clear background and blit text to it self.bg_layer.fill(self.bg_color) self.bg_layer.blit(self.txt_layer,(0,0,0,0)) # Draw console to parent screen # self.parent_screen.fill(self.txt_color_i, (self.rect.x-1, self.rect.y-1, self.size[WIDTH]+2, self.size[HEIGHT]+2)) pygame.draw.rect(self.parent_screen, self.txt_color_i, (self.rect.x-1, self.rect.y-1, self.size[WIDTH]+2, self.size[HEIGHT]+2), 1) self.parent_screen.blit(self.bg_layer,self.rect) ####################################################################### # Functions to communicate with the console and the python interpreter# def set_interpreter(self): if self.python_mode: self.output("Entering Python mode") self.python_mode = True self.python_interpreter = InteractiveConsole() self.tmp_fds = [] self.py_fds = [Writable() for i in range(3)] self.c_ps = self.ps2 else: self.output("Entering Pyconsole mode") self.python_mode = False self.c_ps = self.ps1 def catch_output(self): if not self.tmp_fds: self.tmp_fds = [sys.stdout, sys.stdin, sys.stderr] sys.stdout, sys.stdin, sys.stderr = self.py_fds def release_output(self): if self.tmp_fds: sys.stdout, sys.stdin, sys.stderr = self.tmp_fds self.tmp_fds = [] [fd.reset() for fd in self.py_fds] def submit_input(self, text): '''\ Submit input 1) Move input to output 2) Evaluate input 3) Clear input line ''' self.clear_input() self.output(self.c_ps + text) self.c_scroll = 0 if self.python_mode: self.send_python(text) else: self.send_pyconsole(text) def send_python(self, text): '''\ Sends input the the python interpreter in effect giving the user the ability to do anything python can. ''' self.c_ps = self.ps2 self.catch_output() if text: self.add_to_history(text) r = self.python_interpreter.push(text) if r: self.c_ps = self.ps3 else: code = "".join(self.py_fds[OUT]) self.python_interpreter.push("\n") self.python_interpreter.runsource(code) for i in self.py_fds[OUT]+self.py_fds[ERR]: self.output(i) self.release_output() def send_pyconsole(self, text): '''\ Sends input to pyconsole to be interpreted ''' if not text: # Output a blank row if nothing is entered self.output("") return; self.add_to_history(text) #Determine if the statement is an assignment assign = re_is_assign.match(text) try: #If it is tokenize only the "value" part of $name = value if assign: tokens = self.tokenize(assign.group('value')) else: tokens = self.tokenize(text) except ParseError: self.output(r'At Token: "%s"') return; if tokens == None: return #Evaluate try: out = None # A variable alone on a line if (len(tokens) is 1) and re_is_var.match(text) and not assign: out = tokens[0] # Statement in the form $name = value elif (len(tokens) is 1) and assign: self.setvar(assign.group('name'), tokens[0]) else: # Function out = self.func_calls[tokens[0]](*tokens[1:]) # Assignment from function's return value if assign: self.setvar(assign.group('name'), out) if not out == None: self.output(out) except (KeyError,TypeError): self.output("Unknown Command: " + str(tokens[0])) self.output(r'Type "help" for a list of commands.') #################################################### #-Functions for sharing variables with the console-# def setvar(self, name, value): '''\ Sets the value of a variable ''' if self.user_vars.has_key(name) or not self.__dict__.has_key(name): self.user_vars.update({name:value}) self.user_namespace.update(self.user_vars) elif self.__dict__.has_key(name): self.__dict__.update({name:value}) def getvar(self, name): '''\ Gets the value of a variable, this is useful for people that want to access console variables from within their game ''' if self.user_vars.has_key(name) or not self.__dict__.has_key(name): return self.user_vars[name] elif self.__dict__.has_key(name): return self.__dict__[name] def setvars(self, vars): try: self.user_vars.update(vars) self.user_namespace.update(self.user_vars) except TypeError: self.output("setvars requires a dictionary") def getvars(self, opt_dict=None): if opt_dict: opt_dict.update(self.user_vars) else: return self.user_vars def add_to_history(self, text): '''\ Add specified text to the history ''' self.c_hist.insert(-1,text) self.c_hist_pos = len(self.c_hist)-1 def clear_input(self): '''\ Clear input line and reset cursor position ''' self.c_in = "" self.c_pos = 0 self.c_draw_pos = 0 def set_pos(self, newpos): '''\ Moves cursor safely ''' self.c_pos = newpos if (self.c_pos - self.c_draw_pos) >= (self.max_chars - len(self.c_ps)): self.c_draw_pos = max(0, self.c_pos - (self.max_chars - len(self.c_ps))) elif self.c_draw_pos > self.c_pos: self.c_draw_pos = self.c_pos - (self.max_chars/2) if self.c_draw_pos < 0: self.c_draw_pos = 0 self.c_pos = 0 def str_insert(self, text, strn): '''\ Insert characters at the current cursor position ''' foo = text[:self.c_pos] + strn + text[self.c_pos:] self.set_pos(self.c_pos + len(strn)) return foo def process_input(self): '''\ Loop through pygame events and evaluate them ''' if not self.active: return; if self.preserve_events: eventlist = pygame.event.get(KEYDOWN) else: eventlist = pygame.event.get() for event in eventlist: if event.type == KEYDOWN: self.changed = True ## Special Character Manipulation if event.key == K_TAB: self.c_in = self.str_insert(self.c_in, " ") elif event.key == K_BACKSPACE: if self.c_pos > 0: self.c_in = self.c_in[:self.c_pos-1] + self.c_in[self.c_pos:] self.set_pos(self.c_pos-1) elif event.key == K_DELETE: if self.c_pos < len(self.c_in): self.c_in = self.c_in[:self.c_pos] + self.c_in[self.c_pos+1:] elif event.key == K_RETURN or event.key == 271: self.submit_input(self.c_in) ## Changing Cursor Position elif event.key == K_LEFT: if self.c_pos > 0: self.set_pos(self.c_pos-1) elif event.key == K_RIGHT: if self.c_pos < len(self.c_in): self.set_pos(self.c_pos+1) elif event.key == K_HOME: self.set_pos(0) elif event.key == K_END: self.set_pos(len(self.c_in)) ## History Navigation elif event.key == K_UP: if len(self.c_out): if self.c_hist_pos > 0: self.c_hist_pos -= 1 self.c_in = self.c_hist[self.c_hist_pos] self.set_pos(len(self.c_in)) elif event.key == K_DOWN: if len(self.c_out): if self.c_hist_pos < len(self.c_hist)-1: self.c_hist_pos += 1 self.c_in = self.c_hist[self.c_hist_pos] self.set_pos(len(self.c_in)) ## Scrolling elif event.key == K_PAGEUP: if self.c_scroll < len(self.c_out)-1: self.c_scroll += 1 elif event.key == K_PAGEDOWN: if self.c_scroll > 0: self.c_scroll -= 1 ## Normal character printing elif event.key >= 32: mods = pygame.key.get_mods() if mods & KMOD_CTRL: if event.key in range(256) and chr(event.key) in self.key_calls: self.key_calls[chr(event.key)]() else: char = str(event.unicode) self.c_in = self.str_insert(self.c_in, char) def convert_token(self, tok): '''\ Convert a token to its proper type ''' tok = tok.strip("$") try: tmp = eval(tok, self.__dict__, self.user_namespace) except SyntaxError: self.output("SyntaxError: ") raise ParseError except TypeError: self.output("TypeError: ") raise ParseError except NameError: self.output("NameError: ") except: self.output("Error:") raise ParseError else: return tmp def tokenize(self, s): '''\ Tokenize input line, convert tokens to proper types ''' if re_is_comment.match(s): return [s] for re in self.user_syntax: group = re.match(s) if group: self.user_syntax[re](self, group) return tokens = re_token.findall(s) tokens = [i.strip("\"") for i in tokens] cmd = [] i = 0 while i < len(tokens): t_count = 0 val = tokens[i] if re_is_number.match(val): cmd.append(self.convert_token(val)) elif re_is_var.match(val): cmd.append(self.convert_token(val)) elif val == "True": cmd.append(True) elif val == "False": cmd.append(False) elif re_is_list.match(val): while not balanced(val) and (i + t_count) < len(tokens)-1: t_count += 1 val += tokens[i+t_count] else: if (i + t_count) < len(tokens): cmd.append(self.convert_token(val)) else: raise ParseError else: cmd.append(val) i += t_count + 1 return cmd ########################## #-Some Builtin functions-# def clear(self): '''\ Clear the Screen ''' self.c_out = ["[Screen Cleared]"] self.c_scroll = 0 def help(self, *args): '''\ Output information about functions Arguments: args -- arbitrary argument list of function names |- No Args - A list of available functions will be displayed |- One or more Args - Docstring of each function will be displayed ''' if args: items = [(i,self.func_calls[i]) for i in args if i in self.func_calls] for i,v in items: out = i + ": Takes %d arguments. " % (v.func_code.co_argcount - (v.func_code.co_varnames[0] is "self")) doc = v.func_doc if doc: out += textwrap.dedent(doc) tmp_indent = self.txt_wrapper.subsequent_indent self.txt_wrapper.subsequent_indent = " "*(len(i)+2) self.output(out) self.txt_wrapper.subsequent_indent = tmp_indent else: out = "Available commands: " + str(self.func_calls.keys()).strip("[]") self.output(out) self.output(r'Type "help command-name" for more information on that command')
def runsource(self, source, *args): self.last_buffer = [source] return InteractiveConsole.runsource(self, source, *args)
class PyREPLTextView(NSTextView): def init(self): self = super(PyREPLTextView, self).init() self.setDelegate_(self) self.setDrawsBackground_(True) paragraphStyle = NSMutableParagraphStyle.alloc().init() paragraphStyle.setLineHeightMultiple_(1.2) self.setDefaultParagraphStyle_(paragraphStyle) self.setUsesFindBar_(True) self.setAutomaticQuoteSubstitutionEnabled_(False) self.setAutomaticLinkDetectionEnabled_(False) self.setContinuousSpellCheckingEnabled_(False) self.setGrammarCheckingEnabled_(False) self.setAutomaticDashSubstitutionEnabled_(False) self.setAutomaticDataDetectionEnabled_(False) self.setAutomaticSpellingCorrectionEnabled_(False) self.setAutomaticTextReplacementEnabled_(False) self._codeColor = NSColor.blackColor() self._stderrColor = NSColor.blackColor() self._stdoutColor = NSColor.blackColor() self._glyphWidth = 1 self._console = InteractiveConsole(locals=namespaceInjections) self._stderr = PseudoUTF8Output(self.writeStderr_) self._stdout = PseudoUTF8Output(self.writeStdout_) self._prompt = sys.ps1 self.previousOutput = "" self._tabString = " " self._minInsertionPoint = 0 self._history = [] self._historyIndex = 1 return self # Settings def setTabString_(self, value): self._tabString = value def setFont_(self, value): super(PyREPLTextView, self).setFont_(value) self.getCharacterBox() def getCharacterBox(self): font = self.font() glyph = font.glyphWithName_("space") glyphWidth = font.advancementForGlyph_(glyph).width glyphHeight = font.pointSize() * self.defaultParagraphStyle().lineHeightMultiple() self._glyphWidth = glyphWidth self._glyphHeight = glyphHeight return glyphWidth, glyphHeight def setCodeColor_(self, color): self._codeColor = color self.setTextColor_(color) self.setInsertionPointColor_(color) def setStdoutColor_(self, color): self._stdoutColor = color def setStderrColor_(self, color): self._stderrColor = color def setShowInvisibles_(self, value): self.layoutManager().setShowsInvisibleCharacters_(value) # Raw Text def rawText(self): return self.textStorage().mutableString() def textLength(self): return len(self.rawText()) # Input def scrollToEnd(self): index = self.textLength() self.scrollRangeToVisible_((index, 0)) self.setSelectedRange_((index, 0)) def keyDown_(self, event): if event.modifierFlags() & NSCommandKeyMask and event.characters() == "k": self.clear() elif event.modifierFlags() & NSCommandKeyMask and event.characters() == "c": pb = NSPasteboard.generalPasteboard() pb.clearContents() a = NSArray.arrayWithObject_(self.previousOutput) pb.writeObjects_(a) else: return super(PyREPLTextView, self).keyDown_(event) def insertNewline_(self, sender): line = self.currentLine() self.writeCode_("\n") self.executeLine_(line) self.writePrompt() insertNewlineIgnoringFieldEditor_ = insertNewline_ def insertTab_(self, sender): self.writeLine_withColor_(self._tabString, self._codeColor) def insertBacktab_(self, sender): if self.currentLine().endswith(self._tabString): length = len(self._tabString) begin = self.textLength() - length textStorage = self.textStorage() textStorage.deleteCharactersInRange_((begin, length)) def moveDown_(self, sender): self._historyIndex += 1 if self._historyIndex > len(self._history): self._historyIndex = len(self._history) NSBeep() self._insertHistoryLine() def moveUp_(self, sender): self._historyIndex -= 1 if self._historyIndex < 0: self._historyIndex = 0 NSBeep() self._insertHistoryLine() def _insertHistoryLine(self): if self._historyIndex == len(self._history): text = "" else: text = self._history[self._historyIndex] text = self.makeAttributedString_withColor_(text, self._codeColor) begin = self._minInsertionPoint length = self.textLength() - begin textStorage = self.textStorage() textStorage.replaceCharactersInRange_withAttributedString_((begin, length), text) # Output def makeAttributedString_withColor_(self, text, color): attrs = { NSForegroundColorAttributeName : color, NSFontAttributeName : self.font(), NSParagraphStyleAttributeName : self.defaultParagraphStyle() } text = NSAttributedString.alloc().initWithString_attributes_( text, attrs ) return text def writeLine_withColor_(self, line, color): line = self.makeAttributedString_withColor_(line, color) self.textStorage().appendAttributedString_(line) self.scrollToEnd() def writePrompt(self): self.writeCode_(self._prompt) self._minInsertionPoint = self.textLength() def writeCode_(self, text): self.writeLine_withColor_(text, self._codeColor) def writeStderr_(self, text): self.writeLine_withColor_(text, self._stderrColor) def writeStdout_(self, text): self.writeLine_withColor_(text, self._stdoutColor) def clear(self): self._minInsertionPoint = 0 self.setString_("") self.writePrompt() # Execution def runSource_(self, source): save = (sys.stdout, sys.stderr) sys.stdout = self._stdout sys.stderr = self._stderr try: self._console.runsource(source) finally: sys.stdout, sys.stderr = save def currentLine(self): line = self.rawText().splitlines()[-1] line = line[len(self._prompt):] return line def executeLine_(self, line): if line == "help": self.writeStdout_(documentation) self.writeCode_("\n") return self._history.append(line) self._historyIndex = len(self._history) save = (sys.stdout, sys.stderr, self.rawText()) sys.stdout = self._stdout sys.stderr = self._stderr more = False try: more = self._console.push(line) if more: self._prompt = sys.ps2 else: self._prompt = sys.ps1 except: self._prompt = sys.ps1 finally: sys.stdout, sys.stderr, previousRawText = save self.previousOutput = self.rawText()[len(previousRawText):-1] # Selection, Insertion Point def textView_willChangeSelectionFromCharacterRange_toCharacterRange_(self, textView, fromRange, toRange): begin, length = toRange if length == 0: if begin < self._minInsertionPoint: NSBeep() begin = self._minInsertionPoint toRange = (begin, length) return toRange def textView_shouldChangeTextInRange_replacementString_(self, textView, aRange, newString): begin, length = aRange if begin < self._minInsertionPoint: return False return True def drawInsertionPointInRect_color_turnedOn_(self, rect, color, turnedOn): if hasattr(self, "_glyphWidth"): rect.size.width = self._glyphWidth super(PyREPLTextView, self).drawInsertionPointInRect_color_turnedOn_(rect, color, turnedOn) def setNeedsDisplayInRect_(self, rect): # Ugh: https://gist.github.com/koenbok/a1b8d942977f69ff102b if hasattr(self, "_glyphWidth"): rect.size.width += self._glyphWidth - 1 super(PyREPLTextView, self).setNeedsDisplayInRect_(rect) # Auto Completion (adapted from DrawBot) def rangeForUserCompletion(self): charRange = super(PyREPLTextView, self).rangeForUserCompletion() text = self.string() partialString = text.substringWithRange_(charRange) if "." in partialString: dotSplit = partialString.split(".") partialString = dotSplit.pop() move = len(".".join(dotSplit)) charRange.location += move + 1 charRange.length = len(partialString) for c in partialString: if c not in variableChars: return (NSNotFound, 0) return charRange def completionsForPartialWordRange_indexOfSelectedItem_(self, charRange, index): if not haveJedi: return [], 0 text = self.string() partialString = text.substringWithRange_(charRange) source = "\n".join(self._history + [self.currentLine()]) namespace = self._console.locals script = jedi.Interpreter(source=source, namespaces=[namespace]) completions = [] for completion in script.completions(): name = completion.name completions.append(name) return completions, 0 def selectionRangeForProposedRange_granularity_(self, proposedRange, granularity): location = proposedRange.location if granularity == NSSelectByWord and proposedRange.length == 0 and location != 0: text = self.string() lenText = len(text) length = 1 found = False while not found: location -= 1 length += 1 if location <= 0: found = True else: c = text.substringWithRange_((location, 1))[0] if c not in variableChars: location += 1 found = True found = False while not found: length += 1 if location + length >= lenText: found = True else: c = text.substringWithRange_((location, length))[-1] if c not in variableChars: length -= 1 found = True return location, length else: return super(PyREPLTextView, self).selectionRangeForProposedRange_granularity_(proposedRange, granularity) # Drop def readSelectionFromPasteboard_type_(self, pboard, pbType): if pbType == NSFilenamesPboardType: paths = pboard.propertyListForType_(NSFilenamesPboardType) dropText = "" if len(paths) == 1: dropText = 'u"%s"' % paths[0] else: formattedPaths = [] for path in paths: formattedPaths.append('u"%s"' % path) dropText = "[%s]" % ", ".join(formattedPaths) if dropText: self.insertText_(dropText) return True return super(PyREPLTextView, self).readSelectionFromPasteboard_type_(pboard, pbType)
class Console: """Console object""" def __init__(self, font, toggle_key=None): """Console constructor Arguments: font - path to font file toggle_key - keycode to enable/disable console""" global SCROLLBACK, WRAP self.toggle_key = toggle_key self.active = False # GUI view_buf = Buffer(GL_INT, 4) glGetIntegerv(GL_VIEWPORT, view_buf) view = view_buf.to_list() self.text_size = [None] * 2 self.text_fontid = blf.load(font) if font else 0 blf.size(self.text_fontid, 14, 72) self.text_size[0], self.text_size[1] = blf.dimensions( self.text_fontid, "W") self._text = '' SCROLLBACK = int(SCROLLBACK / (2 * self.text_size[1])) WRAP = int(WRAP / (self.text_size[0])) # Console self.namespace = default_namespace() self.console = InteractiveConsole(self.namespace) self.cursor = 0 self.edit_text = '' self.scrollback = [] self.history = [''] self.is_multiline = False message = """Interactive Console""" self.add_scrollback(message) def _get_text(self): return self._text def set_text(self, value): self.text_size[0], self.text_size[1] = blf.dimensions( self.text_fontid, value) #self._update_position(size, self._base_pos) self._text = value def render(self): """Renders the GUI system""" ww = bge.render.getWindowWidth() wh = bge.render.getWindowHeight() # Get some viewport info view_buf = Buffer(GL_INT, 4) glGetIntegerv(GL_VIEWPORT, view_buf) view = view_buf.to_list() # Save the state glPushMatrix() glPushAttrib(GL_ALL_ATTRIB_BITS) # Diable depth test so we always draw over things glDisable(GL_DEPTH_TEST) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) # Setup the matrices glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(0, view[2], 0, view[3]) glMatrixMode(GL_MODELVIEW) glLoadIdentity() # Render the windows glColor4f(0.3, 0.3, 0.3, 0.5) glBegin(GL_QUADS) glVertex2f(0, 2 * wh / 3) glVertex2f(ww, 2 * wh / 3) glVertex2f(ww, wh) glVertex2f(0, wh) glEnd() glColor4f(0.0, 0.0, 0.0, 1.0) glBegin(GL_LINE_STRIP) glVertex2f(0, 2 * wh / 3) glVertex2f(ww, 2 * wh / 3) glEnd() blf.size(self.text_fontid, 14, 72) glColor4f(1, 1, 1, 1) for i, txt in enumerate([i for i in self._text.split('\n')]): blf.position(self.text_fontid, 20, wh + 20 - (self.text_size[1] * (i - 1)), 0) blf.draw(self.text_fontid, txt.replace('\t', ' ')) # Reset the state glPopAttrib() glPopMatrix() def prev_char(self): cursor = self.cursor - 1 if cursor < 0: return None try: return self.edit_text[cursor] except: return None def next_char(self): try: return self.edit_text[self.cursor] except: return None def fill_scrollback(self): sb = self.scrollback while len(sb) < SCROLLBACK: sb.append('') while len(sb) > SCROLLBACK: sb.pop(0) def add_scrollback(self, data): sb = self.scrollback if isinstance(data, str): data = data.split("\n") for line in data: while len(line) > WRAP: sb.append(line[:WRAP]) line = line[WRAP:] sb.append(line) self.fill_scrollback() def cursor_left_step(self): self.cursor = max(0, self.cursor - 1) def cursor_right_step(self): self.cursor = min(len(self.edit_text), self.cursor + 1) def cursor_right_jump(self): if self.cursor >= len(self.edit_text): return cursor_prev = self.cursor while (not is_delimiter(self.edit_text[self.cursor])): self.cursor_right_step() if cursor_prev == self.cursor: break cursor_prev = self.cursor if self.cursor >= len(self.edit_text): return if self.cursor >= len(self.edit_text): return cursor_prev = self.cursor while is_delimiter(self.edit_text[self.cursor]): self.cursor_right_step() if cursor_prev == self.cursor: break cursor_prev = self.cursor if self.cursor >= len(self.edit_text): return def cursor_left_jump(self): if self.cursor == 0: return cursor_prev = self.cursor while (not is_delimiter(self.edit_text[self.cursor - 1])): self.cursor_left_step() if cursor_prev == self.cursor: break cursor_prev = self.cursor if self.cursor == 0: return cursor_prev = self.cursor while (is_delimiter(self.edit_text[self.cursor - 1])): self.cursor_left_step() if cursor_prev == self.cursor: break cursor_prev = self.cursor def cursor_backspace_step(self): if self.cursor == 0: pass elif self.cursor == len(self.edit_text): self.edit_text = self.edit_text[:-1] else: self.edit_text = self.edit_text[:self.cursor - 1] + self.edit_text[self.cursor:] self.cursor_left_step() def cursor_backspace_jump(self): cursor_prev = self.cursor self.cursor_left_jump() if cursor_prev != self.cursor: self.edit_text = self.edit_text[:self.cursor] + self.edit_text[ cursor_prev:] def cursor_delete_step(self): if self.cursor == 0: self.edit_text = self.edit_text[1:] elif self.cursor == len(self.edit_text): pass else: self.edit_text = self.edit_text[:self.cursor] + self.edit_text[ self.cursor + 1:] def cursor_delete_jump(self): cursor_prev = self.cursor self.cursor_right_jump() if cursor_prev != self.cursor: self.edit_text = self.edit_text[:cursor_prev] + self.edit_text[ self.cursor:] self.cursor = cursor_prev def cursor_insert_char(self, ch): if self.cursor == 0: self.edit_text = ch + self.edit_text elif self.cursor == len(self.edit_text): self.edit_text = self.edit_text + ch else: self.edit_text = self.edit_text[:self. cursor] + ch + self.edit_text[ self.cursor:] if self.cursor > len(self.edit_text): self.cursor = len(self.edit_text) self.cursor_right_step() def cursor_home(self): self.cursor = 0 def cursor_end(self): self.cursor = len(self.edit_text) def history_up(self): hs = self.history hs[0] = self.edit_text hs.append(hs.pop(0)) self.edit_text = hs[0] self.cursor_end() def history_down(self): hs = self.history hs[0] = self.edit_text hs.insert(0, hs.pop()) self.edit_text = hs[0] self.cursor_end() def execute(self): self.add_scrollback(self.get_text_commandline()) stdout_redir = fileRedirect(False) stderr_redir = fileRedirect(True) sys.stdout = stdout_redir sys.stderr = stderr_redir if not self.edit_text.strip(): pytext = '\n' # executes a multiline statement else: pytext = self.edit_text self.is_multiline = self.console.push(pytext) sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ sys.last_trackback = None output = stdout_redir.read() stdout_redir.close() if output: self.add_scrollback(output) # could be stderr_redit too # Avoid double ups, add the new one at the front if pytext != '\n': if self.edit_text in self.history: self.history.remove(self.edit_text) self.history.insert(0, self.edit_text) if '' in self.history: self.history[:] = [v for v in self.history if v] self.history.insert(0, '') self.edit_text = '' self.cursor_end() def autocomp(self): def do_autocomp(autocomp_prefix, autocomp_members): ''' return text to insert and a list of options ''' autocomp_members = [ v for v in autocomp_members if v.startswith(autocomp_prefix) ] if not autocomp_prefix: return '', autocomp_members elif len(autocomp_members) > 1: # find a common string between all members after the prefix # 'ge' [getA, getB, getC] --> 'get' # get the shortest member min_len = min([len(v) for v in autocomp_members]) autocomp_prefix_ret = '' for i in xrange(len(autocomp_prefix), min_len): char_soup = set() for v in autocomp_members: char_soup.add(v[i]) if len(char_soup) > 1: break else: autocomp_prefix_ret += char_soup.pop() return autocomp_prefix_ret, autocomp_members elif len(autocomp_members) == 1: return autocomp_members[0][len(autocomp_prefix):], [] else: return '', [] TEMP_NAME = '___tempname___' cursor_orig = self.cursor ch = self.prev_char() while ch != None and (not is_delimiter(ch)): ch = self.prev_char() self.cursor_left_step() if ch != None: self.cursor_right_step() cursor_base = self.cursor autocomp_prefix = self.edit_text[cursor_base:cursor_orig] # Get the previous word if self.prev_char == '.': self.cursor_left_step() ch = self.prev_char() while ch != None and is_delimiter_autocomp(ch) == False: ch = self.prev_char() self.cursor_left_step() cursor_new = self.cursor if ch != None: cursor_new += 1 pytxt = self.edit_text[cursor_new:cursor_base - 1] if pytxt: self.console.runsource(TEMP_NAME + '=' + pytxt, '<input>', 'single') else: val = None try: val = self.namespace[TEMP_NAME] del self.namespace[TEMP_NAME] except: val = None if val: autocomp_members = dir(val) autocomp_prefix_ret, autocomp_members = do_autocomp( autocomp_prefix, autocomp_members) self.cursor = cursor_orig for v in autocomp_prefix_ret: self.cursor_insert_char(v) cursor_orig = self.cusor if autocomp_members: self.add_scrollback(', '.join(autocomp_members)) del val else: # Autocomp global namespace autocomp_members = self.namespace.keys() if autocomp_prefix: autocomp_members = [ v for v in autocomp_members if v.startswith(autocomp_prefix) ] autocomp_prefix_ret, autocomp_members = do_autocomp( autocomp_prefix, autocomp_members) self.cursor = cursor_orig for v in autocomp_prefix_ret: self.cursor_insert_char(v) cursor_orig = self.cursor if autocomp_members: self.add_scrollback(', '.join(autocomp_members)) self.cursor = cursor_orig def get_text_commandline(self): self.fill_scrollback() if self.is_multiline: prefix = PROMPT_MULTI else: prefix = PROMPT return prefix + self.edit_text def get_text(self): self.fill_scrollback() return '\n'.join(self.scrollback) + '\n' + self.get_text_commandline() def handle_input(self): keyboard = bge.logic.keyboard key_events = keyboard.events is_shift = key_events[bge.events.LEFTSHIFTKEY] == bge.logic.KX_INPUT_ACTIVE or \ key_events[bge.events.RIGHTSHIFTKEY] == bge.logic.KX_INPUT_ACTIVE is_ctrl = key_events[bge.events.LEFTCTRLKEY] == bge.logic.KX_INPUT_ACTIVE or \ key_events[bge.events.RIGHTCTRLKEY] == bge.logic.KX_INPUT_ACTIVE # First deal with important keys if key_events[ bge.events.LEFTARROWKEY] == bge.logic.KX_INPUT_JUST_ACTIVATED: self.cursor_left_jump() if is_ctrl else self.cursor_left_step() return if key_events[ bge.events.RIGHTARROWKEY] == bge.logic.KX_INPUT_JUST_ACTIVATED: self.cursor_right_jump() if is_ctrl else self.cursor_right_step() return if key_events[ bge.events.BACKSPACEKEY] == bge.logic.KX_INPUT_JUST_ACTIVATED: self.cursor_backspace_jump( ) if is_ctrl else self.cursor_backspace_step() return if key_events[bge.events.DELKEY] == bge.logic.KX_INPUT_JUST_ACTIVATED: self.cursor_delete_jump() if is_ctrl else self.cursor_delete_step() return if key_events[bge.events.HOMEKEY] == bge.logic.KX_INPUT_JUST_ACTIVATED: self.cursor_home() return if key_events[bge.events.ENDKEY] == bge.logic.KX_INPUT_JUST_ACTIVATED: self.cursor_end() return if key_events[bge.events.RETKEY] == bge.logic.KX_INPUT_JUST_ACTIVATED: self.execute() return if key_events[ bge.events.UPARROWKEY] == bge.logic.KX_INPUT_JUST_ACTIVATED: self.history_up() return if key_events[ bge.events.DOWNARROWKEY] == bge.logic.KX_INPUT_JUST_ACTIVATED: self.history_down() return if key_events[bge.events.TABKEY] == bge.logic.KX_INPUT_JUST_ACTIVATED: self.autocomp() return # Deal with characters for evt, val in keyboard.events.items(): if val == bge.logic.KX_INPUT_JUST_ACTIVATED and evt != self.toggle_key: ch = bge.events.EventToCharacter(evt, is_shift) if ch: self.cursor_insert_char(ch) def main(self): if self.toggle_key: if bge.logic.keyboard.events[ self.toggle_key] == bge.logic.KX_INPUT_JUST_ACTIVATED: self.active = not self.active if self.active == True: self.handle_input() text = self.get_text() n = len(text) - len(self.edit_text) text = text[:n + self.cursor] + "_" + text[n + self.cursor:] self.text = text if self.render not in bge.logic.getCurrentScene().post_draw: bge.logic.getCurrentScene().post_draw.append(self.render) else: if self.render in bge.logic.getCurrentScene().post_draw: bge.logic.getCurrentScene().post_draw.remove(self.render) text = property(_get_text, set_text)
class Console: def __init__(self, screen, rect, functions={}, key_calls={}, vars={}, syntax={}): if not pygame.display.get_init(): raise pygame.error, "Display not initialized. Initialize the display before creating a Console" if not pygame.font.get_init(): pygame.font.init() self.parent_screen = screen self.rect = pygame.Rect(rect) self.size = self.rect.size self.user_vars = vars self.user_syntax = syntax self.user_namespace = {} self.variables = {\ "bg_alpha":int,\ "bg_color": list,\ "txt_color_i": list,\ "txt_color_o": list,\ "ps1": str,\ "ps2": str,\ "ps3": str,\ "active": bool,\ "repeat_rate": list,\ "preserve_events":bool,\ "python_mode":bool,\ "motd":list } self.init_default_cfg() pygame.key.set_repeat(*self.repeat_rate) self.bg_layer = pygame.Surface(self.size) self.bg_layer.set_alpha(self.bg_alpha) self.txt_layer = pygame.Surface(self.size) self.txt_layer.set_colorkey(self.bg_color) self.font = pygame.font.Font('views/DroidSansMono.ttf', 12) self.font_height = self.font.get_linesize() self.max_lines = (self.size[HEIGHT] / self.font_height) - 1 self.max_chars = ( self.size[WIDTH] / (self.font.size(ascii_letters)[WIDTH] / len(ascii_letters))) - 1 self.txt_wrapper = textwrap.TextWrapper() self.c_out = self.motd self.c_hist = [""] self.c_hist_pos = 0 self.c_in = "" self.c_pos = 0 self.c_draw_pos = 0 self.c_scroll = 0 self.changed = True self.func_calls = {} self.key_calls = {} self.add_func_calls({ "echo": self.output, "clear": self.clear, "help": self.help }) self.add_func_calls(functions) self.add_key_calls({ "l": self.clear, "c": self.clear_input, "w": self.set_active }) self.add_key_calls(key_calls) self.set_interpreter() ################## #-Initialization-# def init_default_cfg(self): self.bg_alpha = 175 self.bg_color = [0x0, 0x44, 0xAA] self.txt_color_i = [0xFF, 0xFF, 0xFF] self.txt_color_o = [0xEE, 0xEE, 0xEE] self.ps1 = "] " self.ps2 = ">>> " self.ps3 = "... " self.active = True self.repeat_rate = [500, 30] self.python_mode = False self.preserve_events = False self.motd = [ "Press Ctrl_w to hide the console", "One day this will have more to say" ] def add_func_calls(self, functions): '''\ Add functions to the func_calls dictionary. Arguments: functions -- dictionary of functions to add. ''' if isinstance(functions, dict): self.func_calls.update(functions) self.user_namespace.update(self.func_calls) def add_key_calls(self, functions): '''\ Add functions to the key_calls dictionary. Arguments: functions -- dictionary of key_calls to add. ''' if isinstance(functions, dict): self.key_calls.update(functions) def output(self, text): '''\ Prepare text to be displayed Arguments: text -- Text to be displayed ''' if not str(text): return try: self.changed = True if not isinstance(text, str): text = str(text) text = text.expandtabs() text = text.splitlines() self.txt_wrapper.width = self.max_chars for line in text: for w in self.txt_wrapper.wrap(line): self.c_out.append(w) except: raise def set_active(self, b=None): '''\ Activate or Deactivate the console Arguments: b -- Optional boolean argument, True=Activate False=Deactivate ''' if not b: self.active = not self.active else: self.active = b def format_input_line(self): '''\ Format input line to be displayed ''' # The \v here is sort of a hack, it's just a character that isn't recognized by the font engine text = self.c_in[:self.c_pos] + "\v" + self.c_in[self.c_pos + 1:] n_max = self.max_chars - len(self.c_ps) vis_range = self.c_draw_pos, self.c_draw_pos + n_max return self.c_ps + text[vis_range[0]:vis_range[1]] def draw(self): '''\ Draw the console to the parent screen ''' if not self.active: return if self.changed: self.changed = False # Draw Output self.txt_layer.fill(self.bg_color) lines = self.c_out[-(self.max_lines + self.c_scroll):len(self.c_out) - self.c_scroll] y_pos = self.size[HEIGHT] - (self.font_height * (len(lines) + 1)) for line in lines: tmp_surf = self.font.render(line, True, self.txt_color_o) self.txt_layer.blit(tmp_surf, (1, y_pos, 0, 0)) y_pos += self.font_height # Draw Input tmp_surf = self.font.render(self.format_input_line(), True, self.txt_color_i) self.txt_layer.blit( tmp_surf, (1, self.size[HEIGHT] - self.font_height, 0, 0)) # Clear background and blit text to it self.bg_layer.fill(self.bg_color) self.bg_layer.blit(self.txt_layer, (0, 0, 0, 0)) # Draw console to parent screen pygame.draw.rect(self.parent_screen, self.txt_color_i, (self.rect.x - 1, self.rect.y - 1, self.size[WIDTH] + 2, self.size[HEIGHT] + 2), 1) self.parent_screen.blit(self.bg_layer, self.rect) ####################################################################### # Functions to communicate with the console and the python interpreter# def set_interpreter(self): #self.output("Entering Python mode") self.python_interpreter = InteractiveConsole() self.tmp_fds = [] self.py_fds = [Writable() for i in range(3)] self.c_ps = self.ps2 def catch_output(self): if not self.tmp_fds: self.tmp_fds = [sys.stdout, sys.stdin, sys.stderr] sys.stdout, sys.stdin, sys.stderr = self.py_fds def release_output(self): if self.tmp_fds: sys.stdout, sys.stdin, sys.stderr = self.tmp_fds self.tmp_fds = [] [fd.reset() for fd in self.py_fds] def submit_input(self, text): '''\ Submit input 1) Move input to output 2) Evaluate input 3) Clear input line ''' self.clear_input() self.output(self.c_ps + text) self.c_scroll = 0 self.send_python(text) def send_python(self, text): '''\ Sends input the the python interpreter in effect giving the user the ability to do anything python can. ''' self.c_ps = self.ps2 self.catch_output() if text: self.add_to_history(text) r = self.python_interpreter.push(text) if r: self.c_ps = self.ps3 else: code = "".join(self.py_fds[OUT]) self.python_interpreter.push("\n") self.python_interpreter.runsource(code) for i in self.py_fds[OUT] + self.py_fds[ERR]: self.output(i) self.release_output() #################################################### #-Functions for sharing variables with the console-# def setvar(self, name, value): '''\ Sets the value of a variable ''' if self.user_vars.has_key(name) or not self.__dict__.has_key(name): self.user_vars.update({name: value}) self.user_namespace.update(self.user_vars) elif self.__dict__.has_key(name): self.__dict__.update({name: value}) def getvar(self, name): '''\ Gets the value of a variable, this is useful for people that want to access console variables from within their game ''' if self.user_vars.has_key(name) or not self.__dict__.has_key(name): return self.user_vars[name] elif self.__dict__.has_key(name): return self.__dict__[name] def setvars(self, vars): try: self.user_vars.update(vars) self.user_namespace.update(self.user_vars) except TypeError: self.output("setvars requires a dictionary") def getvars(self, opt_dict=None): if opt_dict: opt_dict.update(self.user_vars) else: return self.user_vars def add_to_history(self, text): '''\ Add specified text to the history ''' self.c_hist.insert(-1, text) self.c_hist_pos = len(self.c_hist) - 1 def clear_input(self): '''\ Clear input line and reset cursor position ''' self.c_in = "" self.c_pos = 0 self.c_draw_pos = 0 def set_pos(self, newpos): '''\ Moves cursor safely ''' self.c_pos = newpos if (self.c_pos - self.c_draw_pos) >= (self.max_chars - len(self.c_ps)): self.c_draw_pos = max( 0, self.c_pos - (self.max_chars - len(self.c_ps))) elif self.c_draw_pos > self.c_pos: self.c_draw_pos = self.c_pos - (self.max_chars / 2) if self.c_draw_pos < 0: self.c_draw_pos = 0 self.c_pos = 0 def str_insert(self, text, strn): '''\ Insert characters at the current cursor position ''' foo = text[:self.c_pos] + strn + text[self.c_pos:] self.set_pos(self.c_pos + len(strn)) return foo def process_input(self): '''\ Loop through pygame events and evaluate them ''' if not self.active: return if self.preserve_events: eventlist = pygame.event.get(KEYDOWN) else: eventlist = pygame.event.get() for event in eventlist: if event.type == KEYDOWN: self.changed = True ## Special Character Manipulation if event.key == K_TAB: self.c_in = self.str_insert(self.c_in, " ") elif event.key == K_BACKSPACE: if self.c_pos > 0: self.c_in = self.c_in[:self.c_pos - 1] + self.c_in[self.c_pos:] self.set_pos(self.c_pos - 1) elif event.key == K_DELETE: if self.c_pos < len(self.c_in): self.c_in = self.c_in[:self. c_pos] + self.c_in[self.c_pos + 1:] elif event.key == K_RETURN or event.key == 271: self.submit_input(self.c_in) ## Changing Cursor Position elif event.key == K_LEFT: if self.c_pos > 0: self.set_pos(self.c_pos - 1) elif event.key == K_RIGHT: if self.c_pos < len(self.c_in): self.set_pos(self.c_pos + 1) elif event.key == K_HOME: self.set_pos(0) elif event.key == K_END: self.set_pos(len(self.c_in)) ## History Navigation elif event.key == K_UP: if len(self.c_out): if self.c_hist_pos > 0: self.c_hist_pos -= 1 self.c_in = self.c_hist[self.c_hist_pos] self.set_pos(len(self.c_in)) elif event.key == K_DOWN: if len(self.c_out): if self.c_hist_pos < len(self.c_hist) - 1: self.c_hist_pos += 1 self.c_in = self.c_hist[self.c_hist_pos] self.set_pos(len(self.c_in)) ## Scrolling elif event.key == K_PAGEUP: if self.c_scroll < len(self.c_out) - 1: self.c_scroll += 1 elif event.key == K_PAGEDOWN: if self.c_scroll > 0: self.c_scroll -= 1 ## Normal character printing elif event.key >= 32: mods = pygame.key.get_mods() if mods & KMOD_CTRL: if event.key in range(256) and chr( event.key) in self.key_calls: self.key_calls[chr(event.key)]() else: char = str(event.unicode) self.c_in = self.str_insert(self.c_in, char) ########################## #-Some Builtin functions-# def clear(self): '''\ Clear the Screen ''' self.c_out = ["[Screen Cleared]"] self.c_scroll = 0 def help(self, *args): '''\ Output information about functions Arguments: args -- arbitrary argument list of function names |- No Args - A list of available functions will be displayed |- One or more Args - Docstring of each function will be displayed ''' if args: items = [(i, self.func_calls[i]) for i in args if i in self.func_calls] for i, v in items: out = i + ": Takes %d arguments. " % ( v.func_code.co_argcount - (v.func_code.co_varnames[0] is "self")) doc = v.func_doc if doc: out += textwrap.dedent(doc) tmp_indent = self.txt_wrapper.subsequent_indent self.txt_wrapper.subsequent_indent = " " * (len(i) + 2) self.output(out) self.txt_wrapper.subsequent_indent = tmp_indent else: out = "Available commands: " + str( self.func_calls.keys()).strip("[]") self.output(out) self.output( r'Type "help command-name" for more information on that command' )
def runsource(self, source, *args): self.last_buffer = [source.encode("utf-8")] return InteractiveConsole.runsource(self, source, *args)
class Console: def __init__(self, screen, rect, functions={}, key_calls={}, vars={}): if not pygame.display.get_init(): raise pygame.error, "Display not initialized. Initialize the display before creating a Console" if not pygame.font.get_init(): pygame.font.init() self.parent_screen = screen self.rect = pygame.Rect(rect) self.size = self.rect.size self.user_vars = vars self.variables = {\ "bg_alpha":int,\ "bg_color": list,\ "txt_color_i": list,\ "txt_color_o": list,\ "ps1": str,\ "ps2": str,\ "ps3": str,\ "active": bool,\ "repeat_rate": list,\ "preserve_events":bool,\ "python_mode":bool,\ "motd":list } self.load_cfg() self.set_interpreter() pygame.key.set_repeat(*self.repeat_rate) self.bg_layer = pygame.Surface(self.size) self.bg_layer.set_alpha(self.bg_alpha) self.txt_layer = pygame.Surface(self.size) self.txt_layer.set_colorkey(self.bg_color) self.font = pygame.font.Font("../gfx/fixed_width.ttf", 14) self.font_height = self.font.get_linesize() self.max_lines = (self.size[HEIGHT] / self.font_height) - 1 self.max_chars = (self.size[WIDTH] / self.font.size("#")[WIDTH]) - 1 self.txt_wrapper = textwrap.TextWrapper() self.c_out = self.motd self.c_hist = [""] self.c_hist_pos = 0 self.c_in = "" self.c_pos = 0 self.c_draw_pos = 0 self.c_scroll = 0 # if self.python_mode: # self.c_ps = self.ps2 # else: # self.c_ps = self.ps1 self.changed = True self.func_calls = {} self.key_calls = {} self.add_func_calls({ "echo": self.output, "clear": self.clear, "help": self.help }) self.add_func_calls(functions) self.add_key_calls({ "l": self.clear, "c": self.clear_input, "w": self.set_active }) self.add_key_calls(key_calls) def safe_set_attr(self, name, value): """Safely set the console variables""" if name in self.variables: if isinstance(value, self.variables[name]) or not self.variables[name]: self.__dict__[name] = value def add_func_calls(self, functions): """Add functions to the func_calls dictionary. functions -- dictionary of functions to add""" if isinstance(functions, dict): self.func_calls.update(functions) def add_key_calls(self, functions): """Add functions to the key_calls dictionary. functions -- dictionary of key_calls to add""" if isinstance(functions, dict): self.key_calls.update(functions) def clear(self): """Clear the Screen""" self.c_out = ["[Screen Cleared]"] self.c_scroll = 0 def help(self, *args): """Output information about functions args -- arbitrary argument list of function names No Args - A list of available functions will be displayed One or more Args - Docstring of each function will be displayed""" if args: items = [(i, self.func_calls[i]) for i in args if i in self.func_calls] for i, v in items: out = i + ": Takes %d arguments. " % ( v.func_code.co_argcount - (v.func_code.co_varnames[0] is "self")) # TODO: function doc get funny formatting, so need to fiddle here doc = v.func_doc if doc: out += textwrap.dedent(doc) tmp_indent = self.txt_wrapper.subsequent_indent self.txt_wrapper.subsequent_indent = " " * (len(i) + 2) self.output(out) self.txt_wrapper.subsequent_indent = tmp_indent else: out = "Available commands: " + str( self.func_calls.keys()).strip("[]") self.output(out) self.output( r'Type "help command-name" for more information on that command' ) def output(self, text): """Prepare text to be displayed text -- Text to be displayed""" if not str(text): return try: self.changed = True if not isinstance(text, str): text = str(text) text = text.expandtabs() text = text.splitlines() self.txt_wrapper.width = self.max_chars for line in text: for w in self.txt_wrapper.wrap(line): self.c_out.append(w) except: print text def set_active(self, b=None): """Activate or Deactivate the console. Pass with b- Optional boolean argument, True=Activate False=Deactivate""" if not b: self.active = not self.active else: self.active = b def set_interpreter(self): if self.python_mode: # spqr tries to reduce console ouput,but we can still # have some debugging info if (SPQR.DEBUG_MODE == True): self.output("Entering Python mode") self.python_mode = True self.python_interpreter = InteractiveConsole() self.tmp_fds = [] self.py_fds = [Writable() for i in range(3)] self.c_ps = self.ps2 else: if (SPQR.DEBUG_MODE == True): self.output("Entering Pyconsole mode") self.python_mode = False self.c_ps = self.ps1 def catch_output(self): if not self.tmp_fds: self.tmp_fds = [sys.stdout, sys.stdin, sys.stderr] sys.stdout, sys.stdin, sys.stderr = self.py_fds def release_output(self): if self.tmp_fds: sys.stdout, sys.stdin, sys.stderr = self.tmp_fds self.tmp_fds = [] [fd.reset() for fd in self.py_fds] def format_input_line(self): '''\ Format input line to be displayed ''' text = self.c_in[:self.c_pos] + "|" + self.c_in[self.c_pos:] n_max = self.max_chars - len(self.c_ps) vis_range = self.c_draw_pos, self.c_draw_pos + n_max return self.c_ps + text[vis_range[0]:vis_range[1]] def draw(self): '''\ Draw the console to the parent screen ''' if not self.active: return if self.changed: self.changed = False # Draw Output self.txt_layer.fill(self.bg_color) lines = self.c_out[-(self.max_lines + self.c_scroll):len(self.c_out) - self.c_scroll] y_pos = self.size[HEIGHT] - (self.font_height * (len(lines) + 1)) for line in lines: tmp_surf = self.font.render(line, True, self.txt_color_o) self.txt_layer.blit(tmp_surf, (1, y_pos, 0, 0)) y_pos += self.font_height # Draw Input tmp_surf = self.font.render(self.format_input_line(), True, self.txt_color_i) self.txt_layer.blit( tmp_surf, (1, self.size[HEIGHT] - self.font_height, 0, 0)) # Clear background and blit text to it self.bg_layer.fill(self.bg_color) self.bg_layer.blit(self.txt_layer, (0, 0, 0, 0)) # Draw console to parent screen #self.parent_screen.fill(self.txt_color_i, (self.rect.x-1, self.rect.y-1, self.size[WIDTH]+2, self.size[HEIGHT]+2)) pygame.draw.rect(self.parent_screen, self.txt_color_i, (self.rect.x - 1, self.rect.y - 1, self.size[WIDTH] + 2, self.size[HEIGHT] + 2), 1) self.parent_screen.blit(self.bg_layer, self.rect) def submit_input(self, text): """Submit input: 1) Move input to output, 2) Evaluate input, 3) Clear input line""" self.clear_input() self.output(self.c_ps + text) self.c_scroll = 0 if self.python_mode: self.send_python(text) else: self.send_pyconsole(text) def send_python(self, text): """Sends input to the python interpreter giving the user the ability to do anything python can""" self.c_ps = self.ps2 self.catch_output() if text: self.add_to_history(text) r = self.python_interpreter.push(text) if r: self.c_ps = self.ps3 else: code = "".join(self.py_fds[OUT]) self.python_interpreter.push("\n") self.python_interpreter.runsource(code) for i in self.py_fds[OUT] + self.py_fds[ERR]: self.output(i) self.release_output() def send_pyconsole(self, text): """Sends input to pyconsole to be interpreted""" # Output a blank row if nothing is entered if not text: self.output("") return self.add_to_history(text) # Check if the text is in the form: name = value assign = re_is_assign.match(text) try: if assign: tokens = self.tokenize(assign.group('value')) else: tokens = self.tokenize(text) except ParseError, e: self.output(r'At Token: "%s"' % e.at_token()) return try: if (len(tokens) is 1) and re_is_var.match(text) and not assign: out = tokens[0] else: out = self.func_calls[tokens[0]](*tokens[1:]) except (KeyError, TypeError): if (len(tokens) is 1) and assign: self.setvar(assign.group('name'), tokens[0]) else: self.output("Unknown Command: " + str(tokens[0])) self.output(r'Type "help" for a list of commands.') else: self.output(out)
def runsource(self, source, *args): self.last_buffer = [ source.encode('latin-1') ] return InteractiveConsole.runsource(self, source, *args)
#! /usr/bin/env python import os.path from code import InteractiveConsole from deployment import Deployment D = Deployment() console = InteractiveConsole(locals={"D": D, "ec2": D.ec2}) pyrc = os.path.expanduser(os.path.join("~", ".pythonrc.py")) if os.path.exists(pyrc): console.runsource(open(pyrc).read()) console.interact()