mirror of
https://github.com/evennia/evennia.git
synced 2026-03-29 12:07:17 +02:00
Merge branch 'master' of https://github.com/evennia/evennia into puzzles
This commit is contained in:
commit
b99a1b0509
16 changed files with 239 additions and 29 deletions
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
## Evennia 0.8 (2018)
|
||||
|
||||
### Requirements
|
||||
|
||||
- Up requirements to Django 1.11.x, Twisted 18 and pillow 5.2.0
|
||||
- Add `inflect` dependency for automatic pluralization of object names.
|
||||
|
||||
### Server/Portal
|
||||
|
||||
- Removed `evennia_runner`, completely refactor `evennia_launcher.py` (the 'evennia' program)
|
||||
|
|
@ -85,7 +90,6 @@
|
|||
|
||||
### General
|
||||
|
||||
- Up requirements to Django 1.11.x, Twisted 18 and pillow 5.2.0
|
||||
- Start structuring the `CHANGELOG` to list features in more detail.
|
||||
- Docker image `evennia/evennia:develop` is now auto-built, tracking the develop branch.
|
||||
- Inflection and grouping of multiple objects in default room (an box, three boxes)
|
||||
|
|
|
|||
|
|
@ -1001,7 +1001,10 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)):
|
|||
|
||||
if target and not is_iter(target):
|
||||
# single target - just show it
|
||||
return target.return_appearance(self)
|
||||
if hasattr(target, "return_appearance"):
|
||||
return target.return_appearance(self)
|
||||
else:
|
||||
return "{} has no in-game appearance.".format(target)
|
||||
else:
|
||||
# list of targets - make list to disconnect from db
|
||||
characters = list(tar for tar in target if tar) if target else []
|
||||
|
|
|
|||
|
|
@ -612,12 +612,12 @@ class CmdDesc(COMMAND_DEFAULT_CLASS):
|
|||
self.edit_handler()
|
||||
return
|
||||
|
||||
if self.rhs:
|
||||
if '=' in self.args:
|
||||
# We have an =
|
||||
obj = caller.search(self.lhs)
|
||||
if not obj:
|
||||
return
|
||||
desc = self.rhs
|
||||
desc = self.rhs or ''
|
||||
else:
|
||||
obj = caller.location or self.msg("|rYou can't describe oblivion.|n")
|
||||
if not obj:
|
||||
|
|
@ -2856,7 +2856,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
key = "@spawn"
|
||||
aliases = ["olc"]
|
||||
switch_options = ("noloc", "search", "list", "show", "save", "delete", "menu", "olc", "update")
|
||||
switch_options = ("noloc", "search", "list", "show", "examine", "save", "delete", "menu", "olc", "update", "edit")
|
||||
locks = "cmd:perm(spawn) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
|
|
@ -2907,12 +2907,13 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
caller = self.caller
|
||||
|
||||
if self.cmdstring == "olc" or 'menu' in self.switches or 'olc' in self.switches:
|
||||
if self.cmdstring == "olc" or 'menu' in self.switches \
|
||||
or 'olc' in self.switches or 'edit' in self.switches:
|
||||
# OLC menu mode
|
||||
prototype = None
|
||||
if self.lhs:
|
||||
key = self.lhs
|
||||
prototype = spawner.search_prototype(key=key, return_meta=True)
|
||||
prototype = protlib.search_prototype(key=key)
|
||||
if len(prototype) > 1:
|
||||
caller.msg("More than one match for {}:\n{}".format(
|
||||
key, "\n".join(proto.get('prototype_key', '') for proto in prototype)))
|
||||
|
|
@ -2920,6 +2921,10 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
|||
elif prototype:
|
||||
# one match
|
||||
prototype = prototype[0]
|
||||
else:
|
||||
# no match
|
||||
caller.msg("No prototype '{}' was found.".format(key))
|
||||
return
|
||||
olc_menus.start_olc(caller, session=self.session, prototype=prototype)
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -315,6 +315,24 @@ class TestBuilding(CommandTest):
|
|||
def test_desc(self):
|
||||
self.call(building.CmdDesc(), "Obj2=TestDesc", "The description was set on Obj2(#5).")
|
||||
|
||||
def test_empty_desc(self):
|
||||
"""
|
||||
empty desc sets desc as ''
|
||||
"""
|
||||
o2d = self.obj2.db.desc
|
||||
r1d = self.room1.db.desc
|
||||
self.call(building.CmdDesc(), "Obj2=", "The description was set on Obj2(#5).")
|
||||
assert self.obj2.db.desc == '' and self.obj2.db.desc != o2d
|
||||
assert self.room1.db.desc == r1d
|
||||
|
||||
def test_desc_default_to_room(self):
|
||||
"""no rhs changes room's desc"""
|
||||
o2d = self.obj2.db.desc
|
||||
r1d = self.room1.db.desc
|
||||
self.call(building.CmdDesc(), "Obj2", "The description was set on Room(#1).")
|
||||
assert self.obj2.db.desc == o2d
|
||||
assert self.room1.db.desc == 'Obj2' and self.room1.db.desc != r1d
|
||||
|
||||
def test_wipe(self):
|
||||
confirm = building.CmdDestroy.confirm
|
||||
building.CmdDestroy.confirm = False
|
||||
|
|
@ -460,6 +478,61 @@ class TestBuilding(CommandTest):
|
|||
# Test listing commands
|
||||
self.call(building.CmdSpawn(), "/list", "Key ")
|
||||
|
||||
# @spawn/edit (missing prototype)
|
||||
# brings up olc menu
|
||||
msg = self.call(
|
||||
building.CmdSpawn(),
|
||||
'/edit')
|
||||
assert 'Prototype wizard' in msg
|
||||
|
||||
# @spawn/edit with valid prototype
|
||||
# brings up olc menu loaded with prototype
|
||||
msg = self.call(
|
||||
building.CmdSpawn(),
|
||||
'/edit testball')
|
||||
assert 'Prototype wizard' in msg
|
||||
assert hasattr(self.char1.ndb._menutree, "olc_prototype")
|
||||
assert dict == type(self.char1.ndb._menutree.olc_prototype) \
|
||||
and 'prototype_key' in self.char1.ndb._menutree.olc_prototype \
|
||||
and 'key' in self.char1.ndb._menutree.olc_prototype \
|
||||
and 'testball' == self.char1.ndb._menutree.olc_prototype['prototype_key'] \
|
||||
and 'Ball' == self.char1.ndb._menutree.olc_prototype['key']
|
||||
assert 'Ball' in msg and 'testball' in msg
|
||||
|
||||
# @spawn/edit with valid prototype (synomym)
|
||||
msg = self.call(
|
||||
building.CmdSpawn(),
|
||||
'/edit BALL')
|
||||
assert 'Prototype wizard' in msg
|
||||
assert 'Ball' in msg and 'testball' in msg
|
||||
|
||||
# @spawn/edit with invalid prototype
|
||||
msg = self.call(
|
||||
building.CmdSpawn(),
|
||||
'/edit NO_EXISTS',
|
||||
"No prototype 'NO_EXISTS' was found.")
|
||||
|
||||
# @spawn/examine (missing prototype)
|
||||
# lists all prototypes that exist
|
||||
msg = self.call(
|
||||
building.CmdSpawn(),
|
||||
'/examine')
|
||||
assert 'testball' in msg and 'testprot' in msg
|
||||
|
||||
# @spawn/examine with valid prototype
|
||||
# prints the prototype
|
||||
msg = self.call(
|
||||
building.CmdSpawn(),
|
||||
'/examine BALL')
|
||||
assert 'Ball' in msg and 'testball' in msg
|
||||
|
||||
# @spawn/examine with invalid prototype
|
||||
# shows error
|
||||
self.call(
|
||||
building.CmdSpawn(),
|
||||
'/examine NO_EXISTS',
|
||||
"No prototype 'NO_EXISTS' was found.")
|
||||
|
||||
|
||||
class TestComms(CommandTest):
|
||||
|
||||
|
|
|
|||
|
|
@ -475,14 +475,14 @@ class CmdShiftRoot(Command):
|
|||
root_pos["blue"] -= 1
|
||||
self.caller.msg("The root with blue flowers gets in the way and is pushed to the left.")
|
||||
else:
|
||||
self.caller.msg("You cannot move the root in that direction.")
|
||||
self.caller.msg("The root hangs straight down - you can only move it left or right.")
|
||||
elif color == "blue":
|
||||
if direction == "left":
|
||||
root_pos[color] = max(-1, root_pos[color] - 1)
|
||||
self.caller.msg("You shift the root with small blue flowers to the left.")
|
||||
if root_pos[color] != 0 and root_pos[color] == root_pos["red"]:
|
||||
root_pos["red"] += 1
|
||||
self.caller.msg("The reddish root is to big to fit as well, so that one falls away to the left.")
|
||||
self.caller.msg("The reddish root is too big to fit as well, so that one falls away to the left.")
|
||||
elif direction == "right":
|
||||
root_pos[color] = min(1, root_pos[color] + 1)
|
||||
self.caller.msg("You shove the root adorned with small blue flowers to the right.")
|
||||
|
|
@ -490,7 +490,7 @@ class CmdShiftRoot(Command):
|
|||
root_pos["red"] -= 1
|
||||
self.caller.msg("The thick reddish root gets in the way and is pushed back to the left.")
|
||||
else:
|
||||
self.caller.msg("You cannot move the root in that direction.")
|
||||
self.caller.msg("The root hangs straight down - you can only move it left or right.")
|
||||
|
||||
# now the horizontal roots (yellow/green). They can be moved up/down
|
||||
elif color == "yellow":
|
||||
|
|
@ -507,7 +507,7 @@ class CmdShiftRoot(Command):
|
|||
root_pos["green"] -= 1
|
||||
self.caller.msg("The weedy green root is shifted upwards to make room.")
|
||||
else:
|
||||
self.caller.msg("You cannot move the root in that direction.")
|
||||
self.caller.msg("The root hangs across the wall - you can only move it up or down.")
|
||||
elif color == "green":
|
||||
if direction == "up":
|
||||
root_pos[color] = max(-1, root_pos[color] - 1)
|
||||
|
|
@ -522,7 +522,7 @@ class CmdShiftRoot(Command):
|
|||
root_pos["yellow"] -= 1
|
||||
self.caller.msg("The root with yellow flowers gets in the way and is pushed upwards.")
|
||||
else:
|
||||
self.caller.msg("You cannot move the root in that direction.")
|
||||
self.caller.msg("The root hangs across the wall - you can only move it up or down.")
|
||||
|
||||
# we have moved the root. Store new position
|
||||
self.obj.db.root_pos = root_pos
|
||||
|
|
|
|||
|
|
@ -747,9 +747,16 @@ class CmdLookDark(Command):
|
|||
"""
|
||||
caller = self.caller
|
||||
|
||||
if random.random() < 0.75:
|
||||
# count how many searches we've done
|
||||
nr_searches = caller.ndb.dark_searches
|
||||
if nr_searches is None:
|
||||
nr_searches = 0
|
||||
caller.ndb.dark_searches = nr_searches
|
||||
|
||||
if nr_searches < 4 and random.random() < 0.90:
|
||||
# we don't find anything
|
||||
caller.msg(random.choice(DARK_MESSAGES))
|
||||
caller.ndb.dark_searches += 1
|
||||
else:
|
||||
# we could have found something!
|
||||
if any(obj for obj in caller.contents if utils.inherits_from(obj, LightSource)):
|
||||
|
|
@ -791,7 +798,8 @@ class CmdDarkNoMatch(Command):
|
|||
|
||||
def func(self):
|
||||
"""Implements the command."""
|
||||
self.caller.msg("Until you find some light, there's not much you can do. Try feeling around.")
|
||||
self.caller.msg("Until you find some light, there's not much you can do. "
|
||||
"Try feeling around, maybe you'll find something helpful!")
|
||||
|
||||
|
||||
class DarkCmdSet(CmdSet):
|
||||
|
|
@ -814,7 +822,9 @@ class DarkCmdSet(CmdSet):
|
|||
self.add(CmdLookDark())
|
||||
self.add(CmdDarkHelp())
|
||||
self.add(CmdDarkNoMatch())
|
||||
self.add(default_cmds.CmdSay)
|
||||
self.add(default_cmds.CmdSay())
|
||||
self.add(default_cmds.CmdQuit())
|
||||
self.add(default_cmds.CmdHome())
|
||||
|
||||
|
||||
class DarkRoom(TutorialRoom):
|
||||
|
|
|
|||
|
|
@ -562,6 +562,7 @@ def node_index(caller):
|
|||
|
||||
text = """
|
||||
|c --- Prototype wizard --- |n
|
||||
%s
|
||||
|
||||
A |cprototype|n is a 'template' for |wspawning|n an in-game entity. A field of the prototype
|
||||
can either be hard-coded, left empty or scripted using |w$protfuncs|n - for example to
|
||||
|
|
@ -599,6 +600,17 @@ def node_index(caller):
|
|||
{pfuncs}
|
||||
""".format(pfuncs=_format_protfuncs())
|
||||
|
||||
# If a prototype is being edited, show its key and
|
||||
# prototype_key under the title
|
||||
loaded_prototype = ''
|
||||
if 'prototype_key' in prototype \
|
||||
or 'key' in prototype:
|
||||
loaded_prototype = ' --- Editing: |y{}({})|n --- '.format(
|
||||
prototype.get('key', ''),
|
||||
prototype.get('prototype_key', '')
|
||||
)
|
||||
text = text % (loaded_prototype)
|
||||
|
||||
text = (text, helptxt)
|
||||
|
||||
options = []
|
||||
|
|
|
|||
|
|
@ -107,9 +107,10 @@ for mod in settings.PROTOTYPE_MODULES:
|
|||
# internally we store as (key, desc, locks, tags, prototype_dict)
|
||||
prots = []
|
||||
for variable_name, prot in all_from_module(mod).items():
|
||||
if "prototype_key" not in prot:
|
||||
prot['prototype_key'] = variable_name.lower()
|
||||
prots.append((prot['prototype_key'], homogenize_prototype(prot)))
|
||||
if isinstance(prot, dict):
|
||||
if "prototype_key" not in prot:
|
||||
prot['prototype_key'] = variable_name.lower()
|
||||
prots.append((prot['prototype_key'], homogenize_prototype(prot)))
|
||||
# assign module path to each prototype_key for easy reference
|
||||
_MODULE_PROTOTYPE_MODULES.update({prototype_key.lower(): mod for prototype_key, _ in prots})
|
||||
# make sure the prototype contains all meta info
|
||||
|
|
|
|||
|
|
@ -325,7 +325,7 @@ MENU = \
|
|||
| 7) Kill Server only (send kill signal to process) |
|
||||
| 8) Kill Portal + Server |
|
||||
+--- Information -----------------------------------------------+
|
||||
| 9) Tail log files (quickly see errors) |
|
||||
| 9) Tail log files (quickly see errors - Ctrl-C to exit) |
|
||||
| 10) Status |
|
||||
| 11) Port info |
|
||||
+--- Testing ---------------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
|
||||
from evennia.utils.utils import delay
|
||||
# timeout the handshakes in case the client doesn't reply at all
|
||||
delay(2, callback=self.handshake_done, timeout=True)
|
||||
self._handshake_delay = delay(2, callback=self.handshake_done, timeout=True)
|
||||
|
||||
# TCP/IP keepalive watches for dead links
|
||||
self.transport.setTcpKeepAlive(1)
|
||||
|
|
|
|||
|
|
@ -8,9 +8,24 @@ try:
|
|||
except ImportError:
|
||||
import unittest
|
||||
|
||||
from mock import Mock
|
||||
import string
|
||||
from evennia.server.portal import irc
|
||||
|
||||
from twisted.conch.telnet import IAC, WILL, DONT, SB, SE, NAWS, DO
|
||||
from twisted.test import proto_helpers
|
||||
from twisted.trial.unittest import TestCase as TwistedTestCase
|
||||
|
||||
from .telnet import TelnetServerFactory, TelnetProtocol
|
||||
from .portal import PORTAL_SESSIONS
|
||||
from .suppress_ga import SUPPRESS_GA
|
||||
from .naws import DEFAULT_HEIGHT, DEFAULT_WIDTH
|
||||
from .ttype import TTYPE, IS
|
||||
from .mccp import MCCP
|
||||
from .mssp import MSSP
|
||||
from .mxp import MXP
|
||||
from .telnet_oob import MSDP, MSDP_VAL, MSDP_VAR
|
||||
|
||||
|
||||
class TestIRC(TestCase):
|
||||
|
||||
|
|
@ -73,3 +88,64 @@ class TestIRC(TestCase):
|
|||
s = r'|wthis|Xis|gis|Ma|C|complex|*string'
|
||||
|
||||
self.assertEqual(irc.parse_irc_to_ansi(irc.parse_ansi_to_irc(s)), s)
|
||||
|
||||
|
||||
class TestTelnet(TwistedTestCase):
|
||||
def setUp(self):
|
||||
super(TestTelnet, self).setUp()
|
||||
factory = TelnetServerFactory()
|
||||
factory.protocol = TelnetProtocol
|
||||
factory.sessionhandler = PORTAL_SESSIONS
|
||||
factory.sessionhandler.portal = Mock()
|
||||
self.proto = factory.buildProtocol(("localhost", 0))
|
||||
self.transport = proto_helpers.StringTransport()
|
||||
self.addCleanup(factory.sessionhandler.disconnect_all)
|
||||
|
||||
def test_mudlet_ttype(self):
|
||||
self.transport.client = ["localhost"]
|
||||
self.transport.setTcpKeepAlive = Mock()
|
||||
d = self.proto.makeConnection(self.transport)
|
||||
# test suppress_ga
|
||||
self.assertTrue(self.proto.protocol_flags["NOGOAHEAD"])
|
||||
self.proto.dataReceived(IAC + DONT + SUPPRESS_GA)
|
||||
self.assertFalse(self.proto.protocol_flags["NOGOAHEAD"])
|
||||
self.assertEqual(self.proto.handshakes, 7)
|
||||
# test naws
|
||||
self.assertEqual(self.proto.protocol_flags['SCREENWIDTH'], {0: DEFAULT_WIDTH})
|
||||
self.assertEqual(self.proto.protocol_flags['SCREENHEIGHT'], {0: DEFAULT_HEIGHT})
|
||||
self.proto.dataReceived(IAC + WILL + NAWS)
|
||||
self.proto.dataReceived([IAC, SB, NAWS, '', 'x', '', 'd', IAC, SE])
|
||||
self.assertEqual(self.proto.protocol_flags['SCREENWIDTH'][0], 120)
|
||||
self.assertEqual(self.proto.protocol_flags['SCREENHEIGHT'][0], 100)
|
||||
self.assertEqual(self.proto.handshakes, 6)
|
||||
# test ttype
|
||||
self.assertTrue(self.proto.protocol_flags["FORCEDENDLINE"])
|
||||
self.assertFalse(self.proto.protocol_flags["TTYPE"])
|
||||
self.assertTrue(self.proto.protocol_flags["ANSI"])
|
||||
self.proto.dataReceived(IAC + WILL + TTYPE)
|
||||
self.proto.dataReceived([IAC, SB, TTYPE, IS, "MUDLET", IAC, SE])
|
||||
self.assertTrue(self.proto.protocol_flags["XTERM256"])
|
||||
self.assertEqual(self.proto.protocol_flags["CLIENTNAME"], "MUDLET")
|
||||
self.proto.dataReceived([IAC, SB, TTYPE, IS, "XTERM", IAC, SE])
|
||||
self.proto.dataReceived([IAC, SB, TTYPE, IS, "MTTS 137", IAC, SE])
|
||||
self.assertEqual(self.proto.handshakes, 5)
|
||||
# test mccp
|
||||
self.proto.dataReceived(IAC + DONT + MCCP)
|
||||
self.assertFalse(self.proto.protocol_flags['MCCP'])
|
||||
self.assertEqual(self.proto.handshakes, 4)
|
||||
# test mssp
|
||||
self.proto.dataReceived(IAC + DONT + MSSP)
|
||||
self.assertEqual(self.proto.handshakes, 3)
|
||||
# test oob
|
||||
self.proto.dataReceived(IAC + DO + MSDP)
|
||||
self.proto.dataReceived([IAC, SB, MSDP, MSDP_VAR, "LIST", MSDP_VAL, "COMMANDS", IAC, SE])
|
||||
self.assertTrue(self.proto.protocol_flags['OOB'])
|
||||
self.assertEqual(self.proto.handshakes, 2)
|
||||
# test mxp
|
||||
self.proto.dataReceived(IAC + DONT + MXP)
|
||||
self.assertFalse(self.proto.protocol_flags['MXP'])
|
||||
self.assertEqual(self.proto.handshakes, 1)
|
||||
# clean up to prevent Unclean reactor
|
||||
self.proto.nop_keep_alive.stop()
|
||||
self.proto._handshake_delay.cancel()
|
||||
return d
|
||||
|
|
|
|||
|
|
@ -13,14 +13,14 @@ import time
|
|||
# TODO!
|
||||
#sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
#os.environ['DJANGO_SETTINGS_MODULE'] = 'game.settings'
|
||||
import ev
|
||||
from evennia.utils.idmapper import base as _idmapper
|
||||
import evennia
|
||||
from evennia.utils.idmapper import models as _idmapper
|
||||
|
||||
LOGFILE = "logs/memoryusage.log"
|
||||
INTERVAL = 30 # log every 30 seconds
|
||||
|
||||
|
||||
class Memplot(ev.Script):
|
||||
class Memplot(evennia.DefaultScript):
|
||||
"""
|
||||
Describes a memory plotting action.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
from django.test import TestCase
|
||||
from mock import Mock
|
||||
from mock import Mock, patch, mock_open
|
||||
from .dummyrunner_settings import (c_creates_button, c_creates_obj, c_digs, c_examines, c_help, c_idles, c_login,
|
||||
c_login_nodig, c_logout, c_looks, c_moves, c_moves_n, c_moves_s, c_socialize)
|
||||
import memplot
|
||||
|
||||
|
||||
class TestDummyrunnerSettings(TestCase):
|
||||
|
|
@ -91,3 +92,21 @@ class TestDummyrunnerSettings(TestCase):
|
|||
|
||||
def test_c_move_s(self):
|
||||
self.assertEqual(c_moves_s(self.client), "south")
|
||||
|
||||
|
||||
class TestMemPlot(TestCase):
|
||||
@patch.object(memplot, "_idmapper")
|
||||
@patch.object(memplot, "os")
|
||||
@patch.object(memplot, "open", new_callable=mock_open, create=True)
|
||||
@patch.object(memplot, "time")
|
||||
def test_memplot(self, mock_time, mocked_open, mocked_os, mocked_idmapper):
|
||||
from evennia.utils.create import create_script
|
||||
mocked_idmapper.cache_size.return_value = (9, 5000)
|
||||
mock_time.time = Mock(return_value=6000.0)
|
||||
script = create_script(memplot.Memplot)
|
||||
script.db.starttime = 0.0
|
||||
mocked_os.popen.read.return_value = 5000.0
|
||||
script.at_repeat()
|
||||
handle = mocked_open()
|
||||
handle.write.assert_called_with('100.0, 0.001, 0.001, 9\n')
|
||||
script.stop()
|
||||
|
|
|
|||
|
|
@ -407,7 +407,7 @@ class ServerSession(Session):
|
|||
else:
|
||||
self.data_out(**kwargs)
|
||||
|
||||
def execute_cmd(self, raw_string, **kwargs):
|
||||
def execute_cmd(self, raw_string, session=None, **kwargs):
|
||||
"""
|
||||
Do something as this object. This method is normally never
|
||||
called directly, instead incoming command instructions are
|
||||
|
|
@ -417,6 +417,9 @@ class ServerSession(Session):
|
|||
|
||||
Args:
|
||||
raw_string (string): Raw command input
|
||||
session (Session): This is here to make API consistent with
|
||||
Account/Object.execute_cmd. If given, data is passed to
|
||||
that Session, otherwise use self.
|
||||
Kwargs:
|
||||
Other keyword arguments will be added to the found command
|
||||
object instace as variables before it executes. This is
|
||||
|
|
@ -426,7 +429,7 @@ class ServerSession(Session):
|
|||
"""
|
||||
# inject instruction into input stream
|
||||
kwargs["text"] = ((raw_string,), {})
|
||||
self.sessionhandler.data_in(self, **kwargs)
|
||||
self.sessionhandler.data_in(session or self, **kwargs)
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Handle session comparisons"""
|
||||
|
|
|
|||
|
|
@ -69,8 +69,12 @@ let history_plugin = (function () {
|
|||
}
|
||||
|
||||
if (history_entry !== null) {
|
||||
// Doing a history navigation; replace the text in the input.
|
||||
inputfield.val(history_entry);
|
||||
// Performing a history navigation
|
||||
// replace the text in the input and move the cursor to the end of the new value
|
||||
inputfield.val('');
|
||||
inputfield.blur().focus().val(history_entry);
|
||||
event.preventDefault();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ pypiwin32
|
|||
|
||||
django > 1.11, < 2.0
|
||||
twisted >= 18.0.0, < 19.0.0
|
||||
pillow == 2.9.0
|
||||
pillow == 5.2.0
|
||||
pytz
|
||||
future >= 0.15.2
|
||||
django-sekizai
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue