From 1697263fd75202d189c72b2b68e47e521a1e5fba Mon Sep 17 00:00:00 2001 From: Vincent Le Goff Date: Sat, 11 Feb 2017 12:43:58 -0800 Subject: [PATCH] Add the /edit swtich to the @py command --- evennia/commands/default/system.py | 143 +++++++++++++++++++---------- evennia/utils/eveditor.py | 19 +++- 2 files changed, 108 insertions(+), 54 deletions(-) diff --git a/evennia/commands/default/system.py b/evennia/commands/default/system.py index 8ad2eaff8f..a0ac0495d1 100644 --- a/evennia/commands/default/system.py +++ b/evennia/commands/default/system.py @@ -19,6 +19,7 @@ from evennia.scripts.models import ScriptDB from evennia.objects.models import ObjectDB from evennia.players.models import PlayerDB from evennia.utils import logger, utils, gametime, create, prettytable +from evennia.utils.eveditor import EvEditor from evennia.utils.evtable import EvTable from evennia.utils.utils import crop, class_from_module @@ -122,19 +123,101 @@ class CmdShutdown(COMMAND_DEFAULT_CLASS): SESSIONS.portal_shutdown() +def _py_load(caller): + return "" + +def _py_save(caller, buf): + """ + Execute the buffer. + """ + caller.msg("Executing the entered code...") + _run_snippet(caller, buf, mode="exec", show_input=False) + return True + +def _py_quit(caller): + caller.msg("Exited the code editor.") + +def _run_snippet(caller, pycode, mode="eval", m_time=False, + show_input=True): + """ + Run code and try to display information to the caller. + + Args: + caller (Object): the caller. + pycode (str): the Python code to run. + m_time (bool, optional): should we measure the time of execution? + show_input (bookl, optional): should we display the input? + + """ + # Try to retrieve the session + session = caller + if hasattr(caller, "sessions"): + session = caller.sessions.get()[0] + + # import useful variables + import evennia + available_vars = { + 'self': caller, + 'me': caller, + 'here': getattr(caller, "location", None), + 'evennia': evennia, + 'ev': evennia, + 'inherits_from': utils.inherits_from, + } + + if show_input: + try: + caller.msg(">>> %s" % pycode, session=session, + options={"raw":True}) + except TypeError: + caller.msg(">>> %s" % pycode, options={"raw":True}) + + try: + try: + pycode_compiled = compile(pycode, "", mode) + except Exception: + mode = "exec" + pycode_compiled = compile(pycode, "", mode) + + duration = "" + if m_time: + t0 = time.time() + ret = eval(pycode_compiled, {}, available_vars) + t1 = time.time() + duration = " (runtime ~ %.4f ms)" % ((t1 - t0) * 1000) + else: + ret = eval(pycode_compiled, {}, available_vars) + if mode == "eval": + ret = "%s%s" % (str(ret), duration) + else: + ret = " Done (use self.msg() if you want to catch output)%s" % duration + except Exception: + errlist = traceback.format_exc().split('\n') + if len(errlist) > 4: + errlist = errlist[4:] + ret = "\n".join("%s" % line for line in errlist if line) + + try: + caller.msg(ret, session=session, options={"raw":True}) + except TypeError: + caller.msg(ret, options={"raw":True}) + class CmdPy(COMMAND_DEFAULT_CLASS): """ execute a snippet of python code Usage: @py + @py/edit Switch: time - output an approximate execution time for + edit - open a code editor to enter several lines of code - Separate multiple commands by ';'. A few variables are made - available for convenience in order to offer access to the system - (you can import more at execution time). + Separate multiple commands by ';' or open the editor using the + /edit switch. A few variables are made available for convenience + in order to offer access to the system (you can import more at + execution time). Available variables in @py environment: self, me : caller @@ -160,58 +243,18 @@ class CmdPy(COMMAND_DEFAULT_CLASS): caller = self.caller pycode = self.args + if "edit" in self.switches: + EvEditor(self.caller, loadfunc=_py_load, savefunc=_py_save, + quitfunc=_py_quit, key="PyEditor", persistent=True, + code=True) + return + if not pycode: string = "Usage: @py " self.msg(string) return - # check if caller is a player - - # import useful variables - import evennia - available_vars = {'self': caller, - 'me': caller, - 'here': hasattr(caller, "location") and caller.location or None, - 'evennia': evennia, - 'ev': evennia, - 'inherits_from': utils.inherits_from} - - try: - self.msg(">>> %s" % pycode, session=self.session, options={"raw":True}) - except TypeError: - self.msg(">>> %s" % pycode, options={"raw":True}) - - mode = "eval" - try: - try: - pycode_compiled = compile(pycode, "", mode) - except Exception: - mode = "exec" - pycode_compiled = compile(pycode, "", mode) - - duration = "" - if "time" in self.switches: - t0 = time.time() - ret = eval(pycode_compiled, {}, available_vars) - t1 = time.time() - duration = " (runtime ~ %.4f ms)" % ((t1 - t0) * 1000) - else: - ret = eval(pycode_compiled, {}, available_vars) - if mode == "eval": - ret = "%s%s" % (str(ret), duration) - else: - ret = " Done (use self.msg() if you want to catch output)%s" % duration - except Exception: - errlist = traceback.format_exc().split('\n') - if len(errlist) > 4: - errlist = errlist[4:] - ret = "\n".join("%s" % line for line in errlist if line) - - try: - self.msg(ret, session=self.session, options={"raw":True}) - except TypeError: - self.msg(ret, options={"raw":True}) - + _run_snippet(caller, self.args, m_time="time" in self.switches) # helper function. Kept outside so it can be imported and run # by other commands. diff --git a/evennia/utils/eveditor.py b/evennia/utils/eveditor.py index ca4511f4b4..0038fbcc68 100644 --- a/evennia/utils/eveditor.py +++ b/evennia/utils/eveditor.py @@ -375,7 +375,7 @@ class CmdLineInput(CmdEditorBase): buf = editor.get_buffer() # add a line of text to buffer - line = self.raw_string + line = self.raw_string.strip("\r\n") if not editor._code: if not buf: buf = line @@ -396,8 +396,12 @@ class CmdLineInput(CmdEditorBase): cline = len(self.editor.get_buffer().split('\n')) if editor._code: # display the current level of identation - self.caller.msg("{b%02i|{n ({g%d{n) %s" % ( - cline, editor._indent, line)) + indent = editor._indent + if indent < 0: + indent = "off" + + self.caller.msg("{b%02i|{n ({g%s{n) %s" % ( + cline, indent, line)) else: self.caller.msg("{b%02i|{n %s" % (cline, self.args)) @@ -503,6 +507,13 @@ class CmdEditorGroup(CmdEditorBase): elif cmd == ":DD": # clear buffer editor.update_buffer("") + + # Reset indentation level to 0 + if editor._code: + if editor._indent >= 0: + editor._indent = 0 + if editor._persistent: + caller.attributes.add("_eveditor_indent", 0) caller.msg("Cleared %i lines from buffer." % self.nlines) elif cmd == ":y": # :y - yank line(s) to copy buffer @@ -949,7 +960,7 @@ class EvEditor(object): """ string = self._sep * _DEFAULT_WIDTH + _HELP_TEXT - if self.code: + if self._code: string += _HELP_CODE string += _HELP_LEGEND + self._sep * _DEFAULT_WIDTH self._caller.msg(string)