pymud 0.19.0__py3-none-any.whl → 0.19.2__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/__main__.py +16 -1
- pymud/pymud.py +100 -100
- pymud/session.py +695 -175
- pymud/settings.py +7 -8
- pymud/statemachine.py +1525 -0
- {pymud-0.19.0.dist-info → pymud-0.19.2.dist-info}/METADATA +17 -1
- pymud-0.19.2.dist-info/RECORD +17 -0
- {pymud-0.19.0.dist-info → pymud-0.19.2.dist-info}/WHEEL +1 -1
- pymud-0.19.0.dist-info/RECORD +0 -16
- {pymud-0.19.0.dist-info → pymud-0.19.2.dist-info}/LICENSE.txt +0 -0
- {pymud-0.19.0.dist-info → pymud-0.19.2.dist-info}/entry_points.txt +0 -0
- {pymud-0.19.0.dist-info → pymud-0.19.2.dist-info}/top_level.txt +0 -0
pymud/__main__.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import sys, os, json, platform, shutil
|
1
|
+
import sys, os, json, platform, shutil, logging
|
2
2
|
from .pymud import main
|
3
3
|
from .settings import Settings
|
4
4
|
|
@@ -31,6 +31,12 @@ CFG_TEMPLATE = {
|
|
31
31
|
"display_title" : ["yourid", "yourpassword", ""],
|
32
32
|
}
|
33
33
|
}
|
34
|
+
},
|
35
|
+
"keys" : {
|
36
|
+
"f3" : "#ig",
|
37
|
+
"f4" : "#clear",
|
38
|
+
"f11" : "#close",
|
39
|
+
"f12" : "#exit",
|
34
40
|
}
|
35
41
|
}
|
36
42
|
|
@@ -75,6 +81,15 @@ if __name__ == "__main__":
|
|
75
81
|
|
76
82
|
input('所有内容已初始化完毕, 请按回车进入PyMUD.')
|
77
83
|
|
84
|
+
if (len(args) == 2) and (args[1] == "withlog"):
|
85
|
+
# 指定带log时,打印log信息
|
86
|
+
# 所有级别log都存入文件
|
87
|
+
logging.basicConfig(level=logging.NOTSET,
|
88
|
+
format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
|
89
|
+
datefmt='%m-%d %H:%M',
|
90
|
+
filename='myapp.log',
|
91
|
+
filemode='a')
|
92
|
+
|
78
93
|
cfg = "pymud.cfg"
|
79
94
|
if os.path.exists(cfg):
|
80
95
|
with open(cfg, "r", encoding="utf8", errors="ignore") as fp:
|
pymud/pymud.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import asyncio, functools, re, logging, math, json, os
|
1
|
+
import asyncio, functools, re, logging, math, json, os, webbrowser
|
2
2
|
import importlib.util
|
3
3
|
from prompt_toolkit.shortcuts import set_title
|
4
4
|
from prompt_toolkit.output import ColorDepth
|
@@ -49,7 +49,30 @@ class STATUS_DISPLAY(Enum):
|
|
49
49
|
FLOAT = 3
|
50
50
|
|
51
51
|
class PyMudApp:
|
52
|
+
"""
|
53
|
+
PYMUD程序管理主对象,对窗体、操作及所有会话进行管理。
|
54
|
+
|
55
|
+
PyMudApp对象不需要手动创建,在命令行中执行 ``python -m pymud`` 时会自动创建对象实例。
|
56
|
+
|
57
|
+
构造函数参数:
|
58
|
+
- ``cfg_data``: 替代配置数据,由本地pymud.cfg文件读取,用于覆盖settings.py中的默认Settings数据
|
59
|
+
|
60
|
+
可替代字典: 含义请查阅 `应用配置及本地化 <settings.html>`_
|
61
|
+
- sessions: 用于创建菜单栏会话的字典
|
62
|
+
- client: 用于配置客户端属性的字典
|
63
|
+
- text: 用于各默认显示文字内容的字典
|
64
|
+
- server: 用于服务器选项的配置字典
|
65
|
+
- styles: 用于显示样式的定义字典
|
66
|
+
- keys: 用于快捷键定义的字典
|
67
|
+
|
68
|
+
*替代配置按不同的dict使用dict.update进行更新覆盖,因此可以仅指定需替代的部分。*
|
69
|
+
"""
|
70
|
+
|
52
71
|
def __init__(self, cfg_data = None) -> None:
|
72
|
+
"""
|
73
|
+
构造PyMudApp对象实例,并加载替代配置。
|
74
|
+
"""
|
75
|
+
|
53
76
|
if cfg_data and isinstance(cfg_data, dict):
|
54
77
|
for key in cfg_data.keys():
|
55
78
|
if key == "sessions":
|
@@ -65,6 +88,7 @@ class PyMudApp:
|
|
65
88
|
elif key == "keys":
|
66
89
|
Settings.keys.update(cfg_data[key])
|
67
90
|
|
91
|
+
self._mouse_support = True
|
68
92
|
self._plugins = DotDict() # 增加 插件 字典
|
69
93
|
self._globals = DotDict() # 增加所有session使用的全局变量
|
70
94
|
self.sessions = {}
|
@@ -81,8 +105,10 @@ class PyMudApp:
|
|
81
105
|
self.keybindings.add(Keys.Backspace)(self.delete_selection)
|
82
106
|
self.keybindings.add(Keys.ControlLeft, is_global = True)(self.change_session) # Control-左右箭头切换当前会话
|
83
107
|
self.keybindings.add(Keys.ControlRight, is_global = True)(self.change_session)
|
108
|
+
self.keybindings.add(Keys.F1, is_global=True)(lambda event: webbrowser.open(Settings.__website__))
|
109
|
+
self.keybindings.add(Keys.F2, is_global=True)(self.toggle_mousesupport)
|
84
110
|
|
85
|
-
used_keys = [Keys.PageUp, Keys.PageDown, Keys.ControlZ, Keys.ControlC, Keys.ControlR, Keys.Up, Keys.Down, Keys.Left, Keys.Right, Keys.ControlLeft, Keys.ControlRight, Keys.Backspace, Keys.Delete]
|
111
|
+
used_keys = [Keys.PageUp, Keys.PageDown, Keys.ControlZ, Keys.ControlC, Keys.ControlR, Keys.Up, Keys.Down, Keys.Left, Keys.Right, Keys.ControlLeft, Keys.ControlRight, Keys.Backspace, Keys.Delete, Keys.F1, Keys.F2]
|
86
112
|
|
87
113
|
for key, binding in Settings.keys.items():
|
88
114
|
if (key not in used_keys) and binding and isinstance(binding, str):
|
@@ -95,6 +121,7 @@ class PyMudApp:
|
|
95
121
|
try:
|
96
122
|
clipboard = PyperclipClipboard()
|
97
123
|
clipboard.set_text("test pyperclip")
|
124
|
+
clipboard.set_text("")
|
98
125
|
except:
|
99
126
|
clipboard = None
|
100
127
|
|
@@ -102,7 +129,7 @@ class PyMudApp:
|
|
102
129
|
layout = Layout(self.root_container, focused_element=self.commandLine),
|
103
130
|
enable_page_navigation_bindings=True,
|
104
131
|
style=self.style,
|
105
|
-
mouse_support=
|
132
|
+
mouse_support=to_filter(self._mouse_support),
|
106
133
|
full_screen=True,
|
107
134
|
color_depth=ColorDepth.TRUE_COLOR,
|
108
135
|
clipboard=clipboard,
|
@@ -279,6 +306,11 @@ class PyMudApp:
|
|
279
306
|
children=[
|
280
307
|
MenuItem(Settings.text["about"], handler = self.act_about)
|
281
308
|
]
|
309
|
+
),
|
310
|
+
|
311
|
+
MenuItem(
|
312
|
+
"", # 增加一个空名称MenuItem,阻止右侧空白栏点击响应
|
313
|
+
children=[]
|
282
314
|
)
|
283
315
|
],
|
284
316
|
floats=[
|
@@ -346,11 +378,13 @@ class PyMudApp:
|
|
346
378
|
b.cursor_down(lines)
|
347
379
|
|
348
380
|
def page_up(self, event: KeyPressEvent) -> None:
|
349
|
-
lines = (self.app.output.get_size().rows - 5) // 2 - 1
|
381
|
+
#lines = (self.app.output.get_size().rows - 5) // 2 - 1
|
382
|
+
lines = self.get_height() // 2 - 1
|
350
383
|
self.scroll(-1 * lines)
|
351
384
|
|
352
385
|
def page_down(self, event: KeyPressEvent) -> None:
|
353
|
-
lines = (self.app.output.get_size().rows - 5) // 2 - 1
|
386
|
+
#lines = (self.app.output.get_size().rows - 5) // 2 - 1
|
387
|
+
lines = self.get_height() // 2 - 1
|
354
388
|
self.scroll(lines)
|
355
389
|
|
356
390
|
def custom_key_press(self, event: KeyPressEvent):
|
@@ -404,6 +438,13 @@ class PyMudApp:
|
|
404
438
|
new_key = keys[idx-1]
|
405
439
|
self.activate_session(new_key)
|
406
440
|
|
441
|
+
def toggle_mousesupport(self, event: KeyPressEvent):
|
442
|
+
self._mouse_support = not self._mouse_support
|
443
|
+
if self._mouse_support:
|
444
|
+
self.app.renderer.output.enable_mouse_support()
|
445
|
+
else:
|
446
|
+
self.app.renderer.output.disable_mouse_support()
|
447
|
+
|
407
448
|
def copy(self, raw = False):
|
408
449
|
b = self.consoleView.buffer
|
409
450
|
if b.selection_state:
|
@@ -472,6 +513,10 @@ class PyMudApp:
|
|
472
513
|
self.sessions[name] = session
|
473
514
|
self.activate_session(name)
|
474
515
|
|
516
|
+
for plugin in self._plugins.values():
|
517
|
+
if isinstance(plugin, Plugin):
|
518
|
+
plugin.onSessionCreate(session)
|
519
|
+
|
475
520
|
result = True
|
476
521
|
else:
|
477
522
|
self.set_status(f"错误!已存在一个名为{name}的会话,请更换名称再试.")
|
@@ -497,12 +542,17 @@ class PyMudApp:
|
|
497
542
|
result = await self.show_dialog_as_float(dlgQuery)
|
498
543
|
if result:
|
499
544
|
self.current_session.disconnect()
|
545
|
+
|
546
|
+
# 增加延时等待确保会话关闭
|
547
|
+
while self.current_session.connected:
|
548
|
+
await asyncio.sleep(0.1)
|
549
|
+
|
500
550
|
else:
|
501
551
|
return
|
502
552
|
|
503
553
|
for plugin in self._plugins.values():
|
504
554
|
if isinstance(plugin, Plugin):
|
505
|
-
plugin.
|
555
|
+
plugin.onSessionDestroy(self.current_session)
|
506
556
|
|
507
557
|
name = self.current_session.name
|
508
558
|
self.current_session.clean()
|
@@ -600,6 +650,11 @@ class PyMudApp:
|
|
600
650
|
result = await self.show_dialog_as_float(dlgQuery)
|
601
651
|
if result:
|
602
652
|
session.disconnect()
|
653
|
+
|
654
|
+
# 增加延时等待确保会话关闭
|
655
|
+
while session.connected:
|
656
|
+
await asyncio.sleep(0.1)
|
657
|
+
|
603
658
|
else:
|
604
659
|
return
|
605
660
|
|
@@ -651,10 +706,13 @@ class PyMudApp:
|
|
651
706
|
]
|
652
707
|
|
653
708
|
def get_statusbar_right_text(self):
|
654
|
-
con_str, tri_status = "", ""
|
709
|
+
con_str, mouse_support, tri_status = "", "", ""
|
710
|
+
if not self._mouse_support:
|
711
|
+
mouse_support = "鼠标已禁用 "
|
712
|
+
|
655
713
|
if self.current_session:
|
656
714
|
if self.current_session._ignore:
|
657
|
-
tri_status = "全局禁用"
|
715
|
+
tri_status = "全局禁用 "
|
658
716
|
|
659
717
|
if not self.current_session.connected:
|
660
718
|
con_str = "未连接"
|
@@ -678,7 +736,7 @@ class PyMudApp:
|
|
678
736
|
else:
|
679
737
|
con_str = "已连接:{:.0f}秒".format(sec)
|
680
738
|
|
681
|
-
return "{}
|
739
|
+
return "{}{}{} {} {} ".format(mouse_support, tri_status, con_str, Settings.__appname__, Settings.__version__)
|
682
740
|
|
683
741
|
def get_statuswindow_text(self):
|
684
742
|
text = ""
|
@@ -692,13 +750,38 @@ class PyMudApp:
|
|
692
750
|
self.app.invalidate()
|
693
751
|
|
694
752
|
def handle_session(self, *args):
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
753
|
+
'''
|
754
|
+
嵌入命令 #session 的执行函数,创建一个远程连接会话。
|
755
|
+
该函数不应该在代码中直接调用。
|
756
|
+
|
757
|
+
使用:
|
758
|
+
- #session {Name} {Host} {Port} {Encoding}
|
759
|
+
- 当不指定 Encoding: 时, 默认使用utf-8编码
|
760
|
+
- 可以直接使用 #{名称} 切换会话和操作会话命令
|
761
|
+
|
762
|
+
参数:
|
763
|
+
:Name: 会话名称
|
764
|
+
:Host: 服务器域名或IP地址
|
765
|
+
:Port: 端口号
|
766
|
+
:Encoding: 编码格式,不指定时默认为 utf8
|
767
|
+
|
768
|
+
示例:
|
769
|
+
``#session {名称} {宿主机} {端口} {编码}``
|
770
|
+
创建一个远程连接会话,使用指定编码格式连接到远程宿主机的指定端口并保存为 {名称} 。其中,编码可以省略,此时使用Settings.server["default_encoding"]的值,默认为utf8
|
771
|
+
``#session newstart mud.pkuxkx.net 8080 GBK``
|
772
|
+
使用GBK编码连接到mud.pkuxkx.net的8080端口,并将该会话命名为newstart
|
773
|
+
``#session newstart mud.pkuxkx.net 8081``
|
774
|
+
使用UTF8编码连接到mud.pkuxkx.net的8081端口,并将该会话命名为newstart
|
775
|
+
``#newstart``
|
776
|
+
将名称为newstart的会话切换为当前会话
|
777
|
+
``#newstart give miui gold``
|
778
|
+
使名称为newstart的会话执行give miui gold指令,但不切换到该会话
|
779
|
+
|
780
|
+
相关命令:
|
781
|
+
- #close
|
782
|
+
- #exit
|
783
|
+
|
784
|
+
'''
|
702
785
|
|
703
786
|
nothandle = True
|
704
787
|
|
@@ -717,72 +800,6 @@ class PyMudApp:
|
|
717
800
|
if nothandle:
|
718
801
|
self.set_status("错误的#session命令")
|
719
802
|
|
720
|
-
def handle_help(self, *args):
|
721
|
-
"\x1b[1m命令\x1b[0m: #help {主题}\n" \
|
722
|
-
" 当不带参数时, #help会列出所有可用的帮助主题\n" \
|
723
|
-
"\x1b[1m相关\x1b[0m: session, exit\n"
|
724
|
-
|
725
|
-
if self.current_session:
|
726
|
-
if len(args) == 0: # 不带参数,打印所有支持的help主题
|
727
|
-
self._print_all_help()
|
728
|
-
|
729
|
-
elif len(args) >= 1: # 大于1个参数,第1个为 topic, 其余参数丢弃
|
730
|
-
topic = args[0]
|
731
|
-
|
732
|
-
if topic in ("exit", "close", "session", "help"):
|
733
|
-
command = getattr(self, f"handle_{topic}", None)
|
734
|
-
docstring = command.__doc__
|
735
|
-
elif topic in self.current_session._commands_alias.keys():
|
736
|
-
command = self.current_session._commands_alias[topic]
|
737
|
-
docstring = self.current_session._cmds_handler[command].__doc__
|
738
|
-
elif topic in self.current_session._sys_commands:
|
739
|
-
docstring = self.current_session._cmds_handler[topic].__doc__
|
740
|
-
else:
|
741
|
-
docstring = f"未找到主题{topic}, 请确认输入是否正确."
|
742
|
-
|
743
|
-
self.current_session.writetobuffer(docstring)
|
744
|
-
|
745
|
-
else:
|
746
|
-
self.act_about()
|
747
|
-
|
748
|
-
def _print_all_help(self):
|
749
|
-
"""打印所有可用的help主题, 并根据终端尺寸进行排版"""
|
750
|
-
width = self.get_width()
|
751
|
-
|
752
|
-
cmds = ["exit", "close", "session", "all", "help"]
|
753
|
-
cmds.extend(Session._commands_alias.keys())
|
754
|
-
cmds.extend(Session._sys_commands)
|
755
|
-
cmds.sort()
|
756
|
-
|
757
|
-
cmd_count = len(cmds)
|
758
|
-
left = (width - 8) // 2
|
759
|
-
right = width - 8 - left
|
760
|
-
self.current_session.writetobuffer("#"*left + " HELP " + "#"*right, newline = True)
|
761
|
-
cmd_per_line = (width - 2) // 20
|
762
|
-
lines = math.ceil(cmd_count / cmd_per_line)
|
763
|
-
left_space = (width - cmd_per_line * 20) // 2
|
764
|
-
|
765
|
-
for idx in range(0, lines):
|
766
|
-
start = idx * cmd_per_line
|
767
|
-
end = (idx + 1) * cmd_per_line
|
768
|
-
if end > cmd_count: end = cmd_count
|
769
|
-
line_cmds = cmds[start:end]
|
770
|
-
self.current_session.writetobuffer(" " * left_space)
|
771
|
-
for cmd in line_cmds:
|
772
|
-
if cmd in Session._sys_commands:
|
773
|
-
self.current_session.writetobuffer(f"{cmd.upper():<20}")
|
774
|
-
else:
|
775
|
-
self.current_session.writetobuffer(f"\x1b[32m{cmd.upper():<20}\x1b[0m")
|
776
|
-
|
777
|
-
self.current_session.writetobuffer("", newline = True)
|
778
|
-
|
779
|
-
self.current_session.writetobuffer("#"*width, newline = True)
|
780
|
-
|
781
|
-
def handle_exit(self, *args):
|
782
|
-
"\x1b[1m命令\x1b[0m: #exit \n" \
|
783
|
-
" 退出PYMUD程序\n" \
|
784
|
-
"\x1b[1m相关\x1b[0m: session\n"
|
785
|
-
|
786
803
|
def enter_pressed(self, buffer: Buffer):
|
787
804
|
cmd_line = buffer.text
|
788
805
|
space_index = cmd_line.find(" ")
|
@@ -795,31 +812,15 @@ class PyMudApp:
|
|
795
812
|
if self.current_session:
|
796
813
|
self.current_session.last_command = cmd_line
|
797
814
|
|
798
|
-
if cmd_line
|
799
|
-
self.act_exit()
|
800
|
-
|
801
|
-
elif cmd_line == "#close":
|
802
|
-
self.close_session()
|
803
|
-
|
804
|
-
elif cmd_line.startswith("#session"):
|
815
|
+
if cmd_line.startswith("#session"):
|
805
816
|
cmd_tuple = cmd_line[1:].split()
|
806
817
|
self.handle_session(*cmd_tuple[1:])
|
807
818
|
|
808
|
-
elif cmd_line.startswith("#help"):
|
809
|
-
#self.act_about()
|
810
|
-
cmd_tuple = cmd_line[1:].split()
|
811
|
-
self.handle_help(*cmd_tuple[1:])
|
812
|
-
|
813
|
-
elif cmd_line[1:] in self.sessions.keys():
|
814
|
-
self.activate_session(cmd_line[1:])
|
815
|
-
|
816
819
|
else:
|
817
820
|
if self.current_session:
|
818
821
|
if len(cmd_line) == 0:
|
819
822
|
self.current_session.writeline("")
|
820
823
|
else:
|
821
|
-
# 增加额外处置:当创建代码块出现异常时,直接执行本行内容
|
822
|
-
# 是为了解决find-draw里面原图的有关内容,会出现引号、括号不匹配情况
|
823
824
|
try:
|
824
825
|
cb = CodeBlock(cmd_line)
|
825
826
|
cb.execute(self.current_session)
|
@@ -962,7 +963,6 @@ class PyMudApp:
|
|
962
963
|
|
963
964
|
|
964
965
|
def main(cfg_data = None):
|
965
|
-
logging.disable()
|
966
966
|
app = PyMudApp(cfg_data)
|
967
967
|
app.run()
|
968
968
|
|