From 7453cf325ad792d55bd8d2e9babbb137c703f824 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 12 Feb 2017 13:14:59 +0100 Subject: [PATCH] Make 'codefunc' a callable kwarg of EvEditor instead of the code boolean, to offer potential more flexibility if using EvEditor in other conditions. Add :! as a way to run code without saving it. Add support for using the /time switch also with the code editor when using . --- evennia/commands/default/system.py | 29 +++++++++------ evennia/utils/eveditor.py | 58 ++++++++++++++++-------------- 2 files changed, 49 insertions(+), 38 deletions(-) diff --git a/evennia/commands/default/system.py b/evennia/commands/default/system.py index a0ac0495d1..46fb05ec99 100644 --- a/evennia/commands/default/system.py +++ b/evennia/commands/default/system.py @@ -126,18 +126,24 @@ class CmdShutdown(COMMAND_DEFAULT_CLASS): def _py_load(caller): return "" -def _py_save(caller, buf): +def _py_code(caller, buf): """ Execute the buffer. """ - caller.msg("Executing the entered code...") - _run_snippet(caller, buf, mode="exec", show_input=False) + measure_time = caller.db._py_measure_time + string = "Executing code%s ..." % ( + " (measure timing)" if measure_time else "") + caller.msg(string) + _run_code_snippet(caller, buf, mode="exec", + measure_time=measure_time, + show_input=False) return True def _py_quit(caller): + del caller.db._py_measure_time caller.msg("Exited the code editor.") -def _run_snippet(caller, pycode, mode="eval", m_time=False, +def _run_code_snippet(caller, pycode, mode="eval", measure_time=False, show_input=True): """ Run code and try to display information to the caller. @@ -180,7 +186,7 @@ def _run_snippet(caller, pycode, mode="eval", m_time=False, pycode_compiled = compile(pycode, "", mode) duration = "" - if m_time: + if measure_time: t0 = time.time() ret = eval(pycode_compiled, {}, available_vars) t1 = time.time() @@ -210,9 +216,9 @@ class CmdPy(COMMAND_DEFAULT_CLASS): @py @py/edit - Switch: + Switches: time - output an approximate execution time for - edit - open a code editor to enter several lines of code + edit - open a code editor for multi-line code experimentation Separate multiple commands by ';' or open the editor using the /edit switch. A few variables are made available for convenience @@ -244,9 +250,10 @@ class CmdPy(COMMAND_DEFAULT_CLASS): 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) + caller.db._py_measure_time = "time" in self.switches + EvEditor(self.caller, loadfunc=_py_load, savefunc=_py_code, + quitfunc=_py_quit, key="Python exec: :w or :!", persistent=True, + codefunc=_py_code) return if not pycode: @@ -254,7 +261,7 @@ class CmdPy(COMMAND_DEFAULT_CLASS): self.msg(string) return - _run_snippet(caller, self.args, m_time="time" in self.switches) + _run_code_snippet(caller, self.args, measure_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 81c1dc4477..d7f3203afa 100644 --- a/evennia/utils/eveditor.py +++ b/evennia/utils/eveditor.py @@ -115,10 +115,11 @@ _HELP_LEGEND = \ _HELP_CODE = \ """ + :! - Execute code buffer without saving :< - Decrease the level of automatic indentation for the next lines :> - Increase the level of automatic indentation for the next lines := - Switch automatic indentation on/off -""".strip("\n") +""".lstrip("\n") _ERROR_LOADFUNC = \ """ @@ -222,7 +223,6 @@ class CmdEditorBase(Command): locks = "cmd:all()" help_entry = "LineEditor" - code = None editor = None def parse(self): @@ -335,7 +335,6 @@ def _load_editor(caller): saved_options = caller.attributes.get("_eveditor_saved") saved_buffer, saved_undo = caller.attributes.get("_eveditor_buffer_temp", (None, None)) unsaved = caller.attributes.get("_eveditor_unsaved", False) - code = caller.attributes.get("_eveditor_code", False) indent = caller.attributes.get("_eveditor_indent", 0) if saved_options: eveditor = EvEditor(caller, **saved_options[0]) @@ -346,7 +345,6 @@ def _load_editor(caller): setattr(eveditor, "_undo_buffer", saved_undo) setattr(eveditor, "_undo_pos", len(saved_undo) - 1) setattr(eveditor, "_unsaved", unsaved) - setattr(eveditor, "_code", code) setattr(eveditor, "_indent", indent) for key, value in saved_options[1].iteritems(): setattr(eveditor, key, value) @@ -376,7 +374,7 @@ class CmdLineInput(CmdEditorBase): # add a line of text to buffer line = self.raw_string.strip("\r\n") - if not editor._code: + if not editor._codefunc: if not buf: buf = line else: @@ -394,7 +392,7 @@ class CmdLineInput(CmdEditorBase): if self.editor._echo_mode: # need to do it here or we will be off one line cline = len(self.editor.get_buffer().split('\n')) - if editor._code: + if editor._codefunc: # display the current level of identation indent = editor._indent if indent < 0: @@ -415,7 +413,7 @@ class CmdEditorGroup(CmdEditorBase): aliases = [":","::", ":::", ":h", ":w", ":wq", ":q", ":q!", ":u", ":uu", ":UU", ":dd", ":dw", ":DD", ":y", ":x", ":p", ":i", ":j", ":r", ":I", ":A", ":s", ":S", ":f", ":fi", ":fd", ":echo", - ":<", ":>", ":="] + ":!", ":<", ":>", ":="] arg_regex = r"\s.*?|$" def func(self): @@ -509,7 +507,7 @@ class CmdEditorGroup(CmdEditorBase): editor.update_buffer("") # Reset indentation level to 0 - if editor._code: + if editor._codefunc: if editor._indent >= 0: editor._indent = 0 if editor._persistent: @@ -555,7 +553,7 @@ class CmdEditorGroup(CmdEditorBase): caller.msg("Replaced %i line(s) at %s." % (len(new_lines), self.lstr)) elif cmd == ":I": # :I - insert text at beginning of line(s) - if not self.args: + if not self.raw_string and not editor._codefunc: caller.msg("You need to enter text to insert.") else: buf = linebuffer[:lstart] + ["%s%s" % (self.args, line) for line in linebuffer[lstart:lend]] + linebuffer[lend:] @@ -652,9 +650,14 @@ class CmdEditorGroup(CmdEditorBase): # set echoing on/off editor._echo_mode = not editor._echo_mode caller.msg("Echo mode set to %s" % editor._echo_mode) + elif cmd == ":!": + if editor._codefunc: + editor._codefunc(caller, editor._buffer) + else: + caller.msg("This command is only available in code editor mode.") elif cmd == ":<": # :< - if editor._code: + if editor._codefunc: editor.decrease_indent() indent = editor._indent if indent >= 0: @@ -663,10 +666,10 @@ class CmdEditorGroup(CmdEditorBase): else: caller.msg("|rManual indentation is OFF.|n Use := to turn it on.") else: - caller.msg("This is not a code editor, you cannot use this option.") + caller.msg("This command is only available in code editor mode.") elif cmd == ":>": # :> - if editor._code: + if editor._codefunc: editor.increase_indent() indent = editor._indent if indent >= 0: @@ -675,10 +678,10 @@ class CmdEditorGroup(CmdEditorBase): else: caller.msg("|rManual indentation is OFF.|n Use := to turn it on.") else: - caller.msg("This is not a code editor, you cannot use this option.") + caller.msg("This command is only available in code editor mode.") elif cmd == ":=": # := - if editor._code: + if editor._codefunc: editor.swap_autoindent() indent = editor._indent if indent >= 0: @@ -686,7 +689,7 @@ class CmdEditorGroup(CmdEditorBase): else: caller.msg("Auto-indentation turned off.") else: - caller.msg("This is not a code editor, you cannot use this option.") + caller.msg("This command is only available in code editor mode.") class EvEditorCmdSet(CmdSet): @@ -712,7 +715,7 @@ class EvEditor(object): """ def __init__(self, caller, loadfunc=None, savefunc=None, - quitfunc=None, key="", persistent=False, code=False): + quitfunc=None, key="", persistent=False, codefunc=False): """ Launches a full in-game line editor, mimicking the functionality of VIM. @@ -736,7 +739,8 @@ class EvEditor(object): session and make it unique from other editing sessions. persistent (bool, optional): Make the editor survive a reboot. Note that if this is set, all callables must be possible to pickle - code (bool, optional): activate options in a code-like editor + codefunc (bool, optional): If given, will run the editor in code mode. + This will be called as `codefunc(caller, buf)`. Notes: In persistent mode, all the input callables (savefunc etc) @@ -754,7 +758,6 @@ class EvEditor(object): self._buffer = "" self._unsaved = False self._persistent = persistent - self._code = code self._indent = 0 if loadfunc: @@ -770,6 +773,7 @@ class EvEditor(object): self._quitfunc = quitfunc else: self._quitfunc = lambda caller: caller.msg(_DEFAULT_NO_QUITFUNC) + self._codefunc = codefunc # store the original version self._pristine_buffer = self._buffer @@ -788,12 +792,12 @@ class EvEditor(object): try: caller.attributes.add("_eveditor_saved",( {"loadfunc":loadfunc, "savefunc": savefunc, - "quitfunc": quitfunc, "key": key, "persistent": persistent}, + "quitfunc": quitfunc, "codefunc": codefunc, + "key": key, "persistent": persistent}, {"_pristine_buffer": self._pristine_buffer, "_sep": self._sep})) caller.attributes.add("_eveditor_buffer_temp", (self._buffer, self._undo_buffer)) caller.attributes.add("_eveditor_unsaved", False) - caller.attributes.add("_eveditor_code", code) caller.attributes.add("_eveditor_indent", 0) except Exception, err: caller.msg(_ERROR_PERSISTENT_SAVING.format(error=err)) @@ -850,7 +854,6 @@ class EvEditor(object): if self._persistent: self._caller.attributes.add("_eveditor_buffer_temp", (self._buffer, self._undo_buffer)) self._caller.attributes.add("_eveditor_unsaved", True) - self._caller.attributes.add("_eveditor_code", self._code) self._caller.attributes.add("_eveditor_indent", self._indent) def quit(self): @@ -866,7 +869,6 @@ class EvEditor(object): self._caller.attributes.remove("_eveditor_buffer_temp") self._caller.attributes.remove("_eveditor_saved") self._caller.attributes.remove("_eveditor_unsaved") - self._caller.attributes.remove("_eveditor_code") self._caller.attributes.remove("_eveditor_indent") self._caller.cmdset.remove(EvEditorCmdSet) @@ -875,7 +877,9 @@ class EvEditor(object): Saves the content of the buffer. """ - if self._unsaved: + if self._unsaved or self._codefunc: + # always save code - this allows us to tie execution to + # saving if we want. try: if self._savefunc(self._caller, self._buffer): # Save codes should return a true value to indicate @@ -960,7 +964,7 @@ class EvEditor(object): """ string = self._sep * _DEFAULT_WIDTH + _HELP_TEXT - if self._code: + if self._codefunc: string += _HELP_CODE string += _HELP_LEGEND + self._sep * _DEFAULT_WIDTH self._caller.msg(string) @@ -1003,20 +1007,20 @@ class EvEditor(object): def decrease_indent(self): """Decrease automatic indentation by 1 level.""" - if self._code and self._indent > 0: + if self._codefunc and self._indent > 0: self._indent -= 1 if self._persistent: self._caller.attributes.add("_eveditor_indent", self._indent) def increase_indent(self): """Increase automatic indentation by 1 level.""" - if self._code and self._indent >= 0: + if self._codefunc and self._indent >= 0: self._indent += 1 if self._persistent: self._caller.attributes.add("_eveditor_indent", self._indent) def swap_autoindent(self): """Swap automatic indentation on or off.""" - if self._code: + if self._codefunc: if self._indent >= 0: self._indent = -1 else: