pymud 0.21.2a2__tar.gz → 0.21.3__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 (28) hide show
  1. {pymud-0.21.2a2 → pymud-0.21.3}/PKG-INFO +13 -6
  2. {pymud-0.21.2a2 → pymud-0.21.3}/README.md +12 -5
  3. {pymud-0.21.2a2 → pymud-0.21.3}/pyproject.toml +1 -1
  4. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/extras.py +117 -75
  5. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/objects.py +7 -5
  6. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/pymud.py +6 -6
  7. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/session.py +8 -13
  8. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud.egg-info/PKG-INFO +13 -6
  9. {pymud-0.21.2a2 → pymud-0.21.3}/LICENSE.txt +0 -0
  10. {pymud-0.21.2a2 → pymud-0.21.3}/setup.cfg +0 -0
  11. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/__init__.py +0 -0
  12. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/__main__.py +0 -0
  13. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/decorators.py +0 -0
  14. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/dialogs.py +0 -0
  15. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/i18n.py +0 -0
  16. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/lang/i18n_chs.py +0 -0
  17. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/lang/i18n_eng.py +0 -0
  18. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/logger.py +0 -0
  19. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/main.py +0 -0
  20. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/modules.py +0 -0
  21. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/pkuxkx.py +0 -0
  22. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/protocol.py +0 -0
  23. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud/settings.py +0 -0
  24. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud.egg-info/SOURCES.txt +0 -0
  25. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud.egg-info/dependency_links.txt +0 -0
  26. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud.egg-info/entry_points.txt +0 -0
  27. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud.egg-info/requires.txt +0 -0
  28. {pymud-0.21.2a2 → pymud-0.21.3}/src/pymud.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pymud
3
- Version: 0.21.2a2
3
+ Version: 0.21.3
4
4
  Summary: a MUD Client written in Python
5
5
  Author-email: "newstart@pkuxkx" <crapex@hotmail.com>
6
6
  Maintainer-email: "newstart@pkuxkx" <crapex@hotmail.com>
@@ -44,11 +44,11 @@ Dynamic: license-file
44
44
 
45
45
  ### 北大侠客行Mud (www.pkuxkx.net),最好的中文Mud游戏!
46
46
  ### PyMUD是我为了更好的玩北大侠客行,特意自行开发的MUD客户端。PyMUD具有以下特点:
47
- + 原生Python开发,除prompt-toolkit及其依赖库(wcwidth, pygment, pyperclip)外,不需要其他第三方库支持
47
+ + 原生Python开发,除prompt-toolkit及其依赖库 wcwidth, pygment, pyperclip 外,不需要其他第三方库支持
48
48
  + 原生Python的asyncio实现的通信协议处理,支持async/await语法在脚本中直接应用,脚本实现的同步异步两种模式由你自己选择
49
- + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作)
49
+ + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作),极低资源需求,在单核1GB内存的Linux VPS上也可流畅运行
50
50
  + 支持分屏显示,在数据快速滚动的时候,上半屏保持不动,以确保不错过信息
51
- + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题(因为我没有走遍所有地方,不敢保证100%)
51
+ + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题
52
52
  + 真正的支持多session会话,支持命令或鼠标切换会话
53
53
  + 原生支持多种服务器端编码方式,不论是GBK、BIG5、还是UTF-8
54
54
  + 支持NWAS、MTTS协商,支持GMCP、MSDP、MSSP协议
@@ -66,10 +66,17 @@ Dynamic: license-file
66
66
 
67
67
  ## 版本更新信息
68
68
 
69
- ### 0.22.0 (2025-05-31) 本版传错了,已无法使用。
69
+ ### 0.21.3 2025-06-02)
70
+
71
+ + 问题修复: 修复了当缓存行数超过规定值时,由于代码错误导致清屏的问题。
72
+ + 功能增强: 增加清除任务时的异常保护,此时产生asyncio.CancelledError异常为正常现象,因此捕获后禁止异常处理。
73
+ + 功能增强: 对reset进行了异常提示保护,此时产生异常(大部分为asyncio.CancelledError)为正常现象,因此捕获后禁止异常处理。
74
+
75
+ ### 0.21.2 (2025-06-01)
70
76
 
71
77
  + 问题修复: 修复了当自动重连启动时,即使会话关闭了,也会自动重连的问题。
72
- + 实现调整: 重写了专用的SessionBuffer与SessionBufferControl,降低内存使用。
78
+ + 实现调整: 重写了专用的会话缓冲、记录缓冲与PyMud缓冲显示控制器,在prompt_toolkit的原Buffer和BufferControl的基础仅提供了PYMUD所需的基础功能,以降低内存占用。
79
+ 经测试,当前内存基本稳定,视会话数量和脚本情况差异,维持在几百兆左右(500M以下),且不会有大幅波动。重写后,低配置的VPS也可以稳定运行PyMUD。
73
80
 
74
81
  ### 0.21.0 (2025-05-20)
75
82
 
@@ -12,11 +12,11 @@
12
12
 
13
13
  ### 北大侠客行Mud (www.pkuxkx.net),最好的中文Mud游戏!
14
14
  ### PyMUD是我为了更好的玩北大侠客行,特意自行开发的MUD客户端。PyMUD具有以下特点:
15
- + 原生Python开发,除prompt-toolkit及其依赖库(wcwidth, pygment, pyperclip)外,不需要其他第三方库支持
15
+ + 原生Python开发,除prompt-toolkit及其依赖库 wcwidth, pygment, pyperclip 外,不需要其他第三方库支持
16
16
  + 原生Python的asyncio实现的通信协议处理,支持async/await语法在脚本中直接应用,脚本实现的同步异步两种模式由你自己选择
17
- + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作)
17
+ + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作),极低资源需求,在单核1GB内存的Linux VPS上也可流畅运行
18
18
  + 支持分屏显示,在数据快速滚动的时候,上半屏保持不动,以确保不错过信息
19
- + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题(因为我没有走遍所有地方,不敢保证100%)
19
+ + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题
20
20
  + 真正的支持多session会话,支持命令或鼠标切换会话
21
21
  + 原生支持多种服务器端编码方式,不论是GBK、BIG5、还是UTF-8
22
22
  + 支持NWAS、MTTS协商,支持GMCP、MSDP、MSSP协议
@@ -34,10 +34,17 @@
34
34
 
35
35
  ## 版本更新信息
36
36
 
37
- ### 0.22.0 (2025-05-31) 本版传错了,已无法使用。
37
+ ### 0.21.3 2025-06-02)
38
+
39
+ + 问题修复: 修复了当缓存行数超过规定值时,由于代码错误导致清屏的问题。
40
+ + 功能增强: 增加清除任务时的异常保护,此时产生asyncio.CancelledError异常为正常现象,因此捕获后禁止异常处理。
41
+ + 功能增强: 对reset进行了异常提示保护,此时产生异常(大部分为asyncio.CancelledError)为正常现象,因此捕获后禁止异常处理。
42
+
43
+ ### 0.21.2 (2025-06-01)
38
44
 
39
45
  + 问题修复: 修复了当自动重连启动时,即使会话关闭了,也会自动重连的问题。
40
- + 实现调整: 重写了专用的SessionBuffer与SessionBufferControl,降低内存使用。
46
+ + 实现调整: 重写了专用的会话缓冲、记录缓冲与PyMud缓冲显示控制器,在prompt_toolkit的原Buffer和BufferControl的基础仅提供了PYMUD所需的基础功能,以降低内存占用。
47
+ 经测试,当前内存基本稳定,视会话数量和脚本情况差异,维持在几百兆左右(500M以下),且不会有大幅波动。重写后,低配置的VPS也可以稳定运行PyMUD。
41
48
 
42
49
  ### 0.21.0 (2025-05-20)
43
50
 
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
 
3
3
  name = "pymud" # Required
4
- version = "0.21.2a2" # Required
4
+ version = "0.21.3" # Required
5
5
  description = "a MUD Client written in Python" # Optional
6
6
  readme = "README.md" # Optional
7
7
  requires-python = ">=3.8"
@@ -1,9 +1,10 @@
1
1
  # External Libraries
2
+ from functools import lru_cache
2
3
  from unicodedata import east_asian_width
3
4
  from wcwidth import wcwidth
4
5
  from dataclasses import dataclass
5
- import time, re, logging
6
-
6
+ import time, re, logging, linecache, os
7
+ from typing import Optional, List, Dict
7
8
  from typing import Iterable, NamedTuple, Optional, Union, Tuple
8
9
  from prompt_toolkit import ANSI
9
10
  from prompt_toolkit.application import get_app
@@ -236,7 +237,7 @@ class VSplitWindow(Window):
236
237
  below = total - upper - 1
237
238
 
238
239
  #if isNotMargin:
239
- if isinstance(self.content, SessionBufferControl):
240
+ if isinstance(self.content, PyMudBufferControl):
240
241
  b = self.content.buffer
241
242
  if not b:
242
243
  return y
@@ -379,7 +380,7 @@ class VSplitWindow(Window):
379
380
  if info is None:
380
381
  return
381
382
 
382
- if isinstance(self.content, SessionBufferControl):
383
+ if isinstance(self.content, PyMudBufferControl):
383
384
  b = self.content.buffer
384
385
  if not b:
385
386
  return
@@ -396,7 +397,7 @@ class VSplitWindow(Window):
396
397
  if info is None:
397
398
  return
398
399
 
399
- if isinstance(self.content, SessionBufferControl):
400
+ if isinstance(self.content, PyMudBufferControl):
400
401
  b = self.content.buffer
401
402
  if not b:
402
403
  return
@@ -520,6 +521,7 @@ class EasternMenuContainer(MenuContainer):
520
521
 
521
522
  return Window(FormattedTextControl(get_text_fragments), style="class:menu")
522
523
 
524
+
523
525
  @dataclass
524
526
  class SessionSelectionState:
525
527
  start_row: int = -1
@@ -549,9 +551,53 @@ class SessionSelectionState:
549
551
  return self.end_row - self.start_row + 1
550
552
  else:
551
553
  return 0
552
-
553
554
 
554
- class SessionBuffer:
555
+
556
+ class BufferBase:
557
+ def __init__(self, name, newline = "\n", max_buffered_lines = 10000) -> None:
558
+ self.name = name
559
+ self.newline = newline
560
+ self.max_buffered_lines = max_buffered_lines
561
+ self.start_lineno = -1
562
+ self.selection = SessionSelectionState(-1, -1, -1, -1)
563
+
564
+ def clear(self):
565
+ pass
566
+
567
+ @property
568
+ def lineCount(self) -> int:
569
+ return 0
570
+
571
+ def getLine(self, lineno: int) -> str:
572
+ return ""
573
+
574
+ # 获取指定某行到某行的内容。当start未设置时,从首行开始。当end未设置时,到最后一行结束。
575
+ # 注意判断首位顺序逻辑,以及给定参数是否越界
576
+ def selection_range_at_line(self, lineno: int) -> Optional[Tuple[int, int]]:
577
+ if self.selection.is_valid():
578
+ if self.selection.rows > 1:
579
+ if lineno == self.selection.start_row:
580
+ return (self.selection.start_col, len(self.getLine(lineno)) - 1)
581
+ elif lineno == self.selection.end_row:
582
+ return (0, self.selection.end_col)
583
+ elif lineno > self.selection.start_row and lineno < self.selection.end_row:
584
+ return (0, len(self.getLine(lineno)) - 1)
585
+
586
+ elif self.selection.rows == 1:
587
+ if lineno == self.selection.start_row:
588
+ return (self.selection.start_col, self.selection.end_col)
589
+
590
+ return None
591
+
592
+ def exit_selection(self):
593
+ self.selection = SessionSelectionState(-1, -1, -1, -1)
594
+
595
+ def nosplit(self):
596
+ self.start_lineno = -1
597
+ get_app().invalidate()
598
+
599
+
600
+ class SessionBuffer(BufferBase):
555
601
  def __init__(
556
602
  self,
557
603
  name,
@@ -559,13 +605,10 @@ class SessionBuffer:
559
605
  max_buffered_lines = 10000,
560
606
  ) -> None:
561
607
 
562
- self.name = name
563
- self.lines = []
564
- self.newline = newline
565
- self.isnewline = True
566
- self.max_buffered_lines = max_buffered_lines
567
- self.selection = SessionSelectionState(-1, -1, -1, -1)
568
- self.start_lineno = -1
608
+ super().__init__(name, newline, max_buffered_lines)
609
+
610
+ self._lines : List[str] = []
611
+ self._isnewline = True
569
612
 
570
613
  def append(self, line: str):
571
614
  """
@@ -578,25 +621,25 @@ class SessionBuffer:
578
621
  line = line.rstrip(self.newline)
579
622
  newline_after_append = True
580
623
  if not self.newline in line:
581
- if self.isnewline:
582
- self.lines.append(line)
624
+ if self._isnewline:
625
+ self._lines.append(line)
583
626
  else:
584
- self.lines[-1] += line
627
+ self._lines[-1] += line
585
628
 
586
629
  else:
587
630
  lines = line.split(self.newline)
588
- if self.isnewline:
589
- self.lines.extend(lines)
631
+ if self._isnewline:
632
+ self._lines.extend(lines)
590
633
  else:
591
- self.lines[-1] += lines[0]
592
- self.lines.extend(lines[1:])
634
+ self._lines[-1] += lines[0]
635
+ self._lines.extend(lines[1:])
593
636
 
594
- self.isnewline = newline_after_append
637
+ self._isnewline = newline_after_append
595
638
 
596
639
  ## limit buffered lines
597
- if len(self.lines) > self.max_buffered_lines:
598
- diff = self.max_buffered_lines - len(self.lines)
599
- del self.lines[:diff]
640
+ if len(self._lines) > self.max_buffered_lines:
641
+ diff = len(self._lines) - self.max_buffered_lines
642
+ del self._lines[:diff]
600
643
  ## adjust selection
601
644
  if self.selection.start_row >= 0:
602
645
  self.selection.start_row -= diff
@@ -605,68 +648,60 @@ class SessionBuffer:
605
648
  get_app().invalidate()
606
649
 
607
650
  def clear(self):
608
- self.lines.clear()
651
+ self._lines.clear()
609
652
  self.selection = SessionSelectionState(-1, -1, -1, -1)
610
653
 
611
654
  get_app().invalidate()
612
655
 
613
- def loadfile(self, filename, encoding = 'utf-8', errors = 'ignore'):
614
- with open(filename, 'r', encoding = encoding, errors = errors) as fp:
615
- lines = fp.readlines()
616
- self.clear()
617
- self.lines.extend(lines)
618
-
619
- get_app().invalidate()
620
-
621
656
  @property
622
657
  def lineCount(self):
623
- return len(self.lines)
658
+ return len(self._lines)
624
659
 
625
- def getLine(self, lineno):
626
- if lineno < 0 or lineno >= len(self.lines):
660
+ def getLine(self, lineno: int):
661
+ if lineno < 0 or lineno >= len(self._lines):
627
662
  return ""
628
- return self.lines[lineno]
663
+ return self._lines[lineno]
629
664
 
630
- # 获取指定某行到某行的内容。当start未设置时,从首行开始。当end未设置时,到最后一行结束。
631
- # 注意判断首位顺序逻辑,以及给定参数是否越界
632
- def getLines(self, start = None, end = None):
633
- if start is None:
634
- start = 0
635
- if end is None:
636
- end = len(self.lines) - 1
637
- if start < 0:
638
- start = 0
639
- if end >= len(self.lines):
640
- end = len(self.lines) - 1
641
- if start > end:
642
- return []
643
- return self.lines[start:end+1]
644
-
645
- def selection_range_at_line(self, lineno):
646
- if self.selection.is_valid():
647
- if self.selection.rows > 1:
648
- if lineno == self.selection.start_row:
649
- return (self.selection.start_col, len(self.lines[lineno]) - 1)
650
- elif lineno == self.selection.end_row:
651
- return (0, self.selection.end_col)
652
- elif lineno > self.selection.start_row and lineno < self.selection.end_row:
653
- return (0, len(self.lines[lineno]) - 1)
654
665
 
655
- elif self.selection.rows == 1:
656
- if lineno == self.selection.start_row:
657
- return (self.selection.start_col, self.selection.end_col)
666
+ class LogFileBuffer(BufferBase):
667
+ def __init__(
668
+ self,
669
+ name,
670
+ filepath: Optional[str] = None,
671
+ ) -> None:
658
672
 
659
- return None
673
+ super().__init__(name)
674
+ self._lines : Dict[int, str] = {}
675
+ self.loadfile(filepath)
676
+
677
+ def loadfile(self, filepath: Optional[str] = None):
678
+ if filepath and os.path.exists(filepath):
679
+ self.filepath = filepath
680
+ else:
681
+ self.filepath = None
660
682
 
661
- def exit_selection(self):
662
- self.selection = SessionSelectionState(-1, -1, -1, -1)
683
+ def clear(self):
684
+ self.filepath = None
663
685
 
664
- def nosplit(self):
665
- self.start_lineno = -1
666
- get_app().invalidate()
686
+ @property
687
+ def lineCount(self):
688
+ if not self.filepath or not os.path.exists(self.filepath):
689
+ return 0
690
+
691
+ with open(self.filepath, 'r', encoding = 'utf-8', errors = 'ignore') as fp:
692
+ return sum(1 for _ in fp)
693
+
694
+ def getLine(self, lineno: int):
695
+ if not self.filepath or not os.path.exists(self.filepath):
696
+ return ""
667
697
 
668
- class SessionBufferControl(UIControl):
669
- def __init__(self, buffer: Optional[SessionBuffer]) -> None:
698
+ return linecache.getline(self.filepath, lineno).rstrip(self.newline)
699
+
700
+ def __del__(self):
701
+ self._lines.clear()
702
+
703
+ class PyMudBufferControl(UIControl):
704
+ def __init__(self, buffer: Optional[BufferBase]) -> None:
670
705
  self.buffer = buffer
671
706
 
672
707
  # 为MUD显示进行校正的处理,包括对齐校正,换行颜色校正等
@@ -685,7 +720,7 @@ class SessionBufferControl(UIControl):
685
720
  # Default reset. (Doesn't have to be implemented.)
686
721
  pass
687
722
 
688
- def preferred_width(self, max_available_width: int) -> int | None:
723
+ def preferred_width(self, max_available_width: int) -> Optional[int]:
689
724
  return None
690
725
 
691
726
  def is_focusable(self) -> bool:
@@ -746,10 +781,14 @@ class SessionBufferControl(UIControl):
746
781
  def get_line(i: int) -> StyleAndTextTuples:
747
782
  line = buffer.getLine(i)
748
783
  # 颜色校正
784
+ SEARCH_LINES = 10
749
785
  thislinecolors = len(self.AVAI_COLOR_REGX.findall(line))
750
786
  if thislinecolors == 0:
751
787
  lineno = i - 1
752
- while lineno >= 0:
788
+ search = 0
789
+ while lineno >= 0 and search < SEARCH_LINES:
790
+ search += 1
791
+
753
792
  lastline = buffer.getLine(lineno)
754
793
  allcolors = self.ALL_COLOR_REGX.findall(lastline)
755
794
 
@@ -885,6 +924,9 @@ class SessionBufferControl(UIControl):
885
924
  else:
886
925
  # Don't handle scroll events here.
887
926
  return NotImplemented
927
+ else:
928
+ # Don't handle scroll events here.
929
+ return NotImplemented
888
930
 
889
931
  # Not focused, but focusing on click events.
890
932
  else:
@@ -793,12 +793,14 @@ class Command(MatchObject):
793
793
  """
794
794
  复位命令,并取消和清除所有本对象管理的任务。
795
795
  """
796
+ try:
797
+ super().reset()
796
798
 
797
- super().reset()
798
-
799
- for task in list(self._tasks):
800
- if isinstance(task, asyncio.Task) and (not task.done()):
801
- self.remove_task(task)
799
+ for task in list(self._tasks):
800
+ if isinstance(task, asyncio.Task) and (not task.done()):
801
+ self.remove_task(task)
802
+ except:
803
+ pass
802
804
 
803
805
  async def execute(self, cmd, *args, **kwargs) -> Any:
804
806
  """
@@ -37,7 +37,7 @@ from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
37
37
  from wcwidth import wcwidth, wcswidth
38
38
 
39
39
  from .objects import CodeBlock
40
- from .extras import SessionBuffer, SessionBufferControl, EasternMenuContainer, VSplitWindow, DotDict, MenuItem
40
+ from .extras import BufferBase, LogFileBuffer, SessionBuffer, PyMudBufferControl, EasternMenuContainer, VSplitWindow, DotDict, MenuItem
41
41
  from .modules import Plugin
42
42
  from .session import Session
43
43
  from .settings import Settings
@@ -164,7 +164,7 @@ class PyMudApp:
164
164
  self.logFileShown = '' # 记录页显示的记录文件名
165
165
  #self.logSessionBuffer = SessionBuffer()
166
166
  #self.logSessionBuffer.name = "LOGBUFFER"
167
- self.logSessionBuffer = SessionBuffer("LOGBUFFER", max_buffered_lines = -1)
167
+ self.logSessionBuffer = LogFileBuffer("LOGBUFFER")
168
168
 
169
169
  self.load_plugins()
170
170
 
@@ -218,7 +218,7 @@ class PyMudApp:
218
218
  show_cursor=False
219
219
  )
220
220
 
221
- self.consoleView = SessionBufferControl(
221
+ self.consoleView = PyMudBufferControl(
222
222
  buffer = None,
223
223
  )
224
224
 
@@ -398,7 +398,7 @@ class PyMudApp:
398
398
  else:
399
399
  b = None
400
400
 
401
- if isinstance(b, SessionBuffer):
401
+ if isinstance(b, BufferBase):
402
402
  if lines < 0:
403
403
  if b.start_lineno < 0:
404
404
  self.console._scroll_up()
@@ -659,7 +659,7 @@ class PyMudApp:
659
659
  if os.path.exists(filename):
660
660
  lock = threading.RLock()
661
661
  lock.acquire()
662
- self.logSessionBuffer.loadfile(filename, encoding = 'utf-8', errors = 'ignore')
662
+ self.logSessionBuffer.loadfile(filename)
663
663
  lock.release()
664
664
 
665
665
  #self.logSessionBuffer.cursor_position = len(self.logSessionBuffer.text)
@@ -751,7 +751,7 @@ class PyMudApp:
751
751
 
752
752
  elif self.showLog:
753
753
  b = self.logSessionBuffer
754
- b.exit_selection()
754
+ #b.exit_selection()
755
755
  #b.cursor_position = len(b.text)
756
756
  #b.start_lineno = -1
757
757
  b.nosplit()
@@ -571,16 +571,6 @@ class Session:
571
571
  self._line_count += 1
572
572
  self.log.log(self.newline_cli)
573
573
 
574
- def clear_half(self):
575
- """
576
- 清除半数缓冲。 **脚本中无需调用。**
577
-
578
- 半数的数量由 Settings.client['buffer_lines'] 确定,默认为5000行。
579
- """
580
- # if (Settings.client["buffer_lines"] > 0) and (self._line_count >= 2 * Settings.client["buffer_lines"]) and self.buffer.document.is_cursor_at_the_end:
581
- # self._line_count = self.buffer.clear_half()
582
- pass
583
-
584
574
  def feed_data(self, data) -> None:
585
575
  """
586
576
  由协议对象调用,将收到的远程数据加入会话缓冲。永远只会传递1个字节的数据,以bytes形式。 **脚本中无需调用。**
@@ -695,7 +685,6 @@ class Session:
695
685
 
696
686
  # 将数据写入缓存添加到此处
697
687
  if len(self.display_line) > 0:
698
- self.clear_half()
699
688
  self.writetobuffer(self.display_line)
700
689
 
701
690
  def set_exception(self, exc: Exception):
@@ -747,8 +736,14 @@ class Session:
747
736
  :param task: 由本会话管理的一个 asyncio.Task 对象
748
737
  :param msg: 本意是用来反馈 task.cancel() 时的消息,但为了保持兼容低版本Python环境,该参数并未使用。
749
738
  """
750
- result = task.cancel()
751
- self._tasks.discard(task)
739
+
740
+ result = True
741
+ try:
742
+ result = task.cancel()
743
+ self._tasks.discard(task)
744
+
745
+ except asyncio.CancelledError:
746
+ pass
752
747
 
753
748
  return result
754
749
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pymud
3
- Version: 0.21.2a2
3
+ Version: 0.21.3
4
4
  Summary: a MUD Client written in Python
5
5
  Author-email: "newstart@pkuxkx" <crapex@hotmail.com>
6
6
  Maintainer-email: "newstart@pkuxkx" <crapex@hotmail.com>
@@ -44,11 +44,11 @@ Dynamic: license-file
44
44
 
45
45
  ### 北大侠客行Mud (www.pkuxkx.net),最好的中文Mud游戏!
46
46
  ### PyMUD是我为了更好的玩北大侠客行,特意自行开发的MUD客户端。PyMUD具有以下特点:
47
- + 原生Python开发,除prompt-toolkit及其依赖库(wcwidth, pygment, pyperclip)外,不需要其他第三方库支持
47
+ + 原生Python开发,除prompt-toolkit及其依赖库 wcwidth, pygment, pyperclip 外,不需要其他第三方库支持
48
48
  + 原生Python的asyncio实现的通信协议处理,支持async/await语法在脚本中直接应用,脚本实现的同步异步两种模式由你自己选择
49
- + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作)
49
+ + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作),极低资源需求,在单核1GB内存的Linux VPS上也可流畅运行
50
50
  + 支持分屏显示,在数据快速滚动的时候,上半屏保持不动,以确保不错过信息
51
- + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题(因为我没有走遍所有地方,不敢保证100%)
51
+ + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题
52
52
  + 真正的支持多session会话,支持命令或鼠标切换会话
53
53
  + 原生支持多种服务器端编码方式,不论是GBK、BIG5、还是UTF-8
54
54
  + 支持NWAS、MTTS协商,支持GMCP、MSDP、MSSP协议
@@ -66,10 +66,17 @@ Dynamic: license-file
66
66
 
67
67
  ## 版本更新信息
68
68
 
69
- ### 0.22.0 (2025-05-31) 本版传错了,已无法使用。
69
+ ### 0.21.3 2025-06-02)
70
+
71
+ + 问题修复: 修复了当缓存行数超过规定值时,由于代码错误导致清屏的问题。
72
+ + 功能增强: 增加清除任务时的异常保护,此时产生asyncio.CancelledError异常为正常现象,因此捕获后禁止异常处理。
73
+ + 功能增强: 对reset进行了异常提示保护,此时产生异常(大部分为asyncio.CancelledError)为正常现象,因此捕获后禁止异常处理。
74
+
75
+ ### 0.21.2 (2025-06-01)
70
76
 
71
77
  + 问题修复: 修复了当自动重连启动时,即使会话关闭了,也会自动重连的问题。
72
- + 实现调整: 重写了专用的SessionBuffer与SessionBufferControl,降低内存使用。
78
+ + 实现调整: 重写了专用的会话缓冲、记录缓冲与PyMud缓冲显示控制器,在prompt_toolkit的原Buffer和BufferControl的基础仅提供了PYMUD所需的基础功能,以降低内存占用。
79
+ 经测试,当前内存基本稳定,视会话数量和脚本情况差异,维持在几百兆左右(500M以下),且不会有大幅波动。重写后,低配置的VPS也可以稳定运行PyMUD。
73
80
 
74
81
  ### 0.21.0 (2025-05-20)
75
82
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes