'Launches a full in-game line editor, mimicking the functionality of VIM.
Args:
caller (Object): Who is using the editor.
loadfunc (callable, optional): This will be called as
`loadfunc(caller)` when the editor is first started. Its
return will be used as the editor\'s starting buffer.
savefunc (callable, optional): This will be called as
`savefunc(caller, buffer)` 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.
quitfunc (callable, optional): This will optionally be
called as `quitfunc(caller)` 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.
persistent (bool, optional): Make the editor survive a reboot. Note
that if this is set, all callables must be possible to pickle
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)
must be possible to be *pickled*, this excludes e.g.
callables that are class methods or functions defined
dynamically or as part of another function. In
non-persistent mode no such restrictions exist.'

def __init__(self, caller, loadfunc=None, savefunc=None, quitfunc=None, key='', persistent=False, codefunc=False):

    self._key = key
    self._caller = caller
    self._caller.ndb._eveditor = self
    self._buffer = ''
    self._unsaved = False
    self._persistent = persistent
    self._indent = 0
    if loadfunc:
        self._loadfunc = loadfunc
    else:
        self._loadfunc = (lambda caller: self._buffer)
    self.load_buffer()
    if savefunc:
        self._savefunc = savefunc
    else:
        self._savefunc = (lambda caller, buffer: caller.msg(_ERROR_NO_SAVEFUNC))
    if quitfunc:
        self._quitfunc = quitfunc
    else:
        self._quitfunc = (lambda caller: caller.msg(_DEFAULT_NO_QUITFUNC))
    self._codefunc = codefunc
    self._pristine_buffer = self._buffer
    self._sep = '-'
    self._undo_buffer = [self._buffer]
    self._undo_pos = 0
    self._undo_max = 20
    self._copy_buffer = []
    if persistent:
        try:
            caller.attributes.add('_eveditor_saved', (dict(loadfunc=loadfunc, savefunc=savefunc, quitfunc=quitfunc, codefunc=codefunc, key=key, persistent=persistent), dict(_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_indent', 0)
        except Exception as err:
            caller.msg(_ERROR_PERSISTENT_SAVING.format(error=err))
            logger.log_trace(_TRACE_PERSISTENT_SAVING)
            persistent = False
    caller.cmdset.add(EvEditorCmdSet, permanent=persistent)
    self._echo_mode = True
    self.display_buffer()
