default persistent.console_history = None default persistent.console_line_history = None init 1702 python in _console: import datetime class ConsoleHistoryEntry(object): lines = 0 def __init__(self, command, result=None, is_error=False, is_stdio=False): self.command = command self.result = result self.is_error = is_error self.timestamp = datetime.datetime.now().timestamp() self.is_stdio = is_stdio def update_lines(self): if self.result is None: return lines = self.result if len(lines) > config.console_history_lines * 160: lines = "…" + self.result[-config.console_history_lines * 160:] lines = lines.split("\n") if len(lines) > config.console_history_lines: lines = [ "…" ] + lines[-config.console_history_lines:] self.result = "\n".join(lines) self.lines = len(lines) class DebugConsoleNew(object): def __init__(self): self.history = BoundedList(config.console_history_size, config.console_history_lines + config.console_history_size) self.line_history = BoundedList(config.console_history_size) self.line_index = 0 if persistent.console_history is not None: for i in persistent.console_history: he = ConsoleHistoryEntry(i[0], i[1], i[2]) he.update_lines() self.history.append(he) if persistent.console_line_history is not None: self.line_history.extend(persistent.console_line_history) self.first_time = True self.renpy_scripting = False self.reset() def backup(self): persistent.console_history = [ (i.command, i.result, i.is_error) for i in self.history ] persistent.console_line_history = list(self.line_history) def start(self): he = ConsoleHistoryEntry(None) if self.first_time: current_time = datetime.datetime.now() message = ("-" * 50) + " RESTART OCCURED " + ("-" * 50) he.result = message he.update_lines() self.history.append(he) self.first_time = False if self.can_renpy(): self.renpy_scripting = True else: self.renpy_scripting = False def reset(self): self.lines = [ "" ] self.line_index = len(self.line_history) def recall_line(self, offset): self.line_index += offset if self.line_index < 0: self.line_index = 0 if self.line_index > len(self.line_history): self.line_index = len(self.line_history) # Skip adjacent duplicates while self.line_index > 0 and self.line_index < len(self.line_history) and self.line_history[self.line_index] == self.line_history[self.line_index - 1]: self.line_index += offset if self.line_index == len(self.line_history): self.lines = [ "" ] else: self.lines = list(self.line_history[self.line_index]) cs = renpy.get_screen("console") scope = cs.scope consoleinput = scope["consoleinput"] consoleinput.caret_pos = 0 consoleinput.update_text(self.lines[-1], consoleinput.editable) renpy.restart_interaction() def older(self): self.recall_line(-1) def newer(self): self.recall_line(1) def show_stdio(self): old_entry = None if persistent._console_short: if len(stdio_lines) > 30: stdio_lines[:] = stdio_lines[:10] + [ (False, " ... ") ] + stdio_lines[-20:] for error, l in stdio_lines: if persistent._console_short: if len(l) > 200: l = l[:100] + "..." + l[-100:] if (old_entry is not None) and (error == old_entry.is_error): old_entry.result += "\n" + l else: e = ConsoleHistoryEntry(None, l, error) e.update_lines() self.history.append(e) old_entry = e if old_entry is not None: old_entry.update_lines() stdio_lines[:] = _list() def stdout_line(self, l): if not (config.console or config.developer): return he = ConsoleHistoryEntry(l, is_stdio=True) he.update_lines() self.history.append(he) def stderr_line(self, l): if not (config.console or config.developer): return he = ConsoleHistoryEntry(l, is_error=True, is_stdio=True) he.update_lines() def can_renpy(self): """ Returns true if we can run Ren'Py code. """ return renpy.game.context().rollback def format_exception(self): etype, evalue, etb = sys.exc_info() return traceback.format_exception_only(etype, evalue)[-1] def run(self, lines): line_count = len(lines) code = "\n".join(lines) he = ConsoleHistoryEntry(code) self.history.append(he) self.line_history.append(lines) try: # If we have 1 line, try to parse it as a command. if line_count == 1: block = [ ( "", 1, code, [ ]) ] l = renpy.parser.Lexer(block) l.advance() # Command can be None, but that's okay, since the lookup will fail. command = l.word() command_fn = config.console_commands.get(command, None) if command_fn is not None: he.result = command_fn(l) he.update_lines() return error = None # Try to run it as Ren'Py. if self.can_renpy(): # TODO: Can we run Ren'Py code? name = renpy.load_string(code + "\nreturn") if name is not None: renpy.game.context().exception_handler = ScriptErrorHandler() renpy.call(name) else: error = "\n\n".join(renpy.get_parse_errors()) # Try to eval it. try: renpy.python.py_compile(code, 'eval') except Exception: pass else: result = renpy.python.py_eval(code) if persistent._console_short and not getattr(result, "_console_always_long", False): he.result = aRepr.repr(result) else: he.result = repr(result) he.update_lines() return # Try to exec it. try: renpy.python.py_compile(code, "exec") except Exception: if error is None: error = self.format_exception() else: renpy.python.py_exec(code) return if error is not None: he.result = error he.update_lines() he.is_error = True except renpy.game.CONTROL_EXCEPTIONS: raise except Exception: import traceback traceback.print_exc() he.result = self.format_exception().rstrip() he.update_lines() he.is_error = True console = DebugConsoleNew() @command(_("exit: exit the console")) def exit(l): renpy.hide_screen("console") @command() def quit(l): renpy.hide_screen("console") @command() def stack(l): console.run(["renpy.exports.get_return_stack()"]) @command(_("call