pymud 0.20.4__py3-none-any.whl → 0.21.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pymud/__init__.py +7 -2
- pymud/decorators.py +234 -0
- pymud/dialogs.py +37 -31
- pymud/extras.py +7 -135
- pymud/i18n.py +63 -0
- pymud/lang/i18n_chs.py +227 -0
- pymud/lang/i18n_eng.py +851 -0
- pymud/logger.py +9 -4
- pymud/main.py +123 -44
- pymud/modules.py +104 -31
- pymud/objects.py +102 -98
- pymud/pkuxkx.py +267 -142
- pymud/protocol.py +15 -13
- pymud/pymud.py +80 -75
- pymud/session.py +582 -356
- pymud/settings.py +15 -2
- {pymud-0.20.4.dist-info → pymud-0.21.0.dist-info}/METADATA +118 -5
- pymud-0.21.0.dist-info/RECORD +23 -0
- {pymud-0.20.4.dist-info → pymud-0.21.0.dist-info}/WHEEL +1 -1
- pymud-0.20.4.dist-info/RECORD +0 -19
- {pymud-0.20.4.dist-info → pymud-0.21.0.dist-info}/entry_points.txt +0 -0
- {pymud-0.20.4.dist-info → pymud-0.21.0.dist-info}/licenses/LICENSE.txt +0 -0
- {pymud-0.20.4.dist-info → pymud-0.21.0.dist-info}/top_level.txt +0 -0
pymud/session.py
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
import asyncio, logging, re, math, os, pickle, datetime,
|
1
|
+
import asyncio, logging, re, math, os, pickle, datetime, sysconfig, time, dataclasses
|
2
|
+
from pathlib import Path
|
2
3
|
from collections.abc import Iterable
|
3
4
|
from collections import OrderedDict
|
4
|
-
import
|
5
|
-
from logging import FileHandler
|
6
|
-
from logging.handlers import QueueHandler, QueueListener
|
5
|
+
from prompt_toolkit.utils import get_cwidth
|
7
6
|
from wcwidth import wcswidth, wcwidth
|
7
|
+
from typing import Union, Optional, Any, List, Tuple, Dict, Type
|
8
8
|
from .logger import Logger
|
9
9
|
from .extras import SessionBuffer, DotDict
|
10
10
|
from .protocol import MudClientProtocol
|
11
|
-
from .modules import ModuleInfo
|
11
|
+
from .modules import ModuleInfo, Plugin
|
12
12
|
from .objects import BaseObject, Trigger, Alias, Command, Timer, SimpleAlias, SimpleTrigger, SimpleTimer, GMCPTrigger, CodeBlock, CodeLine
|
13
13
|
from .settings import Settings
|
14
|
-
|
14
|
+
from .decorators import exception, async_exception
|
15
15
|
|
16
16
|
class Session:
|
17
17
|
"""
|
@@ -102,6 +102,7 @@ class Session:
|
|
102
102
|
"t+" : "ignore",
|
103
103
|
"t-" : "ignore",
|
104
104
|
"show": "test",
|
105
|
+
"echo": "test",
|
105
106
|
}
|
106
107
|
|
107
108
|
def __init__(self, app, name, host, port, encoding = None, after_connect = None, loop = None, **kwargs):
|
@@ -159,28 +160,36 @@ class Session:
|
|
159
160
|
self.encoding = encoding or self.encoding
|
160
161
|
self.after_connect = after_connect
|
161
162
|
|
162
|
-
# 插件处置移动到 pymud.py 2024-3-22
|
163
|
-
# for plugin in app.plugins.values():
|
164
|
-
# if isinstance(plugin, Plugin):
|
165
|
-
# plugin.onSessionCreate(self)
|
166
|
-
|
167
163
|
self._modules = OrderedDict()
|
168
164
|
|
169
165
|
# 将变量加载和脚本加载调整到会话创建时刻
|
170
166
|
if Settings.client["var_autoload"]:
|
171
|
-
|
167
|
+
muddir = Path.cwd().joinpath('save')
|
168
|
+
if not muddir.exists() or not muddir.is_dir():
|
169
|
+
muddir.mkdir()
|
170
|
+
|
171
|
+
# 处理老版本当前目录的.mud文件,移动到save目录下
|
172
|
+
file = f"{self.name}.mud"
|
173
|
+
new_loc_file = muddir.joinpath(file)
|
174
|
+
if not os.path.exists(new_loc_file):
|
172
175
|
if os.path.exists(file):
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
176
|
+
os.rename(file, new_loc_file)
|
177
|
+
else:
|
178
|
+
if os.path.exists(file):
|
179
|
+
os.remove(file)
|
180
|
+
|
181
|
+
if os.path.exists(new_loc_file):
|
182
|
+
with open(new_loc_file, "rb") as fp:
|
183
|
+
try:
|
184
|
+
vars = pickle.load(fp)
|
185
|
+
self._variables.update(vars)
|
186
|
+
self.info(Settings.gettext("msg_var_autoload_success", file))
|
187
|
+
except Exception as e:
|
188
|
+
self.warning(Settings.gettext("msg_var_autoload_fail", file, e))
|
180
189
|
|
181
190
|
|
182
191
|
if self._auto_script:
|
183
|
-
self.info(
|
192
|
+
self.info(Settings.gettext("msg_auto_script", self._auto_script))
|
184
193
|
self.load_module(self._auto_script)
|
185
194
|
|
186
195
|
if Settings.client["auto_connect"]:
|
@@ -205,7 +214,7 @@ class Session:
|
|
205
214
|
#self._tasks = []
|
206
215
|
self._tasks = set()
|
207
216
|
|
208
|
-
self._command_history = []
|
217
|
+
self._command_history: List[str] = []
|
209
218
|
|
210
219
|
def open(self):
|
211
220
|
"创建到远程服务器的连接,同步方式。通过调用异步connect方法实现。"
|
@@ -214,7 +223,7 @@ class Session:
|
|
214
223
|
async def connect(self):
|
215
224
|
"创建到远程服务器的连接,异步非阻塞方式。"
|
216
225
|
def _protocol_factory():
|
217
|
-
return MudClientProtocol(self, onDisconnected = self.onDisconnected)
|
226
|
+
return MudClientProtocol(self, onDisconnected = self.onDisconnected, encoding = self.encoding, encoding_errors = Settings.server["encoding_errors"])
|
218
227
|
|
219
228
|
try:
|
220
229
|
#self.loop = asyncio.get_running_loop()
|
@@ -229,27 +238,27 @@ class Session:
|
|
229
238
|
|
230
239
|
except Exception as exc:
|
231
240
|
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
232
|
-
self.error(
|
241
|
+
self.error(Settings.gettext("msg_connection_fail", now, exec))
|
233
242
|
self._state = "EXCEPTION"
|
234
243
|
|
235
244
|
if Settings.client["auto_reconnect"]:
|
236
245
|
wait = Settings.client.get("reconnect_wait", 15)
|
237
246
|
asyncio.ensure_future(self.reconnect(wait), loop = self.loop)
|
238
247
|
|
239
|
-
async def reconnect(self, timeout = 15):
|
248
|
+
async def reconnect(self, timeout: float = 15):
|
240
249
|
"""
|
241
250
|
重新连接到远程服务器,异步非阻塞方式。该方法在 `Settings.client['auto_reconnect']` 设置为真时,断开后自动调用
|
242
251
|
|
243
252
|
:param timeout: 重连之前的等待时间,默认15s,可由 `Settings.client['reconnect_wait']` 设置所覆盖
|
244
253
|
"""
|
245
|
-
self.info(
|
254
|
+
self.info(Settings.gettext("msg_auto_reconnect", timeout))
|
246
255
|
await asyncio.sleep(timeout)
|
247
256
|
await self.create_task(self.connect())
|
248
257
|
|
249
258
|
def onConnected(self):
|
250
259
|
"当连接到服务器之后执行的操作。包括打印连接时间,执行自定义事件(若设置)等。"
|
251
260
|
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
252
|
-
self.info(
|
261
|
+
self.info(Settings.gettext("msg_connected", now))
|
253
262
|
if isinstance(self.after_connect, str):
|
254
263
|
self.writeline(self.after_connect)
|
255
264
|
|
@@ -270,7 +279,7 @@ class Session:
|
|
270
279
|
|
271
280
|
self.clean()
|
272
281
|
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
273
|
-
self.info(
|
282
|
+
self.info(Settings.gettext("msg_disconnected", now))
|
274
283
|
|
275
284
|
event_disconnected = self._events["disconnected"]
|
276
285
|
if callable(event_disconnected):
|
@@ -367,7 +376,7 @@ class Session:
|
|
367
376
|
def event_disconnected(self, event):
|
368
377
|
self._events["disconnected"] = event
|
369
378
|
|
370
|
-
def getLogger(self, name, mode = 'a', encoding = 'utf-8', encoding_errors = 'ignore', raw = False) -> Logger:
|
379
|
+
def getLogger(self, name: str, mode = 'a', encoding = 'utf-8', encoding_errors = 'ignore', raw = False) -> Logger:
|
371
380
|
"""
|
372
381
|
根据指定名称和参数获取并返回一个记录器。若指定名称不存在,则创建一个该名称记录器。
|
373
382
|
|
@@ -386,7 +395,7 @@ class Session:
|
|
386
395
|
|
387
396
|
else:
|
388
397
|
if name not in self._loggers.keys():
|
389
|
-
self.warning(
|
398
|
+
self.warning(Settings.gettext("msg_duplicate_logname", name))
|
390
399
|
|
391
400
|
logger = self.application.loggers[name]
|
392
401
|
logger.mode = mode
|
@@ -517,7 +526,7 @@ class Session:
|
|
517
526
|
|
518
527
|
def get_status(self):
|
519
528
|
"返回状态窗口内容的真实函数。 **脚本中无需调用。**"
|
520
|
-
text =
|
529
|
+
text = Settings.gettext("msg_default_statuswindow", self.name, self.connected)
|
521
530
|
if callable(self._status_maker):
|
522
531
|
text = self._status_maker()
|
523
532
|
|
@@ -539,7 +548,7 @@ class Session:
|
|
539
548
|
|
540
549
|
return plainText
|
541
550
|
|
542
|
-
def writetobuffer(self, data, newline = False):
|
551
|
+
def writetobuffer(self, data: str, newline = False):
|
543
552
|
"""
|
544
553
|
将数据写入到用于本地显示的缓冲中。 **脚本中无需调用。**
|
545
554
|
|
@@ -582,7 +591,7 @@ class Session:
|
|
582
591
|
由协议对象调用,处理收到远程 eof 数据,即远程断开连接。 **脚本中无需调用。**
|
583
592
|
"""
|
584
593
|
self._eof = True
|
585
|
-
if self.connected:
|
594
|
+
if self.connected and self._transport:
|
586
595
|
self._transport.write_eof()
|
587
596
|
self.state = "DISCONNECTED"
|
588
597
|
self.syslog.info(f"服务器断开连接! {self._protocol.__repr__}")
|
@@ -646,7 +655,7 @@ class Session:
|
|
646
655
|
self.write(b"\x1b[1z<SUPPORTS>")
|
647
656
|
else:
|
648
657
|
#self.write(b"\x1b[0z")
|
649
|
-
self.warning("
|
658
|
+
self.warning(Settings.gettext("msg_mxp_not_support"))
|
650
659
|
|
651
660
|
# 全局变量%line
|
652
661
|
self.setVariable("%line", tri_line)
|
@@ -659,7 +668,7 @@ class Session:
|
|
659
668
|
|
660
669
|
if not self._ignore:
|
661
670
|
# 修改实现,形成列表时即排除非使能状态触发器,加快响应速度
|
662
|
-
|
671
|
+
|
663
672
|
all_tris = [tri for tri in self._triggers.values() if isinstance(tri, Trigger) and tri.enabled]
|
664
673
|
all_tris.sort(key = lambda tri: tri.priority)
|
665
674
|
|
@@ -689,10 +698,10 @@ class Session:
|
|
689
698
|
|
690
699
|
:param exc: 异常对象
|
691
700
|
"""
|
692
|
-
self.error(
|
701
|
+
self.error(Settings.gettext("msg_connection_fail", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), exc))
|
693
702
|
|
694
703
|
|
695
|
-
def create_task(self, coro, *args, name: str = None) -> asyncio.Task:
|
704
|
+
def create_task(self, coro, *args, name: Optional[str] = None) -> asyncio.Task:
|
696
705
|
"""
|
697
706
|
创建一个任务,并将其加入到会话的任务管理队列中。
|
698
707
|
|
@@ -743,6 +752,25 @@ class Session:
|
|
743
752
|
|
744
753
|
self._tasks = set([t for t in self._tasks if not t.done()])
|
745
754
|
|
755
|
+
@property
|
756
|
+
def commandHistory(self) -> List[str]:
|
757
|
+
"返回发送到服务器的命令历史。保存的历史命令数量由 Settings.client['history_records'] 决定。默认为500条。"
|
758
|
+
return self._command_history
|
759
|
+
|
760
|
+
def record_command(self, cmd: str):
|
761
|
+
"""
|
762
|
+
记录一条命令到会话的命令历史中。 **脚本中无需调用。**
|
763
|
+
:param cmd: 要记录的命令
|
764
|
+
"""
|
765
|
+
record_count = Settings.client["history_records"]
|
766
|
+
if record_count:
|
767
|
+
self._command_history.append(cmd)
|
768
|
+
|
769
|
+
if record_count < 0:
|
770
|
+
pass
|
771
|
+
elif len(self._command_history) > record_count:
|
772
|
+
self._command_history.pop(0)
|
773
|
+
|
746
774
|
def write(self, data) -> None:
|
747
775
|
"""
|
748
776
|
向服务器写入数据(RAW格式字节数组/字节串)。 **一般不应在脚本中直接调用。**
|
@@ -774,6 +802,7 @@ class Session:
|
|
774
802
|
else:
|
775
803
|
self.log.log(f"\x1b[32m{ln}\x1b[0m\n")
|
776
804
|
|
805
|
+
self.record_command(line)
|
777
806
|
cmd = ln + self.newline
|
778
807
|
self.write(cmd.encode(self.encoding, Settings.server["encoding_errors"]))
|
779
808
|
|
@@ -783,6 +812,7 @@ class Session:
|
|
783
812
|
else:
|
784
813
|
self.log.log(f"\x1b[32m{line}\x1b[0m\n")
|
785
814
|
|
815
|
+
self.record_command(line)
|
786
816
|
cmd = line + self.newline
|
787
817
|
self.write(cmd.encode(self.encoding, Settings.server["encoding_errors"]))
|
788
818
|
|
@@ -808,6 +838,7 @@ class Session:
|
|
808
838
|
await asyncio.sleep(wait_time)
|
809
839
|
self.writeline(line)
|
810
840
|
return await awaitable
|
841
|
+
|
811
842
|
|
812
843
|
def exec(self, cmd: str, name = None, *args, **kwargs):
|
813
844
|
r"""
|
@@ -833,7 +864,7 @@ class Session:
|
|
833
864
|
session = self.application.sessions[name]
|
834
865
|
session.exec_command(cmd, *args, **kwargs)
|
835
866
|
else:
|
836
|
-
self.error(
|
867
|
+
self.error(Settings.gettext("msg_no_session", name))
|
837
868
|
|
838
869
|
async def exec_async(self, cmd: str, name = None, *args, **kwargs):
|
839
870
|
"""
|
@@ -848,7 +879,7 @@ class Session:
|
|
848
879
|
session = self.application.sessions[name]
|
849
880
|
return await session.exec_command_async(cmd, *args, **kwargs)
|
850
881
|
else:
|
851
|
-
self.error(
|
882
|
+
self.error(Settings.gettext("msg_no_session", name))
|
852
883
|
|
853
884
|
def exec_code(self, cl: CodeLine, *args, **kwargs):
|
854
885
|
"""
|
@@ -876,7 +907,7 @@ class Session:
|
|
876
907
|
if times > 0:
|
877
908
|
self.create_task(self.handle_num(times, code = cl, *args, **kwargs))
|
878
909
|
else:
|
879
|
-
self.warning("
|
910
|
+
self.warning(Settings.gettext("msg_num_positive"))
|
880
911
|
|
881
912
|
elif cmd in self.application.sessions.keys():
|
882
913
|
name = cmd
|
@@ -905,7 +936,7 @@ class Session:
|
|
905
936
|
else:
|
906
937
|
handler(code = cl, *args, **kwargs)
|
907
938
|
else:
|
908
|
-
self.warning(
|
939
|
+
self.warning(Settings.gettext("msg_cmd_not_recognized", cl.commandText))
|
909
940
|
|
910
941
|
else:
|
911
942
|
cmdtext, code = cl.expand(self, *args, **kwargs)
|
@@ -940,7 +971,7 @@ class Session:
|
|
940
971
|
if times > 0:
|
941
972
|
await self.handle_num(times, code = cl, *args, **kwargs)
|
942
973
|
else:
|
943
|
-
self.warning("
|
974
|
+
self.warning(Settings.gettext("msg_num_positive"))
|
944
975
|
|
945
976
|
elif cmd in self.application.sessions.keys():
|
946
977
|
name = cmd
|
@@ -966,7 +997,7 @@ class Session:
|
|
966
997
|
else:
|
967
998
|
handler(code = cl, *args, **kwargs)
|
968
999
|
else:
|
969
|
-
self.warning(
|
1000
|
+
self.warning(Settings.gettext("msg_cmd_not_recognized", cl.commandText))
|
970
1001
|
|
971
1002
|
else:
|
972
1003
|
cmdtext, code = cl.expand(self, *args, **kwargs)
|
@@ -980,29 +1011,43 @@ class Session:
|
|
980
1011
|
|
981
1012
|
:param cmdtext: 纯文本命令
|
982
1013
|
"""
|
983
|
-
|
1014
|
+
keepEval = True
|
1015
|
+
notHandle = True
|
1016
|
+
|
1017
|
+
# fix bugs, commands filter for enabled and sorted for priority
|
1018
|
+
avai_cmds = [cmd for cmd in self._commands.values() if isinstance(cmd, Command) and cmd.enabled]
|
1019
|
+
avai_cmds.sort(key = lambda cmd: cmd.priority)
|
1020
|
+
|
984
1021
|
for command in self._commands.values():
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
1022
|
+
state = command.match(cmdtext)
|
1023
|
+
if state.result == Command.SUCCESS:
|
1024
|
+
notHandle = False
|
1025
|
+
# 命令的任务名称采用命令id,以便于后续查错
|
1026
|
+
self.create_task(command.execute(cmdtext), name = "task-{0}".format(command.id))
|
1027
|
+
|
1028
|
+
if not command.keepEval:
|
1029
|
+
keepEval = False
|
991
1030
|
break
|
992
1031
|
|
993
|
-
#
|
994
|
-
if
|
995
|
-
|
996
|
-
for
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1032
|
+
# 若持续匹配,再判断是否是别名
|
1033
|
+
if keepEval:
|
1034
|
+
# fix bugs, aliases filter for enabled and sorted for priority, and add oneShot, keepEval judge
|
1035
|
+
avai_alis = [ali for ali in self._aliases.values() if isinstance(ali, Alias) and ali.enabled]
|
1036
|
+
avai_alis.sort(key = lambda ali: ali.priority)
|
1037
|
+
|
1038
|
+
for alias in avai_alis:
|
1039
|
+
state = alias.match(cmdtext)
|
1040
|
+
if state.result == Alias.SUCCESS:
|
1041
|
+
notHandle = False
|
1042
|
+
if alias.oneShot:
|
1043
|
+
self.delAlias(alias.id)
|
1044
|
+
|
1045
|
+
if not alias.keepEval:
|
1001
1046
|
break
|
1002
1047
|
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1048
|
+
# 都前面都未被处理,则直接发送
|
1049
|
+
if notHandle:
|
1050
|
+
self.writeline(cmdtext)
|
1006
1051
|
|
1007
1052
|
async def exec_text_async(self, cmdtext: str):
|
1008
1053
|
"""
|
@@ -1011,29 +1056,43 @@ class Session:
|
|
1011
1056
|
异步调用时,该函数要等待对应的代码执行完毕后才会返回。可以用于确保命令执行完毕。
|
1012
1057
|
"""
|
1013
1058
|
result = None
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1059
|
+
keepEval = True
|
1060
|
+
notHandle = True
|
1061
|
+
|
1062
|
+
# fix bugs, commands filter for enabled and sorted for priority
|
1063
|
+
avai_cmds = [cmd for cmd in self._commands.values() if isinstance(cmd, Command) and cmd.enabled]
|
1064
|
+
avai_cmds.sort(key = lambda cmd: cmd.priority)
|
1065
|
+
|
1066
|
+
for command in avai_cmds:
|
1067
|
+
state = command.match(cmdtext)
|
1068
|
+
if state.result == Command.SUCCESS:
|
1069
|
+
# 命令的任务名称采用命令id,以便于后续查错
|
1070
|
+
result = await self.create_task(command.execute(cmdtext), name = "task-{0}".format(command.id))
|
1071
|
+
notHandle = False
|
1072
|
+
if not command.keepEval:
|
1073
|
+
keepEval = False
|
1022
1074
|
break
|
1023
1075
|
|
1024
1076
|
# 再判断是否是别名
|
1025
|
-
if
|
1026
|
-
|
1027
|
-
for
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1077
|
+
if keepEval:
|
1078
|
+
|
1079
|
+
# fix bugs, aliases filter for enabled and sorted for priority, and add oneShot, keepEval judge
|
1080
|
+
avai_alis = [ali for ali in self._aliases.values() if isinstance(ali, Alias) and ali.enabled]
|
1081
|
+
avai_alis.sort(key = lambda ali: ali.priority)
|
1082
|
+
|
1083
|
+
for alias in avai_alis:
|
1084
|
+
state = alias.match(cmdtext)
|
1085
|
+
if state.result == Alias.SUCCESS:
|
1086
|
+
notHandle = False
|
1087
|
+
if alias.oneShot:
|
1088
|
+
self.delAlias(alias.id)
|
1089
|
+
|
1090
|
+
if not alias.keepEval:
|
1032
1091
|
break
|
1033
1092
|
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1093
|
+
# 若均为处理则是普通命令,直接发送
|
1094
|
+
if notHandle:
|
1095
|
+
self.writeline(cmdtext)
|
1037
1096
|
|
1038
1097
|
return result
|
1039
1098
|
|
@@ -1106,7 +1165,8 @@ class Session:
|
|
1106
1165
|
|
1107
1166
|
若要在脚本中控制断开与服务器的连接,请使用 session.disconnect()
|
1108
1167
|
"""
|
1109
|
-
self._transport
|
1168
|
+
if self._transport:
|
1169
|
+
self._transport.write_eof()
|
1110
1170
|
|
1111
1171
|
def getUniqueNumber(self):
|
1112
1172
|
"""
|
@@ -1126,55 +1186,93 @@ class Session:
|
|
1126
1186
|
"""
|
1127
1187
|
return "{0}_{1}".format(prefix, self.getUniqueNumber())
|
1128
1188
|
|
1129
|
-
def enableGroup(self, group: str, enabled = True):
|
1189
|
+
def enableGroup(self, group: str, enabled = True, subgroup = True, types: Union[Type, Union[Tuple, List]] = (Alias, Trigger, Command, Timer, GMCPTrigger)):
|
1130
1190
|
"""
|
1131
1191
|
使能或禁用Group中所有对象, 返回组内各对象个数。
|
1132
1192
|
|
1133
1193
|
:param group: 组名,即各对象的 group 属性的值
|
1134
1194
|
:param enabled: 使能/禁用开关。为True时表示使能, False为禁用
|
1195
|
+
:param subgroup: 是否对子组同时生效,默认为True。子组是指名称在父组名之后的用.xxx命名的组。例如, 组 group1.group2 是 group1 的子组。
|
1196
|
+
:param types: 要使能的对象类型,默认为 (Alias, Trigger, Command, Timer, GMCPTrigger)。
|
1197
|
+
可以指定为单个类型,也可以指定为类型列表或元组。
|
1198
|
+
若指定为单个类型,则只使能该类型的对象。
|
1199
|
+
若指定为类型列表或元组,则使能该类型列表或元组中的所有类型的对象。
|
1135
1200
|
:return: 5个整数的列表,依次表示改组内操作的 别名,触发器,命令,定时器,GMCP 的个数
|
1136
1201
|
"""
|
1137
1202
|
counts = [0, 0, 0, 0, 0]
|
1138
|
-
|
1139
|
-
|
1140
|
-
ali.
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1203
|
+
if (Alias == types) or (isinstance(types, (list, tuple)) and (Alias in types)):
|
1204
|
+
for ali in self._aliases.values():
|
1205
|
+
if isinstance(ali, Alias) and ((ali.group == group) or (subgroup and ali.group.startswith(group + "."))):
|
1206
|
+
ali.enabled = enabled
|
1207
|
+
counts[0] += 1
|
1208
|
+
|
1209
|
+
if (Trigger == types) or (isinstance(types, (list, tuple)) and (Trigger in types)):
|
1210
|
+
for tri in self._triggers.values():
|
1211
|
+
if isinstance(tri, Trigger) and ((tri.group == group) or (subgroup and tri.group.startswith(group + "."))):
|
1212
|
+
tri.enabled = enabled
|
1213
|
+
counts[1] += 1
|
1214
|
+
|
1215
|
+
if (Command == types) or (isinstance(types, (list, tuple)) and (Command in types)):
|
1216
|
+
for cmd in self._commands.values():
|
1217
|
+
if isinstance(cmd, Command) and ((cmd.group == group) or (subgroup and cmd.group.startswith(group + "."))):
|
1218
|
+
cmd.enabled = enabled
|
1219
|
+
counts[2] += 1
|
1220
|
+
|
1221
|
+
if (Timer == types) or (isinstance(types, (list, tuple)) and (Timer in types)):
|
1222
|
+
for tmr in self._timers.values():
|
1223
|
+
if isinstance(tmr, Timer) and ((tmr.group == group) or (subgroup and tmr.group.startswith(group + "."))):
|
1224
|
+
tmr.enabled = enabled
|
1225
|
+
counts[3] += 1
|
1226
|
+
|
1227
|
+
if (GMCPTrigger == types) or (isinstance(types, (list, tuple)) and (GMCPTrigger in types)):
|
1228
|
+
for gmcp in self._gmcp.values():
|
1229
|
+
if isinstance(gmcp, GMCPTrigger) and ((gmcp.group == group) or (subgroup and gmcp.group.startswith(group + "."))):
|
1230
|
+
gmcp.enabled = enabled
|
1231
|
+
counts[4] += 1
|
1232
|
+
|
1233
|
+
return counts
|
1234
|
+
|
1235
|
+
def deleteGroup(self, group: str, subgroup = True, types: Union[Type, Union[Tuple, List]] = (Alias, Trigger, Command, Timer, GMCPTrigger)):
|
1236
|
+
"""
|
1237
|
+
删除Group中所有对象, 返回组内各对象个数。
|
1238
|
+
|
1239
|
+
:param group: 组名,即各对象的 group 属性的值
|
1240
|
+
:param subgroup: 是否对子组同时生效,默认为True。子组是指名称在父组名之后的用.xxx命名的组。例如, 组 group1.group2 是 group1 的子组。
|
1241
|
+
:param types: 要删除的对象类型,默认为 (Alias, Trigger, Command, Timer, GMCPTrigger)。
|
1242
|
+
可以指定为单个类型,也可以指定为类型列表或元组。
|
1243
|
+
若指定为单个类型,则只删除该类型的对象。
|
1244
|
+
若指定为类型列表或元组,则删除该类型列表或元组中的所有类型的对象。
|
1245
|
+
:return: 5个整数的列表,依次表示改组内操作的 别名,触发器,命令,定时器,GMCP 的个数
|
1246
|
+
"""
|
1247
|
+
counts = [0, 0, 0, 0, 0]
|
1248
|
+
if (Alias == types) or (isinstance(types, (list, tuple)) and (Alias in types)):
|
1249
|
+
ali_ids = [ali.id for ali in self._aliases.values() if isinstance(ali, Alias) and ((ali.group == group) or (subgroup and ali.group.startswith(group + ".")))]
|
1250
|
+
self.delAliases(ali_ids)
|
1251
|
+
counts[0] = len(ali_ids)
|
1252
|
+
|
1253
|
+
if (Trigger == types) or (isinstance(types, (list, tuple)) and (Trigger in types)):
|
1254
|
+
tri_ids = [tri.id for tri in self._triggers.values() if isinstance(tri, Trigger) and ((tri.group == group) or (subgroup and tri.group.startswith(group + ".")))]
|
1255
|
+
self.delTriggers(tri_ids)
|
1256
|
+
counts[1] = len(tri_ids)
|
1257
|
+
|
1258
|
+
if (Command == types) or (isinstance(types, (list, tuple)) and (Command in types)):
|
1259
|
+
cmd_ids = [cmd.id for cmd in self._commands.values() if isinstance(cmd, Command) and ((cmd.group == group) or (subgroup and cmd.group.startswith(group + ".")))]
|
1260
|
+
self.delCommands(cmd_ids)
|
1261
|
+
counts[2] = len(cmd_ids)
|
1262
|
+
|
1263
|
+
if (Timer == types) or (isinstance(types, (list, tuple)) and (Timer in types)):
|
1264
|
+
tmr_ids = [tmr.id for tmr in self._timers.values() if isinstance(tmr, Timer) and ((tmr.group == group) or (subgroup and tmr.group.startswith(group + ".")))]
|
1265
|
+
self.delTimers(tmr_ids)
|
1266
|
+
counts[3] = len(tmr_ids)
|
1267
|
+
|
1268
|
+
if (GMCPTrigger == types) or (isinstance(types, (list, tuple)) and (GMCPTrigger in types)):
|
1269
|
+
gmcp_ids = [gmcp.id for gmcp in self._gmcp.values() if isinstance(gmcp, GMCPTrigger) and ((gmcp.group == group) or (subgroup and gmcp.group.startswith(group + ".")))]
|
1270
|
+
self.delGMCPs(gmcp_ids)
|
1271
|
+
counts[4] = len(gmcp_ids)
|
1162
1272
|
|
1163
1273
|
return counts
|
1164
1274
|
|
1165
|
-
|
1166
|
-
# if cls == Alias:
|
1167
|
-
# self._aliases.update(objs)
|
1168
|
-
# elif cls == Command:
|
1169
|
-
# self._commands.update(objs)
|
1170
|
-
# elif cls == Trigger:
|
1171
|
-
# self._triggers.update(objs)
|
1172
|
-
# elif cls == Timer:
|
1173
|
-
# self._timers.update(objs)
|
1174
|
-
# elif cls == GMCPTrigger:
|
1175
|
-
# self._gmcp.update(objs)
|
1176
|
-
|
1177
|
-
def _addObjects(self, objs):
|
1275
|
+
def _addObjects(self, objs: Union[Union[List[BaseObject], Tuple[BaseObject]], Dict[str, BaseObject]]):
|
1178
1276
|
if isinstance(objs, list) or isinstance(objs, tuple):
|
1179
1277
|
for item in objs:
|
1180
1278
|
self._addObject(item)
|
@@ -1183,25 +1281,11 @@ class Session:
|
|
1183
1281
|
for key, item in objs.items():
|
1184
1282
|
if isinstance(item, BaseObject):
|
1185
1283
|
if key != item.id:
|
1186
|
-
self.warning(
|
1284
|
+
self.warning(Settings.gettext("msg_id_not_consistent", item, key, item.id))
|
1187
1285
|
|
1188
1286
|
self._addObject(item)
|
1189
1287
|
|
1190
|
-
|
1191
|
-
# #if type(obj) == cls:
|
1192
|
-
# if isinstance(obj, cls):
|
1193
|
-
# if cls == Alias:
|
1194
|
-
# self._aliases[obj.id] = obj
|
1195
|
-
# elif cls == Command:
|
1196
|
-
# self._commands[obj.id] = obj
|
1197
|
-
# elif cls == Trigger:
|
1198
|
-
# self._triggers[obj.id] = obj
|
1199
|
-
# elif cls == Timer:
|
1200
|
-
# self._timers[obj.id] = obj
|
1201
|
-
# elif cls == GMCPTrigger:
|
1202
|
-
# self._gmcp[obj.id] = obj
|
1203
|
-
|
1204
|
-
def _addObject(self, obj):
|
1288
|
+
def _addObject(self, obj: BaseObject):
|
1205
1289
|
if isinstance(obj, Alias):
|
1206
1290
|
self._aliases[obj.id] = obj
|
1207
1291
|
elif isinstance(obj, Command):
|
@@ -1233,7 +1317,7 @@ class Session:
|
|
1233
1317
|
"""
|
1234
1318
|
self._addObject(obj)
|
1235
1319
|
|
1236
|
-
def addObjects(self, objs):
|
1320
|
+
def addObjects(self, objs: Union[Union[List[BaseObject], Tuple[BaseObject]], Dict[str, BaseObject]]):
|
1237
1321
|
"""
|
1238
1322
|
向会话中增加多个对象,可直接添加 Alias, Trigger, GMCPTrigger, Command, Timer 或它们的子类的元组、列表或者字典(保持兼容性)
|
1239
1323
|
|
@@ -1327,7 +1411,7 @@ class Session:
|
|
1327
1411
|
elif isinstance(obj, (list, tuple, dict)):
|
1328
1412
|
self.delObjects(obj)
|
1329
1413
|
|
1330
|
-
def delObjects(self, objs):
|
1414
|
+
def delObjects(self, objs: Union[Union[Union[list, tuple], dict], BaseObject]):
|
1331
1415
|
"""
|
1332
1416
|
从会话中移除一组对象,可直接删除多个 Alias, Trigger, GMCPTrigger, Command, Timer
|
1333
1417
|
|
@@ -1600,7 +1684,7 @@ class Session:
|
|
1600
1684
|
for gmcp in gmcp_s:
|
1601
1685
|
self.delGMCP(gmcp)
|
1602
1686
|
|
1603
|
-
def replace(self, newstr):
|
1687
|
+
def replace(self, newstr: str):
|
1604
1688
|
"""
|
1605
1689
|
将当前行内容显示替换为newstr。该方法仅在用于触发器的同步处置中才能正确相应
|
1606
1690
|
|
@@ -1614,17 +1698,17 @@ class Session:
|
|
1614
1698
|
## ###################
|
1615
1699
|
## 变量 Variables 处理
|
1616
1700
|
## ###################
|
1617
|
-
def delVariable(self, name):
|
1701
|
+
def delVariable(self, name: str):
|
1618
1702
|
"""
|
1619
1703
|
删除一个变量。删除变量是从session管理的变量列表中移除关键字,而不是设置为 None
|
1620
1704
|
|
1621
1705
|
:param name: 变量名
|
1622
1706
|
"""
|
1623
|
-
assert isinstance(name, str), "name
|
1707
|
+
assert isinstance(name, str), Settings.gettext("msg_shall_be_string", "name")
|
1624
1708
|
if name in self._variables.keys():
|
1625
1709
|
self._variables.pop(name)
|
1626
1710
|
|
1627
|
-
def setVariable(self, name, value):
|
1711
|
+
def setVariable(self, name: str, value: Any):
|
1628
1712
|
"""
|
1629
1713
|
设置一个变量的值。可以使用vars快捷点访问器实现同样效果。
|
1630
1714
|
|
@@ -1638,10 +1722,10 @@ class Session:
|
|
1638
1722
|
session.setVariable("myvar1", "the value")
|
1639
1723
|
session.vars.myvar1 = "the value"
|
1640
1724
|
"""
|
1641
|
-
assert isinstance(name, str), "name
|
1725
|
+
assert isinstance(name, str), Settings.gettext("msg_shall_be_string", "name")
|
1642
1726
|
self._variables[name] = value
|
1643
1727
|
|
1644
|
-
def getVariable(self, name, default = None):
|
1728
|
+
def getVariable(self, name: str, default = None):
|
1645
1729
|
"""
|
1646
1730
|
获取一个变量的值。可以使用vars快捷点访问器实现类似效果,但vars访问时,默认值总为None。
|
1647
1731
|
|
@@ -1657,10 +1741,10 @@ class Session:
|
|
1657
1741
|
myvar = session.vars.myvar1
|
1658
1742
|
"""
|
1659
1743
|
"""获取一个变量的值. 当name指定的变量不存在时,返回default"""
|
1660
|
-
assert isinstance(name, str), "name
|
1744
|
+
assert isinstance(name, str), Settings.gettext("msg_shall_be_string", "name")
|
1661
1745
|
return self._variables.get(name, default)
|
1662
1746
|
|
1663
|
-
def setVariables(self, names, values):
|
1747
|
+
def setVariables(self, names: Union[List[str], Tuple[str]], values: Union[list, tuple]):
|
1664
1748
|
"""
|
1665
1749
|
同时设置一组变量的值。要注意,变量名称和值的数量要相同。当不相同时,抛出异常。
|
1666
1750
|
|
@@ -1675,15 +1759,15 @@ class Session:
|
|
1675
1759
|
|
1676
1760
|
session.setVariables(hp_key, hp_value)
|
1677
1761
|
"""
|
1678
|
-
assert isinstance(names, tuple) or isinstance(names, list), "names
|
1679
|
-
assert isinstance(values, tuple) or isinstance(values, list), "values
|
1680
|
-
assert (len(names) > 0) and (len(values) > 0) and (len(names) == len(values)), "
|
1762
|
+
assert isinstance(names, tuple) or isinstance(names, list), Settings.gettext("msg_shall_be_list_or_tuple", "names")
|
1763
|
+
assert isinstance(values, tuple) or isinstance(values, list), Settings.gettext("msg_shall_be_list_or_tuple", "values")
|
1764
|
+
assert (len(names) > 0) and (len(values) > 0) and (len(names) == len(values)), Settings.gettext("msg_names_and_values")
|
1681
1765
|
for index in range(0, len(names)):
|
1682
1766
|
name = names[index]
|
1683
1767
|
value = values[index]
|
1684
1768
|
self.setVariable(name, value)
|
1685
1769
|
|
1686
|
-
def getVariables(self, names):
|
1770
|
+
def getVariables(self, names: Union[List[str], Tuple[str]]):
|
1687
1771
|
"""
|
1688
1772
|
同时获取一组变量的值。
|
1689
1773
|
|
@@ -1695,8 +1779,8 @@ class Session:
|
|
1695
1779
|
|
1696
1780
|
qi, jing, neili, jingli = session.getVariables(["qi", "jing", "neili", "jingli"])
|
1697
1781
|
"""
|
1698
|
-
assert isinstance(names, tuple) or isinstance(names, list), "names
|
1699
|
-
assert len(names) > 0, "names
|
1782
|
+
assert isinstance(names, tuple) or isinstance(names, list), Settings.gettext("msg_shall_be_list_or_tuple", "names")
|
1783
|
+
assert len(names) > 0, Settings.gettext("msg_not_null", "names")
|
1700
1784
|
values = list()
|
1701
1785
|
for name in names:
|
1702
1786
|
value = self.getVariable(name)
|
@@ -1704,7 +1788,7 @@ class Session:
|
|
1704
1788
|
|
1705
1789
|
return tuple(values)
|
1706
1790
|
|
1707
|
-
def updateVariables(self, kvdict:
|
1791
|
+
def updateVariables(self, kvdict: Dict[str, Any]):
|
1708
1792
|
"""
|
1709
1793
|
使用字典更新一组变量的值。若变量不存在将自动添加。
|
1710
1794
|
|
@@ -1722,26 +1806,26 @@ class Session:
|
|
1722
1806
|
## ###################
|
1723
1807
|
## 全局变量 Globals 处理
|
1724
1808
|
## ###################
|
1725
|
-
def delGlobal(self, name):
|
1809
|
+
def delGlobal(self, name: str):
|
1726
1810
|
"""
|
1727
1811
|
删除一个全局变量,使用方式与会话变量variable相同
|
1728
1812
|
|
1729
1813
|
:param name: 全局变量的名称
|
1730
1814
|
"""
|
1731
|
-
assert isinstance(name, str), "name
|
1815
|
+
assert isinstance(name, str), Settings.gettext("msg_shall_be_string", "name")
|
1732
1816
|
self.application.del_globals(name)
|
1733
1817
|
|
1734
|
-
def setGlobal(self, name, value):
|
1818
|
+
def setGlobal(self, name: str, value):
|
1735
1819
|
"""
|
1736
1820
|
设置一个全局变量的值,使用方式与会话变量variable相同
|
1737
1821
|
|
1738
1822
|
:param name: 全局变量的名称
|
1739
1823
|
:param value: 全局变量的值
|
1740
1824
|
"""
|
1741
|
-
assert isinstance(name, str), "name
|
1825
|
+
assert isinstance(name, str), Settings.gettext("msg_shall_be_string", "name")
|
1742
1826
|
self.application.set_globals(name, value)
|
1743
1827
|
|
1744
|
-
def getGlobal(self, name, default = None):
|
1828
|
+
def getGlobal(self, name: str, default = None):
|
1745
1829
|
"""
|
1746
1830
|
获取一个全局变量的值,使用方式与会话变量variable相同
|
1747
1831
|
|
@@ -1750,7 +1834,7 @@ class Session:
|
|
1750
1834
|
:return: 全局变量的值,或者 default
|
1751
1835
|
"""
|
1752
1836
|
|
1753
|
-
assert isinstance(name, str), "name
|
1837
|
+
assert isinstance(name, str), Settings.gettext("msg_shall_be_string", "name")
|
1754
1838
|
return self.application.get_globals(name, default)
|
1755
1839
|
|
1756
1840
|
## ###################
|
@@ -1791,7 +1875,7 @@ class Session:
|
|
1791
1875
|
|
1792
1876
|
self.writetobuffer("#"*width, newline = True)
|
1793
1877
|
|
1794
|
-
def handle_help(self, code: CodeLine
|
1878
|
+
def handle_help(self, code: CodeLine, *args, **kwargs):
|
1795
1879
|
'''
|
1796
1880
|
嵌入命令 #help 的执行函数,在当前会话中现实帮助信息。
|
1797
1881
|
当不带参数时, #help会列出所有可用的帮助主题。
|
@@ -1815,7 +1899,6 @@ class Session:
|
|
1815
1899
|
- ``#help session``
|
1816
1900
|
显示 #session 命令有关的帮助
|
1817
1901
|
'''
|
1818
|
-
|
1819
1902
|
if code.length == 2:
|
1820
1903
|
self._print_all_help()
|
1821
1904
|
|
@@ -1832,11 +1915,16 @@ class Session:
|
|
1832
1915
|
elif topic in self._sys_commands:
|
1833
1916
|
docstring = self._cmds_handler[topic].__doc__
|
1834
1917
|
else:
|
1835
|
-
docstring =
|
1918
|
+
docstring = Settings.gettext("msg_topic_not_found", topic)
|
1836
1919
|
|
1837
|
-
|
1920
|
+
title = f" HELP: #{topic.upper()} "
|
1921
|
+
title_line = "=" * 4 + title + "=" * (self.application.get_width() - get_cwidth(title) - 4)
|
1922
|
+
self.writetobuffer("", newline = True)
|
1923
|
+
self.writetobuffer(title_line, newline = False)
|
1924
|
+
self.writetobuffer(docstring, True) # type: ignore
|
1925
|
+
self.writetobuffer("=" * self.application.get_width(), newline = True)
|
1838
1926
|
|
1839
|
-
def handle_exit(self, code: CodeLine = None, *args, **kwargs):
|
1927
|
+
def handle_exit(self, code: Optional[CodeLine] = None, *args, **kwargs):
|
1840
1928
|
'''
|
1841
1929
|
嵌入命令 #exit 的执行函数,退出 `PyMudApp` 应用。
|
1842
1930
|
该函数不应该在代码中直接调用。
|
@@ -1850,7 +1938,7 @@ class Session:
|
|
1850
1938
|
|
1851
1939
|
self.application.act_exit()
|
1852
1940
|
|
1853
|
-
def handle_close(self, code: CodeLine = None, *args, **kwargs):
|
1941
|
+
def handle_close(self, code: Optional[CodeLine] = None, *args, **kwargs):
|
1854
1942
|
'''
|
1855
1943
|
嵌入命令 #close 的执行函数,关闭当前会话,并将当前会话从 `PyMudApp` 的会话列表中移除。
|
1856
1944
|
该函数不应该在代码中直接调用。
|
@@ -1865,7 +1953,7 @@ class Session:
|
|
1865
1953
|
#self.application.close_session()
|
1866
1954
|
self.application.act_close_session()
|
1867
1955
|
|
1868
|
-
async def handle_wait(self, code: CodeLine
|
1956
|
+
async def handle_wait(self, code: CodeLine, *args, **kwargs):
|
1869
1957
|
'''
|
1870
1958
|
嵌入命令 #wait / #wa 的执行函数,异步延时等待指定时间,用于多个命令间的延时等待。
|
1871
1959
|
该函数不应该在代码中直接调用。
|
@@ -1884,13 +1972,13 @@ class Session:
|
|
1884
1972
|
- #gag
|
1885
1973
|
- #replace
|
1886
1974
|
'''
|
1887
|
-
|
1975
|
+
|
1888
1976
|
wait_time = code.code[2]
|
1889
1977
|
if wait_time.isnumeric():
|
1890
1978
|
msec = float(wait_time) / 1000.0
|
1891
1979
|
await asyncio.sleep(msec)
|
1892
1980
|
|
1893
|
-
def handle_connect(self, code: CodeLine = None, *args, **kwargs):
|
1981
|
+
def handle_connect(self, code: Optional[CodeLine] = None, *args, **kwargs):
|
1894
1982
|
'''
|
1895
1983
|
嵌入命令 #connect / #con 的执行函数,连接到远程服务器(仅当远程服务器未连接时有效)。
|
1896
1984
|
该函数不应该在代码中直接调用。
|
@@ -1905,20 +1993,21 @@ class Session:
|
|
1905
1993
|
self.open()
|
1906
1994
|
|
1907
1995
|
else:
|
1908
|
-
duration =
|
1996
|
+
duration = 0
|
1997
|
+
if self._protocol: duration = self._protocol.duration
|
1909
1998
|
hour = duration // 3600
|
1910
1999
|
min = (duration - 3600 * hour) // 60
|
1911
2000
|
sec = duration % 60
|
1912
2001
|
time_msg = ""
|
1913
2002
|
if hour > 0:
|
1914
|
-
time_msg += f"{hour}
|
2003
|
+
time_msg += f"{hour} {Settings.gettext('Hour')}"
|
1915
2004
|
if min > 0:
|
1916
|
-
time_msg += f"{min}
|
1917
|
-
time_msg += f"{math.ceil(sec)}
|
2005
|
+
time_msg += f"{min} {Settings.gettext('Minute')}"
|
2006
|
+
time_msg += f"{math.ceil(sec)} {Settings.gettext('Second')}"
|
1918
2007
|
|
1919
|
-
self.info("
|
2008
|
+
self.info(Settings.gettext("msg_connection_duration",time_msg))
|
1920
2009
|
|
1921
|
-
def handle_disconnect(self, code: CodeLine = None, *args, **kwargs):
|
2010
|
+
def handle_disconnect(self, code: Optional[CodeLine] = None, *args, **kwargs):
|
1922
2011
|
'''
|
1923
2012
|
嵌入命令 #disconnect / #dis 的执行函数,断开到远程服务器的连接(仅当远程服务器已连接时有效)。
|
1924
2013
|
该函数不应该在代码中直接调用。
|
@@ -2078,7 +2167,7 @@ class Session:
|
|
2078
2167
|
|
2079
2168
|
return display_lines
|
2080
2169
|
|
2081
|
-
def handle_variable(self, code: CodeLine
|
2170
|
+
def handle_variable(self, code: CodeLine, *args, **kwargs):
|
2082
2171
|
'''
|
2083
2172
|
嵌入命令 #variable / #var 的执行函数,操作会话变量。
|
2084
2173
|
该命令可以不带参数、带一个参数、两个参数。
|
@@ -2111,14 +2200,14 @@ class Session:
|
|
2111
2200
|
elif len(args) == 1:
|
2112
2201
|
if args[0] in self._variables.keys():
|
2113
2202
|
obj = self.getVariable(args[0])
|
2114
|
-
var_dict = {args[0] : obj}
|
2203
|
+
var_dict = DotDict({args[0] : obj})
|
2115
2204
|
lines = self.buildDisplayLines(var_dict, f" VARIABLE [{args[0]}] IN SESSION {self.name} ")
|
2116
2205
|
|
2117
2206
|
for line in lines:
|
2118
2207
|
self.writetobuffer(line, newline = True)
|
2119
2208
|
|
2120
2209
|
else:
|
2121
|
-
self.warning(
|
2210
|
+
self.warning(Settings.gettext("msg_no_object", args[0], Settings.gettext("variable")))
|
2122
2211
|
|
2123
2212
|
elif len(args) == 2:
|
2124
2213
|
val = None
|
@@ -2128,9 +2217,9 @@ class Session:
|
|
2128
2217
|
val = args[1]
|
2129
2218
|
|
2130
2219
|
self.setVariable(args[0], val)
|
2131
|
-
self.info(
|
2220
|
+
self.info(Settings.gettext("msg_object_value_setted", Settings.gettext("variable"), args[0], val.__repr__()))
|
2132
2221
|
|
2133
|
-
def handle_global(self, code: CodeLine
|
2222
|
+
def handle_global(self, code: CodeLine, *args, **kwargs):
|
2134
2223
|
'''
|
2135
2224
|
嵌入命令 #global 的执行函数,操作全局变量(跨会话共享)。
|
2136
2225
|
该命令可以不带参数、带一个参数、两个参数。
|
@@ -2164,13 +2253,13 @@ class Session:
|
|
2164
2253
|
if var in self.application.globals.keys():
|
2165
2254
|
# self.info("{0:>20} = {1:<22}".format(var, self.application.get_globals(var).__repr__()), "全局变量")
|
2166
2255
|
|
2167
|
-
var_dict = {var : self.application.get_globals(var)}
|
2256
|
+
var_dict = DotDict({var : self.application.get_globals(var)})
|
2168
2257
|
lines = self.buildDisplayLines(var_dict, f" GLOBAL VARIABLE [{var}] ")
|
2169
2258
|
|
2170
2259
|
for line in lines:
|
2171
2260
|
self.writetobuffer(line, newline = True)
|
2172
2261
|
else:
|
2173
|
-
self.
|
2262
|
+
self.warning(Settings.gettext("msg_no_global_object", var, Settings.gettext("variable")))
|
2174
2263
|
|
2175
2264
|
elif len(args) == 2:
|
2176
2265
|
val = None
|
@@ -2179,71 +2268,112 @@ class Session:
|
|
2179
2268
|
except:
|
2180
2269
|
val = args[1]
|
2181
2270
|
self.application.set_globals(args[0], val)
|
2182
|
-
self.info(
|
2271
|
+
self.info(Settings.gettext("msg_object_value_setted", Settings.gettext("globalvar"), args[0], val.__repr__()))
|
2272
|
+
|
2273
|
+
@exception
|
2274
|
+
def _handle_objs(self, type: Type, objs: dict, *args):
|
2275
|
+
if len(args) <= 1:
|
2276
|
+
if len(args) == 0:
|
2277
|
+
display_objs = objs
|
2278
|
+
title = f" {type.__name__.upper()} LIST IN SESSION {self.name} "
|
2279
|
+
else:
|
2280
|
+
arg = args[0]
|
2281
|
+
if arg.startswith(">"):
|
2282
|
+
arg = arg[1:]
|
2283
|
+
title = f" {type.__name__.upper()} LIST IN GROUP <{arg.upper()}> AND ITS SUBGROUPS IN SESSION {self.name} "
|
2284
|
+
display_objs = {obj.id: obj for obj in objs.values() if (obj.group == arg) or obj.group.startswith(f"{arg}.")}
|
2285
|
+
elif arg.startswith("="):
|
2286
|
+
arg = arg[1:]
|
2287
|
+
title = f" {type.__name__.upper()} LIST IN GROUP <{arg.upper()}> IN SESSION {self.name} "
|
2288
|
+
display_objs = {obj.id: obj for obj in objs.values() if (obj.group == arg)}
|
2289
|
+
else:
|
2290
|
+
title = f" {type.__name__.upper()} LIST OF ID <{arg.upper()}> IN SESSION {self.name} "
|
2291
|
+
display_objs = {obj.id: obj for obj in objs.values() if (obj.id == arg)}
|
2183
2292
|
|
2184
|
-
def _handle_objs(self, name: str, objs: dict, *args):
|
2185
|
-
if len(args) == 0:
|
2186
2293
|
width = self.application.get_width()
|
2187
|
-
|
2188
|
-
title = f" {name.upper()} LIST IN SESSION {self.name} "
|
2294
|
+
|
2189
2295
|
left = (width - len(title)) // 2
|
2190
2296
|
right = width - len(title) - left
|
2297
|
+
self.writetobuffer("", newline = True)
|
2191
2298
|
self.writetobuffer("="*left + title + "="*right, newline = True)
|
2192
2299
|
|
2193
|
-
for id in sorted(
|
2300
|
+
for id in sorted(display_objs.keys()):
|
2194
2301
|
self.writetobuffer(" %r" % objs[id], newline = True)
|
2195
2302
|
|
2196
2303
|
self.writetobuffer("="*width, newline = True)
|
2197
2304
|
|
2198
|
-
elif len(args) == 1:
|
2199
|
-
if args[0] in objs.keys():
|
2200
|
-
obj = objs[args[0]]
|
2201
|
-
self.info(obj.__detailed__())
|
2202
|
-
else:
|
2203
|
-
self.warning(f"当前session中不存在key为 {args[0]} 的 {name}, 请确认后重试.")
|
2204
|
-
|
2205
2305
|
elif len(args) == 2:
|
2206
|
-
|
2207
|
-
|
2306
|
+
if args[0].startswith(">"):
|
2307
|
+
group = args[0][1:]
|
2308
|
+
if args[1] == "on":
|
2309
|
+
cnt =self.enableGroup(group, True, True, type)
|
2310
|
+
cnt_total = sum(cnt)
|
2311
|
+
self.info(Settings.gettext("msg_group_objects_enabled", group, cnt_total, type.__name__))
|
2312
|
+
elif args[1] == "off":
|
2313
|
+
cnt =self.enableGroup(group, False, True, type)
|
2314
|
+
cnt_total = sum(cnt)
|
2315
|
+
self.info(Settings.gettext("msg_group_objects_disabled", group, cnt_total, type.__name__))
|
2316
|
+
elif args[1] == "del":
|
2317
|
+
cnt =self.deleteGroup(group, True, type)
|
2318
|
+
cnt_total = sum(cnt)
|
2319
|
+
self.info(Settings.gettext("msg_group_objects_deleted", group, cnt_total, type.__name__))
|
2320
|
+
|
2321
|
+
elif args[0].startswith("="):
|
2322
|
+
group = args[0][1:]
|
2323
|
+
if args[1] == "on":
|
2324
|
+
cnt =self.enableGroup(group, True, False, type)
|
2325
|
+
cnt_total = sum(cnt)
|
2326
|
+
self.info(Settings.gettext("msg_group_objects_enabled", group, cnt_total, type.__name__))
|
2327
|
+
elif args[1] == "off":
|
2328
|
+
cnt =self.enableGroup(group, False, False, type)
|
2329
|
+
cnt_total = sum(cnt)
|
2330
|
+
self.info(Settings.gettext("msg_group_objects_disabled", group, cnt_total, type.__name__))
|
2331
|
+
elif args[1] == "del":
|
2332
|
+
cnt =self.deleteGroup(group, False, type)
|
2333
|
+
cnt_total = sum(cnt)
|
2334
|
+
self.info(Settings.gettext("msg_group_objects_deleted", group, cnt_total, type.__name__))
|
2335
|
+
|
2336
|
+
elif args[0] in objs.keys():
|
2208
2337
|
obj = objs[args[0]]
|
2209
2338
|
if args[1] == "on":
|
2210
2339
|
obj.enabled = True
|
2211
|
-
self.info(
|
2340
|
+
self.info(Settings.gettext("msg_object_enabled", obj.__repr__()))
|
2212
2341
|
elif args[1] == "off":
|
2213
2342
|
obj.enabled = False
|
2214
|
-
self.info(
|
2343
|
+
self.info(Settings.gettext("msg_object_disabled", obj.__repr__()))
|
2215
2344
|
elif args[1] == "del":
|
2345
|
+
if hasattr(obj, "__unload__"):
|
2346
|
+
obj.__unload__()
|
2347
|
+
if hasattr(obj, "unload"):
|
2348
|
+
obj.unload()
|
2216
2349
|
obj.enabled = False
|
2217
2350
|
objs.pop(args[0])
|
2218
|
-
self.info(
|
2351
|
+
self.info(Settings.gettext("msg_object_deleted", obj.__repr__()))
|
2219
2352
|
else:
|
2220
|
-
self.error(
|
2353
|
+
self.error(Settings.gettext("msg_invalid_param", type.__name__.lower()))
|
2221
2354
|
|
2222
|
-
# 当第一个参数为不是对象obj名称时,创建新对象 (此处还有BUG,调试中)
|
2223
2355
|
else:
|
2224
|
-
#self.warning(f"当前session中不存在key为 {args[0]} 的 {name}, 请确认后重试.")
|
2225
2356
|
pattern, code = args[0], args[1]
|
2226
2357
|
if (len(pattern)>=2) and (pattern[0] == '{') and (pattern[-1] == '}'):
|
2227
2358
|
pattern = pattern[1:-1]
|
2228
2359
|
|
2229
|
-
|
2230
|
-
if name == "alias":
|
2360
|
+
if type == Alias:
|
2231
2361
|
ali = SimpleAlias(self, pattern, code)
|
2232
2362
|
self.addAlias(ali)
|
2233
|
-
self.info("
|
2234
|
-
elif
|
2363
|
+
self.info(Settings.gettext("msg_alias_created", ali.id, ali.__repr__()))
|
2364
|
+
elif type == Trigger:
|
2235
2365
|
tri = SimpleTrigger(self, pattern, code)
|
2236
2366
|
self.addTrigger(tri)
|
2237
|
-
self.info("
|
2238
|
-
elif
|
2367
|
+
self.info(Settings.gettext("msg_trigger_created", tri.id, tri.__repr__()))
|
2368
|
+
elif type == Timer:
|
2239
2369
|
if pattern.isnumeric():
|
2240
2370
|
timeout = float(pattern)
|
2241
2371
|
if timeout > 0:
|
2242
2372
|
ti = SimpleTimer(self, code, timeout = timeout)
|
2243
2373
|
self.addTimer(ti)
|
2244
|
-
self.info("
|
2374
|
+
self.info(Settings.gettext("msg_timer_created", ti.id, ti.__repr__()))
|
2245
2375
|
|
2246
|
-
def handle_alias(self, code: CodeLine
|
2376
|
+
def handle_alias(self, code: CodeLine, *args, **kwargs):
|
2247
2377
|
r"""
|
2248
2378
|
嵌入命令 #alias / #ali 的执行函数,操作别名。该命令可以不带参数、带一个参数或者两个参数。
|
2249
2379
|
该函数不应该在代码中直接调用。
|
@@ -2253,10 +2383,14 @@ class Session:
|
|
2253
2383
|
- #ali {ali_id}: 显示本会话中id为{ali_id}的别名信息
|
2254
2384
|
- #ali {ali_id} {on/off/del}: 使能/禁用/删除本会话中id为{ali_id}的别名
|
2255
2385
|
- #ali {pattern} {code}: 创建一个新别名,匹配为{pattern},匹配时执行{code}
|
2386
|
+
- #ali [>=]{groupname}: 显示本会话中组名为{groupname}(当为=时)及其子组(当为>时)的所有别名
|
2387
|
+
- #ali [>=]{groupname} {on/off/del}: 使能/禁用/删除本会话中组名为groupname(当为=时)及其子组(当为>时)的所有别名
|
2256
2388
|
- 别名的code中,可以使用%line代表行,%1~%9代表捕获信息
|
2257
2389
|
|
2258
2390
|
参数:
|
2259
2391
|
:ali_id: 别名Alias的id
|
2392
|
+
:>/=: 二者选择其一,标记第二个参数为组名,且指定是否包含子组。当为=时,表示仅指定组,当为>时,表示指定组及其子组。
|
2393
|
+
:groupname: 组名,即 alias 的 group 属性
|
2260
2394
|
:on: 使能
|
2261
2395
|
:off: 禁用
|
2262
2396
|
:del: 删除
|
@@ -2266,9 +2400,13 @@ class Session:
|
|
2266
2400
|
示例:
|
2267
2401
|
- ``#ali`` : 无参数, 打印列出当前会话中所有的别名清单
|
2268
2402
|
- ``#ali my_ali`` : 一个参数, 列出id为my_ali的Alias对象的详细信息
|
2403
|
+
- ``#ali =mygroup`` : 一个参数,列出所有 group 名为 "mygroup" 的 Alias 对象的详细信息
|
2404
|
+
- ``#ali >mygroup`` : 一个参数,列出所有 group 名为 "mygroup" 或以 "mygroup." 开头的下级组(子组,比如 mygroup.subgroup1, mygroup.subgroup2 等)内的 Alias 对象的详细信息
|
2269
2405
|
- ``#ali my_ali on`` : 两个参数,启用id为my_ali的Alias对象(enabled = True)
|
2270
2406
|
- ``#ali my_ali off`` : 两个参数, 禁用id为my_ali的Alias对象(enabled = False)
|
2271
2407
|
- ``#ali my_ali del`` : 两个参数,删除id为my_ali的Alias对象
|
2408
|
+
- ``#ali =mygroup on`` : 两个参数,启用所有 group 名为 "mygroup" 的 Alias 对象
|
2409
|
+
- ``#ali >mygroup off`` : 两个参数,禁用所有 group 名为 "mygroup" 或以 "mygroup." 开头的下级组(子组,比如 mygroup.subgroup1, mygroup.subgroup2 等)内的 Alias 对象
|
2272
2410
|
- ``#ali {^gp\s(.+)$} {get %1 from corpse}`` : 两个参数,新增创建一个Alias对象。使用时, ``gp gold = get gold from corpse``
|
2273
2411
|
|
2274
2412
|
相关命令:
|
@@ -2277,9 +2415,9 @@ class Session:
|
|
2277
2415
|
- #command
|
2278
2416
|
"""
|
2279
2417
|
|
2280
|
-
self._handle_objs(
|
2418
|
+
self._handle_objs(Alias, self._aliases, *code.code[2:])
|
2281
2419
|
|
2282
|
-
def handle_timer(self, code: CodeLine
|
2420
|
+
def handle_timer(self, code: CodeLine, *args, **kwargs):
|
2283
2421
|
'''
|
2284
2422
|
嵌入命令 #timer / #ti 的执行函数,操作定时器。该命令可以不带参数、带一个参数或者两个参数。
|
2285
2423
|
该函数不应该在代码中直接调用。
|
@@ -2288,11 +2426,15 @@ class Session:
|
|
2288
2426
|
- #ti: 显示本会话所有定时器
|
2289
2427
|
- #ti {ti_id}: 显示本会话中id为{ti_id}的定时器信息
|
2290
2428
|
- #ti {ti_id} {on/off/del}: 使能/禁用/删除本会话中id为{ti_id}的定时器
|
2429
|
+
- #ti [>=]{groupname}: 显示本会话中组名为{groupname}(当为=时)及其子组(当为>时)的所有定时器
|
2430
|
+
- #ti [>=]{groupname} {on/off/del}: 使能/禁用/删除本会话中组名为groupname(当为=时)及其子组(当为>时)的所有定时器
|
2291
2431
|
- #ti {second} {code}: 创建一个新定时器,定时间隔为{second}秒,定时器到时间执行{code}
|
2292
2432
|
- PyMUD支持同时任意多个定时器。
|
2293
2433
|
|
2294
2434
|
参数:
|
2295
2435
|
:ti_id: 定时器Timer的id
|
2436
|
+
:>/=: 二者选择其一,标记第二个参数为组名,且指定是否包含子组。当为=时,表示仅指定组,当为>时,表示指定组及其子组。
|
2437
|
+
:groupname: 组名,即 timer 的 group 属性
|
2296
2438
|
:on: 使能
|
2297
2439
|
:off: 禁用
|
2298
2440
|
:del: 删除
|
@@ -2302,9 +2444,13 @@ class Session:
|
|
2302
2444
|
示例:
|
2303
2445
|
- ``#ti``: 无参数, 打印列出当前会话中所有的定时器清单
|
2304
2446
|
- ``#ti my_timer``: 一个参数, 列出id为my_timer的Timer对象的详细信息
|
2447
|
+
- ``#ti =mygroup``: 一个参数,列出所有 group 名为 "mygroup" 的 Timer 对象的详细信息
|
2448
|
+
- ``#ti >mygroup``: 一个参数,列出所有 group 名为 "mygroup" 或以 "mygroup." 开头的下级组(子组,比如 mygroup.subgroup1, mygroup.subgroup2 等)内的 Timer 对象的详细信息
|
2305
2449
|
- ``#ti my_timer on``: 两个参数,启用id为my_timer的Timer对象(enabled = True)
|
2306
2450
|
- ``#ti my_timer off``: 两个参数, 禁用id为my_timer的Timer对象(enabled = False)
|
2307
2451
|
- ``#ti my_timer del``: 两个参数,删除id为my_timer的Timer对象
|
2452
|
+
- ``#ti =mygroup on``: 两个参数,启用所有 group 名为 "mygroup" 的 Timer 对象
|
2453
|
+
- ``#ti >mygroup off``: 两个参数,禁用所有 group 名为 "mygroup" 或以 "mygroup." 开头的下级组(子组,比如 mygroup.subgroup1, mygroup.subgroup2 等)内的 Timer 对象
|
2308
2454
|
- ``#ti 100 {drink jiudai;#wa 200;eat liang}``: 两个参数,新增创建一个Timer对象。每隔100s,自动执行一次喝酒袋吃干粮。
|
2309
2455
|
|
2310
2456
|
相关命令:
|
@@ -2313,9 +2459,9 @@ class Session:
|
|
2313
2459
|
- #command
|
2314
2460
|
'''
|
2315
2461
|
|
2316
|
-
self._handle_objs(
|
2462
|
+
self._handle_objs(Timer, self._timers, *code.code[2:])
|
2317
2463
|
|
2318
|
-
def handle_command(self, code: CodeLine
|
2464
|
+
def handle_command(self, code: CodeLine, *args, **kwargs):
|
2319
2465
|
'''
|
2320
2466
|
嵌入命令 #command / #cmd 的执行函数,操作命令。该命令可以不带参数、带一个参数或者两个参数。
|
2321
2467
|
该函数不应该在代码中直接调用。
|
@@ -2324,10 +2470,14 @@ class Session:
|
|
2324
2470
|
- #cmd: 显示本会话所有命令(Command及其子类)
|
2325
2471
|
- #cmd {cmd_id}: 显示本会话中id为{cmd_id}的命令信息
|
2326
2472
|
- #cmd {cmd_id} {on/off/del}: 使能/禁用/删除本会话中id为{cmd_id}的命令
|
2473
|
+
- #cmd [>=]{groupname}: 显示本会话中组名为{groupname}(当为=时)及其子组(当为>时)的所有命令
|
2474
|
+
- #cmd [>=]{groupname} {on/off/del}: 使能/禁用/删除本会话中组名为groupname(当为=时)及其子组(当为>时)的所有命令
|
2327
2475
|
- 由于命令的特殊性,其只能使用脚本代码创建
|
2328
2476
|
|
2329
2477
|
参数:
|
2330
2478
|
:cmd_id: 命令Command的id
|
2479
|
+
:>/=: 二者选择其一,标记第二个参数为组名,且指定是否包含子组。当为=时,表示仅指定组,当为>时,表示指定组及其子组。
|
2480
|
+
:groupname: 组名,即 command 的 group 属性
|
2331
2481
|
:on: 使能
|
2332
2482
|
:off: 禁用
|
2333
2483
|
:del: 删除
|
@@ -2335,9 +2485,13 @@ class Session:
|
|
2335
2485
|
示例:
|
2336
2486
|
- ``#cmd`` : 无参数, 打印列出当前会话中所有的命令清单
|
2337
2487
|
- ``#cmd my_cmd`` : 一个参数, 列出id为my_cmd的Command对象的详细信息
|
2488
|
+
- ``#cmd =mygroup`` : 一个参数,列出所有 group 名为 "mygroup" 的 Command 对象的详细信息
|
2489
|
+
- ``#cmd >mygroup`` : 一个参数,列出所有 group 名为 "mygroup" 或以 "mygroup." 开头的下级组(子组,比如 mygroup.subgroup1, mygroup.subgroup2 等)内的 Command 对象的详细信息
|
2338
2490
|
- ``#cmd my_cmd on`` : 两个参数,启用id为my_cmd的Command对象(enabled = True)
|
2339
2491
|
- ``#cmd my_cmd off`` : 两个参数, 禁用id为my_cmd的Command对象(enabled = False)
|
2340
2492
|
- ``#cmd my_cmd del`` : 两个参数,删除id为my_cmd的Command对象
|
2493
|
+
- ``#cmd =mygroup on`` : 两个参数,启用所有 group 名为 "mygroup" 的 Command 对象
|
2494
|
+
- ``#cmd >mygroup off`` : 两个参数,禁用所有 group 名为 "mygroup" 或以 "mygroup." 开头的下级组(子组,比如 mygroup.subgroup1, mygroup.subgroup2 等)内的 Command 对象
|
2341
2495
|
|
2342
2496
|
相关命令:
|
2343
2497
|
- #alias
|
@@ -2345,9 +2499,9 @@ class Session:
|
|
2345
2499
|
- #timer
|
2346
2500
|
'''
|
2347
2501
|
|
2348
|
-
self._handle_objs(
|
2502
|
+
self._handle_objs(Command, self._commands, *code.code[2:])
|
2349
2503
|
|
2350
|
-
def handle_trigger(self, code: CodeLine
|
2504
|
+
def handle_trigger(self, code: CodeLine, *args, **kwargs):
|
2351
2505
|
'''
|
2352
2506
|
嵌入命令 #trigger / #tri / #action 的执行函数,操作触发器。该命令可以不带参数、带一个参数或者两个参数。
|
2353
2507
|
该函数不应该在代码中直接调用。
|
@@ -2356,11 +2510,15 @@ class Session:
|
|
2356
2510
|
- #tri: 显示本会话所有触发器
|
2357
2511
|
- #tri {tri_id}: 显示本会话中id为{tri_id}的触发器信息
|
2358
2512
|
- #tri {tri_id} {on/off/del}: 使能/禁用/删除本会话中id为{tri_id}的触发器
|
2513
|
+
- #tri [>=]{groupname}: 显示本会话中组名为{groupname}(当为=时)及其子组(当为>时)的所有触发器
|
2514
|
+
- #tri [>=]{groupname} {on/off/del}: 使能/禁用/删除本会话中组名为groupname(当为=时)及其子组(当为>时)的所有触发器
|
2359
2515
|
- #tri {pattern} {code}: 创建一个新触发器,匹配为{pattern},匹配时执行{code}
|
2360
2516
|
- 触发器的code中,可以使用%line代表行,%1~%9代表捕获信息
|
2361
2517
|
|
2362
2518
|
参数:
|
2363
2519
|
:tri_id: 触发器Trigger的id
|
2520
|
+
:[>=]: 二者选择其一,标记第二个参数为组名,且指定是否包含子组。当为=时,表示仅指定组,当为>时,表示指定组及其子组。
|
2521
|
+
:groupname: 组名,即 trigger 的 group 属性
|
2364
2522
|
:on: 使能
|
2365
2523
|
:off: 禁用
|
2366
2524
|
:del: 删除
|
@@ -2370,9 +2528,13 @@ class Session:
|
|
2370
2528
|
示例:
|
2371
2529
|
- ``#tri``: 无参数, 打印列出当前会话中所有的触发器清单
|
2372
2530
|
- ``#tri my_tri``: 一个参数, 列出id为my_tri的Trigger对象的详细信息
|
2531
|
+
- ``#tri =mygroup``: 一个参数,列出所有 group 名为 "mygroup" 的 Trigger 对象的详细信息
|
2532
|
+
- ``#tri >mygroup``: 一个参数,列出所有 group 名为 "mygroup" 或以 "mygroup." 开头的下级组(子组,比如 mygroup.subgroup1, mygroup.subgroup2 等)内的 Trigger 对象的详细信息
|
2373
2533
|
- ``#tri my_tri on``: 两个参数,启用id为my_tri的Trigger对象(enabled = True)
|
2374
2534
|
- ``#tri my_tri off``: 两个参数, 禁用id为my_tri的Trigger对象(enabled = False)
|
2375
2535
|
- ``#tri my_tri del``: 两个参数,删除id为my_tri的Trigger对象
|
2536
|
+
- ``#tri =mygroup on``: 两个参数,启用所有 group 名为 "mygroup" 的 Trigger 对象
|
2537
|
+
- ``#tri >mygroup off``: 两个参数,禁用所有 group 名为 "mygroup" 或以 "mygroup." 开头的下级组(子组,比如 mygroup.subgroup1, mygroup.subgroup2 等)内的 Trigger 对象
|
2376
2538
|
- ``#tri {^[> ]*段誉脚下一个不稳.+} {get duan}``: 两个参数,新增创建一个Trigger对象。当段誉被打倒的时刻把他背起来。
|
2377
2539
|
|
2378
2540
|
相关命令:
|
@@ -2381,9 +2543,9 @@ class Session:
|
|
2381
2543
|
- #command
|
2382
2544
|
'''
|
2383
2545
|
|
2384
|
-
self._handle_objs(
|
2546
|
+
self._handle_objs(Trigger, self._triggers, *code.code[2:])
|
2385
2547
|
|
2386
|
-
def handle_task(self, code: CodeLine = None, *args, **kwargs):
|
2548
|
+
def handle_task(self, code: Optional[CodeLine] = None, *args, **kwargs):
|
2387
2549
|
'''
|
2388
2550
|
嵌入命令 #task 的执行函数,显示当前管理的所有任务清单(仅用于调试)。
|
2389
2551
|
该函数不应该在代码中直接调用。
|
@@ -2404,24 +2566,28 @@ class Session:
|
|
2404
2566
|
self.writetobuffer("="*width, newline = True)
|
2405
2567
|
|
2406
2568
|
|
2407
|
-
def handle_ignore(self, code: CodeLine
|
2569
|
+
def handle_ignore(self, code: CodeLine, *args, **kwargs):
|
2408
2570
|
'''
|
2409
2571
|
嵌入命令 #ignore / #ig, #t+ / #t- 的执行函数,处理使能/禁用状态。
|
2410
2572
|
该函数不应该在代码中直接调用。
|
2411
2573
|
|
2412
2574
|
使用:
|
2413
2575
|
- #ig: 切换触发器全局使能/禁用状态
|
2414
|
-
- #t+ {group}: 使能{group}组内的所有对象,包括别名、触发器、命令、定时器、GMCPTrigger等
|
2415
|
-
- #t- {group}: 禁用{group}组内的所有对象,包括别名、触发器、命令、定时器、GMCPTrigger等
|
2576
|
+
- #t+ [>=]{group}: 使能{group}组内的所有对象,包括别名、触发器、命令、定时器、GMCPTrigger等
|
2577
|
+
- #t- [>=]{group}: 禁用{group}组内的所有对象,包括别名、触发器、命令、定时器、GMCPTrigger等
|
2416
2578
|
|
2417
2579
|
参数:
|
2418
|
-
:group:
|
2580
|
+
:group: 组名。可以在组名前带 '=', '>' 表示对当前组生效或对当前组及子组同时生效。当省略 >/= 时,相当于 =,即仅对当前组生效。
|
2419
2581
|
|
2420
2582
|
示例:
|
2421
2583
|
- ``#ig``: 切换全局触发器的使能/禁用状态。为禁用时,状态栏右下角会显示“全局已禁用”
|
2422
2584
|
- ``#t+ mygroup``: 使能名称为 mygroup 的组内的所有对象,包括别名、触发器、命令、定时器、GMCPTrigger等
|
2423
2585
|
- ``#t- mygroup``: 禁用名称为 mygroup 的组内的所有对象,包括别名、触发器、命令、定时器、GMCPTrigger等
|
2586
|
+
- ``#t+ >mygroup``: 使能名称为 mygroup 的组及子组(所有以 mygroup. 开头的其他组,如 mygroup.subgroup)内的所有对象,包括别名、触发器、命令、定时器、GMCPTrigger等
|
2424
2587
|
|
2588
|
+
注意:
|
2589
|
+
使用#t+/#t-调用时,相当于enableGroup传递的默认参数,即subgroup为True, 且types为所有类型。
|
2590
|
+
|
2425
2591
|
相关命令:
|
2426
2592
|
- #trigger
|
2427
2593
|
- #alias
|
@@ -2432,28 +2598,42 @@ class Session:
|
|
2432
2598
|
if cmd in ("ig", "ignore"):
|
2433
2599
|
self._ignore = not self._ignore
|
2434
2600
|
if self._ignore:
|
2435
|
-
self.info("
|
2601
|
+
self.info(Settings.gettext("msg_ignore_on"))
|
2436
2602
|
else:
|
2437
|
-
self.info("
|
2603
|
+
self.info(Settings.gettext("msg_ignore_off"))
|
2438
2604
|
elif cmd == "t+":
|
2439
2605
|
if code.length <= 2:
|
2440
|
-
self.warning("
|
2606
|
+
self.warning(Settings.gettext("msg_T_plus_incorrect"))
|
2441
2607
|
return
|
2442
2608
|
|
2443
2609
|
groupname = code.code[2]
|
2444
|
-
|
2445
|
-
|
2610
|
+
# 组名支持=, >两种,分别代表仅当前组组,当前组及子组
|
2611
|
+
# #t+、t-不指定 >, =时,按 = 处理
|
2612
|
+
if groupname.startswith(">"):
|
2613
|
+
cnts = self.enableGroup(groupname[1:])
|
2614
|
+
elif groupname.startswith("="):
|
2615
|
+
cnts = self.enableGroup(groupname[1:], subgroup = False)
|
2616
|
+
else:
|
2617
|
+
cnts = self.enableGroup(groupname, subgroup = False)
|
2618
|
+
|
2619
|
+
self.info(Settings.gettext("msg_group_enabled", groupname, *cnts))
|
2446
2620
|
|
2447
2621
|
elif cmd == "t-":
|
2448
2622
|
if code.length <= 2:
|
2449
|
-
self.warning("
|
2623
|
+
self.warning(Settings.gettext("msg_T_minus_incorrect"))
|
2450
2624
|
return
|
2451
2625
|
|
2452
2626
|
groupname = code.code[2]
|
2453
|
-
|
2454
|
-
|
2627
|
+
if groupname.startswith(">"):
|
2628
|
+
cnts = self.enableGroup(groupname[1:], False)
|
2629
|
+
elif groupname.startswith("="):
|
2630
|
+
cnts = self.enableGroup(groupname[1:], False, subgroup = False)
|
2631
|
+
else:
|
2632
|
+
cnts = self.enableGroup(groupname, False)
|
2455
2633
|
|
2456
|
-
|
2634
|
+
self.info(Settings.gettext("msg_group_disabled", groupname, *cnts))
|
2635
|
+
|
2636
|
+
def handle_repeat(self, code: Optional[CodeLine] = None, *args, **kwargs):
|
2457
2637
|
'''
|
2458
2638
|
嵌入命令 #repeat / #rep 的执行函数,重复向session输出上一次人工输入的命令。
|
2459
2639
|
该函数不应该在代码中直接调用。
|
@@ -2468,9 +2648,9 @@ class Session:
|
|
2468
2648
|
if self.connected and self.last_command:
|
2469
2649
|
self.exec_command(self.last_command)
|
2470
2650
|
else:
|
2471
|
-
self.info("
|
2651
|
+
self.info(Settings.gettext("msg_repeat_invalid"))
|
2472
2652
|
|
2473
|
-
async def handle_num(self, times, code: CodeLine
|
2653
|
+
async def handle_num(self, times, code: CodeLine, *args, **kwargs):
|
2474
2654
|
'''
|
2475
2655
|
嵌入命令 #{num} 的执行函数,重复执行多次命令。
|
2476
2656
|
该函数不应该在代码中直接调用。
|
@@ -2499,7 +2679,7 @@ class Session:
|
|
2499
2679
|
for i in range(0, times):
|
2500
2680
|
await cmd.async_execute(self, *args, **kwargs)
|
2501
2681
|
|
2502
|
-
def handle_gmcp(self, code: CodeLine
|
2682
|
+
def handle_gmcp(self, code: CodeLine, *args, **kwargs):
|
2503
2683
|
'''
|
2504
2684
|
嵌入命令 #gmcp 的执行函数,操作GMCPTrigger。该命令可以不带参数、带一个参数或者两个参数。
|
2505
2685
|
该函数不应该在代码中直接调用。
|
@@ -2508,10 +2688,14 @@ class Session:
|
|
2508
2688
|
- #gmcp: 显示本会话所有GMCPTrigger
|
2509
2689
|
- #gmcp {gmcp_key}: 显示本会话中name为{gmcp_key}的GMCPTrigger信息
|
2510
2690
|
- #gmcp {gmcp_key} {on/off/del}: 使能/禁用/删除本会话中name为{gmcp_key}的GMCPTrigger
|
2691
|
+
- #gmcp [>=]{groupname}: 显示本会话中组名为{groupname}(当为=时)及其子组(当为>时)的所有GMCPTrigger
|
2692
|
+
- #gmcp [>=]{groupname} {on/off/del}: 使能/禁用/删除本会话中group为{groupname}的GMCPTrigger
|
2511
2693
|
- 由于GMCPTrigger的特殊性,其只能使用脚本代码创建
|
2512
2694
|
|
2513
2695
|
参数:
|
2514
2696
|
:gmcp_key: GMCPTrigger的关键字name
|
2697
|
+
:>/=: 二者选择其一,标记第二个参数为组名,且指定是否包含子组。当为=时,表示仅指定组,当为>时,表示指定组及其子组。
|
2698
|
+
:groupname: 组名,即 gmcp 的 group 属性。虽然GMCP大概率不会使用group,但仍支持此功能。
|
2515
2699
|
:on: 使能
|
2516
2700
|
:off: 禁用
|
2517
2701
|
:del: 删除
|
@@ -2529,9 +2713,9 @@ class Session:
|
|
2529
2713
|
- #timer
|
2530
2714
|
'''
|
2531
2715
|
|
2532
|
-
self._handle_objs(
|
2716
|
+
self._handle_objs(GMCPTrigger, self._gmcp, *code.code[2:])
|
2533
2717
|
|
2534
|
-
def handle_message(self, code: CodeLine
|
2718
|
+
def handle_message(self, code: CodeLine, *args, **kwargs):
|
2535
2719
|
'''
|
2536
2720
|
嵌入命令 #message / #mess 的执行函数,弹出对话框显示给定信息。
|
2537
2721
|
该函数不应该在代码中直接调用。
|
@@ -2547,14 +2731,14 @@ class Session:
|
|
2547
2731
|
- ``#mess %line`` : 使用弹出窗口显示系统变量%line的值
|
2548
2732
|
'''
|
2549
2733
|
|
2550
|
-
title = "
|
2734
|
+
title = Settings.gettext("msg_window_title", self.name)
|
2551
2735
|
|
2552
2736
|
new_cmd_text, new_code = code.expand(self, *args, **kwargs)
|
2553
2737
|
index = new_cmd_text.find(" ")
|
2554
2738
|
self.application.show_message(title, new_cmd_text[index:], False)
|
2555
2739
|
|
2556
2740
|
|
2557
|
-
def handle_all(self, code: CodeLine
|
2741
|
+
def handle_all(self, code: CodeLine, *args, **kwargs):
|
2558
2742
|
'''
|
2559
2743
|
嵌入命令 #all 的执行函数,向所有会话发送统一命令。
|
2560
2744
|
该函数不应该在代码中直接调用。
|
@@ -2657,7 +2841,13 @@ class Session:
|
|
2657
2841
|
def _load_module(self, module_name):
|
2658
2842
|
"加载指定名称模块"
|
2659
2843
|
try:
|
2660
|
-
if module_name
|
2844
|
+
if module_name in self.application.plugins.keys():
|
2845
|
+
plugin = self.application.plugins[module_name]
|
2846
|
+
if isinstance(plugin, Plugin):
|
2847
|
+
plugin.onSessionCreate(self)
|
2848
|
+
self.info(Settings.gettext("msg_plugin_loaded", module_name))
|
2849
|
+
|
2850
|
+
elif module_name not in self._modules.keys():
|
2661
2851
|
self._modules[module_name] = ModuleInfo(module_name, self)
|
2662
2852
|
|
2663
2853
|
else:
|
@@ -2667,8 +2857,8 @@ class Session:
|
|
2667
2857
|
|
2668
2858
|
except Exception as e:
|
2669
2859
|
import traceback
|
2670
|
-
self.error(
|
2671
|
-
self.error(
|
2860
|
+
self.error(Settings.gettext("msg_module_load_fail", module_name, e, type(e)))
|
2861
|
+
self.error(Settings.gettext("msg_exception_traceback", traceback.format_exc()))
|
2672
2862
|
|
2673
2863
|
def unload_module(self, module_names):
|
2674
2864
|
"""
|
@@ -2695,8 +2885,14 @@ class Session:
|
|
2695
2885
|
if isinstance(mod, ModuleInfo):
|
2696
2886
|
mod.unload()
|
2697
2887
|
|
2888
|
+
elif module_name in self.application.plugins.keys():
|
2889
|
+
plugin = self.application.plugins[module_name]
|
2890
|
+
if isinstance(plugin, Plugin):
|
2891
|
+
plugin.onSessionDestroy(self)
|
2892
|
+
self.info(Settings.gettext("msg_plugin_unloaded", module_name))
|
2893
|
+
|
2698
2894
|
else:
|
2699
|
-
self.warning(
|
2895
|
+
self.warning(Settings.gettext("msg_module_not_loaded", module_name))
|
2700
2896
|
|
2701
2897
|
def reload_module(self, module_names = None):
|
2702
2898
|
"""
|
@@ -2711,7 +2907,7 @@ class Session:
|
|
2711
2907
|
if isinstance(module, ModuleInfo):
|
2712
2908
|
module.reload()
|
2713
2909
|
|
2714
|
-
self.info(
|
2910
|
+
self.info(Settings.gettext("msg_all_module_reloaded"))
|
2715
2911
|
|
2716
2912
|
elif isinstance(module_names, (list, tuple)):
|
2717
2913
|
for mod in module_names:
|
@@ -2721,7 +2917,7 @@ class Session:
|
|
2721
2917
|
if isinstance(module, ModuleInfo):
|
2722
2918
|
module.reload()
|
2723
2919
|
else:
|
2724
|
-
self.warning(
|
2920
|
+
self.warning(Settings.gettext("msg_module_not_loaded", mod))
|
2725
2921
|
|
2726
2922
|
elif isinstance(module_names, str):
|
2727
2923
|
if module_names in self._modules.keys():
|
@@ -2729,10 +2925,10 @@ class Session:
|
|
2729
2925
|
if isinstance(module, ModuleInfo):
|
2730
2926
|
module.reload()
|
2731
2927
|
else:
|
2732
|
-
self.warning(
|
2928
|
+
self.warning(Settings.gettext("msg_module_not_loaded", module_names))
|
2733
2929
|
|
2734
2930
|
|
2735
|
-
def handle_load(self, code: CodeLine
|
2931
|
+
def handle_load(self, code: CodeLine, *args, **kwargs):
|
2736
2932
|
'''
|
2737
2933
|
嵌入命令 #load 的执行函数,为当前会话执行模块加载操作。当要加载多个模块时,使用空格或英文逗号隔开。
|
2738
2934
|
该函数不应该在代码中直接调用。
|
@@ -2761,7 +2957,7 @@ class Session:
|
|
2761
2957
|
modules = ",".join(code.code[2:]).split(",")
|
2762
2958
|
self.load_module(modules)
|
2763
2959
|
|
2764
|
-
def handle_reload(self, code: CodeLine = None, *args, **kwargs):
|
2960
|
+
def handle_reload(self, code: Optional[CodeLine] = None, *args, **kwargs):
|
2765
2961
|
'''
|
2766
2962
|
嵌入命令 #reload 的执行函数,重新加载模块/插件。
|
2767
2963
|
该函数不应该在代码中直接调用。
|
@@ -2811,11 +3007,11 @@ class Session:
|
|
2811
3007
|
|
2812
3008
|
elif mod in self.plugins.keys():
|
2813
3009
|
self.application.reload_plugin(self.plugins[mod])
|
2814
|
-
self.info(
|
3010
|
+
self.info(Settings.gettext("msg_plugins_reloaded", mod))
|
2815
3011
|
else:
|
2816
|
-
self.warning(
|
3012
|
+
self.warning(Settings.gettext("msg_name_not_found", mod))
|
2817
3013
|
|
2818
|
-
def handle_unload(self, code: CodeLine
|
3014
|
+
def handle_unload(self, code: CodeLine, *args, **kwargs):
|
2819
3015
|
'''
|
2820
3016
|
嵌入命令 #unload 的执行函数,卸载模块。
|
2821
3017
|
该函数不应该在代码中直接调用。
|
@@ -2851,7 +3047,7 @@ class Session:
|
|
2851
3047
|
modules = ",".join(args).split(",")
|
2852
3048
|
self.unload_module(modules)
|
2853
3049
|
|
2854
|
-
def handle_modules(self, code: CodeLine
|
3050
|
+
def handle_modules(self, code: CodeLine, *args, **kwargs):
|
2855
3051
|
'''
|
2856
3052
|
嵌入命令 #modules / #mods 的执行函数,显示加载模块清单。该命令不带参数。
|
2857
3053
|
该函数不应该在代码中直接调用。
|
@@ -2870,9 +3066,9 @@ class Session:
|
|
2870
3066
|
if len(args) == 0:
|
2871
3067
|
count = len(self._modules.keys())
|
2872
3068
|
if count == 0:
|
2873
|
-
self.info("
|
3069
|
+
self.info(Settings.gettext("msg_no_module"), "MODULES")
|
2874
3070
|
else:
|
2875
|
-
self.info(
|
3071
|
+
self.info(Settings.gettext("msg_module_list", count, list(self._modules.keys()).__repr__()))
|
2876
3072
|
|
2877
3073
|
elif len(args) >= 1:
|
2878
3074
|
modules = ",".join(args).split(",")
|
@@ -2881,14 +3077,14 @@ class Session:
|
|
2881
3077
|
module = self._modules[mod]
|
2882
3078
|
if isinstance(module, ModuleInfo):
|
2883
3079
|
if module.ismainmodule:
|
2884
|
-
self.info(
|
3080
|
+
self.info(Settings.gettext("msg_module_configurations", module.name, ",".join(module.config.keys())))
|
2885
3081
|
else:
|
2886
|
-
self.info(
|
3082
|
+
self.info(Settings.gettext("msg_submodule_no_config"))
|
2887
3083
|
|
2888
3084
|
else:
|
2889
|
-
self.info(
|
3085
|
+
self.info(Settings.gettext("msg_module_not_loaded", mod))
|
2890
3086
|
|
2891
|
-
def handle_reset(self, code: CodeLine
|
3087
|
+
def handle_reset(self, code: CodeLine, *args, **kwargs):
|
2892
3088
|
'''
|
2893
3089
|
嵌入命令 #reset 的执行函数,复位全部脚本。该命令不带参数。
|
2894
3090
|
复位操作将复位所有的触发器、命令、未完成的任务,并清空所有触发器、命令、别名、变量。
|
@@ -2905,7 +3101,7 @@ class Session:
|
|
2905
3101
|
|
2906
3102
|
self.reset()
|
2907
3103
|
|
2908
|
-
def handle_save(self, code: CodeLine = None, *args, **kwargs):
|
3104
|
+
def handle_save(self, code: Optional[CodeLine] = None, *args, **kwargs):
|
2909
3105
|
'''
|
2910
3106
|
嵌入命令 #save 的执行函数,保存当前会话变量(系统变量和临时变量除外)至文件。该命令不带参数。
|
2911
3107
|
系统变量包括 %line, %copy 和 %raw 三个,临时变量是指变量名已下划线开头的变量
|
@@ -2924,7 +3120,11 @@ class Session:
|
|
2924
3120
|
- #variable
|
2925
3121
|
'''
|
2926
3122
|
|
2927
|
-
|
3123
|
+
muddir = Path.cwd().joinpath('save')
|
3124
|
+
if not muddir.exists() or not muddir.is_dir():
|
3125
|
+
muddir.mkdir()
|
3126
|
+
|
3127
|
+
file = muddir.joinpath(f"{self.name}.mud")
|
2928
3128
|
|
2929
3129
|
with open(file, "wb") as fp:
|
2930
3130
|
saved = dict()
|
@@ -2937,9 +3137,9 @@ class Session:
|
|
2937
3137
|
saved.pop("%raw", None)
|
2938
3138
|
saved.pop("%copy", None)
|
2939
3139
|
pickle.dump(saved, fp)
|
2940
|
-
self.info(
|
3140
|
+
self.info(Settings.gettext("msg_variables_saved", file))
|
2941
3141
|
|
2942
|
-
def handle_clear(self, code: CodeLine
|
3142
|
+
def handle_clear(self, code: CodeLine, *args, **kwargs):
|
2943
3143
|
'''
|
2944
3144
|
嵌入命令 #clear / #cls 的执行函数,清空当前会话缓冲与显示。
|
2945
3145
|
该函数不应该在代码中直接调用。
|
@@ -2950,28 +3150,32 @@ class Session:
|
|
2950
3150
|
|
2951
3151
|
self.buffer.text = ""
|
2952
3152
|
|
2953
|
-
|
3153
|
+
@exception
|
3154
|
+
def handle_test(self, code: CodeLine, *args, **kwargs):
|
2954
3155
|
'''
|
2955
|
-
嵌入命令 #test / #show 的执行函数,触发器测试命令。类似于zmud的#show命令。
|
3156
|
+
嵌入命令 #test / #show / #echo 的执行函数,触发器测试命令。类似于zmud的#show命令。
|
2956
3157
|
该函数不应该在代码中直接调用。
|
2957
3158
|
|
2958
3159
|
使用:
|
2959
|
-
- #
|
2960
|
-
- #
|
3160
|
+
- #show {some_text}: 测试收到服务器{some_text}时的触发器响应情况。此时,触发器不会真的响应。
|
3161
|
+
- #test {some_test}: 与#show 的差异是,若存在匹配的触发器,无论其是否被使能,该触发器均会实际响应。
|
3162
|
+
- #echo {some_text}: 模拟收到服务器 {some_text}的情况,触发器按正常情况响应,但不会显示测试结果。
|
2961
3163
|
|
2962
3164
|
示例:
|
2963
|
-
- ``#
|
3165
|
+
- ``#show 你深深吸了口气,站了起来。`` : 模拟收到服务器“你深深吸了口气,站了起来。”时的情况进行触发测试(仅显示触发测试情况)
|
2964
3166
|
- ``#test %copy``: 复制一句话,模拟服务器再次收到复制的这句内容时的情况进行触发器测试
|
2965
|
-
- ``#test 你深深吸了口气,站了起来。`` :
|
3167
|
+
- ``#test 你深深吸了口气,站了起来。`` : 模拟收到服务器“你深深吸了口气,站了起来。”时的情况进行触发测试(会实际导致触发器动作)
|
3168
|
+
- ``#echo 你深深吸了口气,站了起来。`` : 模拟收到服务器“你深深吸了口气,站了起来。”时的情况进行触发测试(不会显示测试结果)
|
2966
3169
|
|
2967
3170
|
注意:
|
2968
|
-
- #
|
2969
|
-
- #
|
3171
|
+
- #show命令测试触发器时,触发器不会真的响应。
|
3172
|
+
- #test命令测试触发器时,触发器无论是否使能,均会真的响应。
|
3173
|
+
- #echo命令可以用来人工激发触发器。
|
2970
3174
|
'''
|
2971
3175
|
cmd = code.code[1].lower()
|
2972
|
-
docallback =
|
2973
|
-
if cmd == "
|
2974
|
-
docallback =
|
3176
|
+
docallback = True
|
3177
|
+
if cmd == "show":
|
3178
|
+
docallback = False
|
2975
3179
|
|
2976
3180
|
new_cmd_text, new_code = code.expand(self, *args, **kwargs)
|
2977
3181
|
line = new_cmd_text[6:] # 取出#test 之后的所有内容
|
@@ -2997,6 +3201,10 @@ class Session:
|
|
2997
3201
|
tris_disabled.sort(key = lambda tri: tri.priority)
|
2998
3202
|
|
2999
3203
|
for raw_line in lines:
|
3204
|
+
# echo 模式下,直接将原始数据输出到窗口,并进行触发测试
|
3205
|
+
if cmd == "echo":
|
3206
|
+
self.writetobuffer(raw_line, True)
|
3207
|
+
|
3000
3208
|
tri_line = self.getPlainText(raw_line)
|
3001
3209
|
|
3002
3210
|
block = False
|
@@ -3006,67 +3214,76 @@ class Session:
|
|
3006
3214
|
else:
|
3007
3215
|
state = tri.match(tri_line, docallback = docallback)
|
3008
3216
|
|
3009
|
-
if state.result == Trigger.SUCCESS:
|
3217
|
+
if state and (state.result == Trigger.SUCCESS):
|
3010
3218
|
triggered_enabled += 1
|
3011
3219
|
if not block:
|
3012
3220
|
triggered += 1
|
3013
|
-
|
3014
|
-
|
3015
|
-
info_enabled.append(f" {tri.__detailed__()} 正常触发。")
|
3016
|
-
info_enabled.append(f" 捕获:{state.wildcards}")
|
3221
|
+
info_enabled.append(Settings.gettext("msg_tri_triggered", tri.__detailed__()))
|
3222
|
+
info_enabled.append(Settings.gettext("msg_tri_wildcards", state.wildcards))
|
3017
3223
|
|
3018
3224
|
if not tri.keepEval: # 非持续匹配的trigger,匹配成功后停止检测后续Trigger
|
3019
|
-
info_enabled.append(
|
3020
|
-
#info_enabled.append(f"
|
3225
|
+
info_enabled.append(Settings.gettext("msg_tri_prevent", Settings.WARN_STYLE, Settings.CLR_STYLE))
|
3226
|
+
#info_enabled.append(f" {Settings.WARN_STYLE}该触发器未开启keepEval, 会阻止后续触发器。{Settings.CLR_STYLE}")
|
3021
3227
|
block = True
|
3022
3228
|
else:
|
3023
|
-
info_enabled.append(
|
3024
|
-
#info_enabled.append(f"
|
3229
|
+
info_enabled.append(Settings.gettext("msg_tri_ignored", tri.__detailed__(), Settings.WARN_STYLE, Settings.CLR_STYLE))
|
3230
|
+
# info_enabled.append(f" {Settings.WARN_STYLE}{tri.__detailed__()} 可以触发,但由于优先级与keepEval设定,触发器不会触发。{Settings.CLR_STYLE}")
|
3025
3231
|
|
3026
|
-
|
3027
|
-
|
3028
|
-
|
3029
|
-
|
3030
|
-
|
3031
|
-
|
3032
|
-
|
3033
|
-
|
3034
|
-
|
3035
|
-
|
3036
|
-
|
3232
|
+
if cmd != "echo":
|
3233
|
+
for tri in tris_disabled:
|
3234
|
+
if tri.raw:
|
3235
|
+
state = tri.match(raw_line, docallback = docallback)
|
3236
|
+
else:
|
3237
|
+
state = tri.match(tri_line, docallback = docallback)
|
3238
|
+
|
3239
|
+
if state and (state.result == Trigger.SUCCESS):
|
3240
|
+
triggered_disabled += 1
|
3241
|
+
#info_disabled.append(f" {tri.__detailed__()} 可以匹配触发。")
|
3242
|
+
info_disabled.append(Settings.gettext("msg_tri_matched", tri.__detailed__()))
|
3243
|
+
|
3244
|
+
if triggered_enabled + triggered_disabled == 0:
|
3245
|
+
info_all.append("")
|
3246
|
+
|
3247
|
+
if cmd != "echo":
|
3248
|
+
if triggered_enabled == 0:
|
3249
|
+
info_enabled.insert(0, Settings.gettext("msg_enabled_summary_0", Settings.INFO_STYLE))
|
3250
|
+
#info_enabled.insert(0, f"{Settings.INFO_STYLE} 使能的触发器中,没有可以触发的。")
|
3251
|
+
elif triggered < triggered_enabled:
|
3252
|
+
info_enabled.insert(0, Settings.gettext("msg_enabled_summary_1", Settings.INFO_STYLE, triggered_enabled, triggered, triggered_enabled - triggered))
|
3253
|
+
#info_enabled.insert(0, f"{Settings.INFO_STYLE} 使能的触发器中,共有 {triggered_enabled} 个可以触发,实际触发 {triggered} 个,另有 {triggered_enabled - triggered} 个由于 keepEval 原因实际不会触发。")
|
3254
|
+
else:
|
3255
|
+
info_enabled.insert(0, Settings.gettext("msg_enabled_summary_2", Settings.INFO_STYLE, triggered_enabled))
|
3256
|
+
#info_enabled.insert(0, f"{Settings.INFO_STYLE} 使能的触发器中,共有 {triggered_enabled} 个全部可以被正常触发。")
|
3037
3257
|
|
3258
|
+
if triggered_disabled > 0:
|
3259
|
+
info_disabled.insert(0, Settings.gettext("msg_disabled_summary_0", Settings.INFO_STYLE, triggered_disabled))
|
3260
|
+
#info_disabled.insert(0, f"{Settings.INFO_STYLE} 未使能的触发器中,共有 {triggered_disabled} 个可以匹配。")
|
3261
|
+
else:
|
3262
|
+
info_disabled.insert(0, Settings.gettext("msg_disabled_summary_1", Settings.INFO_STYLE))
|
3263
|
+
#info_disabled.insert(0, f"{Settings.INFO_STYLE} 未使能触发器,没有可以匹配的。")
|
3264
|
+
|
3265
|
+
info_all.append("")
|
3038
3266
|
if triggered_enabled + triggered_disabled == 0:
|
3039
|
-
info_all.append("")
|
3040
|
-
|
3041
|
-
|
3042
|
-
|
3043
|
-
|
3044
|
-
|
3045
|
-
|
3046
|
-
|
3047
|
-
|
3048
|
-
|
3049
|
-
|
3050
|
-
|
3051
|
-
|
3052
|
-
|
3053
|
-
|
3054
|
-
|
3055
|
-
|
3056
|
-
|
3057
|
-
info_all.append(f" 测试结果: 没有可以匹配的触发器。")
|
3058
|
-
else:
|
3059
|
-
#info_all.append(f"PYMUD 触发器测试: {'响应模式' if docallback else '测试模式'}")
|
3060
|
-
info_all.append(f" 测试内容: {line}")
|
3061
|
-
info_all.append(f" 测试结果: 有{triggered}个触发器可以被正常触发,一共有{triggered_enabled + triggered_disabled}个满足匹配触发要求。")
|
3062
|
-
info_all.extend(info_enabled)
|
3063
|
-
info_all.extend(info_disabled)
|
3064
|
-
|
3065
|
-
title = f"触发器测试 - {'响应模式' if docallback else '测试模式'}"
|
3066
|
-
self.info("\n".join(info_all), title)
|
3067
|
-
#self.info("PYMUD 触发器测试 完毕")
|
3267
|
+
#info_all.append(f"PYMUD 触发器测试: {'响应模式' if docallback else '测试模式'}")
|
3268
|
+
info_all.append(Settings.gettext("msg_test_summary_0", line))
|
3269
|
+
info_all.append(Settings.gettext("msg_test_summary_1"))
|
3270
|
+
#info_all.append(f" 测试内容: {line}")
|
3271
|
+
#info_all.append(f" 测试结果: 没有可以匹配的触发器。")
|
3272
|
+
else:
|
3273
|
+
#info_all.append(f"PYMUD 触发器测试: {'响应模式' if docallback else '测试模式'}")
|
3274
|
+
info_all.append(Settings.gettext("msg_test_summary_0", line))
|
3275
|
+
info_all.append(Settings.gettext("msg_test_summary_2", triggered, triggered_enabled + triggered_disabled))
|
3276
|
+
#info_all.append(f" 测试内容: {line}")
|
3277
|
+
#info_all.append(f" 测试结果: 有{triggered}个触发器可以被正常触发,一共有{triggered_enabled + triggered_disabled}个满足匹配触发要求。")
|
3278
|
+
info_all.extend(info_enabled)
|
3279
|
+
info_all.extend(info_disabled)
|
3280
|
+
|
3281
|
+
title = Settings.gettext("msg_test_title", Settings.gettext("msg_triggered_mode") if docallback else Settings.gettext("msg_matched_mode"))
|
3282
|
+
#title = f"触发器测试 - {'响应模式' if docallback else '测试模式'}"
|
3283
|
+
self.info("\n".join(info_all), title)
|
3284
|
+
#self.info("PYMUD 触发器测试 完毕")
|
3068
3285
|
|
3069
|
-
def handle_plugins(self, code: CodeLine
|
3286
|
+
def handle_plugins(self, code: CodeLine, *args, **kwargs):
|
3070
3287
|
'''
|
3071
3288
|
嵌入命令 #plugins 的执行函数,显示插件信息。该命令可以不带参数、带一个参数。
|
3072
3289
|
该函数不应该在代码中直接调用。
|
@@ -3084,20 +3301,24 @@ class Session:
|
|
3084
3301
|
if len(args) == 0:
|
3085
3302
|
count = len(self.plugins.keys())
|
3086
3303
|
if count == 0:
|
3087
|
-
self.info("
|
3304
|
+
self.info(Settings.gettext("msg_no_plugins"), "PLUGINS")
|
3305
|
+
#self.info("PYMUD当前并未加载任何插件。", "PLUGINS")
|
3088
3306
|
else:
|
3089
|
-
self.info(
|
3307
|
+
self.info(Settings.gettext("msg_plugins_list", count), "PLUGINS")
|
3308
|
+
#self.info(f"PYMUD当前已加载 {count} 个插件,分别为:", "PLUGINS")
|
3090
3309
|
for name, plugin in self.plugins.items():
|
3091
|
-
self.info(
|
3310
|
+
self.info(Settings.gettext("msg_plugins_info", plugin.desc['DESCRIPTION'], plugin.desc['VERSION'], plugin.desc['AUTHOR'], plugin.desc['RELEASE_DATE']), f"PLUGIN {name}")
|
3311
|
+
#self.info(f"{plugin.desc['DESCRIPTION']}, 版本 {plugin.desc['VERSION']} 作者 {plugin.desc['AUTHOR']} 发布日期 {plugin.desc['RELEASE_DATE']}", f"PLUGIN {name}")
|
3092
3312
|
|
3093
3313
|
elif len(args) == 1:
|
3094
3314
|
name = args[0]
|
3095
3315
|
if name in self.plugins.keys():
|
3096
3316
|
plugin = self.plugins[name]
|
3097
|
-
self.info(
|
3317
|
+
self.info(Settings.gettext("msg_plugins_info", plugin.desc['DESCRIPTION'], plugin.desc['VERSION'], plugin.desc['AUTHOR'], plugin.desc['RELEASE_DATE']), f"PLUGIN {name}")
|
3318
|
+
#self.info(f"{plugin.desc['DESCRIPTION']}, 版本 {plugin.desc['VERSION']} 作者 {plugin.desc['AUTHOR']} 发布日期 {plugin.desc['RELEASE_DATE']}", f"PLUGIN {name}")
|
3098
3319
|
self.writetobuffer(plugin.help, True)
|
3099
3320
|
|
3100
|
-
def handle_replace(self, code: CodeLine
|
3321
|
+
def handle_replace(self, code: CodeLine, *args, **kwargs):
|
3101
3322
|
'''
|
3102
3323
|
嵌入命令 #replace 的执行函数,修改显示内容,将当前行原本显示内容替换为msg显示。不需要增加换行符。
|
3103
3324
|
该函数不应该在代码中直接调用。
|
@@ -3121,7 +3342,7 @@ class Session:
|
|
3121
3342
|
new_text, new_code = code.expand(self, *args, **kwargs)
|
3122
3343
|
self.replace(new_text[9:])
|
3123
3344
|
|
3124
|
-
def handle_gag(self, code: CodeLine = None, *args, **kwargs):
|
3345
|
+
def handle_gag(self, code: Optional[CodeLine] = None, *args, **kwargs):
|
3125
3346
|
'''
|
3126
3347
|
嵌入命令 #gag 的执行函数,在主窗口中不显示当前行内容,一般用于触发器中。
|
3127
3348
|
该函数不应该在代码中直接调用。
|
@@ -3138,7 +3359,7 @@ class Session:
|
|
3138
3359
|
|
3139
3360
|
self.display_line = ""
|
3140
3361
|
|
3141
|
-
def handle_py(self, code: CodeLine
|
3362
|
+
def handle_py(self, code: CodeLine, *args, **kwargs):
|
3142
3363
|
'''
|
3143
3364
|
嵌入命令 #py 的执行函数,执行 Python 语句。
|
3144
3365
|
该函数不应该在代码中直接调用。
|
@@ -3155,9 +3376,9 @@ class Session:
|
|
3155
3376
|
try:
|
3156
3377
|
exec(code.commandText[4:])
|
3157
3378
|
except Exception as e:
|
3158
|
-
self.error(
|
3379
|
+
self.error(Settings.gettext("msg_py_exception", e))
|
3159
3380
|
|
3160
|
-
def handle_info(self, code: CodeLine
|
3381
|
+
def handle_info(self, code: CodeLine, *args, **kwargs):
|
3161
3382
|
'''
|
3162
3383
|
嵌入命令 #info 的执行函数,使用 session.info 输出一行,主要用于测试。
|
3163
3384
|
该函数不应该在代码中直接调用。
|
@@ -3173,7 +3394,7 @@ class Session:
|
|
3173
3394
|
new_text, new_code = code.expand(self, *args, **kwargs)
|
3174
3395
|
self.info(new_text[6:])
|
3175
3396
|
|
3176
|
-
def handle_warning(self, code: CodeLine
|
3397
|
+
def handle_warning(self, code: CodeLine, *args, **kwargs):
|
3177
3398
|
'''
|
3178
3399
|
嵌入命令 #warning 的执行函数,使用 session.warning 输出一行,主要用于测试。
|
3179
3400
|
该函数不应该在代码中直接调用。
|
@@ -3189,7 +3410,7 @@ class Session:
|
|
3189
3410
|
new_text, new_code = code.expand(self, *args, **kwargs)
|
3190
3411
|
self.warning(new_text[9:])
|
3191
3412
|
|
3192
|
-
def handle_error(self, code: CodeLine
|
3413
|
+
def handle_error(self, code: CodeLine, *args, **kwargs):
|
3193
3414
|
'''
|
3194
3415
|
嵌入命令 #error 的执行函数,使用 session.error 输出一行,主要用于测试。
|
3195
3416
|
该函数不应该在代码中直接调用。
|
@@ -3205,21 +3426,12 @@ class Session:
|
|
3205
3426
|
new_text, new_code = code.expand(self, *args, **kwargs)
|
3206
3427
|
self.error(new_text[7:])
|
3207
3428
|
|
3208
|
-
def info2(self, msg, title =
|
3429
|
+
def info2(self, msg, title = None, style = Settings.INFO_STYLE):
|
3430
|
+
title = title or Settings.gettext("title_msg")
|
3209
3431
|
msg = f"{msg}"
|
3210
|
-
|
3211
|
-
# if Settings.client["newline"] in msg:
|
3212
|
-
# new_lines = list()
|
3213
|
-
# msg_lines = msg.split(Settings.client["newline"])
|
3214
|
-
# for line in msg_lines:
|
3215
|
-
# new_lines.append("{}{}".format(style, line))
|
3216
|
-
|
3217
|
-
# msg = Settings.client["newline"].join(new_lines)
|
3218
|
-
|
3219
|
-
# 将颜色跨行显示移动到了MudFormatProcessor中,此处无需再处理(不行,还得恢复)
|
3220
3432
|
self.writetobuffer("{}〔{}〕{}{}".format(style, title, msg, Settings.CLR_STYLE), newline = True)
|
3221
3433
|
|
3222
|
-
def info(self, msg, title =
|
3434
|
+
def info(self, msg, title = None, style = Settings.INFO_STYLE):
|
3223
3435
|
"""
|
3224
3436
|
使用默认的INFO_STYLE(绿色)输出信息,并自动换行。信息格式类似 [title] msg
|
3225
3437
|
|
@@ -3227,9 +3439,10 @@ class Session:
|
|
3227
3439
|
:param title: 要显示在前面的标题,不指定时默认为 PYMUD INFO
|
3228
3440
|
:param style: 要输出信息的格式(ANSI), 默认为 INFO_STYLE, \x1b[32m
|
3229
3441
|
"""
|
3442
|
+
title = title or Settings.gettext("title_info")
|
3230
3443
|
self.info2(msg, title, style)
|
3231
3444
|
|
3232
|
-
def warning(self, msg, title =
|
3445
|
+
def warning(self, msg, title = None, style = Settings.WARN_STYLE):
|
3233
3446
|
"""
|
3234
3447
|
使用默认的WARN_STYLE(黄色)输出信息,并自动换行。信息格式类似 [title] msg
|
3235
3448
|
|
@@ -3237,9 +3450,10 @@ class Session:
|
|
3237
3450
|
:param title: 要显示在前面的标题,不指定时默认为 PYMUD WARNING
|
3238
3451
|
:param style: 要输出信息的格式(ANSI), 默认为 WARN_STYLE, \x1b[33m
|
3239
3452
|
"""
|
3453
|
+
title = title or Settings.gettext("title_warning")
|
3240
3454
|
self.info2(msg, title, style)
|
3241
3455
|
|
3242
|
-
def error(self, msg, title =
|
3456
|
+
def error(self, msg, title = None, style = Settings.ERR_STYLE):
|
3243
3457
|
"""
|
3244
3458
|
使用默认的ERR_STYLE(红色)输出信息,并自动换行。信息格式类似 [title] msg
|
3245
3459
|
|
@@ -3247,9 +3461,10 @@ class Session:
|
|
3247
3461
|
:param title: 要显示在前面的标题,不指定时默认为 PYMUD ERROR
|
3248
3462
|
:param style: 要输出信息的格式(ANSI), 默认为 ERR_STYLE, \x1b[31m
|
3249
3463
|
"""
|
3464
|
+
title = title or Settings.gettext("title_error")
|
3250
3465
|
self.info2(msg, title, style)
|
3251
3466
|
|
3252
|
-
def handle_log(self, code: CodeLine
|
3467
|
+
def handle_log(self, code: CodeLine, *args, **kwargs):
|
3253
3468
|
'''
|
3254
3469
|
嵌入命令 #log 的执行函数,控制当前会话的记录状态。
|
3255
3470
|
该函数不应该在代码中直接调用。
|
@@ -3292,16 +3507,21 @@ class Session:
|
|
3292
3507
|
if len(args) == 0:
|
3293
3508
|
session_loggers = set(self._loggers.keys())
|
3294
3509
|
app_loggers = set(self.application.loggers.keys()).difference(session_loggers)
|
3295
|
-
|
3510
|
+
|
3511
|
+
self.info(Settings.gettext("msg_log_title"))
|
3512
|
+
#self.info("本会话中的记录器情况:")
|
3296
3513
|
for name in session_loggers:
|
3297
3514
|
logger = self.application.loggers[name]
|
3298
|
-
self.info(f"
|
3515
|
+
self.info(f"{Settings.gettext('logger')} {logger.name}, {Settings.gettext('logger_status')}: {Settings.gettext('enabled') if logger.enabled else Settings.gettext('disabled')}, {Settings.gettext('file_mode')}: {logger.mode}, {Settings.gettext('logger_mode')}: {Settings.gettext('ANSI') if logger.raw else Settings.gettext('plain_text')}")
|
3516
|
+
#self.info(f"记录器 {logger.name}, 当前状态: {'开启' if logger.enabled else '关闭'}, 文件模式: {logger.mode}, 记录模式: {'ANSI' if logger.raw else '纯文本'}")
|
3299
3517
|
|
3300
3518
|
if len(app_loggers) > 0:
|
3301
|
-
self.info("
|
3519
|
+
self.info(Settings.gettext("msg_log_title2"))
|
3520
|
+
#self.info("本应用其他会话中的记录器情况:")
|
3302
3521
|
for name in app_loggers:
|
3303
3522
|
logger = self.application.loggers[name]
|
3304
|
-
self.info(f"
|
3523
|
+
self.info(f"{Settings.gettext('logger')} {logger.name}, {Settings.gettext('logger_status')}: {Settings.gettext('enabled') if logger.enabled else Settings.gettext('disabled')}, {Settings.gettext('file_mode')}: {logger.mode}, {Settings.gettext('logger_mode')}: {Settings.gettext('ANSI') if logger.raw else Settings.gettext('plain_text')}")
|
3524
|
+
#self.info(f"记录器 {logger.name}, 当前状态: {'开启' if logger.enabled else '关闭'}, 文件模式: {logger.mode}, 记录模式: {'ANSI' if logger.raw else '纯文本'}")
|
3305
3525
|
|
3306
3526
|
else:
|
3307
3527
|
name = self.name
|
@@ -3311,24 +3531,30 @@ class Session:
|
|
3311
3531
|
if (args[0] == "start"):
|
3312
3532
|
if "-n" in args:
|
3313
3533
|
mode = "n"
|
3314
|
-
mode_name = '新建'
|
3534
|
+
#mode_name = '新建'
|
3535
|
+
mode_name = Settings.gettext("filemode_new")
|
3315
3536
|
elif "-w" in args:
|
3316
3537
|
mode = "w"
|
3317
|
-
mode_name = '覆写'
|
3538
|
+
#mode_name = '覆写'
|
3539
|
+
mode_name = Settings.gettext("filemode_overwrite")
|
3318
3540
|
else:
|
3319
3541
|
mode = "a"
|
3320
|
-
mode_name = '
|
3542
|
+
#mode_name = '追加'
|
3543
|
+
mode_name = Settings.gettext("filemode_append")
|
3321
3544
|
|
3322
3545
|
raw = True if "-r" in args else False
|
3323
|
-
raw_name = '原始ANSI' if raw else '纯文本'
|
3546
|
+
#raw_name = '原始ANSI' if raw else '纯文本'
|
3547
|
+
raw_name = Settings.gettext("ANSI") if raw else Settings.gettext("plain_text")
|
3324
3548
|
|
3325
3549
|
logger = self.getLogger(name = name, mode = mode, raw = raw)
|
3326
3550
|
logger.enabled = True
|
3327
3551
|
|
3328
|
-
self.info(f"{datetime.datetime.now()}: 记录器{name}以{mode_name}文件模式以及{raw_name}记录模式开启。")
|
3552
|
+
#self.info(f"{datetime.datetime.now()}: 记录器{name}以{mode_name}文件模式以及{raw_name}记录模式开启。")
|
3553
|
+
self.info(Settings.gettext("msg_logger_enabled", datetime.datetime.now(), name, mode_name, raw_name))
|
3329
3554
|
|
3330
3555
|
elif (args[0] == "stop"):
|
3331
|
-
self.info(f"{datetime.datetime.now()}: 记录器{name}记录已关闭。")
|
3556
|
+
#self.info(f"{datetime.datetime.now()}: 记录器{name}记录已关闭。")
|
3557
|
+
self.info(Settings.gettext("msg_logger_disabled", datetime.datetime.now(), name))
|
3332
3558
|
self.log.enabled = False
|
3333
3559
|
|
3334
3560
|
elif (args[0] == "show"):
|
@@ -3345,7 +3571,7 @@ class Session:
|
|
3345
3571
|
self.application.logFileShown = filepath
|
3346
3572
|
self.application.showLogInTab()
|
3347
3573
|
else:
|
3348
|
-
self.warning(
|
3574
|
+
self.warning(Settings.gettext("msg_logfile_not_exists", file))
|
3349
3575
|
|
3350
3576
|
else:
|
3351
3577
|
self.application.show_logSelectDialog()
|