Moved lineditor into utils/eveditor.py. The line editor is accessed by simply importing the class (same as EvTable, EvMenu etc), so the utils.get_line_editor function was removed.

This commit is contained in:
Griatch 2015-07-08 15:26:12 +02:00
parent adae4f2ec4
commit cc2b094bc6
5 changed files with 143 additions and 112 deletions

View file

@ -13,6 +13,7 @@ from evennia.commands.default.muxcommand import MuxCommand
from evennia.commands.cmdhandler import get_and_merge_cmdsets from evennia.commands.cmdhandler import get_and_merge_cmdsets
from evennia.utils import create, utils, search from evennia.utils import create, utils, search
from evennia.utils.utils import inherits_from from evennia.utils.utils import inherits_from
from evennia.utils.eveditor import EvEditor
from evennia.utils.spawner import spawn from evennia.utils.spawner import spawn
from evennia.utils.ansi import raw from evennia.utils.ansi import raw
@ -554,12 +555,11 @@ class CmdDesc(MuxCommand):
self.caller.msg("Saved.") self.caller.msg("Saved.")
return True return True
self.editor = utils.get_line_editor()( self.editor = EvEditor(
self.caller, self.caller,
loadfunc=load, loadfunc=load,
savefunc=save, savefunc=save,
key="desc", key="desc")
)
return return
def func(self): def func(self):

View file

@ -300,11 +300,6 @@ CMDSET_PLAYER = "commands.default_cmdsets.PlayerCmdSet"
# Location to search for cmdsets if full path not given # Location to search for cmdsets if full path not given
CMDSET_PATHS = ["commands", "evennia", "contribs"] CMDSET_PATHS = ["commands", "evennia", "contribs"]
# Line editor path. Points to a line editor class that commands may use to give
# users extended editing control. See the default path for a reference implementation
# and usage.
LINE_EDITOR = 'evennia.commands.default.lineeditor.LineEditor'
###################################################################### ######################################################################
# Typeclasses and other paths # Typeclasses and other paths
###################################################################### ######################################################################

View file

@ -1,9 +1,9 @@
""" """
Evennia Line Editor EvEditor (Evennia Line Editor)
This implements an advanced line editor for editing longer texts This implements an advanced line editor for editing longer texts
in-game. The editor mimics the command mechanisms of the VI editor as in-game. The editor mimics the command mechanisms of the "VI" editor
far as possible. (a famous line-by-line editor) as far as reasonable.
Features of the editor: Features of the editor:
@ -13,36 +13,99 @@ Features of the editor:
- formatting of buffer, or selection, to certain width + indentations. - formatting of buffer, or selection, to certain width + indentations.
- allow to echo the input or not, depending on your client. - allow to echo the input or not, depending on your client.
Testing / Tutorial: To use the editor, just import EvEditor from this module
and initialize it:
Whereas the editor is intended to be called from other commands that from evennia.utils.eveditor import EvEditor
requires more elaborate text editing of data, there is also a
stand-alone editor command for editing Attributes at the end of this EvEditor(caller,
module. To test it it just import and add it to your default `cmdset`. loadfunc=None, loadfunc_args=None,
savefunc=None, savefunc_args=None,
quitfunc=None, quitfunc_args=None,
key=""):
Where the load/save/quitfunc are callbacks (with matching arguments)
to trigger when the editor loads, saves and quits respectively.
""" """
import re import re
from django.conf import settings from django.conf import settings
from evennia import Command, CmdSet, utils from evennia import Command, CmdSet, utils
from evennia import syscmdkeys from evennia.commands import cmdhandler
__all__ = ("CmdEditor", ) # we use cmdhandler instead of evennia.syscmdkeys to
# avoid some cases of loading before evennia init'd
_CMD_NOMATCH = cmdhandler.CMD_NOMATCH
_CMD_NOINPUT = cmdhandler.CMD_NOINPUT
CMD_NOMATCH = syscmdkeys.CMD_NOMATCH _RE_GROUP = re.compile(r"\".*?\"|\'.*?\'|\S*")
CMD_NOINPUT = syscmdkeys.CMD_NOINPUT # use NAWS in the future?
RE_GROUP = re.compile(r"\".*?\"|\'.*?\'|\S*")
_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH _DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
#------------------------------------------------------------
#
# texts
#
#------------------------------------------------------------
_HELP_TEXT = \
"""
<txt> - any non-command is appended to the end of the buffer.
: <l> - view buffer or only line <l>
:: <l> - view buffer without line numbers or other parsing
::: - print a ':' as the only character on the line...
:h - this help.
:w - saves the buffer (don't quit)
:wq - save buffer and quit
:q - quits (will be asked to save if buffer was changed)
:q! - quit without saving, no questions asked
:u - (undo) step backwards in undo history
:uu - (redo) step forward in undo history
:UU - reset all changes back to initial
:dd <l> - delete line <n>
:dw <l> <w> - delete word or regex <w> in entire buffer or on line <l>
:DD - clear buffer
:y <l> - yank (copy) line <l> to the copy buffer
:x <l> - cut line <l> and store it in the copy buffer
:p <l> - put (paste) previously copied line directly after <l>
:i <l> <txt> - insert new text <txt> at line <l>. Old line will move down
:r <l> <txt> - replace line <l> with text <txt>
:I <l> <txt> - insert text at the beginning of line <l>
:A <l> <txt> - append text after the end of line <l>
:s <l> <w> <txt> - search/replace word or regex <w> in buffer or on line <l>
:f <l> - flood-fill entire buffer or line <l>
:fi <l> - indent entire buffer or line <l>
:fd <l> - de-indent entire buffer or line <l>
:echo - turn echoing of the input on/off (helpful for some clients)
Legend:
<l> - line numbers, or range lstart:lend, e.g. '3:7'.
<w> - one word or several enclosed in quotes.
<txt> - longer string, usually not needed to be enclosed in quotes.
"""
#------------------------------------------------------------
#
# Handle yes/no quit question
#
#------------------------------------------------------------
class CmdSaveYesNo(Command): class CmdSaveYesNo(Command):
""" """
Save the editor state on quit. This catches Save the editor state on quit. This catches
nomatches (defaults to Yes), and avoid saves only if nomatches (defaults to Yes), and avoid saves only if
command was given specifically as "no" or "n". command was given specifically as "no" or "n".
""" """
key = CMD_NOMATCH key = _CMD_NOMATCH
aliases = CMD_NOINPUT aliases = _CMD_NOINPUT
locks = "cmd:all()" locks = "cmd:all()"
help_cateogory = "LineEditor" help_cateogory = "LineEditor"
@ -72,6 +135,12 @@ class SaveYesNoCmdSet(CmdSet):
self.add(CmdSaveYesNo()) self.add(CmdSaveYesNo())
#------------------------------------------------------------
#
# Editor commands
#
#------------------------------------------------------------
class CmdEditorBase(Command): class CmdEditorBase(Command):
""" """
Base parent for editor commands Base parent for editor commands
@ -107,7 +176,7 @@ class CmdEditorBase(Command):
# will be kept together and extra whitespace preserved. You # will be kept together and extra whitespace preserved. You
# can input quotes on the line by alternating single and # can input quotes on the line by alternating single and
# double quotes. # double quotes.
arglist = [part for part in RE_GROUP.findall(self.args) if part] arglist = [part for part in _RE_GROUP.findall(self.args) if part]
temp = [] temp = []
for arg in arglist: for arg in arglist:
# we want to clean the quotes, but only one type, # we want to clean the quotes, but only one type,
@ -186,8 +255,8 @@ class CmdLineInput(CmdEditorBase):
""" """
No command match - Inputs line of text into buffer. No command match - Inputs line of text into buffer.
""" """
key = CMD_NOMATCH key = _CMD_NOMATCH
aliases = [CMD_NOINPUT] aliases = _CMD_NOINPUT
def func(self): def func(self):
""" """
@ -267,9 +336,6 @@ class CmdEditorGroup(CmdEditorBase):
if self.editor.unsaved: if self.editor.unsaved:
caller.cmdset.add(SaveYesNoCmdSet) caller.cmdset.add(SaveYesNoCmdSet)
caller.msg("Save before quitting? {lcyes{lt[Y]{le/{lcno{ltN{le") caller.msg("Save before quitting? {lcyes{lt[Y]{le/{lcno{ltN{le")
#prompt_yesno(caller, "Save before quitting?",
# yescode = "self.caller.ndb._lineeditor.save_buffer()\nself.caller.ndb._lineeditor.quit()",
# nocode = "self.caller.msg(self.caller.ndb._lineeditor.quit())", default="Y")
else: else:
string = editor.quit() string = editor.quit()
elif cmd == ":q!": elif cmd == ":q!":
@ -429,17 +495,23 @@ class CmdEditorGroup(CmdEditorBase):
caller.msg(string) caller.msg(string)
class EditorCmdSet(CmdSet): class EvEditorCmdSet(CmdSet):
"CmdSet for the editor commands" "CmdSet for the editor commands"
key = "editorcmdset" key = "editorcmdset"
mergetype = "Replace" mergetype = "Replace"
#------------------------------------------------------------
#
# Main Editor object
#
#------------------------------------------------------------
class LineEditor(object): class EvEditor(object):
""" """
This defines a line editor object. It creates all relevant commands This defines a line editor object. It creates all relevant commands
and tracks the current state of the buffer. It also cleans up after and tracks the current state of the buffer. It also cleans up after
itself. itself.
""" """
def __init__(self, caller, def __init__(self, caller,
@ -448,23 +520,29 @@ class LineEditor(object):
quitfunc=None, quitfunc_args=None, quitfunc=None, quitfunc_args=None,
key=""): key=""):
""" """
caller - who is using the editor. Args:
caller (Object): Who is using the editor.
loadfunc (callable, optional): This will be called as
`func(*loadfunc_args)` when the editor is first started,
e.g. for pre-loading text into it.
loadfunc_args (tuple, optional): Optional tuple of
arguments to supply to `loadfunc`.
savefunc (callable, optional): This will be called as
`func(*savefunc_args)` when the save-command is given and
is used to actually determine where/how result is saved.
It should return `True` if save was successful and also
handle any feedback to the user.
savefunc_args (tuple, optional): Optional tuple of
arguments to supply to `savefunc`.
quitfunc (callable, optional): This will optionally be
called as `func(*quitfunc_args)` when the editor is
exited. If defined, it should handle all wanted feedback
to the user.
quitfunc_args (tuple, optional): Optional tuple of arguments to
supply to `quitfunc`.
key (str, optional): An optional key for naming this
session and make it unique from other editing sessions.
loadfunc - this will be called as `func(*loadfunc_args)` when the
editor is first started, e.g. for pre-loading text into it.
loadfunc_args - optional tuple of arguments to supply to `loadfunc`.
savefunc - this will be called as `func(*savefunc_args)` when the
save-command is given and is used to actually determine
where/how result is saved. It should return `True` if save
was successful and also handle any feedback to the user.
savefunc_args - optional tuple of arguments to supply to `savefunc`.
quitfunc - this will optionally be called as `func(*quitfunc_args)`
when the editor is exited. If defined, it should handle
all wanted feedback to the user.
quitfunc_args - optional tuple of arguments to supply to `quitfunc`.
key = an optional key for naming this session (such as which attribute
is being edited).
""" """
self.key = key self.key = key
self.caller = caller self.caller = caller
@ -497,7 +575,7 @@ class LineEditor(object):
cmd2.obj = self cmd2.obj = self
cmd2.editor = self cmd2.editor = self
# Populate cmdset and add it to caller # Populate cmdset and add it to caller
editor_cmdset = EditorCmdSet() editor_cmdset = EvEditorCmdSet()
editor_cmdset.add(cmd1) editor_cmdset.add(cmd1)
editor_cmdset.add(cmd2) editor_cmdset.add(cmd2)
self.caller.cmdset.add(editor_cmdset) self.caller.cmdset.add(editor_cmdset)
@ -544,7 +622,7 @@ class LineEditor(object):
except Exception, e: except Exception, e:
self.caller.msg("%s\n{Quit function gave an error. Skipping.{n" % e) self.caller.msg("%s\n{Quit function gave an error. Skipping.{n" % e)
del self.caller.ndb._lineeditor del self.caller.ndb._lineeditor
self.caller.cmdset.remove(EditorCmdSet) self.caller.cmdset.remove(EvEditorCmdSet)
if self.quitfunc: if self.quitfunc:
# if quitfunc is defined, it should manage exit messages. # if quitfunc is defined, it should manage exit messages.
return "" return ""
@ -620,53 +698,15 @@ class LineEditor(object):
""" """
Shows the help entry for the editor. Shows the help entry for the editor.
""" """
string = self.sep * _DEFAULT_WIDTH + """ string = self.sep * _DEFAULT_WIDTH + _HELP_TEXT + self.sep * _DEFAULT_WIDTH
<txt> - any non-command is appended to the end of the buffer.
: <l> - view buffer or only line <l>
:: <l> - view buffer without line numbers or other parsing
::: - print a ':' as the only character on the line...
:h - this help.
:w - saves the buffer (don't quit)
:wq - save buffer and quit
:q - quits (will be asked to save if buffer was changed)
:q! - quit without saving, no questions asked
:u - (undo) step backwards in undo history
:uu - (redo) step forward in undo history
:UU - reset all changes back to initial
:dd <l> - delete line <n>
:dw <l> <w> - delete word or regex <w> in entire buffer or on line <l>
:DD - clear buffer
:y <l> - yank (copy) line <l> to the copy buffer
:x <l> - cut line <l> and store it in the copy buffer
:p <l> - put (paste) previously copied line directly after <l>
:i <l> <txt> - insert new text <txt> at line <l>. Old line will move down
:r <l> <txt> - replace line <l> with text <txt>
:I <l> <txt> - insert text at the beginning of line <l>
:A <l> <txt> - append text after the end of line <l>
:s <l> <w> <txt> - search/replace word or regex <w> in buffer or on line <l>
:f <l> - flood-fill entire buffer or line <l>
:fi <l> - indent entire buffer or line <l>
:fd <l> - de-indent entire buffer or line <l>
:echo - turn echoing of the input on/off (helpful for some clients)
Legend:
<l> - line numbers, or range lstart:lend, e.g. '3:7'.
<w> - one word or several enclosed in quotes.
<txt> - longer string, usually not needed to be enclosed in quotes.
""" + self.sep * _DEFAULT_WIDTH
return string return string
#------------------------------------------------------------------
# #
# Editor access command for editing a given attribute on an object. # Editor access command for editing a given attribute on an object.
# #
#------------------------------------------------------------------
class CmdEditor(Command): class CmdEditor(Command):
""" """
@ -722,11 +762,12 @@ class CmdEditor(Command):
self.caller.msg("Exited Editor.") self.caller.msg("Exited Editor.")
editor_key = "%s/%s" % (self.objname, self.attrname) editor_key = "%s/%s" % (self.objname, self.attrname)
# start editor, it will handle things from here.
self.editor = utils.get_line_editor()( # start editor, it will handle things from here. We need to
self.caller, # store it on the command object since we set up callback functions
loadfunc=load_attr, # to refer to it that way.
savefunc=save_attr, self.editor = EvEditor(self.caller,
quitfunc=quit_hook, loadfunc=load_attr,
key=editor_key savefunc=save_attr,
) quitfunc=quit_hook,
key=editor_key)

View file

@ -130,17 +130,19 @@ evennia.utils.evdemo`.
from textwrap import dedent from textwrap import dedent
from inspect import isfunction, getargspec from inspect import isfunction, getargspec
from django.conf import settings from django.conf import settings
from evennia import syscmdkeys
from evennia import Command, CmdSet from evennia import Command, CmdSet
from evennia.utils.evtable import EvTable from evennia.utils.evtable import EvTable
from evennia.utils.ansi import ANSIString, strip_ansi from evennia.utils.ansi import ANSIString, strip_ansi
from evennia.utils.utils import mod_import, make_iter, pad, m_len from evennia.utils.utils import mod_import, make_iter, pad, m_len
from evennia.commands import cmdhandler
# read from protocol NAWS later? # read from protocol NAWS later?
_MAX_TEXT_WIDTH = settings.CLIENT_DEFAULT_WIDTH _MAX_TEXT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
_CMD_NOMATCH = syscmdkeys.CMD_NOMATCH # we use cmdhandler instead of evennia.syscmdkeys to
_CMD_NOINPUT = syscmdkeys.CMD_NOINPUT # avoid some cases of loading before evennia init'd
_CMD_NOMATCH = cmdhandler.CMD_NOMATCH
_CMD_NOINPUT = cmdhandler.CMD_NOINPUT
# Return messages # Return messages

View file

@ -1226,10 +1226,3 @@ def m_len(target):
if inherits_from(target, basestring): if inherits_from(target, basestring):
return len(ANSI_PARSER.strip_mxp(target)) return len(ANSI_PARSER.strip_mxp(target))
return len(target) return len(target)
def get_line_editor():
"""
Get the line editor for this game.
"""
return variable_from_module(*settings.LINE_EDITOR.rsplit('.', 1))