pymud 0.20.0a4__tar.gz → 0.20.1__tar.gz

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.
Files changed (24) hide show
  1. {pymud-0.20.0a4/src/pymud.egg-info → pymud-0.20.1}/PKG-INFO +26 -15
  2. {pymud-0.20.0a4 → pymud-0.20.1}/README.md +22 -11
  3. {pymud-0.20.0a4 → pymud-0.20.1}/pyproject.toml +5 -5
  4. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud/__init__.py +2 -1
  5. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud/dialogs.py +11 -6
  6. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud/extras.py +32 -75
  7. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud/logger.py +9 -3
  8. pymud-0.20.1/src/pymud/modules.py +188 -0
  9. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud/objects.py +37 -20
  10. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud/pymud.py +43 -8
  11. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud/session.py +192 -116
  12. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud/settings.py +2 -2
  13. {pymud-0.20.0a4 → pymud-0.20.1/src/pymud.egg-info}/PKG-INFO +26 -15
  14. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud.egg-info/SOURCES.txt +1 -0
  15. {pymud-0.20.0a4 → pymud-0.20.1}/LICENSE.txt +0 -0
  16. {pymud-0.20.0a4 → pymud-0.20.1}/setup.cfg +0 -0
  17. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud/__main__.py +0 -0
  18. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud/main.py +0 -0
  19. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud/pkuxkx.py +0 -0
  20. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud/protocol.py +0 -0
  21. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud.egg-info/dependency_links.txt +0 -0
  22. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud.egg-info/entry_points.txt +0 -0
  23. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud.egg-info/requires.txt +0 -0
  24. {pymud-0.20.0a4 → pymud-0.20.1}/src/pymud.egg-info/top_level.txt +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pymud
3
- Version: 0.20.0a4
3
+ Version: 0.20.1
4
4
  Summary: a MUD Client written in Python
5
- Author-email: "newstart@pkuxkx" <crapex@crapex.cc>
6
- Maintainer-email: "newstart@pkuxkx" <crapex@crapex.cc>
5
+ Author-email: "newstart@pkuxkx" <crapex@hotmail.com>
6
+ Maintainer-email: "newstart@pkuxkx" <crapex@hotmail.com>
7
7
  License: GNU GENERAL PUBLIC LICENSE
8
8
  Version 3, 29 June 2007
9
9
 
@@ -684,7 +684,7 @@ Project-URL: Bug Reports, https://github.com/crapex/pymud/issues
684
684
  Project-URL: Source, https://github.com/crapex/pymud/
685
685
  Project-URL: document, https://pymud.readthedocs.io/
686
686
  Keywords: MUD,multi-user dungeon,client
687
- Classifier: Development Status :: 3 - Alpha
687
+ Classifier: Development Status :: 5 - Production/Stable
688
688
  Classifier: Intended Audience :: End Users/Desktop
689
689
  Classifier: Topic :: Games/Entertainment :: Multi-User Dungeons (MUD)
690
690
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
@@ -707,7 +707,7 @@ Requires-Dist: prompt-toolkit
707
707
  # PyMUD - Python原生MUD客户端
708
708
  ## 简介
709
709
 
710
- ### 帮助文件见北侠WIKI: https://www.pkuxkx.net/wiki/tools/pymud
710
+ ### 北侠WIKI: https://www.pkuxkx.net/wiki/tools/pymud
711
711
  ### 源代码地址: https://github.com/crapex/pymud
712
712
  ### 帮助文档地址: https://pymud.readthedocs.org
713
713
  ### PyPi项目地址: https://pypi.org/project/pymud
@@ -729,9 +729,20 @@ Requires-Dist: prompt-toolkit
729
729
  + Python拥有极为丰富的第三方库,能支持的第三方库,就能在PyMud中支持
730
730
  + 我自己还在玩,所以本客户端会持续进行更新:)
731
731
 
732
+ ### 哪些人适合使用PyMUD
733
+ + 比较熟悉Python语言,会使用Python写代码的 -> PyMUD是纯Python原生开发,不会有其他客户端对Python的支持能比得过PyMUD
734
+ + 虽不太熟悉Python语言,但有想法想学习Python语言的 -> 正好使用PyMUD玩北侠写脚本的过程中学习Python语言
735
+ + 觉得还有些功能现在所有客户端都没有的 -> 你有需求,我来增加,就是这么方便
736
+ + 觉得也想自己整一个定制客户端玩玩的 -> PyMUD完全开源,且除ui框架外全部都是一行一行代码自己写的,可以直接参考PyMUD的设计
737
+
732
738
  ## 版本更新信息
733
739
 
734
- ## 0.20.0 (2024-08-XX)
740
+ ### 0.20.1 (2024-11-16)
741
+ + 功能调整: 会话中触发器匹配实现进行部分调整,减少循环次数以提高响应速度
742
+ + 功能调整: #test / #show 触发器测试功能调整,现在会对使能的和未使能的触发器均进行匹配测试。其中,#show 命令仅测试,而 #test 命令会导致触发器真正响应。
743
+ + 功能新增: pymud对象新增了一个持续运行的1s的周期定时任务。该任务中会刷新页面显示。可以使用 session.application.addTimerTickCallback 和 session.application.removeTimerTickCallback 来注册和解除定时器回调。
744
+
745
+ ## 0.20.0 (2024-08-25)
735
746
  + 功能调整: 将模块主入口函数从__main__.py中移动到main.py中,以使可以在当前目录下,可直接使用pymud,也可使用python -m pymud启动
736
747
  + 功能调整: 使用argsparser标准模块来配置命令行,可以使用 pymud -h 查看命令行具体参数及说明
737
748
  + 功能新增: 命令行参数增加指定启动目录的功能,参数为 -s, --startup_dir。即可以从任意目录通过指定脚本目录方式启动PyMUD了。
@@ -743,10 +754,12 @@ Requires-Dist: prompt-toolkit
743
754
  + 功能调整: 在没有session的时候,也可以执行#exit命令
744
755
  + 功能新增: #session 命令增加快捷创建会话功能,假如已有快捷菜单 世界->pkuxkx->newstart , 则可以通过 #session pkuxkx.newstart 直接创建该会话,效果等同于点击该菜单
745
756
  + 功能调整: 点击菜单创建会话时,若会话已存在,则将该会话切换为当前会话
746
- + 问题修复: 修复原unload方法不能正确卸载的问题
747
- + 功能新增: 主模块卸载现在既可以定义在__unload__方法中,也可以定义在unload方法中。可以根据自己喜好选择一个即可。
748
- + 功能调整: 模块加载和重新加载前,会自动调用模块的__unload__方法或unload方法(若有)
757
+ + 重大更新: 完全重写了模块的加载、卸载、重新加载方法,修复模块使用中的问题
758
+ + 功能调整: 现在只要将一个类型继承 IConfig 接口,即被识别为配置类型。这种类型在模块加载时会自动创建其实例。当然,名称为Configuration的类型也同样被认为是配置类型,保持向前兼容性。唯一要求是,该类型的构造函数允许仅传递一个session对象。
759
+ + 功能新增: 各类配置类型的卸载现在既可以定义在__unload__方法中,也可以定义在unload方法中。可以根据自己喜好选择一个即可。
760
+ + 功能调整: 各配置类型加载和重新加载前,会自动调用模块的__unload__方法或unload方法(若有)
749
761
  + 功能新增: Command基类增加__unload__方法和unload方法,二者在从会话中移除该 Command 时均会自动调用。自定义的Command子类应覆盖这两种方法中的一种方法,并在其中增加清除类型自行创建的 Trigger, Alias 等会话对象。这样,模块卸载时只要移除命令本身,在命令中新建的其他关联对象将被一同移除。
762
+ + 功能新增: 所有PyMUD基础对象类型及其子类型,包括 Alias, Trigger, Timer, Command, GMCPTrigger 及它们的子类型,在创建的时候会自动添加到会话中,无需再进行 addObject 等操作了
750
763
  + 问题修复: 修复部分正则表达式书写错误问题
751
764
  + 功能新增: Session类新增waitfor函数,用于执行一段代码后立即等待某个触发器的情况,简化原三行代码写法
752
765
 
@@ -766,11 +779,6 @@ Requires-Dist: prompt-toolkit
766
779
  - 使用示例:
767
780
 
768
781
  ```Python
769
- # 所有对象均可以使用 addObject 直接添加到会话中,而不用管是什么具体类型
770
- session.addObject(Timer(...))
771
- session.addObject(Trigger(...))
772
- session.addObject(Alias(...))
773
-
774
782
  # 所有对象均可以使用 delObject 直接从会话中移除,会自动根据对象类型推断,无需通过函数名区分
775
783
  session.delObject(self.tri1)
776
784
  session.delObject(self.ali1)
@@ -784,7 +792,6 @@ Requires-Dist: prompt-toolkit
784
792
  GMCPTrigger(session, xxx)
785
793
  ]
786
794
 
787
- session.addObjects(objs) # 可以直接将一个数组中所有对象添加到会话中,会自动判断各对象类别
788
795
  session.delObjects(objs) # 可以直接从会话中移除一个数组中的所有对象,会自动判断对象类别
789
796
  ```
790
797
 
@@ -792,6 +799,10 @@ Requires-Dist: prompt-toolkit
792
799
  + 功能新增: Session的所有异步命令调用函数增加返回值,现在调用 session.exec_async, exec_command_async 等方法执行的内容若匹配为命令时,会返回最后最后一个 Command 对象的 execute 函数的返回值
793
800
  - 例如, result = await self.session.cmds.cmd_runto.execute('rt yz') 与 result = await self.session.exec_async('rt yz') 等价,返回值相同
794
801
  - 但 result = await self.session.exec_async('rt yz;dzt'),该返回的result 仅是 dzt 命令的 execute 的返回值。 rt yz 命令返回值被丢弃。
802
+ + 功能新增: 增加临时变量概念,变量名以下划线开头的为临时变量,此类变量不会被保存到 .mud 文件中。
803
+ + 功能新增: 为 BaseObject 基类的 self.session 增加了 Session 类型限定,现在自定义 Command 等时候,使用 self.session 时会有 IntelliSence 函数智能提示了,所有帮助说明已补全
804
+ + 问题修复: 修复 #var 等命令中,若含有中文则等号位置不对齐的问题
805
+ + 功能调整: 在 #tri 等命令中,当对象的 group 为空时,将不再显示 group 属性,减少无用信息
795
806
 
796
807
  ## 0.19.4 (2024-04-20)
797
808
  + 功能调整: info 现在 msg 恢复为可接受任何类型参数,不一定是 str
@@ -1,7 +1,7 @@
1
1
  # PyMUD - Python原生MUD客户端
2
2
  ## 简介
3
3
 
4
- ### 帮助文件见北侠WIKI: https://www.pkuxkx.net/wiki/tools/pymud
4
+ ### 北侠WIKI: https://www.pkuxkx.net/wiki/tools/pymud
5
5
  ### 源代码地址: https://github.com/crapex/pymud
6
6
  ### 帮助文档地址: https://pymud.readthedocs.org
7
7
  ### PyPi项目地址: https://pypi.org/project/pymud
@@ -23,9 +23,20 @@
23
23
  + Python拥有极为丰富的第三方库,能支持的第三方库,就能在PyMud中支持
24
24
  + 我自己还在玩,所以本客户端会持续进行更新:)
25
25
 
26
+ ### 哪些人适合使用PyMUD
27
+ + 比较熟悉Python语言,会使用Python写代码的 -> PyMUD是纯Python原生开发,不会有其他客户端对Python的支持能比得过PyMUD
28
+ + 虽不太熟悉Python语言,但有想法想学习Python语言的 -> 正好使用PyMUD玩北侠写脚本的过程中学习Python语言
29
+ + 觉得还有些功能现在所有客户端都没有的 -> 你有需求,我来增加,就是这么方便
30
+ + 觉得也想自己整一个定制客户端玩玩的 -> PyMUD完全开源,且除ui框架外全部都是一行一行代码自己写的,可以直接参考PyMUD的设计
31
+
26
32
  ## 版本更新信息
27
33
 
28
- ## 0.20.0 (2024-08-XX)
34
+ ### 0.20.1 (2024-11-16)
35
+ + 功能调整: 会话中触发器匹配实现进行部分调整,减少循环次数以提高响应速度
36
+ + 功能调整: #test / #show 触发器测试功能调整,现在会对使能的和未使能的触发器均进行匹配测试。其中,#show 命令仅测试,而 #test 命令会导致触发器真正响应。
37
+ + 功能新增: pymud对象新增了一个持续运行的1s的周期定时任务。该任务中会刷新页面显示。可以使用 session.application.addTimerTickCallback 和 session.application.removeTimerTickCallback 来注册和解除定时器回调。
38
+
39
+ ## 0.20.0 (2024-08-25)
29
40
  + 功能调整: 将模块主入口函数从__main__.py中移动到main.py中,以使可以在当前目录下,可直接使用pymud,也可使用python -m pymud启动
30
41
  + 功能调整: 使用argsparser标准模块来配置命令行,可以使用 pymud -h 查看命令行具体参数及说明
31
42
  + 功能新增: 命令行参数增加指定启动目录的功能,参数为 -s, --startup_dir。即可以从任意目录通过指定脚本目录方式启动PyMUD了。
@@ -37,10 +48,12 @@
37
48
  + 功能调整: 在没有session的时候,也可以执行#exit命令
38
49
  + 功能新增: #session 命令增加快捷创建会话功能,假如已有快捷菜单 世界->pkuxkx->newstart , 则可以通过 #session pkuxkx.newstart 直接创建该会话,效果等同于点击该菜单
39
50
  + 功能调整: 点击菜单创建会话时,若会话已存在,则将该会话切换为当前会话
40
- + 问题修复: 修复原unload方法不能正确卸载的问题
41
- + 功能新增: 主模块卸载现在既可以定义在__unload__方法中,也可以定义在unload方法中。可以根据自己喜好选择一个即可。
42
- + 功能调整: 模块加载和重新加载前,会自动调用模块的__unload__方法或unload方法(若有)
51
+ + 重大更新: 完全重写了模块的加载、卸载、重新加载方法,修复模块使用中的问题
52
+ + 功能调整: 现在只要将一个类型继承 IConfig 接口,即被识别为配置类型。这种类型在模块加载时会自动创建其实例。当然,名称为Configuration的类型也同样被认为是配置类型,保持向前兼容性。唯一要求是,该类型的构造函数允许仅传递一个session对象。
53
+ + 功能新增: 各类配置类型的卸载现在既可以定义在__unload__方法中,也可以定义在unload方法中。可以根据自己喜好选择一个即可。
54
+ + 功能调整: 各配置类型加载和重新加载前,会自动调用模块的__unload__方法或unload方法(若有)
43
55
  + 功能新增: Command基类增加__unload__方法和unload方法,二者在从会话中移除该 Command 时均会自动调用。自定义的Command子类应覆盖这两种方法中的一种方法,并在其中增加清除类型自行创建的 Trigger, Alias 等会话对象。这样,模块卸载时只要移除命令本身,在命令中新建的其他关联对象将被一同移除。
56
+ + 功能新增: 所有PyMUD基础对象类型及其子类型,包括 Alias, Trigger, Timer, Command, GMCPTrigger 及它们的子类型,在创建的时候会自动添加到会话中,无需再进行 addObject 等操作了
44
57
  + 问题修复: 修复部分正则表达式书写错误问题
45
58
  + 功能新增: Session类新增waitfor函数,用于执行一段代码后立即等待某个触发器的情况,简化原三行代码写法
46
59
 
@@ -60,11 +73,6 @@
60
73
  - 使用示例:
61
74
 
62
75
  ```Python
63
- # 所有对象均可以使用 addObject 直接添加到会话中,而不用管是什么具体类型
64
- session.addObject(Timer(...))
65
- session.addObject(Trigger(...))
66
- session.addObject(Alias(...))
67
-
68
76
  # 所有对象均可以使用 delObject 直接从会话中移除,会自动根据对象类型推断,无需通过函数名区分
69
77
  session.delObject(self.tri1)
70
78
  session.delObject(self.ali1)
@@ -78,7 +86,6 @@
78
86
  GMCPTrigger(session, xxx)
79
87
  ]
80
88
 
81
- session.addObjects(objs) # 可以直接将一个数组中所有对象添加到会话中,会自动判断各对象类别
82
89
  session.delObjects(objs) # 可以直接从会话中移除一个数组中的所有对象,会自动判断对象类别
83
90
  ```
84
91
 
@@ -86,6 +93,10 @@
86
93
  + 功能新增: Session的所有异步命令调用函数增加返回值,现在调用 session.exec_async, exec_command_async 等方法执行的内容若匹配为命令时,会返回最后最后一个 Command 对象的 execute 函数的返回值
87
94
  - 例如, result = await self.session.cmds.cmd_runto.execute('rt yz') 与 result = await self.session.exec_async('rt yz') 等价,返回值相同
88
95
  - 但 result = await self.session.exec_async('rt yz;dzt'),该返回的result 仅是 dzt 命令的 execute 的返回值。 rt yz 命令返回值被丢弃。
96
+ + 功能新增: 增加临时变量概念,变量名以下划线开头的为临时变量,此类变量不会被保存到 .mud 文件中。
97
+ + 功能新增: 为 BaseObject 基类的 self.session 增加了 Session 类型限定,现在自定义 Command 等时候,使用 self.session 时会有 IntelliSence 函数智能提示了,所有帮助说明已补全
98
+ + 问题修复: 修复 #var 等命令中,若含有中文则等号位置不对齐的问题
99
+ + 功能调整: 在 #tri 等命令中,当对象的 group 为空时,将不再显示 group 属性,减少无用信息
89
100
 
90
101
  ## 0.19.4 (2024-04-20)
91
102
  + 功能调整: info 现在 msg 恢复为可接受任何类型参数,不一定是 str
@@ -1,17 +1,17 @@
1
1
  [project]
2
2
 
3
3
  name = "pymud" # Required
4
- version = "0.20.0a4" # Required
4
+ version = "0.20.1" # Required
5
5
  description = "a MUD Client written in Python" # Optional
6
6
  readme = "README.md" # Optional
7
7
  requires-python = ">=3.7"
8
8
  license = {file = "LICENSE.txt"}
9
9
  keywords = ["MUD", "multi-user dungeon", "client"] # Optional
10
10
  authors = [
11
- {name = "newstart@pkuxkx", email = "crapex@crapex.cc" } # Optional
11
+ {name = "newstart@pkuxkx", email = "crapex@hotmail.com" } # Optional
12
12
  ]
13
13
  maintainers = [
14
- {name = "newstart@pkuxkx", email = "crapex@crapex.cc" } # Optional
14
+ {name = "newstart@pkuxkx", email = "crapex@hotmail.com" } # Optional
15
15
  ]
16
16
 
17
17
  classifiers = [ # Optional
@@ -19,8 +19,8 @@ classifiers = [ # Optional
19
19
  # 3 - Alpha
20
20
  # 4 - Beta
21
21
  # 5 - Production/Stable
22
- # "Development Status :: 5 - Production/Stable",
23
- "Development Status :: 3 - Alpha",
22
+ "Development Status :: 5 - Production/Stable",
23
+ # "Development Status :: 3 - Alpha",
24
24
  "Intended Audience :: End Users/Desktop",
25
25
  "Topic :: Games/Entertainment :: Multi-User Dungeons (MUD)",
26
26
  "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
@@ -1,5 +1,6 @@
1
1
  from .settings import Settings
2
2
  from .pymud import PyMudApp
3
+ from .modules import IConfig
3
4
  from .objects import CodeBlock, Alias, SimpleAlias, Trigger, SimpleTrigger, Command, SimpleCommand, Timer, SimpleTimer, GMCPTrigger
4
5
  from .extras import DotDict
5
6
  from .session import Session
@@ -7,5 +8,5 @@ from .logger import Logger
7
8
  from .main import main
8
9
 
9
10
  __all__ = [
10
- "PyMudApp", "Settings", "CodeBlock", "Alias", "SimpleAlias", "Trigger", "SimpleTrigger", "Command", "SimpleCommand", "Timer", "SimpleTimer", "GMCPTrigger", "Session", "PyMudApp", "DotDict", "Logger", "main"
11
+ "IConfig", "PyMudApp", "Settings", "CodeBlock", "Alias", "SimpleAlias", "Trigger", "SimpleTrigger", "Command", "SimpleCommand", "Timer", "SimpleTimer", "GMCPTrigger", "Session", "PyMudApp", "DotDict", "Logger", "main"
11
12
  ]
@@ -1,7 +1,7 @@
1
1
  import asyncio, webbrowser
2
2
 
3
3
  from prompt_toolkit.layout import AnyContainer, ConditionalContainer, Float, VSplit, HSplit, Window, WindowAlign, ScrollablePane, ScrollOffsets
4
- from prompt_toolkit.widgets import Button, Dialog, Label, MenuContainer, MenuItem, TextArea, SystemToolbar, Frame, RadioList
4
+ from prompt_toolkit.widgets import Button, Dialog, Label, MenuContainer, MenuItem, TextArea, SystemToolbar, Frame, RadioList
5
5
  from prompt_toolkit.layout.dimension import Dimension, D
6
6
  from prompt_toolkit import ANSI, HTML
7
7
  from prompt_toolkit.mouse_events import MouseEvent, MouseEventType
@@ -133,12 +133,14 @@ class LogSelectionDialog(BasicDialog):
133
133
  def __init__(self, text, values, modal=True):
134
134
  self._header_text = text
135
135
  self._selection_values = values
136
- self._radio_list = RadioList(values = self._selection_values)
136
+ self._itemsCount = len(values)
137
+ if len(values) > 0:
138
+ self._radio_list = RadioList(values = self._selection_values)
139
+ else:
140
+ self._radio_list = Label('无记录'.center(13))
137
141
  super().__init__('选择查看的记录', modal)
138
142
 
139
143
  def create_body(self) -> AnyContainer:
140
-
141
-
142
144
  body=HSplit([
143
145
  Label(text = self._header_text, dont_extend_height=True),
144
146
  self._radio_list
@@ -151,6 +153,9 @@ class LogSelectionDialog(BasicDialog):
151
153
  return [ok_button, cancel_button]
152
154
 
153
155
  def btn_ok_clicked(self):
154
- result = self._radio_list.current_value
155
- self.set_done(result)
156
+ if self._itemsCount:
157
+ result = self._radio_list.current_value
158
+ self.set_done(result)
159
+ else:
160
+ self.set_done(False)
156
161
 
@@ -1,8 +1,7 @@
1
1
  # External Libraries
2
2
  from unicodedata import east_asian_width
3
3
  from wcwidth import wcwidth
4
- from typing import Any
5
- import time, datetime
4
+ import time, re, logging
6
5
 
7
6
  from typing import Iterable
8
7
  from prompt_toolkit import ANSI
@@ -65,6 +64,10 @@ class MudFormatProcessor(Processor):
65
64
  self.FULL_BLOCKS = set("▂▃▅▆▇▄█")
66
65
  self.SINGLE_LINES = set("┌└├┬┼┴╭╰─")
67
66
  self.DOUBLE_LINES = set("╔╚╠╦╪╩═")
67
+ self.START_COLOR_REGX = re.compile(r"^\[[\d;]+m")
68
+ self.COLOR_REGX = re.compile(r"\[[\d;]+m")
69
+ self._color_start = ""
70
+ self._color_correction = False
68
71
 
69
72
  def width_correction(self, line: str) -> str:
70
73
  new_str = []
@@ -88,11 +91,36 @@ class MudFormatProcessor(Processor):
88
91
  def tab_correction(self, line: str):
89
92
  return line.replace("\t", " " * Settings.client["tabstop"])
90
93
 
94
+ def color_correction(self, line: str):
95
+ # 注:发现processer处理并非自上而下逐行处理的,因此不能使用这种颜色校正方式。
96
+ if self._color_correction:
97
+ other = self.COLOR_REGX.findall(line)
98
+
99
+ line = f"{self._color_start}{line}"
100
+ logging.debug(f"已校正增加颜色标志 {self._color_start}: {line}")
101
+
102
+ if other:
103
+ self._color_correction = False
104
+ self._color_start = ""
105
+ logging.debug(f"颜色校正结束: {line}")
106
+ else:
107
+ color = self.START_COLOR_REGX.findall(line)
108
+ if color:
109
+ other = self.COLOR_REGX.findall(line)
110
+ if len(other) == 1:
111
+ self._color_correction = True
112
+ self._color_start = color[0]
113
+ logging.debug(f"获取到一个颜色开头 {color[0]}: {line}")
114
+
115
+ return line
116
+
91
117
  def line_correction(self, line: str):
92
118
  # 处理\r符号(^M)
93
119
  line = self.return_correction(line)
94
120
  # 处理Tab(\r)符号(^I)
95
121
  line = self.tab_correction(line)
122
+ # 处理颜色跨行问题。发现processer处理并非自上而下逐行处理的,因此不能使用这种颜色校正方式。
123
+ # line = self.color_correction(line)
96
124
  # 美化(解决中文英文在Console中不对齐的问题)
97
125
  if Settings.client["beautify"]:
98
126
  line = self.width_correction(line)
@@ -430,9 +458,9 @@ class SessionBufferControl(BufferControl):
430
458
 
431
459
  if double_click:
432
460
  start = buffer.document.translate_row_col_to_index(position.y, 0)
433
- end = buffer.document.translate_row_col_to_index(position.y, 10000000)
461
+ end = buffer.document.translate_row_col_to_index(position.y + 1, 0) - 1
434
462
  buffer.cursor_position = start
435
- buffer.start_selection(selection_type=SelectionType.CHARACTERS)
463
+ buffer.start_selection(selection_type=SelectionType.LINES)
436
464
  buffer.cursor_position = end
437
465
 
438
466
  else:
@@ -1008,76 +1036,5 @@ class DotDict(dict):
1008
1036
  def __setstate__(self, state):
1009
1037
  self.update(state)
1010
1038
 
1011
- import importlib
1012
- import importlib.util
1013
-
1014
- class Plugin:
1015
- """
1016
- 插件管理类。对加载的插件文件进行管理。该类型由PyMudApp进行管理,无需人工创建。
1017
-
1018
- 有关插件的详细信息,请参见 `插件 <plugins.html>`_
1019
-
1020
- :param name: 插件的文件名, 如'myplugin.py'
1021
- :param location: 插件所在的目录。自动加载的插件包括PyMUD包目录下的plugins目录以及当前目录下的plugins目录
1022
-
1023
- """
1024
- def __init__(self, name, location):
1025
- self._plugin_file = name
1026
- self._plugin_loc = location
1027
-
1028
- self.reload()
1029
-
1030
- def reload(self):
1031
- "加载/重新加载插件对象"
1032
- #del self.modspec, self.mod
1033
- self.modspec = importlib.util.spec_from_file_location(self._plugin_file[:-3], self._plugin_loc)
1034
- self.mod = importlib.util.module_from_spec(self.modspec)
1035
- self.modspec.loader.exec_module(self.mod)
1036
-
1037
- self._app_init = self.mod.__dict__["PLUGIN_PYMUD_START"]
1038
- self._session_create = self.mod.__dict__["PLUGIN_SESSION_CREATE"]
1039
- self._session_destroy = self.mod.__dict__["PLUGIN_SESSION_DESTROY"]
1040
-
1041
- @property
1042
- def name(self):
1043
- "插件名称,由插件文件中的 PLUGIN_NAME 常量定义"
1044
- return self.mod.__dict__["PLUGIN_NAME"]
1045
-
1046
- @property
1047
- def desc(self):
1048
- "插件描述,由插件文件中的 PLUGIN_DESC 常量定义"
1049
- return self.mod.__dict__["PLUGIN_DESC"]
1050
-
1051
- @property
1052
- def help(self):
1053
- "插件帮助,由插件文件中的文档字符串定义"
1054
- return self.mod.__doc__
1055
-
1056
- def onAppInit(self, app):
1057
- """
1058
- PyMUD应用启动时对插件执行的操作,由插件文件中的 PLUGIN_PYMUD_START 函数定义
1059
-
1060
- :param app: 启动的 PyMudApp 对象实例
1061
- """
1062
- self._app_init(app)
1063
-
1064
- def onSessionCreate(self, session):
1065
- """
1066
- 新会话创建时对插件执行的操作,由插件文件中的 PLUGIN_SESSION_CREATE 函数定义
1067
-
1068
- :param session: 新创建的会话对象实例
1069
- """
1070
- self._session_create(session)
1071
-
1072
- def onSessionDestroy(self, session):
1073
- """
1074
- 会话关闭时(注意不是断开)对插件执行的操作,由插件文件中的 PLUGIN_SESSION_DESTROY 函数定义
1075
-
1076
- :param session: 所关闭的会话对象实例
1077
- """
1078
- self._session_destroy(session)
1079
1039
 
1080
- def __getattr__(self, __name: str) -> Any:
1081
- if hasattr(self.mod, __name):
1082
- return self.mod.__getattribute__(__name)
1083
1040
 
@@ -1,9 +1,10 @@
1
- import os, re, datetime, threading
1
+ import os, re, datetime, threading, pathlib
2
2
  from queue import SimpleQueue, Empty
3
+ from pathlib import Path
3
4
 
4
5
  class Logger:
5
6
  """
6
- PyMUD 的记录器类型,可用于会话中向文件记录数据
7
+ PyMUD 的记录器类型,可用于会话中向文件记录数据。记录文件保存在当前目录下的 log 子目录中
7
8
 
8
9
  :param name: 记录器名称,各记录器名称应保持唯一。记录器名称会作为记录文件名称的主要参数
9
10
  :param mode: 记录模式。可选模式包括 a, w, n 三种。
@@ -56,7 +57,12 @@ class Logger:
56
57
  now = datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
57
58
  filename = f"{self.name}.{now}.log"
58
59
 
59
- filename = os.path.abspath(filename)
60
+ logdir = Path.cwd().joinpath('log')
61
+ if not logdir.exists() or not logdir.is_dir():
62
+ logdir.mkdir()
63
+
64
+ filename = logdir.joinpath(filename)
65
+ #filename = os.path.abspath(filename)
60
66
  self._stream = open(filename, mode = mode, encoding = self._encoding, errors = self._errors)
61
67
  self._thread = t = threading.Thread(target=self._monitor)
62
68
  t.daemon = True
@@ -0,0 +1,188 @@
1
+
2
+ import importlib, importlib.util
3
+ from abc import ABC, ABCMeta
4
+ from typing import Any
5
+ from .objects import BaseObject, Command
6
+
7
+ class ModuleInfo:
8
+ """
9
+ 模块管理类。对加载的模块文件进行管理。该类型由Session类进行管理,无需人工创建和干预。
10
+
11
+ 有关模块的分类和使用的详细信息,请参见 `脚本 <scripts.html>`_
12
+
13
+ :param module_name: 模块的名称, 应与 import xxx 语法中的 xxx 保持一致
14
+ :param session: 加载/创建本模块的会话
15
+
16
+ """
17
+ def __init__(self, module_name: str, session):
18
+ self.session = session
19
+ self._name = module_name
20
+ self._ismainmodule = False
21
+ self.load()
22
+
23
+ def _load(self, reload = False):
24
+ result = True
25
+ if reload:
26
+ self._module = importlib.reload(self._module)
27
+ else:
28
+ self._module = importlib.import_module(self.name)
29
+ self._config = {}
30
+ for attr_name in dir(self._module):
31
+ attr = getattr(self._module, attr_name)
32
+ if isinstance(attr, type) and attr.__module__ == self._module.__name__:
33
+ if (attr_name == "Configuration") or issubclass(attr, IConfig):
34
+ try:
35
+ self._config[f"{self.name}.{attr_name}"] = attr(self.session, reload = reload)
36
+ self.session.info(f"配置对象 {self.name}.{attr_name} {'重新' if reload else ''}创建成功.")
37
+ except Exception as e:
38
+ result = False
39
+ self.session.error(f"配置对象 {self.name}.{attr_name} 创建失败. 错误信息为: {e}")
40
+ self._ismainmodule = (self._config != {})
41
+ return result
42
+
43
+ def _unload(self):
44
+ for key, config in self._config.items():
45
+ if isinstance(config, Command):
46
+ # Command 对象在从会话中移除时,自动调用其 unload 系列方法,因此不能产生递归
47
+ self.session.delObject(config)
48
+
49
+ else:
50
+
51
+ if hasattr(config, "__unload__"):
52
+ unload = getattr(config, "__unload__", None)
53
+ if callable(unload): unload()
54
+
55
+ if hasattr(config, "unload"):
56
+ unload = getattr(config, "unload", None)
57
+ if callable(unload): unload()
58
+
59
+ if isinstance(config, BaseObject):
60
+ self.session.delObject(config)
61
+
62
+ del config
63
+ self._config.clear()
64
+
65
+ def load(self):
66
+ "加载模块内容"
67
+ if self._load():
68
+ self.session.info(f"{'主' if self.ismainmodule else '从'}配置模块 {self.name} 加载完成.")
69
+ else:
70
+ self.session.error(f"{'主' if self.ismainmodule else '从'}配置模块 {self.name} 加载失败.")
71
+
72
+ def unload(self):
73
+ "卸载模块内容"
74
+ self._unload()
75
+ self._loaded = False
76
+ self.session.info(f"{'主' if self.ismainmodule else '从'}配置模块 {self.name} 卸载完成.")
77
+
78
+ def reload(self):
79
+ "模块文件更新后调用,重新加载已加载的模块内容"
80
+ self._unload()
81
+ self._load(reload = True)
82
+ self.session.info(f"{'主' if self.ismainmodule else '从'}配置模块 {self.name} 重新加载完成.")
83
+
84
+ @property
85
+ def name(self):
86
+ "只读属性,模块名称"
87
+ return self._name
88
+
89
+ @property
90
+ def module(self):
91
+ "只读属性,模块文件的 ModuleType 对象"
92
+ return self._module
93
+
94
+ @property
95
+ def config(self):
96
+ "只读字典属性,根据模块文件 ModuleType 对象创建的其中名为 Configuration 的类型或继承自 IConfig 的子类型实例(若有)"
97
+ return self._config
98
+
99
+ @property
100
+ def ismainmodule(self):
101
+ "只读属性,区分是否主模块(即包含具体config的模块)"
102
+ return self._ismainmodule
103
+
104
+ class IConfig(metaclass = ABCMeta):
105
+ """
106
+ 用于提示PyMUD应用是否自动创建该配置类型的基础类(模拟接口)。
107
+
108
+ 继承 IConfig 类型让应用自动管理该类型,唯一需要的是,构造函数中,仅存在一个必须指定的参数 Session。
109
+
110
+ 在应用自动创建 IConfig 实例时,除 session 参数外,还会传递一个 reload 参数 (bool类型),表示是首次加载还是重新加载特性。
111
+ 可以从kwargs 中获取该参数,并针对性的设计相应代码。例如,重新加载相关联的其他模块等。
112
+ """
113
+ def __init__(self, session, *args, **kwargs):
114
+ self.session = session
115
+
116
+ def __unload__(self):
117
+ if self.session:
118
+ self.session.delObject(self)
119
+
120
+ class Plugin:
121
+ """
122
+ 插件管理类。对加载的插件文件进行管理。该类型由PyMudApp进行管理,无需人工创建。
123
+
124
+ 有关插件的详细信息,请参见 `插件 <plugins.html>`_
125
+
126
+ :param name: 插件的文件名, 如'myplugin.py'
127
+ :param location: 插件所在的目录。自动加载的插件包括PyMUD包目录下的plugins目录以及当前目录下的plugins目录
128
+
129
+ """
130
+ def __init__(self, name, location):
131
+ self._plugin_file = name
132
+ self._plugin_loc = location
133
+
134
+ self.reload()
135
+
136
+ def reload(self):
137
+ "加载/重新加载插件对象"
138
+ #del self.modspec, self.mod
139
+ self.modspec = importlib.util.spec_from_file_location(self._plugin_file[:-3], self._plugin_loc)
140
+ self.mod = importlib.util.module_from_spec(self.modspec)
141
+ self.modspec.loader.exec_module(self.mod)
142
+
143
+ self._app_init = self.mod.__dict__["PLUGIN_PYMUD_START"]
144
+ self._session_create = self.mod.__dict__["PLUGIN_SESSION_CREATE"]
145
+ self._session_destroy = self.mod.__dict__["PLUGIN_SESSION_DESTROY"]
146
+
147
+ @property
148
+ def name(self):
149
+ "插件名称,由插件文件中的 PLUGIN_NAME 常量定义"
150
+ return self.mod.__dict__["PLUGIN_NAME"]
151
+
152
+ @property
153
+ def desc(self):
154
+ "插件描述,由插件文件中的 PLUGIN_DESC 常量定义"
155
+ return self.mod.__dict__["PLUGIN_DESC"]
156
+
157
+ @property
158
+ def help(self):
159
+ "插件帮助,由插件文件中的文档字符串定义"
160
+ return self.mod.__doc__
161
+
162
+ def onAppInit(self, app):
163
+ """
164
+ PyMUD应用启动时对插件执行的操作,由插件文件中的 PLUGIN_PYMUD_START 函数定义
165
+
166
+ :param app: 启动的 PyMudApp 对象实例
167
+ """
168
+ self._app_init(app)
169
+
170
+ def onSessionCreate(self, session):
171
+ """
172
+ 新会话创建时对插件执行的操作,由插件文件中的 PLUGIN_SESSION_CREATE 函数定义
173
+
174
+ :param session: 新创建的会话对象实例
175
+ """
176
+ self._session_create(session)
177
+
178
+ def onSessionDestroy(self, session):
179
+ """
180
+ 会话关闭时(注意不是断开)对插件执行的操作,由插件文件中的 PLUGIN_SESSION_DESTROY 函数定义
181
+
182
+ :param session: 所关闭的会话对象实例
183
+ """
184
+ self._session_destroy(session)
185
+
186
+ def __getattr__(self, __name: str) -> Any:
187
+ if hasattr(self.mod, __name):
188
+ return self.mod.__getattribute__(__name)